chore(audit): security headers, smoke-on-tag CI, quickstart shape fix, doc refs#32
Merged
Conversation
…, doc refs
Findings from a systematic launch-readiness audit (2026-05-22). The
quickstart fix is the highest-impact item — every HN reader who copies
the README would have hit `matches[0].body === undefined` before this.
Fixes:
1. apps/web/next.config.mjs — security headers on every route.
CSP (locked except unavoidable Next inline runtime/styles),
X-Frame-Options: DENY, X-Content-Type-Options: nosniff,
Referrer-Policy: strict-origin-when-cross-origin, and a
Permissions-Policy that disables camera / microphone / geolocation
/ interest-cohort. poweredByHeader off (small ergonomic cleanup;
stops leaking "X-Powered-By: Next.js"). HSTS was already set by
Vercel — the rest were missing entirely.
2. README.md quickstart — `mneme.recall()` returns
`{ record, score }[]`, where `record.body` is itself
`{ mode, data }`. The previous quickstart wrote the call but
showed nothing about how to read the result, so a literal
copy-paste left the reader with `matches[0].body === undefined`.
Now the example iterates `{ record, score }` and prints
`record.body.data` — verified working against a fresh
`bun add @mnemehq/sdk` in /tmp. Also added explicit `path:` to
the `Mneme.open()` comments so re-runs don't trip the
"keyring already exists" conflict.
3. ARCHITECTURE.md — two broken references to `mneme.dev` paths
we don't own:
§6: "Published at `mneme.dev/protocol`" → points at the in-repo
`docs/protocol/` draft, will move when domain is provisioned.
§10: "Threat model published: `mneme.dev/security/threat-model`"
→ points at ARCHITECTURE.md §5 + §11 (the actual threat
model) and at SECURITY.md (the live disclosure path).
A DD reviewer would otherwise see "we say X is published at Y"
and find Y 404-ing.
4. .github/workflows/smoke.yml — runs `bun run smoke` (the live-npm
end-to-end verification) on a nightly cron, on every tag push, and
on workflow_dispatch. Deliberately NOT on every PR — smoke pulls
from live npm, so it's a release-gate signal, not a code-review
signal. The nightly cron catches silent npm-registry or
dependency drift between releases.
Memory updates (in lockstep):
- `project_mneme_current_state.md` ADR table extended 0011 → 0015
(was stale — ADRs 0012-0015 existed on disk but the table
capped at 0011).
What this PR explicitly does NOT include (surfaced for Pedro):
- Rate limiting on the WebSocket sync server. Currently has none.
Acknowledged in code + README + ADR 0010 as "LAN-only, auth in
v0.1.0 with Cloud." Adding a connection-cap defence-in-depth
layer is ~20 lines; ship or defer to Cloud?
- npm publish provenance (`--provenance` flag). Free, supply-chain
attestation, no downsides. Worth enabling on the next publish.
- Performance benchmark. CLAUDE.md non-negotiable claims sub-100ms
P95; in this audit, in-memory recall after a fresh install
measured ~6ms. We have anecdote, not measurement. A
`bun run bench` script + a tracked baseline closes this.
- Self-hosted analytics on the landing. Pedro asked about building
ourselves; on-brand for "privacy is the product." ~1-day build.
Test plan:
- bun run build — green; security headers configured on all routes
- bun run lint — 9 pre-existing warnings, none new
- bun run --filter '*' typecheck — green across 9 packages
- bun test — 185 pass / 2 skip / 0 fail
- bun run smoke — 7/7 green on live npm (run pre-branch on main)
- README quickstart literal — verified end-to-end against a fresh
`bun add @mnemehq/sdk @mnemehq/embedder-local` in /tmp:
`0.35 preference — Prefers concise code review comments`
Docs touched: README.md, ARCHITECTURE.md.
No protocol changes, no public API changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
Summary
Findings from a systematic launch-readiness audit (2026-05-22). The quickstart fix is the highest-impact item — every HN reader who copied the README literally would have hit
matches[0].body === undefinedbefore this.mneme.recall()returns{ record, score }[], whererecord.bodyis itself{ mode, data }. The previous quickstart wrote the call but showed nothing about how to read the result. Now the example iterates and printsrecord.body.data. Verified working against a freshbun add @mnemehq/sdk @mnemehq/embedder-localin /tmp.apps/web/next.config.mjsnow sets CSP (locked except for the unavoidable Next inline runtime/styles),X-Frame-Options: DENY,X-Content-Type-Options: nosniff,Referrer-Policy: strict-origin-when-cross-origin, and aPermissions-Policydisabling camera / microphone / geolocation / interest-cohort. HSTS was already set by Vercel — the rest were missing entirely.poweredByHeader: falsestops leakingX-Powered-By: Next.js.mneme.dev/protocol" and §10 "Threat model published:mneme.dev/security/threat-model" both pointed at URLs we don't own. Now point at the in-repodocs/protocol/draft and at ARCHITECTURE.md §5 + §11 / SECURITY.md respectively. Will move to canonical URLs whenmneme.devis provisioned..github/workflows/smoke.ymlrunsbun run smoke(live-npm end-to-end) on a nightly cron, on every tag push, and on workflow_dispatch. Deliberately NOT on every PR — smoke pulls from live npm, so it's a release-gate signal, not a code-review signal. The nightly cron catches silent npm-registry / dependency drift between releases.What this PR explicitly does NOT include (surfaced for Pedro's decision)
These came out of the audit but I held off rather than ship without your call:
--provenanceflag) — free, supply-chain attestation, no downsides. Worth enabling on the next publish.bun run benchscript + tracked baseline closes this.Test plan
bun run build— green; security headers configured on all routesbun run lint— 9 pre-existing warnings, none from this PRbun run --filter '*' typecheck— green across all 9 packagesbun test— 185 pass / 2 skip / 0 failbun run smoke— 7/7 green on live npm (pre-branch verification on main)bun add @mnemehq/sdk @mnemehq/embedder-localin /tmp:0.35 preference — Prefers concise code review commentsDocs touched
README.md— quickstart shape fix + clearerMneme.open()re-run commentsARCHITECTURE.md— §6 and §10 broken references fixedproject_mneme_current_state.mdADR table extended 0011 → 0015 (was stale — ADRs 0012-0015 existed on disk but the table capped at 0011)No protocol changes, no public API changes.
🤖 Generated with Claude Code