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

14 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, estimate, must_haves
phase plan type wave depends_on files_modified autonomous requirements estimate must_haves
09-backend-admin-authentication-and-schema-pipeline 11 execute 8
09-07
09-08
09-09
09-10
cabana/registry.go
cabana/navigation.go
cabana/settings.go
cabana/http.go
../fonoteka.go/plugins/golem15/fonoteka/admin_permissions.go
../fonoteka.go/plugins/golem15/fonoteka/admin_navigation.go
../fonoteka.go/plugins/golem15/fonoteka/admin_settings.go
../fonoteka.go/plugins/golem15/fonoteka/models/settings/fields.yaml
../fonoteka.go/plugins/golem15/fonoteka/admin_metadata_test.go
../fonoteka.go/plugins/golem15/fonoteka/admin_settings_test.go
true
AUTH-08
ADMIN-05
tokens raw_tokens tasks confidence
30000 30000 3 low
truths artifacts key_links prohibitions
Per D-01/D-03, the developer role/superuser path receives all registered permissions while publisher receives only its explicit assignments; wildcard semantics remain deterministic and every controller/setting permission resolves from the registry.
Per D-18, navigation preserves the plugin's Winter IDs, labels, icons, ordering, and controller targets, removes entries the principal cannot use, and never exposes an unauthorized route or setting through metadata.
Per D-18, settings-list entries preserve code, label, description, category, icon, order, keywords, and permissions, are stable by order then code, and are filtered through the same backend principal permission set.
Per D-17, the Fonoteka singleton setting serves its localized schema and GET/PUT through Fill then Validate with `required: true` producing a 422; only compiled fillable fields can change.
statement verification
[flagged assumption ADMIN-05] Before a singleton row exists, GET is side-effect-free and returns exists: false plus the model's default-valued data; the first valid PUT creates it, and repeating an identical PUT is an idempotent success with unchanged persisted values. backstop
AUTH-08 identity no-change remains in force: all permission/navigation/settings evaluation uses the distinct backend_users principal and backend guard, never a generalized frontend user or add-alongside role.
path provides
../fonoteka.go/plugins/golem15/fonoteka/admin_permissions.go Complete exact plugin permission registry and role assignments
path provides
cabana/navigation.go Permission-filtered stable navigation and settings-list metadata
path provides
cabana/settings.go HasSettings registry plus singleton Fill/Validate GET/PUT service
path provides
../fonoteka.go/plugins/golem15/fonoteka/models/settings/fields.yaml Fonoteka settings form schema
from to via
Fonoteka permission registry backend role HasPermissions exact registered codes plus wildcard/superuser evaluation
from to via
cabana/navigation.go controller/settings registry permission-filtered target validation
from to via
cabana/settings.go lagoon.Fill and lagoon.Validate compiled writable projection and singleton transaction
[flagged-unverified] Navigation and settings metadata must not reveal the existence, label, or target of entries the backend principal cannot access.
[flagged-unverified] Reading a missing settings singleton must not create a database row or mutate defaults.

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.

Complete the backend permission catalog, permission-filtered navigation, and singleton settings capability.

Purpose: Make AUTH-08 authorization visible and coherent across discovery metadata and deliver ADMIN-05 without bypassing the schema/lifecycle pipeline. Output: Exact plugin registries, stable filtered metadata endpoints, and permissioned singleton settings schema/read/write routes.

<execution_context> @/home/jin/.codex/gsd-core/workflows/execute-plan.md @/home/jin/.codex/gsd-core/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.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-02-SUMMARY.md @.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-07-SUMMARY.md @.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-08-SUMMARY.md @.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-09-SUMMARY.md @.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-10-SUMMARY.md @pact/capabilities.go @lagoon/fill.go @lagoon/validate.go @../fonoteka.go/plugins/golem15/fonoteka/models/settings.go

Artifacts this phase produces

  • Complete Fonoteka backend permission declarations and publisher assignments
  • cabana.NavigationItem, cabana.SettingsEntry, and filtered metadata response services
  • cabana.SettingsService and D-09 /settings schema/GET/PUT routes
  • fonoteka.AdminSettings registration plus embedded settings fields.yaml
  • Assembled TestAdminMetadata* and TestAdminSettings* suites
