Skip to content

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
mainfrom
feat/deploy-freshness-guard
Open

feat(deploy): OPS-A deploy-freshness guard (+ SEC-B frame-ancestors cleanup, P3 closeout status)#49
F-e-u-e-r wants to merge 4 commits into
mainfrom
feat/deploy-freshness-guard

Conversation

@F-e-u-e-r

Copy link
Copy Markdown
Owner

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 — pure parseLiveStarsSha / compareFreshness + a checkFreshness fetch wrapper that throws on network/HTTP/malformed (never silently "fresh").
  • deploy freshness CLI subcommand — reads main HEAD's dataset-meta.json, fetches the public live artifact (URL from GITHUB_REPOSITORY or --url), exits 0 fresh / 3 drift (+ step-summary alert) / 1 unreachable.
  • .github/workflows/deploy-freshness.yml — daily, read-only (contents:read), no secret, no write.
  • Tests: match, mismatch, missing (404), malformed JSON, schema-invalid, network failure.
  • Verified live against https://f-e-u-e-r.github.io/starledger/: reports fresh (exit 0); drift path exits 3.

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 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)

  • 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 — your STAR_SYNC_TOKEN step.

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

F-e-u-e-r and others added 4 commits July 8, 2026 00:26
…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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant