feat(deploy): OPS-A deploy-freshness guard (+ SEC-B frame-ancestors cleanup, P3 closeout status)#49
Open
F-e-u-e-r wants to merge 4 commits into
Open
feat(deploy): OPS-A deploy-freshness guard (+ SEC-B frame-ancestors cleanup, P3 closeout status)#49F-e-u-e-r wants to merge 4 commits into
F-e-u-e-r wants to merge 4 commits into
Conversation
…eanup + P3 closeout status Builds the roadmap's first Next-item skeleton (the deploy-freshness guard) and records the P3 closeout progress verified this session. Deploy-freshness guard (OPS-A): - packages/deploy/src/freshness.ts — pure parse/compare of the live site's published dataset-meta stars_sha256 vs main HEAD; fetch wrapper throws on network/HTTP/malformed so the monitor never silently concludes "fresh". - `deploy freshness` CLI subcommand: reads main HEAD's dataset-meta, fetches the public live artifact (URL derived from GITHUB_REPOSITORY or --url), exits 0 fresh / 3 on drift (with a step-summary alert) / 1 on unreachable. - .github/workflows/deploy-freshness.yml — daily read-only monitor; no secret, no write, contents:read only. A persistent red run is the silent-freeze signal the OPS-A invariant warns about. - tests cover match, mismatch, missing (404), malformed JSON, schema-invalid, and network failure. Verified live: reports "fresh" against the real Pages site. SEC-B follow-up: - Drop `frame-ancestors 'none'` from the CSP meta. Browsers ignore it (and X-Frame-Options) when delivered via <meta>, so it provided no protection and logged a console error on every load. Verified in a real browser that the strict CSP otherwise does not break the app (React mounts, styles apply). P3 closeout status (docs/P3-ai-spec.md), accurate to what was verified: - public-dashboard visual confirmation: DONE (live, under the new CSP); - no-churn replay deterministic half: DONE offline (verify-artifacts + byte- identical re-serialization + hash/count match); - live credentialed planner replay: PENDING (owner's STAR_SYNC_TOKEN step). Also gitignore .playwright-mcp/ browser-session artifacts. Does NOT touch AI budget, PROV-5, max_total_per_run, or semantic search. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011k4Jo11N3mwLtb3r4fMMJK
- freshness expected sha now comes from verifyDatasetIntegrity (re-hash stars.json + confirm dataset-meta agrees), so a stale/corrupt committed meta cannot self-certify the site as fresh (Codex: design-robustness). - extract the CLI flow into the pure, testable evaluateDeployFreshness + deriveLiveMetaUrl; add tests for fresh/drift/missing-data/underivable-url/ unreachable and URL derivation (Codex: CLI test gap). - deploy verify now rejects a reintroduced frame-ancestors directive (extracts the CSP from the content attribute so a comment can't trip it) + negative test (Codex: SEC-B not pinned). - reconcile docs/P3-ai-spec.md: coverage 492-at-the-time vs 550-today, visual confirmation marked DONE everywhere, live no-churn replay marked PENDING everywhere (Codex: 3 doc inconsistencies). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011k4Jo11N3mwLtb3r4fMMJK
…e CSP check Codex: the CSP assertion regex matched anywhere in the HTML, so a commented-out `<!-- <meta ...CSP...> -->` (which the browser does NOT enforce) could still pass verifyBuiltArtifact. Strip HTML comments before matching so a commented-out or inert CSP meta fails the gate. Adds a regression test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011k4Jo11N3mwLtb3r4fMMJK
…eta> tag Codex: the CSP regex `[\s\S]*?content=` could skip past `>` and borrow a content attribute from a LATER, unrelated meta tag, so a split-tag construct (`<meta http-equiv="Content-Security-Policy"><meta name="x" content="…required…">`) would pass while the CSP meta itself is empty and enforces nothing. Now extract a single `<meta …>` tag (attributes cannot cross the closing `>`) and read ITS content; an empty CSP meta is rejected. Adds a split-tag regression test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011k4Jo11N3mwLtb3r4fMMJK
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The roadmap's first Next-item skeleton — a read-only monitor that makes the OPS-A silent-freeze failure mode observable — plus a small SEC-B follow-up and the P3 closeout status verified this session.
Deploy-freshness guard (OPS-A)
The daily sync commits fresh data and relies on a workflow-triggering push token to fire
pages.yml. If that invariant ever breaks, the commit lands but no deploy runs and the site silently freezes with no failed run to notice. This guard turns that into a red scheduled run.packages/deploy/src/freshness.ts— pureparseLiveStarsSha/compareFreshness+ acheckFreshnessfetch wrapper that throws on network/HTTP/malformed (never silently "fresh").deploy freshnessCLI subcommand — reads main HEAD'sdataset-meta.json, fetches the public live artifact (URL fromGITHUB_REPOSITORYor--url), exits0fresh /3drift (+ step-summary alert) /1unreachable..github/workflows/deploy-freshness.yml— daily, read-only (contents:read), no secret, no write.https://f-e-u-e-r.github.io/starledger/: reportsfresh(exit 0); drift path exits 3.SEC-B follow-up
Drop
frame-ancestors 'none'from the CSP meta — browsers ignore it (andX-Frame-Options) when delivered via<meta>, so it gave no protection and logged a console error every load. A real-browser check confirmed the strict CSP otherwise doesn't break the app (React mounts, styles apply, 550 repos + AI enrichment render).P3 closeout status (
docs/P3-ai-spec.md)verify-artifacts+ byte-identical re-serialization + hash/count match);STAR_SYNC_TOKENstep.Scope guard
Does not touch AI budget, PROV-5,
max_total_per_run, or semantic search (per the agreed Not-now list).Validation: typecheck ✅ · lint ✅ · format ✅ · full suite 644 passed (+7) · dashboard build +
deploy verify(CSP still enforced) ✅.🤖 Generated with Claude Code