Task 1: Register exact permissions and validate every operation reference cabana/registry.go, ../fonoteka.go/plugins/golem15/fonoteka/admin_permissions.go, ../fonoteka.go/plugins/golem15/fonoteka/admin_metadata_test.go cabana/registry.go, pact/capabilities.go, bouncer/registry.go, bouncer/guard.go, /media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/Plugin.php, .planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-CONTEXT.md - Test 1: every source Fonoteka permission code/label is registered exactly once, publisher assignments match the source, and developer/superuser wildcard grants all registered codes. - Test 2: every controller operation, relation, navigation target, and setting names a registered permission; unknown or duplicate codes fail activation. - Test 3: a frontend user identity with matching numeric ID/permissions cannot satisfy a backend permission check. Implement the complete D-03 permission contribution from the tracked plugin source and bind it to D-01's developer/publisher roles. Extend cabana activation validation so all controller operations, relations, navigation items, and settings reference registered codes and duplicate/unknown declarations stop boot. Keep evaluation on the backend `bouncer.Principal` established by the named backend guard, preserving exact and wildcard semantics; do not adapt frontend-user roles into the admin registry. (cd ../fonoteka.go && go test ./plugins/golem15/fonoteka -run '^TestAdminMetadata(Permissions|Publisher|Wildcard|RegistryReferences|RejectsFrontendPrincipal)$' -count=1) The command exits non-zero, reports no matching test, a source permission/assignment is absent, duplicate/unknown references activate, wildcard/exact semantics drift, or a frontend identity passes backend authorization. The exact permission catalog is complete, referentially valid, role-assigned, and exclusively evaluated against the distinct backend identity. Every backend operation and metadata entry has a validated permission code with correct role behavior. Task 2: Serve exact permission-filtered navigation and settings metadata cabana/navigation.go, ../fonoteka.go/plugins/golem15/fonoteka/admin_navigation.go, ../fonoteka.go/plugins/golem15/fonoteka/admin_metadata_test.go /media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/Plugin.php, ../fonoteka.go/plugins/golem15/fonoteka/admin_permissions.go, cabana/registry.go, bouncer/guard.go - Test 1: navigation/settings metadata exactly preserves registered labels/icons/order/targets/keywords and sorts by order then stable code. - Test 2: developer sees all source entries, publisher sees only permitted entries, and a no-permission admin receives allocated empty arrays. - Test 3: a metadata item with missing target or permission fails activation; responses never include denied item fields. Port D-18's exact `registerNavigation()` shape and provide typed HasNavigation/HasSettings registry consumption. Validate controller/setting targets and permissions at activation, then filter whole entries before serialization through `HasPermissions`; never serialize then mask selected fields. Preserve the declared plugin shape and stable order/code tie-break, use request-time localization, and return non-null empty arrays. (cd ../fonoteka.go && go test ./plugins/golem15/fonoteka -run '^TestAdminMetadata(Navigation|SettingsList|Filtering|StableOrder|RejectsInvalidTarget)$' -count=1) The command exits non-zero, reports no matching test, source metadata differs, ordering is unstable, empty output is null, an invalid target activates, or any denied entry field appears in the response. Navigation and settings-list metadata are exact, stable, localized, referentially valid, and filtered as whole entries by backend permission. An admin discovers only the controllers and settings pages that they can actually open. Task 3: Serve permissioned singleton settings through Fill and Validate cabana/settings.go, cabana/http.go, ../fonoteka.go/plugins/golem15/fonoteka/admin_settings.go, ../fonoteka.go/plugins/golem15/fonoteka/models/settings/fields.yaml, ../fonoteka.go/plugins/golem15/fonoteka/admin_settings_test.go ../fonoteka.go/plugins/golem15/fonoteka/models/settings.go, /media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/models/settings/fields.yaml, lagoon/fill.go, lagoon/validate.go, cabana/form_schema.go, cabana/http.go - Test 1: schema/GET/PUT require the settings permission before model/database work and return the D-17 localized typed form contract. - Test 2: missing GET creates no row and returns exists false/default data; valid first PUT creates one row; identical repeated PUT leaves one row with unchanged values. - Test 3: unknown/protected fields are ignored/rejected by writable projection, required/modeled Rules failures return 422, and failed update rolls back the singleton. Implement the D-17 HasSettings registry/service and D-09 routes for schema, GET, and PUT. Register the existing typed Fonoteka settings model and a complete embedded form schema under code `fonoteka` with `golem15.fonoteka.manage_settings`. For the flagged ADMIN-05 edge assumption, make missing GET side-effect-free with `exists: false` and a default-valued safe DTO, then make PUT lock/find-or-create the singleton and apply compiled writable projection, lagoon.Fill, and lagoon.Validate in one transaction. Treat identical PUT as success without adding rows or changing timestamps solely due to replay. (cd ../fonoteka.go && go test ./plugins/golem15/fonoteka -run '^TestAdminSettings(Schema|PermissionOrder|MissingRead|Create|IdempotentUpdate|Projection|Validation|Rollback)$' -count=1) The command exits non-zero, reports no matching test, PostgreSQL is skipped, permission follows model/database work, GET creates a row, repeated PUT creates/mutates again, a protected key changes, required/Rules validation is skipped, or failure commits state. ADMIN-05 has explicit missing/create/repeat semantics and all D-17 schema, permission, Fill, Validate, projection, singleton, and transaction guarantees. Fonoteka settings are discoverable only when permitted and safely readable/updatable as one validated singleton.

<threat_model>

Trust Boundaries

Boundary Description
backend principal→metadata Authorization determines which controller/setting existence can be disclosed
settings JSON→singleton row Untrusted fields attempt to mutate persistent global configuration

STRIDE Threat Register

Threat ID Category Component Severity Disposition Mitigation Plan
T-09-18 Tampering / Elevation settings PUT high mitigate Permission first, compiled writable projection, Fill/Validate, singleton row lock, transaction rollback, and protected-field fixtures in Task 3.
T-09-19 Information Disclosure navigation/settings metadata medium mitigate Filter whole entries before serialization, validate targets/permissions at activation, and test no-permission responses for field leakage.
T-09-SC Tampering npm/pip/cargo installs high mitigate No npm/pip/cargo install occurs; existing Go dependencies only, so the package-legitimacy gate remains closed.
</threat_model>
Run `(cd ../fonoteka.go && go test ./plugins/golem15/fonoteka -run '^(TestAdminMetadata|TestAdminSettings)' -count=1)`; it fails on non-zero exit, zero matched tests, catalog/source drift, backend/frontend identity crossover, metadata disclosure, settings mass assignment, singleton replay drift, or validation/transaction bypass.

<success_criteria>

  • Permission declarations and publisher/developer behavior match the tracked plugin source and D-01/D-03.
  • D-18 navigation and settings metadata are stable and filter denied entries before serialization.
  • D-17 settings schema/GET/PUT use permission-first writable projection, Fill, Validate, and singleton transactions.
  • The flagged ADMIN-05 missing/create/repeat assumption has executable assembled backstop tests. </success_criteria>
Create `.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-11-SUMMARY.md` when done.