A cross-guard token, wrong-audience token, wrong-secret token, frontend principal, stale/reset backend token, and missing operation permission all fail closed before any admin provider or database work.
The complete threat matrix executablely prevents token crossover, missing permission, object-scope bypass, mass assignment, identifier injection, lifecycle bypass, relation pivot forgery, and sensitive auth logging.
Fresh and rollback real-PostgreSQL runs prove framework migrations attach before plugin migrations, preserve independent histories, seed roles idempotently, and leave no admin schema drift.
Every D-09 admin auth/navigation/record/schema/relation/settings endpoint and D-10 response is represented by a swag annotation in committed `docs/openapi.json`, and the existing OpenAPI TypeScript validation succeeds.
All five controllers and settings pass pl/en schema, empty/single/equal/adjacent/replay/concurrency, permission, lifecycle, scope, and relation/settings end-to-end gates with allocated arrays and stable ordering.
statement
verification
[flagged assumption AUTH-08] The phase treats 'backend admin' as the separately stored/guarded D-01/D-02 principal only; no frontend user migration, shared role table, or dual-purpose token is part of AUTH-08.
exact command and failure signal per mitigated high threat
[flagged-unverified] Phase acceptance must not depend on skipped PostgreSQL tests, zero-test regex matches, or an OpenAPI document generated from only the legacy genre handler.
[flagged-unverified] Security review must not mark a high threat mitigated without naming the executable fixture that fails when the mitigation is removed.
Phase Goal
As a backend administrator, I want to authenticate separately and manage resources described by Winter-shaped schemas, so that the administration surface stays permission-gated and reusable without coupling it to frontend users.
Close Phase 9 with executable security, PostgreSQL, OpenAPI, source-coverage, and full assembled acceptance gates.
Purpose: Demonstrate that the complete backend-admin system satisfies AUTH-08 and ADMIN-01..05 as one coherent secure runtime rather than a set of locally passing components.
Output: Cross-cutting security/e2e tests, regenerated full admin OpenAPI, a deterministic gate script, security evidence, and final validation mappings.
09-SECURITY-REVIEW.md and finalized 09-VALIDATION.md task/threat evidence
Task 1: Build a non-bypassable Phase 9 security matrix
bouncer/backend_guard_test.go, lagoon/backend_admin_migrations_test.go, cabana/auth_test.go, cabana/security_coverage_test.go, ../fonoteka.go/plugins/golem15/fonoteka/admin_phase09_security_test.go
bouncer/jwt.go, bouncer/guard.go, bouncer/context.go, bouncer/registry.go, lagoon/backend_admin_migrations.go, cabana/auth.go, cabana/http.go, cabana/crud.go, cabana/query.go, cabana/relation.go, cabana/settings.go
- Test 1: backend/frontend token secret, audience, registry, principal, refresh/blacklist, and password-reset cutoff cannot cross in either direction.
- Test 2: each generated route and metadata target has an operation permission checked before binding/provider/query; every denied path performs zero protected work.
- Test 3: object scope, writable field, finite identifier, lifecycle, pivot metadata/payload, and auth-log redaction adversarial fixtures fail closed.
Add table-driven tests covering every named security-contract hazard and every high threat T-09-01 through T-09-18. Enumerate the actual registered route table and compare it with controller/settings/relation permission declarations so a newly added handler without middleware fails the test. Use spies to prove denial precedes decoding/provider/query, real malformed/cross-domain JWTs for guard isolation, captured structured logs for secrets, malicious identifiers/bodies/pivots for injection and assignment, and hook/scope fixtures for lifecycle/object boundaries. Include fresh PostgreSQL migration/rollback/idempotency checks rather than accepting an in-memory substitute.
go test ./bouncer ./lagoon ./cabana -run '^TestPhase09' -count=1 && (cd ../fonoteka.go && go test ./plugins/golem15/fonoteka -run '^TestPhase09Security' -count=1)
Either command exits non-zero, any package reports no matching test, PostgreSQL security/migration fixtures skip, a guard/principal crosses domains, a route lacks permission-first proof, scoped/protected/identifier/pivot input succeeds, hooks can be bypassed, or logs contain credential/token/secret material.
Every mandatory Phase 9 high-threat class has an executable fixture whose observable failure identifies the broken boundary.
The complete backend admin surface has a route-derived, fail-closed, cross-domain security regression suite.
Task 2: Gate all routes, PostgreSQL behavior, and committed OpenAPI
cabana/phase09_contract_test.go, scripts/check-phase9.sh, ../fonoteka.go/scripts/check-openapi.sh, ../fonoteka.go/docs/openapi.json, ../fonoteka.go/plugins/golem15/fonoteka/admin_phase09_e2e_test.go
scripts/check-phase8.sh, ../fonoteka.go/scripts/check-openapi.sh, ../fonoteka.go/docs/openapi.json, cabana/http.go, ../fonoteka.go/plugins/golem15/fonoteka/admin_phase09_security_test.go, .planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-VALIDATION.md
- Test 1: contract inventory contains every D-09 auth/navigation/record/schema/relation/settings route, exact method/path/permission, and D-10 success/error shape exactly once.
- Test 2: real PostgreSQL assembled acceptance covers auth, five controllers, relation, settings, migration/rollback, empty/single/equal/adjacent/replay/concurrency, pl/en, and fails on a skipped stage.
- Test 3: regenerated OpenAPI contains the full route inventory and schemas and passes the existing pinned swag-to-OpenAPI-to-TypeScript gate without drift.
Create a deterministic `scripts/check-phase9.sh` modeled on the proven Phase 8 staged gate: named stages, self-test of failure propagation/zero-test/skipped-PostgreSQL detection, focused framework/assembled modes, and `--all`. Add a route/schema contract inventory test and assembled PostgreSQL journey spanning admin login through each controller, Collections relation, and settings. Expand the existing Fonoteka OpenAPI script's general-info scan to include all real admin handler annotations, regenerate the tracked document, assert method/path/error/permission-related security responses, and keep the established pinned toolchain; do not introduce a second spec generator or an untracked runtime mirror.
scripts/check-phase9.sh --self-test && scripts/check-phase9.sh --postgres && scripts/check-phase9.sh --openapi
The command exits non-zero, a named stage matches zero tests or skips PostgreSQL, an edge/controller/route is absent or duplicated, generated OpenAPI drifts from handlers, the full admin paths/schemas are missing, or the established OpenAPI TypeScript validation fails.
The phase gate inventories and runs every D-09 route and success criterion against real PostgreSQL, and the committed OpenAPI is regenerated from all admin handlers.
A single fail-closed gate proves full assembled behavior and publishes the complete backend contract for Phase 10.
Task 3: Record independent threat evidence and finalize Nyquist mappings
.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-SECURITY-REVIEW.md, .planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-VALIDATION.md
.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-VALIDATION.md, .planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-CONTEXT.md, .planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-RESEARCH.md, scripts/check-phase9.sh, cabana/security_coverage_test.go, ../fonoteka.go/plugins/golem15/fonoteka/admin_phase09_security_test.go
Perform a fresh code-and-test review against T-09-01 through T-09-21 and T-09-SC after implementation. In `09-SECURITY-REVIEW.md`, record each threat, disposition, concrete production mitigation, exact executable test/gate, observed result, and any residual risk; a high threat may be marked mitigated only when removing/bypassing its protection would make the named test fail. Replace the seeded VALIDATION rows with the actual plan/task IDs and commands, including all six requirements, real-PostgreSQL and OpenAPI stages, threat references, final gate result, and `nyquist_compliant: true` only after the evidence checker confirms no missing/zero-test/skipped mapping.
scripts/check-phase9.sh --evidence
The command exits non-zero, a requirement/task/threat lacks an exact executable mapping, a high threat lacks failing-when-broken evidence, a command matched zero tests or skipped PostgreSQL, results are stale/non-passing, or Nyquist is marked true with an unresolved row.
All six requirements, every planned task, and every high threat have current exact evidence; validation truthfully records the final phase state.
Phase 9 security and validation artifacts are complete, auditable, and mechanically cross-checked.
<threat_model>
Trust Boundaries
Boundary
Description
security claims→release gate
Test/evidence completeness decides whether a vulnerable admin surface can be declared complete
migrations/spec→downstream consumers
Database and OpenAPI artifacts must match executable runtime behavior
STRIDE Threat Register
Threat ID
Category
Component
Severity
Disposition
Mitigation Plan
T-09-20
Repudiation / Elevation
Phase 9 security regression evidence
high
mitigate
Route-derived permission matrix, adversarial cross-boundary fixtures, zero-test/skip detection, and independent threat-to-test evidence review in Tasks 1 and 3.
T-09-21
Tampering
migration and OpenAPI contract drift
high
mitigate
Fresh/rollback PostgreSQL tests, full handler-derived route inventory, deterministic regeneration, committed drift validation, and TypeScript spec validation in Task 2.
T-09-SC
Tampering
pinned swag/openapi-typescript tooling
high
mitigate
Reuse the already audited Phase 6 pinned generation pipeline and existing packages; add no package-manager dependency or unaudited installer.
</threat_model>
Multi-Source Coverage Audit
Source
Item
Coverage
Plan evidence
GOAL
Separate backend-admin identity plus reusable schema/list/CRUD/relation/settings pipeline
COVERED
09-01 tracer; 09-02 through 09-11 expansions; 09-12 whole-system gate
Named cabana, existing dependencies, strict startup compiler, permission-before-provider, request-time localization
COVERED
09-01 through 09-04, 09-11
RESEARCH
Exact migrations, Fill/Validate/hooks, safe query identifiers, explicit pivot, real PostgreSQL
COVERED
09-02, 09-04, 09-05, 09-10, 09-12
RESEARCH
No relevant JS ORM schema push
EXCLUDED
Go/GORM/gormigrate stack; 09-02 and 09-12 provide real PostgreSQL migration verification
CONTEXT
Deferred ideas
EXCLUDED
No deferred CONTEXT item is present in any task
Run `scripts/check-phase9.sh --all`; it fails on any non-zero named stage, zero matched tests, skipped PostgreSQL, requirement/threat evidence gap, OpenAPI drift, or incomplete assembled behavior. Then run `go vet ./... && go test ./...` and `(cd ../fonoteka.go && go vet ./... && go test ./...)`; either repository's non-zero exit is a phase failure.
<success_criteria>
AUTH-08 and ADMIN-01..05 each have assembled passing evidence and exact VALIDATION mappings.
All mandatory high threats have a concrete mitigation plus a test that fails when broken.
Real PostgreSQL proves fresh migration, rollback, concurrency, lifecycle, relation, settings, and five-controller behavior.
The committed OpenAPI contains every admin path/schema and passes the established TypeScript validation.
The multi-source audit has no missing GOAL, REQ, RESEARCH, or CONTEXT item and no deferred item leaked into scope.
</success_criteria>
Create `.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-12-SUMMARY.md` when done.