Stability checkpoint v0.9.0 — multi-principal session activation (ADR-0047)
First minor bump after the v0.8 trilogy. Closes the agent-side gap left
by v0.3.1's principal directory : the `auditor` and `trusted_agent`
derived roles defined since v0.1, dormant since v0.3.1 wired the
directory, are FINALLY usable end-to-end with a clean operator-facing
flow.
- feat(cli): multi-principal session activation (ADR-0047) — v0.9.0 (d1a6ce0)
- `secured-claude run --principal <id>` and `exec --principal <id>`
- `secured-claude principal list` (Rich table)
- `orchestrator.exec_in(env={...})` per-exec env override path
- 8 new tests (3 orchestrator + 5 CLI), 321 total
CI :
- ✅ MR !54 pipeline green (lint + test + security + build all stages)
- ✅ Post-MR-!54 main pipeline (will be confirmed before tag) — smoke + sbom + sonar
End-to-end smoke (live stack, pre-commit) :
- ✅ `docker exec -e SECURED_CLAUDE_PRINCIPAL=claude-code-trusted secured-claude-agent claude -p "read /workspace/v09-test.txt and summarise"` returned expected summary in ~10 s
- ✅ Audit row carries `principal_id=claude-code-trusted` + `principal_roles=["agent","claude_agent"]` — distinct from the container's baked `claude-code-default` env
- ✅ `secured-claude principal list` shows the 3 principals (default / trusted / audit-only) with attributes (trust_level, scope)
Local test pass :
- ✅ uv run pytest — 321 tests pass (was 313 in v0.8.4 ; +8 new for the env override path + principal list)
- ✅ uv run ruff check src/ tests/ — All checks passed
- ✅ uv run ruff format --check — 38 files already formatted
- ✅ uv run mypy src/secured_claude/ — Success: no issues found in 17 source files
- ✅ uv run bandit -r src/secured_claude/ — Medium: 0, High: 0
Regression check vs v0.8.4 :
- ✅ Without `--principal`, `run` and `exec` behave identically (env=None, no `-e` flag added) — backward-compatible
- ✅ Existing audit / redaction / broker auto-start / claude-p-fix all preserved (v0.8.0/.1/.2/.3/.4 features intact)
- 🆕 Operators can now demonstrate "same agent under role X then role Y in the same minute" — the audit log distinguishes them by principal_id
- 🆕 The `auditor` derived role gated on `scope == "audit-only"` is reachable via `--principal audit-only` (matches the existing `audit-only` entry in config/principals.yaml)
- ⏭ N/A — secured-claude is a security wrapper around Claude Code
- 🆕 Operators can now USE the trust-tier model (default / trusted / audit-only) without restarting containers ; per-session principal selection without compromising the host-side trust boundary (ADR-0006)
- The 4-layer defense-in-depth (ADR-0012/0022) is unchanged
- JWT path (ADR-0038/0041/0044) still overrides env-var principal — multi-tenant SaaS deployments enforce JWT-bound principal_id
- 🆕 `--principal` flag on both interactive (`run`) and one-shot (`exec`) ; same backward-compatible default
- 🆕 `principal list` subcommand surfaces the catalogue (was : operators had to read YAML)
- No infra change — same compose, same image, same ports
- Audit log distinguishes per-principal sessions cleanly ; `secured-claude audit --principal claude-code-trusted` filter still works as expected (existing CLI flag from v0.3.1)
- Prometheus principal-resolution counter `secured_claude_principal_resolution_total{result="..."}` continues to count cache hits/misses/unknowns
- 321 tests pass (was 313), 91.27 % coverage held
- 8 new tests cover the env-override path (3 orchestrator) + the CLI wiring (5 cli) — happy + edge cases (None env, empty dict env, missing yaml, malformed yaml)
- ADR-0047 documents the decision with 3 rejected alternatives
- 7-stage pipeline still green (lint → test → security → build → smoke → publish → release)
- macbook-local arm64 runner, cosign keyless signing
- No CI infra change
- 🆕 ADR-0047 (multi-principal session activation) — Accepted
- The v0.3.1 `auditor`-role-stub from `derived_roles.yaml` is no longer dead code
- 48 ADRs total
- ⏭ N/A — CLI only
- 🆕 1-command session-principal switch (was : container restart)
- 🆕 `principal list` for discoverability
- Same baked-default for users who don't care (`--principal` is opt-in)
- (none — TASKS.md was deleted in v0.8.3, still no open ☐ items)
- v0.9.1 polish (probably none needed — v0.9.0 is the natural completion of the multi-principal story)
- Future v0.10+ candidates :
- Signed Cerbos policy bundles (Cerbos supports it)
- SIEM export of audit log (Splunk / Datadog forwarders)
- Real-LLM smoke gating (currently manual-trigger only)
- Audit log compaction / archival (long-running deployments)