This packet replaces the old Task 18 notes. It is aligned to Phase 16 / Task 18 in docs/plans/2026-01-25-end-state.md and the current repo structure.
Use this as the exact execution guide for an agent implementing Task 18.
Harden Workbench authentication and authorization and deliver real governance export output (signed, content-addressed bundles).
Verify current auth and policy export locations:
services/workbench-bff/src/api/auth.pyapps/workbench/src/contexts/auth.tsxservices/policy-gateway/src/api/routes.pyIf any of these differ, update this packet before coding.
AuthProviderJWT Validation Details
exp, iat, nbf and reject expired/invalid tokens with 401.Claims Mapping
roles by default (configurable via env, e.g., AUTH_ROLE_CLAIM).viewer|operator|admin.viewer (authenticated but least-privileged).Session Management
Enforcement
Roles:
vieweroperatoradminRules:
admin ⇒ operator ⇒ viewer.admin until explicitly added to the matrix.| Capability / Endpoint Group | viewer | operator | admin |
|---|---|---|---|
Manifest read (GET /manifests, /manifests/{id}, /manifests/{id}/versions, /manifests/{id}/diff, /manifests/{id}/source) |
✅ | ✅ | ✅ |
Provenance read (GET /provenance/graph, /provenance/nodes/{id}, /provenance/lineage/{id}, /provenance/search, /provenance/impact/{id}, /provenance/compare) |
✅ | ✅ | ✅ |
Drift read (GET /drift/context/{context}, /drift/report/{node_id}, /drift/history) |
✅ | ✅ | ✅ |
Behavior read (GET /behavior/summaries, /behavior/nodes/{id}, /behavior/trends, /behavior/openobserve-config) |
✅ | ✅ | ✅ |
Ops read (GET /ops/actions, /ops/actions/{id}, /ops/runs, /ops/runs/{id}, /ops/runs/{id}/logs, /ops/runs/{id}/summary) |
❌ | ✅ | ✅ |
Ops write (POST /ops/runs, /ops/runs/{id}/cancel) |
❌ | ✅ | ✅ |
Drift analyze (POST /drift/analyze) |
❌ | ✅ | ✅ |
Behavior scan (POST /behavior/scan) |
❌ | ✅ | ✅ |
Drift remediation (POST /drift/remediate) |
❌ | ❌ | ✅ |
Governance export (POST /governance/export) |
❌ | ❌ | ✅ |
Policy reload (POST /policy/reload) |
❌ | ❌ | ✅ |
| RBAC / auth config changes | ❌ | ❌ | ✅ |
Extension rule: adding a new endpoint requires an explicit matrix entry and tests for 401/403 behavior.
services/policy-gateway/src/api/routes.py must export real evidence (no placeholder)Cryptography
bundle.sig.Content addressing
sha256:<hex>.Bundle layout
1
2
3
4
5
6
manifest.json
evidence/ledger.jsonl
evidence/objects/<evidence_id>/<artifact_id>
manifests/<manifest_id>.json
policies/opa/...
bundle.sig
manifest.json format
version, hash_alg, files[], root_sha256, generated_at (fixed epoch).files[] entries map path → sha256 + bytes.root_sha256 computed from sorted "{sha256} {path}\n" lines.Verification process (consumer)
bundle.sig using the public Ed25519 key.manifest.json.root_sha256 and compare to manifest.apps/workbench/e2e/auth.spec.ts
services/workbench-bff/tests/test_auth.py
services/policy-gateway/tests/test_export.py
Run:
1
2
3
4
pnpm exec nx test workbench -- --testPathPattern=auth
pnpm exec nx test workbench -- --testNamePattern="requires login"
pytest services/workbench-bff/tests/test_auth.py -v
pytest services/policy-gateway/tests/test_export.py -v
(And appropriate backend tests for BFF + policy-gateway.)
just ci passes