docs(15): create phase plan
This commit is contained in:
287
.planning/phases/15-journal-plugin/15-04-PLAN.md
Normal file
287
.planning/phases/15-journal-plugin/15-04-PLAN.md
Normal file
@@ -0,0 +1,287 @@
|
||||
---
|
||||
phase: 15-journal-plugin
|
||||
plan: 04
|
||||
type: execute
|
||||
wave: 4
|
||||
depends_on: ["15-03"]
|
||||
files_modified:
|
||||
- ../sm-journal-plugin/updates/postgres_test.go
|
||||
- ../sm-journal-plugin/updates/migrations_test.go
|
||||
- ../sm-journal-plugin/models/fillable_test.go
|
||||
- ../sm-journal-plugin/models/translatable_test.go
|
||||
- ../sm-journal-plugin/classes/format_html_test.go
|
||||
- ../sm-journal-plugin/admin_harness_test.go
|
||||
- ../sm-journal-plugin/controllers/api/posts_test.go
|
||||
- ../sm-journal-plugin/controllers/api/media_test.go
|
||||
- ../sm-journal-plugin/search_test.go
|
||||
- ../sm-journal-plugin/integration_test.go
|
||||
- ../sm-grzybyfunkcjonalne-app/boot_test.go
|
||||
- scripts/check-phase15.sh
|
||||
- .planning/phases/15-journal-plugin/15-SECURITY-REVIEW.md
|
||||
- .planning/phases/15-journal-plugin/15-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, D-18, D-19, D-20, D-21, D-22, D-23]
|
||||
estimate:
|
||||
tokens: 90000
|
||||
raw_tokens: 90000
|
||||
tasks: 3
|
||||
confidence: low
|
||||
must_haves:
|
||||
truths:
|
||||
- "D-05: every RESEARCH §8 PHPUnit row has a named Go test (JOURNAL-001/002 fillable, JOURNAL-005 draft 404, JOURNAL-006 media, FormatHTML substitutes JOURNAL-003/004 templates, redactor_id not fillable)."
|
||||
- "Real Postgres migrates all golem15_journal_* tables plus author_slug, rolls back, and remigrates."
|
||||
- "Anonymous list hides drafts; GET categories and tags return 200 PHP {data} lists; GET rss is well-formed RSS 2.0 honoring rss_*; write without Bearer is 401 Authentication required including featured-images POST/DELETE; Typesense gate off records zero HTTP."
|
||||
- "Host Activate still returns user+translate+journal; CORS includes _journal/api/*; plugin README stays application-neutral."
|
||||
- "scripts/check-phase15.sh --all is fail-closed; 15-SECURITY-REVIEW.md closes every high T-15-* threat."
|
||||
artifacts:
|
||||
- path: "../sm-journal-plugin/integration_test.go"
|
||||
provides: "end-to-end migrate, admin create, public GET, Bearer write, draft 404"
|
||||
contains: "TestJournalEndToEnd"
|
||||
- path: "../sm-journal-plugin/models/fillable_test.go"
|
||||
provides: "JOURNAL-001/002"
|
||||
contains: "TestFillable"
|
||||
- path: "../sm-journal-plugin/controllers/api/posts_test.go"
|
||||
provides: "JOURNAL-005, 401 PHP shape, categories/tags lists, RSS XML, featured-image auth"
|
||||
contains: "TestJournal005DraftShow"
|
||||
- path: "scripts/check-phase15.sh"
|
||||
provides: "fail-closed phase gate"
|
||||
contains: "sm-journal-plugin"
|
||||
- path: ".planning/phases/15-journal-plugin/15-SECURITY-REVIEW.md"
|
||||
provides: "ASVS L1 threat evidence"
|
||||
contains: "T-15-01"
|
||||
key_links:
|
||||
- from: "../sm-journal-plugin/integration_test.go"
|
||||
to: "../sm-journal-plugin/routes.go"
|
||||
via: "assembled public GET and Bearer POST through production handlers"
|
||||
pattern: "TestJournalEndToEnd"
|
||||
- from: "scripts/check-phase15.sh"
|
||||
to: "../sm-journal-plugin/updates/migrations_test.go"
|
||||
via: "full plugin suite with Docker/Postgres, not -short as final evidence"
|
||||
pattern: "go -C"
|
||||
- from: ".planning/phases/15-journal-plugin/15-SECURITY-REVIEW.md"
|
||||
to: "../sm-journal-plugin/controllers/api/posts_test.go"
|
||||
via: "each high threat cites an executed TestName"
|
||||
pattern: "T-15-"
|
||||
prohibitions:
|
||||
- requirement_id: D-07
|
||||
category: safety
|
||||
statement: "Gate fails if the PHP journal tree at SHA 02110eb has a git diff"
|
||||
status: resolved
|
||||
verification: test
|
||||
- requirement_id: D-16
|
||||
category: architecture
|
||||
statement: "Gate fails if fonoteka.go parity/tide files newly mention /_journal/api/v1"
|
||||
status: resolved
|
||||
verification: test
|
||||
- requirement_id: D-12
|
||||
category: safety
|
||||
statement: "TestSearchGateOff must not skip and must observe zero search HTTP"
|
||||
status: resolved
|
||||
verification: test
|
||||
---
|
||||
|
||||
## Phase Goal
|
||||
|
||||
**As a** application developer, **I want to** mount `sm-journal-plugin` in a host the same way `sm-user-plugin` mounts, **so that** a blog can run on SummerCMS without the PHP plugin.
|
||||
|
||||
This plan's slice: the last plan of the phase — full unit/integration coverage, PHPUnit map, phase gate, and security review.
|
||||
|
||||
<objective>
|
||||
Finish Phase 15 with the dedicated test plan: PHPUnit behavioral map, migration rollback, HTTP/security cases, fail-closed gate, and ASVS L1 review.
|
||||
|
||||
Purpose: every locked D-ID and high threat fails closed when broken.
|
||||
Output: test matrix, scripts/check-phase15.sh, 15-SECURITY-REVIEW.md, validated 15-VALIDATION.md.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@~/.codex/gsd-core/workflows/execute-plan.md
|
||||
@~/.codex/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/phases/15-journal-plugin/15-VALIDATION.md
|
||||
@.planning/phases/15-journal-plugin/15-RESEARCH.md
|
||||
@.planning/phases/15-journal-plugin/15-PATTERNS.md
|
||||
@../sm-translate-plugin/updates/postgres_test.go
|
||||
@../sm-translate-plugin/admin_harness_test.go
|
||||
@scripts/check-phase14.2.1.sh
|
||||
</context>
|
||||
|
||||
## Spec-less probe fallback
|
||||
|
||||
Visible skip: no REQUIREMENTS.md IDs and no phase SPEC Edge Coverage/Prohibitions to lift. Tests map to D-01..D-23, RESEARCH §8, and VALIDATION rows. Do not generate probe predicates. Do not claim API-09 or QA-05.
|
||||
|
||||
## API coverage
|
||||
|
||||
No external API integration: this phase ports a compiled plugin's own `/_journal/api/v1` surface and an optional beachcomber Gate that stays off; it does not integrate a third-party SaaS SDK. Do not fabricate a capability matrix.
|
||||
|
||||
## Artifacts this phase produces
|
||||
|
||||
- `TestJournalEndToEnd` spanning migrate, Activate, admin mlmarkdown save, anonymous list, Bearer write, JOURNAL-005, media 403.
|
||||
- Real-Postgres up/down for all seven journal migrations.
|
||||
- `scripts/check-phase15.sh` with plugin/host/PHP-pin/docs-neutral/security stages using `go -C ../sm-journal-plugin` and `go -C ../sm-grzybyfunkcjonalne-app`.
|
||||
- `15-SECURITY-REVIEW.md` and completed `15-VALIDATION.md`.
|
||||
|
||||
## Multi-source coverage audit
|
||||
|
||||
| SOURCE | ID | Feature/Requirement | Plan | Status | Notes |
|
||||
|---|---|---|---|---|---|
|
||||
| GOAL | — | Port Golem15.Journal to sm-journal-plugin and mount in a host | 01-04 | COVERED | Schema, admin, API, tests |
|
||||
| REQ | — | No mapped requirement IDs (TBD) | — | COVERED | Visible spec-less fallback; D-IDs used; API-09/QA-05 are Phase 20 |
|
||||
| CONTEXT | D-01..D-04 | Frozen PHP pin, tables, YAML/API binding | 01-04 | COVERED | SHA asserted; PHP unchanged |
|
||||
| CONTEXT | D-05 | PHPUnit map | 04 | COVERED | RESEARCH §8 |
|
||||
| CONTEXT | D-06 | en+pl only | 01,04 | COVERED | Lang files + gate |
|
||||
| CONTEXT | D-07 | No PHP edits | 01,04 | COVERED | git diff empty |
|
||||
| CONTEXT | D-08 | Nav SVG | 02,04 | COVERED | Embedded bytes |
|
||||
| CONTEXT | D-09 | Translate is a prior phase; Journal Requires it | 01,04 | COVERED | No Translate port inside Journal |
|
||||
| CONTEXT | D-10 | Translatable attributes | 01-04 | COVERED | MorphName PHP strings |
|
||||
| CONTEXT | D-11 | cabana markdown | 02,04 | COVERED | No-op; mlmarkdown only |
|
||||
| CONTEXT | D-12 | Typesense off by default | 03,04 | COVERED | Gate + TestSearchGateOff |
|
||||
| CONTEXT | D-13 | CSV CLI + toolbar | 02,04 | COVERED | TestJournalCommands |
|
||||
| CONTEXT | D-14 | Full /_journal/api/v1 | 03,04 | COVERED | routes.php wins |
|
||||
| CONTEXT | D-15 | Backend Bearer writes | 03,04 | COVERED | Not frontend tokens |
|
||||
| CONTEXT | D-16 | Not tide | 03,04 | COVERED | Gate forbids harness add |
|
||||
| CONTEXT | D-17 | Limiters + CORS | 01,03,04 | COVERED | Buckets + http.yaml |
|
||||
| CONTEXT | D-18..D-23 | Proof host and remotes | 01,04 | COVERED | Three-plugin boot |
|
||||
| RESEARCH | — | Squash golem15_journal_*; no rainlab-era names | 01,04 | COVERED | Migration tests |
|
||||
| RESEARCH | — | YAML rewrite; FilterScopes | 02,04 | COVERED | Form compile tests |
|
||||
| RESEARCH | — | FormatHTML plugin-local | 02,04 | COVERED | XSS substitute tests |
|
||||
| RESEARCH | — | PHP {error} JSON; per_page 9/30; slug show | 03,04 | COVERED | API tests |
|
||||
| RESEARCH | — | Sibling replace ../summercms.go | 01,04 | COVERED | Isolated go test |
|
||||
|
||||
Excluded (deferred / other phases): Phase 16 HTML/views/components; Winter.Pages menu types; dashboard widget; Apparatus personal tokens; 19 extra locales; WYSIWYG/redactor; editing wn-journal-plugin; tide 154-route harness; sitemap.
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="tracer">
|
||||
<name>Task 1: Prove migrate → admin save → anonymous list → Bearer write → draft 404 end to end</name>
|
||||
<files>../sm-journal-plugin/updates/postgres_test.go, ../sm-journal-plugin/admin_harness_test.go, ../sm-journal-plugin/integration_test.go, ../sm-grzybyfunkcjonalne-app/boot_test.go</files>
|
||||
<read_first>../sm-translate-plugin/updates/postgres_test.go, ../sm-translate-plugin/admin_harness_test.go, ../sm-translate-plugin/integration_test.go, ../sm-journal-plugin/plugin.go, ../sm-journal-plugin/routes.go, ../sm-journal-plugin/controllers/posts.go, ../sm-journal-plugin/controllers/api/posts.go, .planning/phases/15-journal-plugin/15-VALIDATION.md, .planning/phases/15-journal-plugin/15-RESEARCH.md (§8 PHPUnit map)</read_first>
|
||||
<action>Copy the translate/user fail-closed TestMain: testcontainers Postgres, dedicated database, Docker unavailability fails full runs; only explicit -short may skip.
|
||||
|
||||
TestJournalEndToEnd (D-05, D-14, D-15, D-19): migrate user, translate, and journal in Requires order; party.Activate those three plus a process-local test fixture only if needed (no production fixture plugin); cabana.Activate; surf.Assemble. Mint a backend principal with golem15.journal.access_posts plus access_publish, and a second principal without access_other_posts.
|
||||
|
||||
Create a published post and a draft via admin or model helpers using mlmarkdown maps for en/pl. Assert English on host columns and Polish in golem15_translate_attributes under MorphName Golem15\Journal\Models\Post.
|
||||
|
||||
GET /_journal/api/v1/posts with no Authorization returns 200 and only the published post (D-14). POST /posts without Bearer is 401 Authentication required (D-15, T-15-01). POST with backend Bearer creates a row. GET draft slug as anonymous is 404 with no data key (JOURNAL-005, T-15-02). Owner or access_other_posts sees 200.
|
||||
|
||||
Host TestBootUserTranslateJournal still activates three plugins, sees Journal controller IDs, CORS path, and /_journal/api/v1 GET+POST. It must not duplicate the full fixture matrix.
|
||||
|
||||
Do not import sm-user-plugin from journal production code; host tests may join users if present. redactor_id column exists and is not in Fillable; set only via explicit assign (PostRedactor analog, D-05).</action>
|
||||
<verify>
|
||||
<automated>go -C ../sm-journal-plugin test ./... -count=1 -v -run '^(TestJournalEndToEnd)$' && go -C ../sm-grzybyfunkcjonalne-app test ./... -count=1 -v -run '^(TestBootUserTranslateJournal)$'</automated>
|
||||
<fails_when>Non-zero exit; either run prints "--- FAIL", "--- SKIP", "no tests to run", or container startup treated as skip; lacks its named PASS line.</fails_when>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- Integration uses real Postgres and production gormigrate/party/surf/cabana paths.
|
||||
- Anonymous list hides the draft; draft show 404 has no data key.
|
||||
- Bearer write succeeds for a permitted backend principal and 401s without Authorization using the PHP string error.
|
||||
- Polish title is in translate attributes keyed by the PHP Post morph string.
|
||||
- Host boot still lists exactly the three production plugins.
|
||||
</acceptance_criteria>
|
||||
<done>The Phase 15 user-visible path is proven on real Postgres before the horizontal test matrix.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Complete PHPUnit map, migrations, YAML, FormatHTML, and search-gate tests</name>
|
||||
<files>../sm-journal-plugin/updates/migrations_test.go, ../sm-journal-plugin/models/fillable_test.go, ../sm-journal-plugin/models/translatable_test.go, ../sm-journal-plugin/classes/format_html_test.go, ../sm-journal-plugin/controllers/api/posts_test.go, ../sm-journal-plugin/controllers/api/media_test.go, ../sm-journal-plugin/search_test.go, ../sm-journal-plugin/admin_harness_test.go</files>
|
||||
<read_first>.planning/phases/15-journal-plugin/15-RESEARCH.md (§8 PHPUnit map, JOURNAL-001..006), /media/nvme/dev/golem15/fonoteka/plugins/golem15/journal/tests/security/AccessControlTest.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/journal/tests/security/MassAssignmentTest.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/journal/tests/security/XssTest.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/journal/tests/unit/models/PostRedactorTest.php, ../sm-journal-plugin/models/post.go, ../sm-journal-plugin/classes/format_html.go, ../sm-journal-plugin/controllers/api/media.go, modules/cabana/markdown_test.go</read_first>
|
||||
<action>Complete D-05 without porting Phase 16 Twig templates.
|
||||
|
||||
Migrations (D-01, D-04): TestJournalTables and rollback/remigrate assert every final table/column/index, unique slugs, JSONB metadata/sources, settings defaults including search_use_typesense false, author_slug on backend_users, and absence of rainlab-era journal table names.
|
||||
|
||||
Fillable (JOURNAL-001/002, T-15-04): Tag allow-list name/slug/description only; Category excludes nest_*; extra JSON keys dropped; Post API assigns never persist redactor_id or user_id from the body.
|
||||
|
||||
Translatable (D-10): Post/Category MorphName PHP strings; slug is indexed; Tag has no Translatable.
|
||||
|
||||
FormatHTML (JOURNAL-003/004 substitute): reject script, iframe, event handlers, javascript/vbscript/data schemes; footnotes/tables from goldmark extensions still pass the reject gate. Do not port .htm files.
|
||||
|
||||
API: per_page 9/30; slug show; numeric fallback; previous_post/next_post/related_posts present on show; unpublished lock prefix absent from JSON; editor Bearer on GET sees drafts; invalid frontend-audience token on POST is 401; publish without access_publish 403. Named TestJournalPublicCategories and TestJournalPublicTags: anonymous GET /_journal/api/v1/categories and /tags return 200 PHP {data} list shapes (categories honor include_empty; tags ordered by name). Named TestJournalRSS: GET /rss is well-formed RSS 2.0 XML honoring rss_title, rss_posts_per_feed, rss_include_content, and rss_enabled. Named TestJournalFeaturedImageUnauthenticated: featured-image POST/DELETE without Bearer is 401 Authentication required; without canEdit is 403 You do not have permission to edit this post.
|
||||
|
||||
Media (JOURNAL-006, T-15-03): 403 without access_posts; 201 with permission; folder .. rejected; stored path under journal/.
|
||||
|
||||
Search (D-12, T-15-11): TestSearchGateOff zero HTTP; unpublished ShouldBeSearchable false even if someone flipped the setting in-memory.
|
||||
|
||||
Admin: 403 without access_posts; YAML compile TestPostsFormCompiles; FilterScopes without illegal filter keys; commands registered; SVG embed present.
|
||||
|
||||
Limiter names and CORS: TestJournalBuckets; host or plugin test reading ../sm-grzybyfunkcjonalne-app/config/http.yaml requires _journal/api/* (D-17). Isolated plugin tests that cannot see the host file skip only that assertion, not the bucket test.
|
||||
|
||||
D-11: assert content field type mlmarkdown in compiled schema; assert modules/cabana/form_schema.go already lists markdown/mltext/mlmarkdown (no-op this phase). D-16: no new tide fixtures.</action>
|
||||
<verify>
|
||||
<automated>go -C ../sm-journal-plugin test ./... -count=1 -v -race && go -C ../sm-grzybyfunkcjonalne-app test ./... -count=1 -v -race</automated>
|
||||
<fails_when>Non-zero exit; Go race detector reports a race; any package reports FAIL; integration tests unexpectedly SKIP in the plugin run; output lacks PASS lines for TestJournalPublicCategories, TestJournalPublicTags, TestJournalRSS, and TestJournalFeaturedImageUnauthenticated.</fails_when>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- Named tests exist for JOURNAL-001, JOURNAL-002, JOURNAL-005, JOURNAL-006, FormatHTML unsafe tags, redactor_id not fillable, TestSearchGateOff, TestJournalCommands, TestPostsFormCompiles, TestJournalBuckets, TestJournalPublicCategories, TestJournalPublicTags, TestJournalRSS, TestJournalFeaturedImageUnauthenticated.
|
||||
- Migration rollback and remigrate pass on real Postgres.
|
||||
- High threats T-15-01, T-15-02, T-15-03, T-15-04, T-15-07, T-15-08, T-15-09, T-15-10, T-15-11, T-15-13 have fail-when-broken tests.
|
||||
- No test requires Pages menu types, dashboard widgets, extra locales, or PHP tree writes.
|
||||
</acceptance_criteria>
|
||||
<done>Every D-05 PHPUnit row and every in-scope high threat has named Go evidence.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Phase gate, security review, and validation sign-off</name>
|
||||
<files>scripts/check-phase15.sh, .planning/phases/15-journal-plugin/15-SECURITY-REVIEW.md, .planning/phases/15-journal-plugin/15-VALIDATION.md</files>
|
||||
<read_first>scripts/check-phase14.2.1.sh, .planning/phases/15-journal-plugin/15-VALIDATION.md, .planning/phases/15-journal-plugin/15-RESEARCH.md (Security Domain), .planning/phases/15-journal-plugin/15-01-PLAN.md, .planning/phases/15-journal-plugin/15-02-PLAN.md, .planning/phases/15-journal-plugin/15-03-PLAN.md</read_first>
|
||||
<action>Create scripts/check-phase15.sh modeled on check-phase14.2.1.sh. Stages: PHP SHA 02110eb1c0c3861370b0b9b47b209a0702ac5d88 and empty git diff on the PHP journal tree (D-01, D-02, D-03, D-07); plugin module/layout/replace ../summercms.go (D-22, D-23, pitfall 9); plugin go vet, full tests, race; host go vet/test/build including TestBootUserTranslateJournal (D-18..D-21); CORS _journal/api/*; plugin README forbidden-name scan (the application / blog only); no rainlab-era table names; no cabana field_markdown.go diff from this phase (D-11 no-op); no tide harness add (D-16); security-review file present. Use go -C ../sm-journal-plugin and go -C ../sm-grzybyfunkcjonalne-app. Full mode requires Postgres; Docker missing is failure; -short is not final evidence. Require named PASS lines for TestJournalEndToEnd, TestJournal005DraftShow, TestJournal006MediaUpload, TestFillable, TestSearchGateOff, TestJournalWriteUnauthenticated, TestBootUserTranslateJournal, TestJournalPublicCategories, TestJournalPublicTags, TestJournalRSS, TestJournalFeaturedImageUnauthenticated. End with Phase 15 gate passed.
|
||||
|
||||
Run the security-review lane over local Phase 15 changes (CONTEXT discretion: after implementation, not a code-writing plan). If a typed security-review subagent is unavailable, self-perform as 14.2.1-04 did and disclose that in 15-SECURITY-REVIEW.md frontmatter. Produce 15-SECURITY-REVIEW.md at ASVS L1, block_on high. Preserve unique threat IDs T-15-01 through T-15-15 plus T-15-SC (reserved, never colliding). For every high threat cite source control and executed TestName. Review draft enumeration, media traversal, fillable, stored XSS in content_html, cross-user edit, publish permission, frontend token on writes, Typesense leak, rate-limit XFF, envelope mixup, submodule provenance.
|
||||
|
||||
Record the API-coverage declaration in the review: no external SaaS SDK this phase.
|
||||
|
||||
Update 15-VALIDATION.md frontmatter to validated / nyquist_compliant / wave_0_complete only after mapped commands pass. Replace pending rows with exact test names and threat refs. Keep the manual SPA UAT row (admin login, Journal nav, mlmarkdown post) as human-check, not a silent pass.
|
||||
|
||||
Do not commit unless the user asks; this planner run also does not commit.</action>
|
||||
<verify>
|
||||
<automated>bash scripts/check-phase15.sh --all</automated>
|
||||
<fails_when>Non-zero exit; any stage absent or skipped; output contains FAIL, a Go race, no-tests-to-run, unexpected SKIP, unmitigated high threat, PHP tree dirty; lacks PASS evidence for TestJournalPublicCategories, TestJournalPublicTags, TestJournalRSS, or TestJournalFeaturedImageUnauthenticated; or lacks the final Phase 15 gate passed line.</fails_when>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- Gate uses go -C ../sm-journal-plugin and go -C ../sm-grzybyfunkcjonalne-app.
|
||||
- PHP pin SHA matches 02110eb1c0c3861370b0b9b47b209a0702ac5d88 and the PHP tree has no diff.
|
||||
- 15-SECURITY-REVIEW.md lists each T-15-NN once, keeps T-15-SC, and blocks on high findings.
|
||||
- VALIDATION rows name existing tests; frontmatter is validated only after green execution.
|
||||
- Gate confirms no PHP edits, no extra locales, no Pages/dashboard, no tide add, no Typesense contact in TestSearchGateOff, no consuming-application name in the plugin README.
|
||||
- Gate requires named PASS for TestJournalPublicCategories, TestJournalPublicTags, TestJournalRSS, and TestJournalFeaturedImageUnauthenticated.
|
||||
</acceptance_criteria>
|
||||
<done>The two-repository phase gate is green, 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 filter, skipped container, or dirty PHP tree must not pass |
|
||||
| Security review → phase completion | High findings block completion |
|
||||
| Public HTTP → draft rows | JOURNAL-005 regressions must fail the gate |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-15-14 | Repudiation | phase gate | high | mitigate | Require named PASS lines and final marker; reject no-tests and unexpected skips |
|
||||
| T-15-15 | Information Disclosure | unpublished title prefix on API | medium | mitigate | Assert JSON titles omit the unpublished lock prefix |
|
||||
| T-15-SC | Tampering | package installs | high | mitigate | Gate confirms no new undecided require in plugin go.mod |
|
||||
|
||||
ASVS L1: block_on high. T-15-01..T-15-13 originate in plans 01–03 and must appear in 15-SECURITY-REVIEW.md with executed tests, not as duplicate rows here.
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
Run TestJournalEndToEnd, the race suites, then bash scripts/check-phase15.sh --all.
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- PHPUnit map D-05 is covered by named Go tests.
|
||||
- Plugin and host vet/test/race are green.
|
||||
- Phase 15 gate passed.
|
||||
- High T-15 threats are mitigated with evidence.
|
||||
- Deferred Phase 16/Pages/dashboard/Apparatus-token/extra-locale/PHP-edit items remain absent.
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/15-journal-plugin/15-04-SUMMARY.md` when done
|
||||
</output>
|
||||
Reference in New Issue
Block a user