Files
agentic-dev/docs/work/epics/security-headers-rate-limit-sbom/07-security-header-adapters/_story.md

3.4 KiB

id, epic, title, type, status, feature, depends-on, blocks, created, updated
id epic title type status feature depends-on blocks created updated
07-security-header-adapters security-headers-rate-limit-sbom Per-framework security header adapters technical-story done core-shared
06-security-headers-core-module
08-app-wiring-web-next
09-app-wiring-web-tanstack-and-cms
2026-05-20T00:00:00Z 2026-05-20T09:58:23.659Z

Goal

Ship the two framework-specific adapter subpaths — core-shared/security/next (Next.js middleware + getNonce() Server Component helper) and core-shared/security/tanstack (TanStack Start server middleware + request-context nonce extractor) — so the app-wiring stories can wire them end-to-end without touching the underlying header builder.

Why

Adapters follow the core-analytics/react subpath pattern established in the codebase: framework-specific code lives in a subpath export so the core module remains importable without dragging in framework dependencies. Each adapter generates a per-request nonce, calls buildSecurityHeaders, sets all six headers on the response, and forwards the nonce via x-nonce for downstream Server Component access. Landing the adapters before app wiring keeps the integration commits thin.

Done when

  • packages/core-shared/src/security/next/index.ts exports a Next.js middleware function and getNonce() helper; adapter tests assert all six headers set on response, x-nonce present, getNonce() reads the value from headers().
  • packages/core-shared/src/security/tanstack/index.ts exports a TanStack Start server middleware and a nonce extractor for server context; adapter tests assert equivalent header + nonce behaviour.
  • Both subpaths declared in packages/core-shared/package.json exports map.
  • pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff all pass after each task.

In scope

  • core-shared/security/next — middleware calling generateNonce() + buildSecurityHeaders({ mode: process.env.NODE_ENV === "production" ? "production" : "development", nonce }), setting headers on the response, writing nonce to x-nonce response header; getNonce() reading x-nonce from headers() for use in Server Components.
  • core-shared/security/tanstack — equivalent using TanStack Start's server middleware API; nonce extractor for TanStack Server context.
  • package.json subpath exports for both adapters.
  • Adapter unit tests for each.

Out of scope

  • App middleware wiring, Sentry nonce init, layout nonce threading — Stories 08 and 09.
  • CMS adapter — apps/cms uses the framework-agnostic buildSecurityHeaders directly (Story 09).
  • Storybook CSP — explicitly out of Epic C scope.

Tasks

  • Implement packages/core-shared/src/security/next/index.ts: Next.js middleware calling generateNonce() + buildSecurityHeaders, setting all six headers and x-nonce on the response, plus getNonce() helper reading x-nonce from Next.js headers(); add subpath to package.json exports; adapter tests asserting all headers present, nonce in response headers, getNonce() reads it; all gates pass.
  • Implement packages/core-shared/src/security/tanstack/index.ts: TanStack Start server middleware equivalent (generate nonce, set headers + x-nonce) plus request-context nonce extractor; add subpath to package.json exports; adapter tests asserting equivalent header + nonce behaviour; all gates pass.