Set the approval store tenant to exact tenant:platform
Operator decision 5ed3fb35-eca9-413a-82b9-95171ba85bf6 accepts tenant:platform
as the platform management, administration and services tenant, with no alias
to platform or tenant:coulomb and no implicit cross-tenant grant. This closes
the collision recorded in 5c87ba8, where the manifest served --tenant platform
while the requested registrations issued tenant:coulomb.
The store tenant is now exactly tenant:platform in the manifest, the CLI
default, and the Engine default, and the requested client registrations ask for
the same spelling. Exact JWT/store equality is retained: no mapping table, no
normalisation, no prefix handling.
Moving the defaults rather than only the manifest is deliberate. A default of
platform under a sanctioned value of tenant:platform is a trap, because a serve
that omits --tenant would come up healthy and then refuse every authenticated
call -- the exact failure this decision exists to prevent.
That default change broke ten tests whose identity fixtures hard-coded
platform. This is the hazard flex-auth reported as FLEX-DEC-2026-008: fixtures
that all carry one tenant prove nothing about the tenant field. Fixtures are
aligned to the exact spelling, and the field is now varied rather than merely
present. test_near_miss_tenant_spellings_are_forbidden refuses platform,
tenant:coulomb, case variants, whitespace variants and empty against a
tenant:platform store; test_exact_sanctioned_tenant_is_admitted pins the other
half so a reject-everything bug cannot pass it. 111 tests pass.
Also records the credential-independent half of the GLAS-WP-0015 image request:
the image builds non-root uid 10001 off the pinned base, carries schema v3 and
the new tenant default, migrates and verifies a fresh store to schema_version 3
with integrity ok, and refuses production without a persistent database or
authenticated audit delivery. No scan was run -- no scanner is installed here --
and no release digest exists, so T01 and T03 both stay open.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PM5HnEAhokxdfcPqBNpT7D
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 715850@bnt-lap001
Assistant-Session: eb557e93-7cb1-45d0-9e57-7d15b3edc60e
This commit is contained in:
parent
5c87ba8610
commit
6d18f62a90
8 changed files with 182 additions and 38 deletions
|
|
@ -90,6 +90,37 @@ the approval store. The registrations doc's stale issuer
|
|||
(`https://auth.netkingdom.local`) is corrected to the live
|
||||
`https://kc.coulomb.social` from `06544b0`. T01 stays `progress`.
|
||||
|
||||
2026-09-06 resolution: the operator accepted `tenant:platform` as the platform
|
||||
management/administration/services tenant (landlord zone) — decision
|
||||
`5ed3fb35-eca9-413a-82b9-95171ba85bf6`,
|
||||
`glas-harness/docs/platform-tenant-decision.md`, relayed by `glas-harness`. The
|
||||
collision above is closed by setting the store tenant to exactly
|
||||
`tenant:platform`: `deploy/approval-engine.yaml` `--tenant`, the
|
||||
`approval_engine/cli.py` `--tenant` default, and the `Engine(tenant=…)` default
|
||||
all move off bare `platform`, and the requested client registrations now ask for
|
||||
`tenant: tenant:platform`. Exact JWT/store equality is retained — no alias, no
|
||||
normalisation, no prefix handling, and no implicit cross-tenant grant.
|
||||
|
||||
Moving the *defaults* rather than only the manifest is deliberate: a default of
|
||||
`platform` under a sanctioned value of `tenant:platform` is a trap, because a
|
||||
`serve` that omits `--tenant` would come up healthy and then refuse every
|
||||
authenticated call.
|
||||
|
||||
The default change broke ten tests whose identity fixtures hard-coded
|
||||
`platform`, which is the fixture-consistency hazard flex-auth reported as
|
||||
`FLEX-DEC-2026-008` (29 fixtures all carrying one tenant proved nothing about
|
||||
the field). Fixtures are aligned to the exact spelling, and the field is now
|
||||
*varied* rather than merely present:
|
||||
`tests/test_auth.py::test_near_miss_tenant_spellings_are_forbidden` refuses
|
||||
`platform`, `tenant:coulomb`, case variants, whitespace variants and empty
|
||||
against a `tenant:platform` store, and
|
||||
`test_exact_sanctioned_tenant_is_admitted` pins the other half so a
|
||||
reject-everything bug cannot pass. 111 tests pass.
|
||||
|
||||
This resolves the choice of value only. T01 stays `progress`: KeyCape still has
|
||||
to own and prove these registrations, and credential materialization is
|
||||
unchanged.
|
||||
|
||||
## Harden durable storage and migrations
|
||||
|
||||
```task
|
||||
|
|
@ -138,6 +169,40 @@ read-only root, resources, probes, and default-deny policies pass client dry-run
|
|||
Waiting on release digest, KeyCape/audit registrations and credentials, rollout,
|
||||
restart, and restore evidence.
|
||||
|
||||
2026-09-06 image preparation (GLAS-WP-0015 request; credential-independent half):
|
||||
built and validated locally against the agreed tenant and current schema.
|
||||
|
||||
- Build: `make image-build` off the digest-pinned base
|
||||
`python:3.12-slim@sha256:d764629c…`. Local manifest-list digest
|
||||
`sha256:85e46ddf47b3ac0cdab620163a7b034027451dff286b63ecff6a2493d7a57ecc`.
|
||||
**This is a local build digest, not a release digest** — the manifest still
|
||||
carries `REPLACE_WITH_RELEASE_DIGEST` because pinning requires a push to
|
||||
`forgejo.coulomb.social`, which needs registry credentials this session does
|
||||
not hold.
|
||||
- Runtime identity: `uid=10001(approval) gid=10001(approval)`, non-root as
|
||||
required.
|
||||
- Schema: image carries `LATEST_SCHEMA_VERSION = 3`, matching the migrated
|
||||
store, and `Engine` tenant default `tenant:platform`.
|
||||
- First-install migration (no prior DB): `migrate` then `verify` on a fresh
|
||||
volume both report `schema_version: 3`, `schema_current: true`,
|
||||
`integrity: ["ok"]`, `foreign_key_violations: 0`, `persistent: true`.
|
||||
- Fail-closed configuration proven in the image, not only in tests:
|
||||
`serve --production --db :memory:` refuses with "production requires a
|
||||
persistent database"; `serve --production` on a real DB without audit
|
||||
configuration refuses with "production requires authenticated audit
|
||||
delivery".
|
||||
- Manifest inputs: `kubectl apply --dry-run=client` passes for the namespace,
|
||||
service, and StatefulSet with the new `--tenant tenant:platform`.
|
||||
|
||||
Scan gate NOT met: no scanner (`trivy`, `grype`, `docker scout`) is installed on
|
||||
this workstation, so no vulnerability scan was run and none is claimed. The
|
||||
inventory a scanner needs is the pinned base above plus
|
||||
`cryptography==50.0.1`, `PyJWT==2.13.0`, `waitress==3.0.2`, `cffi==2.1.1`,
|
||||
`pycparser==3.0`, `pip==25.0.1`.
|
||||
|
||||
T03 stays `wait`: still no release digest, no KeyCape/audit credentials, no
|
||||
rollout, and no restart/restore evidence. Nothing here is a deploy.
|
||||
|
||||
## Wire outbox delivery and reconciliation
|
||||
|
||||
```task
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue