Execute-phase Task 2 chose golem15-prefix over the researched winter_translate_* names so the plugin ships vendor tables; PHP winter names stay a later import mapping. Co-authored-by: Cursor <cursoragent@cursor.com>
247 lines
20 KiB
Markdown
247 lines
20 KiB
Markdown
---
|
|
phase: 14.2.1-translate-plugin
|
|
plan: 04
|
|
type: execute
|
|
wave: 4
|
|
depends_on: ["14.2.1-03"]
|
|
files_modified:
|
|
- ../sm-translate-plugin/updates/postgres_test.go
|
|
- ../sm-translate-plugin/updates/migrations_test.go
|
|
- ../sm-translate-plugin/classes/translator_test.go
|
|
- ../sm-translate-plugin/classes/translatable_test.go
|
|
- ../sm-translate-plugin/admin_harness_test.go
|
|
- ../sm-translate-plugin/locales_admin_test.go
|
|
- ../sm-translate-plugin/integration_test.go
|
|
- modules/surf/locale_resolver_test.go
|
|
- modules/cabana/ml_test.go
|
|
- modules/cabana/markdown_test.go
|
|
- modules/cabana/openapi_conformance_test.go
|
|
- admin/tests/form/MLFields.test.ts
|
|
- admin/tests/form/MarkdownField.test.ts
|
|
- ../sm-grzybyfunkcjonalne-app/boot_test.go
|
|
- scripts/check-phase14.2.1.sh
|
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-SECURITY-REVIEW.md
|
|
- .planning/phases/14.2.1-translate-plugin/14.2.1-VALIDATION.md
|
|
autonomous: true
|
|
requirements: [D-01, D-02, D-03, D-04, D-05, D-06, D-07, D-08, D-09, D-10, D-11, D-12, D-13, D-14, D-15, D-16, D-17]
|
|
must_haves:
|
|
truths:
|
|
- "A real-Postgres integration test migrates all four golem15_translate tables, activates user+translate+fixture, saves en/pl through cabana ML fields, reads via WithLocale, and reaches Locales admin."
|
|
- "Migration up/down verifies every final column/index, empty Messages table, idempotent en/pl seed, absence of de, and complete rollback."
|
|
- "Translator tests prove URL → preferred_locale → remembered locale → cookie-gated Accept-Language → default, invalid-code rejection, API order, plugin-absent surf behavior, and concurrent request isolation."
|
|
- "Translatable tests prove default-row storage, non-default JSON, default fallback, indexed lookup, undeclared-field rejection, invalid-locale rejection, and atomic preservation of sibling fields."
|
|
- "Admin/ML tests prove manage_locales authorization, default-locale lifecycle guards, mass-assignment resistance, nested-map preservation, synchronized locale controls, and stored-XSS rejection."
|
|
- "All three repositories pass vet/tests; docs/OpenAPI/types/dist consistency checks pass; a security review closes every high threat."
|
|
artifacts:
|
|
- path: "../sm-translate-plugin/integration_test.go"
|
|
provides: "full production-path integration proof"
|
|
contains: "TestTranslateEndToEnd"
|
|
- path: "../sm-translate-plugin/updates/migrations_test.go"
|
|
provides: "real Postgres migration up/down and seed proof"
|
|
contains: "golem15_translate_messages"
|
|
- path: "modules/surf/locale_resolver_test.go"
|
|
provides: "resolver-present/absent and request-isolation tests"
|
|
contains: "TestLocaleResolver"
|
|
- path: "modules/cabana/ml_test.go"
|
|
provides: "nested ML write and mass-assignment tests"
|
|
contains: "TestML"
|
|
- path: "scripts/check-phase14.2.1.sh"
|
|
provides: "fail-closed phase gate"
|
|
contains: "sm-translate-plugin"
|
|
- path: ".planning/phases/14.2.1-translate-plugin/14.2.1-SECURITY-REVIEW.md"
|
|
provides: "ASVS L1 threat evidence"
|
|
contains: "T-14.2.1-01"
|
|
key_links:
|
|
- from: "../sm-translate-plugin/integration_test.go"
|
|
to: "modules/cabana/field_ml.go"
|
|
via: "fixture admin save uses real TranslationWriter"
|
|
pattern: "TestTranslateEndToEnd"
|
|
- from: "scripts/check-phase14.2.1.sh"
|
|
to: "../sm-translate-plugin/updates/migrations_test.go"
|
|
via: "full plugin test suite runs with Docker/Postgres, not -short"
|
|
pattern: "go -C"
|
|
- from: ".planning/phases/14.2.1-translate-plugin/14.2.1-SECURITY-REVIEW.md"
|
|
to: "modules/cabana/ml_test.go"
|
|
via: "each mitigated high threat cites executed failure evidence"
|
|
pattern: "T-14.2.1"
|
|
---
|
|
|
|
<objective>
|
|
Finish Phase 14.2.1 with the dedicated unit/integration/security test plan and one fail-closed gate across plugin, framework, admin SPA, and proof host.
|
|
|
|
Purpose: make every locked decision and high-risk locale/admin write behavior observably fail when broken.
|
|
Output: full test matrix, migration rollback proof, phase gate, security review, and validated validation map.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@~/.codex/gsd-core/workflows/execute-plan.md
|
|
@~/.codex/gsd-core/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/phases/14.2.1-translate-plugin/14.2.1-01-SUMMARY.md
|
|
@.planning/phases/14.2.1-translate-plugin/14.2.1-02-SUMMARY.md
|
|
@.planning/phases/14.2.1-translate-plugin/14.2.1-03-SUMMARY.md
|
|
@.planning/phases/14.2.1-translate-plugin/14.2.1-VALIDATION.md
|
|
@.planning/phases/14.2.1-translate-plugin/14.2.1-RESEARCH.md
|
|
@.planning/phases/14.2.1-translate-plugin/14.2.1-PATTERNS.md
|
|
@../fonoteka.go/plugins/golem15/user/updates/postgres_test.go
|
|
@../fonoteka.go/plugins/golem15/user/admin_harness_test.go
|
|
@scripts/check-phase14.sh
|
|
</context>
|
|
|
|
## Spec-less probe fallback
|
|
|
|
The phase has no mapped REQUIREMENTS.md IDs. This is a visible, intentional skip of spec-less probes. Tests and gate rows map directly to D-01 through D-17, the frozen PHP pin, and the RESEARCH validation/threat tables.
|
|
|
|
## Artifacts this phase produces
|
|
|
|
- `TestTranslateEndToEnd` spanning migration, activation, resolver, permissioned admin, nested ML write, en/pl storage, fallback, and indexed query.
|
|
- Real-Postgres migration/seed/rollback suite.
|
|
- Translator, surf, Translatable, Locales admin, cabana ML/markdown, SPA, generated-contract, and proof-host tests.
|
|
- `scripts/check-phase14.2.1.sh` with short/full/docs/admin/host/security stages.
|
|
- `14.2.1-SECURITY-REVIEW.md` and a completed `14.2.1-VALIDATION.md`.
|
|
|
|
## Multi-source coverage audit
|
|
|
|
| SOURCE | ID | Feature/Requirement | Plan | Status | Notes |
|
|
|---|---|---|---|---|---|
|
|
| GOAL | — | Lean Translate core lets Journal keep translatable fields and boots in proof host | 01-04 | COVERED | Schema, API, admin, ML fields, host, tests |
|
|
| REQ | — | No mapped requirement IDs | — | COVERED | Visible spec-less fallback; D-IDs are used |
|
|
| CONTEXT | D-01..D-04 | Frozen/read-only PHP SHA | 01,04 | COVERED | Pin asserted; PHP tree unchanged |
|
|
| CONTEXT | D-05 | Locale/admin/behavior lean scope; deferred surfaces absent | 02,04 | COVERED | Negative scope checks in gate |
|
|
| CONTEXT | D-06 | markdown/mltext/mlmarkdown compose | 03,04 | COVERED | Go + SPA + generated artifacts |
|
|
| CONTEXT | D-07 | full request locale resolution | 01,04 | COVERED | Ordered and concurrent tests |
|
|
| CONTEXT | D-08 | en/pl only | 01,04 | COVERED | Seed/absence tests |
|
|
| CONTEXT | D-09..D-12 | explicit Translatable APIs/storage/fallback | 02-04 | COVERED | Fixture and full matrix |
|
|
| CONTEXT | D-13..D-17 | proof host, remotes, submodules, boot/proof | 01,03,04 | COVERED | Host smoke and layout checks |
|
|
| RESEARCH | — | Exact four final tables/columns/indexes and migrations up/down | 01,04 | COVERED | Real Postgres |
|
|
| RESEARCH | — | Permission, default-locale guards, phrasebook separation | 02,04 | COVERED | Admin suite |
|
|
| RESEARCH | — | Nested ML map before projection, safe markdown | 03,04 | COVERED | Security tests |
|
|
| RESEARCH | — | README/docs/OpenAPI/TS/dist same change | 03,04 | COVERED | Consistency gate |
|
|
| RESEARCH | — | No external SaaS API integration | 01-04 | COVERED | No COVERAGE matrix or fabricated API tests |
|
|
|
|
Excluded by explicit scope: Messages catalogue/admin, CMS locale components, locale picker/hreflang/banner, AI/theme commands, message import/export, extra locale seeds, PHP edits, and Phase 15 Journal implementation.
|
|
|
|
<tasks>
|
|
|
|
<task type="tracer">
|
|
<name>Task 1: Prove migration → activation → resolver → Locales admin → ML save → WithLocale read end to end</name>
|
|
<files>../sm-translate-plugin/updates/postgres_test.go, ../sm-translate-plugin/integration_test.go, ../sm-translate-plugin/admin_harness_test.go, ../sm-grzybyfunkcjonalne-app/boot_test.go</files>
|
|
<read_first>../fonoteka.go/plugins/golem15/user/updates/postgres_test.go, ../fonoteka.go/plugins/golem15/user/admin_harness_test.go, ../sm-translate-plugin/plugin.go, ../sm-translate-plugin/classes/translator.go, ../sm-translate-plugin/classes/translatable.go, ../sm-translate-plugin/controllers/locales.go, modules/cabana/ml_smoke_test.go, ../sm-grzybyfunkcjonalne-app/boot_test.go, .planning/phases/14.2.1-translate-plugin/14.2.1-VALIDATION.md</read_first>
|
|
<action>Build the final integration harness on testcontainers Postgres, copying the proven user-plugin fail-closed TestMain/dedicated database pattern. Docker unavailability is a failure for full runs; only an explicit `-short` invocation may skip integration.
|
|
|
|
`TestTranslateEndToEnd` must migrate user and translate plugin sets in dependency order, activate the real user and translate plugins plus a test-only neutral fixture controller/model, assemble surf/cabana, and create backend principals with and without `golem15.translate.manage_locales`. Assert unauthorized Locales access is 403 and authorized schema/list sees en then pl. Send one real fixture create/update body with mltext title and mlmarkdown body maps for en/pl. Assert host columns contain English, only the Polish non-default attribute row exists, safe markdown source round-trips, `WithLocale(...,"pl")` reads Polish, a missing Polish field falls back to English, and indexed Polish slug lookup finds only the fixture.
|
|
|
|
Exercise a request with `/pl/...` and conflicting preferred/session/header candidates to prove URL precedence reaches `towel.Locale(ctx) == "pl"`. Keep all fixture plugin/model registration process-local to the test.
|
|
|
|
Expand host `TestBootUserTranslate` to prove both actual gitlink plugins activate, migrations are discoverable, and the Locales controller/permission are registered. It need not duplicate the fixture model.</action>
|
|
<verify>
|
|
<automated>go -C ../sm-translate-plugin test ./... -count=1 -v -run '^(TestTranslateEndToEnd)$' && go -C ../sm-grzybyfunkcjonalne-app test ./... -count=1 -v -run '^(TestBootUserTranslate)$'</automated>
|
|
<fails_when>Non-zero exit; either run prints "--- FAIL", "--- SKIP", "no tests to run", container startup failure treated as skip, or lacks its named "--- PASS" line.</fails_when>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- Integration uses real Postgres and actual gormigrate/party/surf/cabana production paths.
|
|
- Unauthorized Locales is 403; authorized list includes only seeded en/pl in order.
|
|
- One nested admin save persists English on the host and Polish in attributes/indexes.
|
|
- WithLocale Polish read, default fallback, and indexed lookup all pass.
|
|
- URL prefix wins over all conflicting candidates and locale is context-only.
|
|
- Fixture registration cannot appear in the production plugin list or host binary.
|
|
</acceptance_criteria>
|
|
<done>The entire Phase 14.2.1 user-visible path is proven through production wiring on real Postgres before horizontal test expansion.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Complete migration, Translator, Translatable, admin, ML, markdown, and SPA test matrices</name>
|
|
<files>../sm-translate-plugin/updates/migrations_test.go, ../sm-translate-plugin/classes/translator_test.go, ../sm-translate-plugin/classes/translatable_test.go, ../sm-translate-plugin/locales_admin_test.go, modules/surf/locale_resolver_test.go, modules/cabana/ml_test.go, modules/cabana/markdown_test.go, modules/cabana/openapi_conformance_test.go, admin/tests/form/MLFields.test.ts, admin/tests/form/MarkdownField.test.ts</files>
|
|
<read_first>/media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/tests/unit/behaviors/TranslatableModelTest.php, ../sm-translate-plugin/integration_test.go, ../sm-translate-plugin/updates/202610060001_create_golem15_translate_locales.go, ../sm-translate-plugin/classes/translator.go, ../sm-translate-plugin/classes/translatable.go, modules/surf/locale_from_principal_test.go, modules/cabana/form_schema_test.go, modules/cabana/field_permission.go, admin/tests/form/DatepickerField.test.ts, admin/tests/form/registry.test.ts</read_first>
|
|
<action>Complete the decision and security matrix without adding unrelated PHP-suite surfaces.
|
|
|
|
Migration tests: assert every final table, column type/default, PHP-indexed column, empty Messages row count, no rainlab/provisional tables, idempotent seed, en/pl exact flags/order/names, no de, and rollback removes all four tables in reverse-safe order. Re-migrate after rollback.
|
|
|
|
Translator tests: table-drive URL prefix precedence and stripping; preferred locale; remembered locale; absent/present manual flag behavior; weighted Accept-Language reduced only to enabled codes; default fallback; invalid URL/session/header ignored; API resolver preferred → header → default without persistence; plugin-absent surf retains old behavior. Run parallel requests with conflicting locales under `-race` and assert no cross-request leak.
|
|
|
|
Translatable tests: default/non-default storage, D-11 fallback, explicit empty translation, invalid locale and undeclared field no-write, sibling JSON field preservation, indexed upsert/update and morph/model isolation, WithLocale context isolation, transaction rollback. Admin tests: exact permission 403/allowed, is_default/sort_order mass-assignment rejection, delete/unset/disabled-default guards, no manage_messages surface, phrasebook keys in en/pl.
|
|
|
|
Cabana tests: three types compile and unknown `mlunknown` fails; non-ML nested values remain blocked; ML values lift before projection; malformed/extra locale keys fail; writer failure rolls back host write; writer is not invoked before permission/query checks. Markdown tests include script, iframe, event attributes, javascript/vbscript/data schemes. SPA tests cover selector synchronization, per-locale editing, copy, complete nested payload, and markdown composition without raw-HTML sinks. Extend OpenAPI conformance for all types.</action>
|
|
<verify>
|
|
<automated>go -C ../sm-translate-plugin test ./... -count=1 -race && go test ./modules/surf ./modules/cabana -count=1 -race && npm --prefix admin test -- --run admin/tests/form/registry.test.ts admin/tests/form/MLFields.test.ts admin/tests/form/MarkdownField.test.ts</automated>
|
|
<fails_when>Non-zero exit; Go race detector reports a race; any package/test reports FAIL; integration tests unexpectedly SKIP in the plugin run; or Vitest reports no tests or failures.</fails_when>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- Every D-01..D-17 behavior assigned to code has at least one named assertion or gate check.
|
|
- Migrate, rollback, and re-migrate are proven against real Postgres.
|
|
- Parallel locale tests pass under `-race` with no shared current-locale state.
|
|
- High threats T-14.2.1-01/02/04/05/06/07/09/10/11/12 have concrete fail-when-broken tests.
|
|
- No tests require Messages admin, CMS components, AI/theme commands, import/export, or extra locale seeds.
|
|
</acceptance_criteria>
|
|
<done>All production branches introduced by Plans 01-03 have focused unit or integration evidence, including race, rollback, authorization, mass-assignment, and XSS cases.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 3: Build the fail-closed phase gate, security review, and validation sign-off</name>
|
|
<files>scripts/check-phase14.2.1.sh, .planning/phases/14.2.1-translate-plugin/14.2.1-SECURITY-REVIEW.md, .planning/phases/14.2.1-translate-plugin/14.2.1-VALIDATION.md</files>
|
|
<read_first>scripts/check-phase14.sh, scripts/check-phase12.2.sh, .planning/phases/14.2.1-translate-plugin/14.2.1-VALIDATION.md, .planning/phases/14.2.1-translate-plugin/14.2.1-RESEARCH.md (Security Domain and Validation Architecture), .planning/phases/14.2.1-translate-plugin/14.2.1-01-PLAN.md (T-14.2.1-01..04), .planning/phases/14.2.1-translate-plugin/14.2.1-02-PLAN.md (T-14.2.1-05..08), .planning/phases/14.2.1-translate-plugin/14.2.1-03-PLAN.md (T-14.2.1-09..13)</read_first>
|
|
<action>Create `scripts/check-phase14.2.1.sh` with explicit stages: frozen PHP SHA and no PHP diff; tracked-source/module/layout checks; plugin vet/full tests/race; framework cabana+surf vet/tests/race; docs tree and docs build check; admin typecheck/tests/build plus generated OpenAPI/schema/dist cleanliness; proof-host vet/test/build; forbidden-scope scan; security evidence. Use `go -C <repo>` exactly for sibling repositories. Full mode must run Postgres integration and fail if Docker is unavailable; do not treat `-short` as final evidence. Detect zero-test filters by requiring named PASS lines where a filter is used.
|
|
|
|
Run the requested security-review lane over the local Phase 14.2.1 changes. Produce `14.2.1-SECURITY-REVIEW.md` at ASVS L1, preserving unique threat IDs T-14.2.1-01 through T-14.2.1-18. For every high threat, cite the exact source control and executed named test; status must be mitigated or the phase gate remains red. Review locale injection, manage_locales privilege, nested ML JSON, stored XSS, mass assignment, process-wide leakage, and submodule provenance. Do not fabricate an external-API matrix: state `No external API integration: this phase ports a compiled plugin and local framework/host contracts only.`
|
|
|
|
Update VALIDATION frontmatter to validated/nyquist compliant/wave 0 complete only after all mapped commands pass. Replace pending rows with exact test names and threat references, record the proof-host/manual Locales SPA check as end-of-phase UAT, and run the phase gate once in full.</action>
|
|
<verify>
|
|
<automated>bash scripts/check-phase14.2.1.sh --all</automated>
|
|
<fails_when>Non-zero exit; any stage is absent/skipped; output contains FAIL, a Go race, no-tests-to-run, unexpected SKIP, stale generated artifacts, forbidden deferred surface, unmitigated high threat, or lacks the final `Phase 14.2.1 gate passed` line.</fails_when>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- Gate uses `go -C ../sm-translate-plugin` and `go -C ../sm-grzybyfunkcjonalne-app`; it does not invent a nested application directory.
|
|
- Plugin, cabana, surf, admin, docs, generated artifacts, and proof host all have explicit fail-closed stages.
|
|
- Security review contains every T-14.2.1-NN exactly once and blocks on all high findings.
|
|
- Validation rows name existing tests/commands and frontmatter is marked validated/nyquist compliant only after green execution.
|
|
- Gate confirms no Messages admin/manage_messages, CMS locale components, AI/theme commands, import/export, de seed, runtime plugin loading, AutoMigrate, or PHP modifications.
|
|
</acceptance_criteria>
|
|
<done>The full three-repository phase gate is green, all high threats are mitigated with executed evidence, and validation is signed off.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<threat_model>
|
|
## Trust Boundaries
|
|
|
|
| Boundary | Description |
|
|
|----------|-------------|
|
|
| Test/gate → production claims | A no-op, skipped container, or stale generated artifact must not pass |
|
|
| Concurrent requests → context locale | Conflicting request locales must stay isolated |
|
|
| Security review → phase completion | High findings block completion |
|
|
|
|
## STRIDE Threat Register
|
|
|
|
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
|
|-----------|----------|-----------|----------|-------------|-----------------|
|
|
| T-14.2.1-14 | Repudiation | phase gate | high | mitigate | Require named PASS/final marker; reject no-tests and unexpected skips |
|
|
| T-14.2.1-15 | Information Disclosure | concurrent Translator | high | mitigate | Race-enabled conflicting-locale test asserts context isolation |
|
|
| T-14.2.1-16 | Tampering | migration rollback | medium | mitigate | Up/down/re-up on dedicated Postgres with exact schema assertions |
|
|
| T-14.2.1-17 | Tampering | generated admin artifacts | medium | mitigate | Regenerate and require clean OpenAPI/TS/dist diff after build |
|
|
| T-14.2.1-18 | Elevation of Privilege | test fixture | high | mitigate | Fixture plugin is process-local/test-only and absent from generated production imports |
|
|
| T-14.2.1-SC | Tampering | package installs | high | mitigate | No dependency installation; existing exact pins and lockfile only |
|
|
|
|
ASVS L1: phase completion is blocked on every high finding.
|
|
</threat_model>
|
|
|
|
<verification>
|
|
`bash scripts/check-phase14.2.1.sh --all` is the authoritative final command and must end with `Phase 14.2.1 gate passed`.
|
|
|
|
<human-check>
|
|
With the executor-started proof host and admin SPA, sign in as an administrator holding `golem15.translate.manage_locales`; open Locales, confirm English and Polski appear in order, edit the permitted name/enabled fields, and verify a user without the permission cannot open the controller.
|
|
</human-check>
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Full unit, integration, race, migration rollback, SPA, docs, generated-artifact, and host gates pass.
|
|
- Every locked D-01..D-17 decision is covered.
|
|
- Every high STRIDE threat is mitigated with source and named-test evidence.
|
|
- No deferred surface or new external dependency entered the phase.
|
|
</success_criteria>
|
|
|
|
<output>
|
|
Create `.planning/phases/14.2.1-translate-plugin/14.2.1-04-SUMMARY.md` when done.
|
|
</output>
|