chore(work): decompose security-headers-rate-limit-sbom epic
Generated 1 epic + 11 stories under docs/work/epics/ from the approved PRD docs/work/prds/security-headers-rate-limit-sbom.prd.md. Stories cover rate-limit type primitives + implementations + ESLint rule + withRateLimit wrapper, auth.signIn rate-limit backfill, security headers core module + framework adapters, app wiring across web-next / web-tanstack / cms, SBOM CI workflow, and documentation. Ready for `pnpm work dispatch --execute`.
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
---
|
||||
id: 07-security-header-adapters
|
||||
epic: security-headers-rate-limit-sbom
|
||||
title: Per-framework security header adapters
|
||||
type: technical-story
|
||||
status: todo
|
||||
feature: core-shared
|
||||
depends-on: [06-security-headers-core-module]
|
||||
blocks: [08-app-wiring-web-next, 09-app-wiring-web-tanstack-and-cms]
|
||||
created: 2026-05-20T00:00:00Z
|
||||
updated: 2026-05-20T08:14:55.907Z
|
||||
---
|
||||
|
||||
## 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.
|
||||
Reference in New Issue
Block a user