> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# v0.11.0

Released: October 28, 2026

This release is about secrets. Each service reads the shared secrets and its own, on every provider, and the cloud permissions follow the same rule. Azure gets a Key Vault per service, and the gateway reads its secrets when it starts. Existing environments upgrade with two new commands.

***

## Secrets per service

- Each service reads two scopes: shared and its own.
- When a key is in both, the service's own value wins. This works the same locally and on every provider.
- Both scopes are read in parallel.
- A secret that doesn't exist is "not found". Access and network problems are reported as errors.
- One cache for every provider: 5 minutes in the cloud, 1 minute locally. URLs are never cached.

## Auth secrets

- The JWT signing keys, the refresh token secret, `BCRYPT_ROUNDS` and `ADMIN_EMAILS` live in the auth service's scope. Only the auth service reads them.
- `cloud-secrets:push` keeps an environment's existing keys, so your users stay logged in.
- `cloud-secrets:set`, `get` and `remove` find these keys in the auth service's scope.
- The gateway trust token and the service API keys are shared. Every service checks them.

## Cloud permissions

- **GCP and AWS:** each service's account reads the shared secrets and its own. Names are matched exactly, so `auth` and `auth-service` stay apart.
- **Azure:** each backend service gets its own Key Vault next to the shared one. Its identity reads the shared vault and its own.
- **AWS:** the role that starts containers reads the shared secrets and each service's database URL. The database setup tasks have a role of their own.
- **Reserved names:** `shared`, `secrets` and `kv` can't be service names, and neither can names starting with `shared-`.

## Gateway secrets at startup

The gateway image holds no secrets. Its config references them (`{vault://env/redis-password}`), and the gateway reads them from its environment when it starts.

- **Locally:** docker-compose passes them from the root `.env`.
- **GCP:** Cloud Run sets them from Secret Manager.
- **AWS:** the task definition injects them.
- **Azure:** App Service reads them from Key Vault. `infra:deploy-kong` waits until all three are resolved.

The gateway's identity reads exactly these three secrets. A new framework plugin, `tsdevstack-trust`, sets the trust header.

## New commands

- **`cloud-secrets:migrate`** copies secrets from where earlier versions kept them to where services read them now. It never deletes or overwrites.
- **`cloud-secrets:cleanup`** deletes the old copies after the deploy. It asks first. A copy whose value differs from the new one gets its own question, and `--force` never deletes it. On Azure, it runs once every service is on the new deploy.
- **`cloud-secrets:set --stdin`** reads the value from standard input. It stays out of your shell history and the process list.

The MCP server (cli-mcp 0.9.0) has two new tools, `cloud_secrets_migrate` and `cloud_secrets_cleanup`, and an upgrade workflow in its guide.

## Pushing your secrets

- `cloud-secrets:push` pushes the values in a service's section of `.secrets.user.json` to that service's scope.
- Values in a frontend's or a worker's section are listed, not pushed.
- Values only local development needs stay local.

## Improvements

- **Login** takes the same time whether or not the email has an account. Projects created before this version apply the change themselves: see the upgrade steps.
- **nest-common** declares `class-transformer` and `class-validator`, so every NestJS service image has them.
- **`cloud:init` on Azure** checks that it can read the Key Vault's secrets, and names the missing role when it can't.
- **`cloud-secrets:push`** lists each secret that failed, with its error, and continues with the others.
- **Deploys** tag images with the last commit. Without `--tag`, they warn about uncommitted changes.
- **Azure:** Key Vault names are the same in every command, for any project name length.
- **Azure:** the deploy stops with an error when it can't read the managed identities.
- **GCP:** the deploy lists only the DNS records that are missing, with what each one is for.
- **GCP:** when Google is still releasing the network, destroy says so and tells you to run it again later.

## Breaking changes

Pre-1.0, so they ship in a minor version. The upgrade steps below cover each.

- **nest-common:** `SecretsService.set()` and `delete()` are removed. Custom `SecretsProvider` implementations implement `read(key, scope)`.
- **Lookup order:** a service's own value wins over a shared one with the same key.
- **`kong.user.yml`:** the Kong commands stop while a `request-transformer` adds `X-Kong-Trust:${KONG_TRUST_TOKEN}`.
- **Existing cloud environments** run `cloud-secrets:migrate` before their first deploy with this version.
- **Reserved names:** a service named `shared`, `secrets` or `kv`, or starting with `shared-`, needs a new name.
- **AWS with the scoped IAM statements:** add `arn:aws:iam::*:role/PROJECT_NAME-db-tasks-execution` to `ManageFrameworkRoles`.

## Upgrading an existing project

**1. Packages.**

```bash
npm install -D @tsdevstack/cli@^0.11.0
npm install @tsdevstack/nest-common@^0.11.0 -w <service>
```

Run the second command for each NestJS service. Remove any calls to `SecretsService.set()` or `delete()`.

**2. `kong.user.yml`.** In the `request-transformer` plugin, delete `X-Kong-Trust:${KONG_TRUST_TOKEN}` from `add.headers` and `X-Kong-Trust` from `remove.headers`. If `add` is left empty, delete it too.

**3. Auth service.** If your auth service came from the template, add this to `src/auth/auth.service.ts`:

```ts
private dummyPasswordHash!: string;

// In onModuleInit, after bcryptRounds is set:
this.dummyPasswordHash = await bcrypt.hash(
  randomBytes(16).toString('hex'),
  this.bcryptRounds,
);

// In login, before throwing for an unknown user:
await bcrypt.compare(password, this.dummyPasswordHash);
```

**4. Local stack.**

```bash
npx tsdevstack sync
```

This moves the auth secrets into the auth service's section of `.secrets.local.json`. It also gives the gateway its three secrets from the root `.env`.

**5. Each cloud environment.** In this order:

```bash
npx tsdevstack cloud-secrets:migrate --env <env>
npx tsdevstack infra:deploy --env <env>
npx tsdevstack cloud-secrets:cleanup --env <env>
```

`migrate` only copies, and `cleanup` only deletes the old copies. If your environments deploy from CI only, run these once from a machine with the environment's credentials.

New projects get all of this from the start.
