Skip to content

Harden input validation, doc access, and CI - #23

Merged
facundofarias merged 1 commit into
mainfrom
chore/hardening-ci-limits-auth
Oct 25, 2026
Merged

facundofarias merged 1 commit into
mainfrom
chore/hardening-ci-limits-auth

Conversation

@facundofarias

Copy link
Copy Markdown
Contributor

Summary

A hardening pass covering the five items from the repo scan, all in one PR.

1. Green baseline + CI

  • Adds .github/workflows/ci.yml: lint, typecheck, unit tests, and integration tests against a Postgres service.
  • Adds typecheck, test:unit, and test:integration scripts.
  • Fixes the 3 pre-existing tsc errors (Prisma JSON input types in test helpers) and all 41 ESLint errors (35 jsx-no-comment-textnodes, 6 react-hooks/set-state-in-effect).
  • The six effect warnings are fixed properly where practical: ThemeToggle, useReviewerName, and created/[slug] now read browser state via useSyncExternalStore; the three fetch-on-mount effects keep a scoped, commented disable.

2. Payload caps

  • POST/PATCH /docs: content ≤ 1 MB (UTF-8), title/version_note ≤ 500 chars, meta ≤ 16 KB and must be a JSON object.
  • Comments (single + batch): body ≤ 20k chars, author ≤ 100, anchor_text ≤ 2k, anchor_type limited to line|selection.
  • Oversized/invalid inputs return 400 instead of hitting Prisma/disk.

3. Indexes

New migration 20261025120000_add_query_indexes for:

  • docs(user_id, updated_at) and docs(visibility, created_at)
  • doc_versions(doc_id, version_number)
  • comments(doc_id, created_at) and comments(doc_id, status)

4. Unified doc access

  • One pure evaluateDocAccess + shared request adapter in src/lib/auth.ts.
  • GET /docs/:slug, the feedback endpoints, and the share page all use it; three divergent implementations removed.
  • Side fix: a magic token sent via X-Magic-Token now unlocks owner-only fields (meta, views_count) on GET /docs/:slug, matching the other token sources.
  • New doc-access.test.ts covers public, magic token (query/header/cookie), doc API key, share token (both params), account API key, wrong token, and owner-field visibility.

5. Security headers

  • X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy on all routes.
  • Production-only HSTS + CSP. CSP allows 'unsafe-inline' for the theme/bootstrap scripts and Mermaid/Redoc styles, plus cdn.redoc.ly and Google Fonts for /api-docs.

Test plan

  • npm run lint — clean
  • npm run typecheck — clean
  • npm run test:unit — 100 passed
  • npm run test:integration — 172 passed (server on :3333, test DB on :5435)
  • npm run build — succeeds
  • prisma migrate diff — no drift

Notes

  • No new runtime dependencies.
  • POST /docs with empty content and PATCH with content: "" now return 400 (previously accepted/near-500).
  • HSTS is emitted for all production responses; deployment terminates TLS at Cloudflare/kamal-proxy.

- CI: add GitHub Actions (lint, typecheck, unit + integration); add
  typecheck/test:unit/test:integration scripts; fix the 3 tsc errors and
  41 ESLint errors that were blocking a green baseline.
- Payload caps: bound doc content (1 MB), title, version_note, meta, and
  comment body/author/anchor_text/anchor_type with 400s instead of
  unbounded writes.
- DB: index the hot read paths (docs userId+updatedAt and visibility+
  createdAt, doc_versions docId+versionNumber, comments docId+createdAt
  and docId+status).
- Auth: extract one evaluateDocAccess used by GET /docs/:slug, the
  feedback endpoints, and the share page, removing three divergent
  implementations. Fixes magic tokens sent via X-Magic-Token not
  unlocking owner-only fields on GET.
- Security: add HSTS/CSP and related headers (CSP production-only, with
  the Redoc CDN and Google Fonts allowed for /api-docs).
- Tests: cover every doc read access path and the new payload limits.
@facundofarias
facundofarias merged commit 2093eff into main Oct 25, 2026
2 checks passed
@facundofarias
facundofarias deleted the chore/hardening-ci-limits-auth branch October 25, 2026 08:22
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