Files
summercms/.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-12-PLAN.md
2026-09-24 16:45:45 +02:00

208 lines
17 KiB
Markdown

---
phase: 09-backend-admin-authentication-and-schema-pipeline
plan: 12
type: execute
wave: 9
depends_on: [09-02, 09-03, 09-04, 09-05, 09-06, 09-07, 09-08, 09-09, 09-10, 09-11]
files_modified:
- 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
- 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
- .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
autonomous: true
requirements: [AUTH-08, ADMIN-01, ADMIN-02, ADMIN-03, ADMIN-04, ADMIN-05]
estimate:
tokens: 30000
raw_tokens: 30000
tasks: 3
confidence: low
must_haves:
truths:
- "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: "[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."
verification: backstop
artifacts:
- path: "cabana/security_coverage_test.go"
provides: "Executable framework-wide Phase 9 high-threat matrix"
- path: "../fonoteka.go/plugins/golem15/fonoteka/admin_phase09_e2e_test.go"
provides: "Real assembled route, PostgreSQL, edge, and lifecycle acceptance"
- path: "../fonoteka.go/docs/openapi.json"
provides: "Committed all-route admin OpenAPI contract"
- path: "scripts/check-phase9.sh"
provides: "Fail-closed deterministic Phase 9 gate"
- path: ".planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-SECURITY-REVIEW.md"
provides: "Threat-to-mitigation-to-test evidence ledger"
key_links:
- from: "scripts/check-phase9.sh"
to: "framework and assembled security/contract tests"
via: "named non-skippable stages with zero-test detection"
- from: "handler swag annotations"
to: "../fonoteka.go/docs/openapi.json"
via: "existing pinned check-openapi generation/conversion/validation pipeline"
- from: "09-SECURITY-REVIEW.md"
to: "T-09-01..T-09-21 test evidence"
via: "exact command and failure signal per mitigated high threat"
prohibitions:
- "[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.
<objective>
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.
</objective>
<execution_context>
@/home/jin/.codex/gsd-core/workflows/execute-plan.md
@/home/jin/.codex/gsd-core/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/REQUIREMENTS.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
@.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-VALIDATION.md
@.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-02-SUMMARY.md
@.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-11-SUMMARY.md
@../fonoteka.go/scripts/check-openapi.sh
@../fonoteka.go/docs/openapi.json
</context>
## Artifacts this phase produces
- `TestPhase09GuardIsolation`, `TestPhase09PermissionMatrix`, and `TestPhase09SecurityCoverage`
- `TestPhase09MigrationsFreshRollback` and `TestPhase09AssembledAcceptance`
- `scripts/check-phase9.sh` with `--self-test`, `--security`, `--postgres`, `--openapi`, `--evidence`, and `--all`
- Expanded deterministic `../fonoteka.go/docs/openapi.json`
- `09-SECURITY-REVIEW.md` and finalized `09-VALIDATION.md` task/threat evidence
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Build a non-bypassable Phase 9 security matrix</name>
<files>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</files>
<read_first>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</read_first>
<behavior>
- 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.
</behavior>
<action>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.</action>
<verify>
<automated>go test ./bouncer ./lagoon ./cabana -run '^TestPhase09' -count=1 &amp;&amp; (cd ../fonoteka.go &amp;&amp; go test ./plugins/golem15/fonoteka -run '^TestPhase09Security' -count=1)</automated>
<fails_when>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.</fails_when>
</verify>
<acceptance_criteria>Every mandatory Phase 9 high-threat class has an executable fixture whose observable failure identifies the broken boundary.</acceptance_criteria>
<done>The complete backend admin surface has a route-derived, fail-closed, cross-domain security regression suite.</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Gate all routes, PostgreSQL behavior, and committed OpenAPI</name>
<files>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</files>
<read_first>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</read_first>
<behavior>
- 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.
</behavior>
<action>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.</action>
<verify>
<automated>scripts/check-phase9.sh --self-test &amp;&amp; scripts/check-phase9.sh --postgres &amp;&amp; scripts/check-phase9.sh --openapi</automated>
<fails_when>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.</fails_when>
</verify>
<acceptance_criteria>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.</acceptance_criteria>
<done>A single fail-closed gate proves full assembled behavior and publishes the complete backend contract for Phase 10.</done>
</task>
<task type="auto">
<name>Task 3: Record independent threat evidence and finalize Nyquist mappings</name>
<files>.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</files>
<read_first>.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</read_first>
<action>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.</action>
<verify>
<automated>scripts/check-phase9.sh --evidence</automated>
<fails_when>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.</fails_when>
</verify>
<acceptance_criteria>All six requirements, every planned task, and every high threat have current exact evidence; validation truthfully records the final phase state.</acceptance_criteria>
<done>Phase 9 security and validation artifacts are complete, auditable, and mechanically cross-checked.</done>
</task>
</tasks>
<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 |
| REQ | AUTH-08 | COVERED | 09-01, 09-02, 09-11, 09-12 |
| REQ | ADMIN-01 | COVERED | 09-03, 09-06 through 09-10, 09-12 |
| REQ | ADMIN-02 | COVERED | 09-01, 09-04, 09-06 through 09-10, 09-12 |
| REQ | ADMIN-03 | COVERED | 09-10, 09-12 |
| REQ | ADMIN-04 | COVERED | 09-05 through 09-10, 09-12 |
| REQ | ADMIN-05 | COVERED | 09-11, 09-12 |
| CONTEXT | D-01..D-04 identity, guard, permissions, commands | COVERED | 09-01, 09-02, 09-11 |
| CONTEXT | D-05..D-08 YAML, typed schema, localization, options | COVERED | 09-03, 09-06 through 09-10 |
| CONTEXT | D-09..D-10 route/error contracts | COVERED | 09-01, 09-02, 09-05, 09-10, 09-11, 09-12 |
| CONTEXT | D-11..D-12 list/filter/query contract | COVERED | 09-04 and assembled controller plans |
| CONTEXT | D-13..D-14 lifecycle and album collection match | COVERED | 09-05, 09-06 |
| CONTEXT | D-15..D-16 relation schema/pivot ownership | COVERED | 09-10 |
| CONTEXT | D-17..D-18 settings/navigation | COVERED | 09-11 |
| RESEARCH | 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 |
<verification>
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.
</verification>
<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>
<output>
Create `.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-12-SUMMARY.md` when done.
</output>