Local edition generates its own credential-wrapping and signing
Supersedes draft 10156. Security-relevant: a real install's stored AI-provider keys are wrapped with a keypair published in the repo.
Reproduction: `infra/local-edition/compose.yml` runs the api with `APP_ENV=local`; without it `apps/api/app/credential_keys.py` has no wrapping key and refuses to store a credential. Under `APP_ENV=local` every secret is wrapped with the published dev keypair and compliance signing uses the published dev P-256 key.
Cause: `credential_keys.provider()` accepts a local keypair only in fixture envs; `apps/api/app/local_bootstrap.py::ensure_secrets` generates the session secret and tier-1 key but not the credential keypair or signing key.
Fix: have `ensure_secrets` also generate `CREDENTIAL_LOCAL_PRIVATE_KEY` and the compliance signing key on the secrets volume (0600); let `credential_keys.provider()` accept the local keypair when `edition.IS_LOCAL`; drop `APP_ENV: local` from compose and confirm nothing else on the local boot path depends on it (`console_direct`, `auth.session_cookie` warning).
Out of scope: the cloud KMS path; any cloud deployment change.
Done means:
- A fresh `docker compose up -d` with no `APP_ENV` boots and stores a credential.
- A unit test pins that a wrapped secret does NOT open with the published dev keypair.
- Api suite and `./dc check quick` green.
Outcome
Local edition now generates its own RSA wrapping and P-256 signing keys (0600), refuses the published dev keys, and needs no APP_ENV (proven on the tree image). Quick and api tests green; security lane passed; #6964 merged 1c3320eb1. Dev deploy failed on the runner-workspace fault (draft 10185), not this diff. Memory: none applied.
Artifacts
- epic-summary.html
- run-report.html
- epic-summary.html
- report.html
- epic-10077-final-10180.html
- run-report-10180.html
Activity
- Ready
- Runner started
- Runner ended (done)
- Run
- Runner started
- Runner ended (done)
- Run
- Runner started
- Runner ended (done)