Skip to content

Audit (phase 0-1) + M0 truth/CI + M1 security closes#1

Open
aurph wants to merge 3 commits into
mainfrom
fix/m0-m1-truth-security
Open

Audit (phase 0-1) + M0 truth/CI + M1 security closes#1
aurph wants to merge 3 commits into
mainfrom
fix/m0-m1-truth-security

Conversation

@aurph

@aurph aurph commented Jun 9, 2026

Copy link
Copy Markdown
Owner

Phase 0-1 audit plus the first two milestones from docs/audit/02_plan.md. For review — do not merge/redeploy yet. A push is not a ship on Replit.

What's here

Audit (docs/)ARCHITECTURE.md and docs/audit/{00_baseline,01_findings,02_plan}.md. 31 findings, severity-ranked, file:line evidence. TL;DR: production is healthy and current (the May-21 "ACTIVE BLOCKER" is resolved); the index-methodology chain is exemplary; almost every other doc had drifted; two routes were unauthenticated.

M0 — truth + local dev

  • Removes the phantom Drizzle/Postgres/storage.ts/shared/ persistence claims from README/CLAUDE.md (verified absent: 0 drizzle refs, 0 DATABASE_URL refs, no such files). Persistence is curated JSON in server/data/.
  • Fixes README counts: 8→13 Stack layers / 60+→100 tickers; 21/44→24/52 supply-chain nodes/links.
  • SECURITY.md now matches shipped headers (CSP script/frame-src 'self', no Twitter origin; notes Permissions-Policy isn't currently emitted).
  • Stamps both HANDOFFs historical; rewrites the May-18 replit.md fossil.
  • reusePort only off-darwin so npm run dev boots on macOS.

M1 — security closes (all verified, with a new test)

  • SEC-1 GET /api/newsletter/preview now admin-gated (was public, leaked subscriber count). The /newsletter/send internal call forwards the server's own key.
  • SEC-2 POST /api/social/generate now admin-gated (was public).
  • SEC-3 /api/stack?timeframe= allowlisted to [1D,5D,1M] and cache keyed on the normalized value — kills the arbitrary-string cache-miss that fanned out ~200 Yahoo calls/request.
  • SEC-4 the backlog/uranium news scanners (which write JSON) no longer run from public GET /api/news; only via authenticated /api/admin/scan-news-now.
  • SEC-5 datacenter names HTML-escaped before Leaflet divIcon interpolation (stored-XSS via the admin/ingester pipeline).
  • TEST-1 server/__tests__/auth-boundary.test.ts: every admin route rejects a missing key; the correct key is accepted; SEC-3 coercion.

Verification

npm run check clean · npm test 33/33 pass · npm run build clean.

Two things that need you

  1. CI is not in this PR. .github/workflows/ci.yml is ready in the working tree, but pushing workflow files needs the workflow OAuth scope. To activate: run gh auth refresh -s workflow then push the file (or add it via the GitHub UI). It runs check/test/build/npm audit --omit=dev.
  2. SEC-4 is a deliberate behavior change. News-driven auto-updates now require the authenticated scan endpoint. Wire /api/admin/scan-news-now into the same cron that fires the daily tweet to restore automation.

Next

M2 (durability — the Critical ephemeral-subscriber fix) needs your call on the store (Neon Postgres / SQLite / Resend-as-truth) before I build it. See docs/audit/02_plan.md.

aurph added 3 commits June 9, 2026 15:53
- Kill the phantom Drizzle/Postgres/storage.ts/shared persistence claims
  (README, CLAUDE.md); persistence is curated JSON in server/data/ (no DB).
- Fix Stack count (8->13 layers, 60+->100 tickers) and Supply Chain count
  (21/44 -> 24/52 nodes/links) in README.
- SECURITY.md: match shipped CSP (script/frame-src 'self', no Twitter origin)
  and note Permissions-Policy is not currently emitted (SEC-7).
- Stamp HANDOFF.md and HOMEPAGE_HANDOFF.md historical; the May-21 deploy
  blocker is long resolved and the LBNL queue + route split shipped.
- Rewrite replit.md (was a May-18 fossil: react-simple-maps, org-chart
  supply chain, SESSION_SECRET).
- reusePort only off-darwin so 'npm run dev' works on macOS (PORT-1).

CI workflow (.github/workflows/ci.yml) is ready in the tree but not pushed:
pushing workflow files needs the 'workflow' OAuth scope. Activate separately
(see PR description).
- SEC-1: require admin on GET /api/newsletter/preview (was public, leaked
  the subscriber count). The internal call from /newsletter/send forwards
  the server's own admin key so sends keep working.
- SEC-2: require admin on POST /api/social/generate (was public).
- SEC-3: allowlist /api/stack timeframe to [1D,5D,1M] and key the cache on
  the normalized value, killing the ~200-Yahoo-call cache-miss amplification.
- SEC-4: stop running the backlog/uranium news scanners (which write JSON)
  from public GET /api/news; they now run only via authenticated
  /api/admin/scan-news-now. Wire that into cron to restore automation.
- SEC-5: HTML-escape datacenter names before Leaflet divIcon interpolation.
- TEST-1: add auth-boundary.test.ts (every admin route rejects missing key,
  correct key accepted, SEC-3 coercion). 33/33 tests pass.
aurph added a commit that referenced this pull request Jun 20, 2026
main fast-forwarded to the feature and pushed (Jack's call). Notes the Replit
redeploy still needed, that PRs #1/#2 now rebase onto the new main, and that
live render is unverified from here (harness blocks running the dev server).
aurph added a commit that referenced this pull request Jul 2, 2026
Replaces the 2026-05-22 version, which claimed Drizzle/Postgres, a
server/storage.ts, and a shared/ dir (none exist) and described a
homepage redesign that landed and then evolved past its own spec.

Derived from a three-agent sweep of client, server, and docs. New
sections: full module/route table, data-source table with cadences and
stale behavior, server/data custody map, do-not-touch list, known debt
(incl. the live Math.random correlation scatter and the unmerged PR #1
security closes). Conventions confirmed by Jack: kebab-case new files,
default queryFn + apiRequest, raw #F07800.
aurph added a commit that referenced this pull request Jul 4, 2026
…, adapted to current code

SEC-1: /api/newsletter/preview requires admin (was public, leaked the
subscriber count); the internal send-path call forwards the server's
own key. SEC-2: /api/social/generate requires admin (was public,
burned Yahoo quota). SEC-3: /api/stack timeframe allowlisted to
1D/5D/1M and cached on the normalized value, killing the ~200-call
Yahoo fan-out an arbitrary query string caused. SEC-4: the news
scanners (which write curated JSON) no longer run from public GET
/api/news - only from authenticated /api/admin/scan-news-now. SEC-5:
datacenter names HTML-escaped before Leaflet divIcon interpolation
(stored XSS via the admin/ingester pipeline).

Ported the auth-boundary test suite: every admin route rejects a
missing key, the correct key is accepted, junk timeframes coerce
gracefully. Suite 209 tests.

Operational note: cron-job.org needs a second job POSTing
/api/admin/scan-news-now (x-admin-key header) to restore the automated
news-driven dataset updates that SEC-4 removed from the public path.
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