Skip to content

test(middleware): pin NODE_ENV for the CSP assertions - #934

Merged
joryirving merged 1 commit into
mainfrom
fix/middleware-csp-tests-pin-node-env
Sep 4, 2026
Merged

test(middleware): pin NODE_ENV for the CSP assertions#934
joryirving merged 1 commit into
mainfrom
fix/middleware-csp-tests-pin-node-env

Conversation

@joryirving

Copy link
Copy Markdown
Contributor

Summary

  • The security headers block stubs NODE_ENV instead of inheriting it from the runner.
  • Adds the test the development exemption never had.

Second and final blocker on #929 (vitest 5). With #933 already merged, this makes it green.

Why

applySecurityHeaders skips the CSP in development on purpose — Next invokes the proxy several times per document request and the browser intersects the resulting CSP headers, collapsing script-src and breaking hydration. src/middleware.ts explains it at length.

The tests never stated that dependency. They read whatever NODE_ENV the runner provided, and passed only because vitest 4 overrode it to test inside the test environment — even though npm run test runs NODE_ENV=development vitest run.

vitest 5 does not override it. The value reaches the middleware as development, the CSP branch is skipped, and twelve assertions read a null header:

AssertionError: the given combination of arguments (null and string) is invalid
for this assertion.
 ❯ src/middleware.test.ts:404:56

So the assertions were correct and the setup was accidental. This makes the block state the condition it is testing.

The missing test

The development branch had no coverage at all, which is why nothing noticed when it silently became the branch under test. Added: in development there is no CSP, but the static headers are still set. That pins the exemption in both directions.

Verification

  • vitest 4 (this branch): 2529 pass, 5 skipped; typecheck and lint clean.
  • vitest 5: copied this file into a worktree with vitest/5.0.0 installed and ran it with NODE_ENV=development — 31/31 pass, where it was 12 failed / 18 passed before.

Note

Worth knowing separately: npm run test sets NODE_ENV=development, and under vitest 5 that now actually reaches the code under test. Any other test whose behaviour forks on NODE_ENV is in the same position — these were the only ones failing, but they were also the only ones with a fork.

https://claude.ai/code/session_01YSuDvZq9ncvyX85Uzx3cQh

applySecurityHeaders skips the CSP in development on purpose, so the security
header assertions only hold outside it. They never said so: they inherited
whatever the runner set, and passed only because vitest 4 overrode
NODE_ENV to 'test' inside the test environment despite 'npm run test' passing
NODE_ENV=development.

vitest 5 does not override it. The value reaches the middleware as
'development', the CSP branch is skipped, and twelve assertions read a null
header — the whole of the remaining failure on the vitest 5 bump.

Stub the value in the block that depends on it, and add the test the dev
exemption never had: in development there is no CSP, but the static headers
are still set. That branch flipping is what went unnoticed.

Verified on both: 2529 pass on vitest 4, and 31/31 in this file on vitest 5
with NODE_ENV=development.

@its-saffron its-saffron Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Automated Review

Full PR review.

Analysis engine: MiniMax-M2.7@https://litellm.jory.dev/v1 (anthropic) — primary route

PR PR 934: test(middleware): pin NODE_ENV for the CSP assertions

Recommendation

Approve. This is a focused, well-documented test fix that addresses flaky CSP header assertions caused by vitest 5 no longer overriding NODE_ENV to "test" inside the test environment. All CI checks pass.


Change-by-Change Findings

File Change Assessment
src/middleware.test.ts Pin NODE_ENV to "production" in beforeEach via vi.stubEnv Correct — explicitly states the environment condition the CSP assertions test against
src/middleware.test.ts Add vi.unstubAllEnvs() in afterEach Correct — restores the environment after each test
src/middleware.test.ts Add new test: "does not set a CSP in development, but still sets the static headers" Good — provides coverage for the previously untested development exemption branch

The new test asserts that in development mode: (1) content-security-policy is null, and (2) static headers (x-content-type-options, x-frame-options) are still set. This pins the exemption behavior in both directions.


Standards Compliance

The repository's AGENTS.md and codebase conventions were consulted. This PR:

  • Uses vi.stubEnv / vi.unstubAllEnvs — the canonical vitest pattern for environment variable isolation in tests
  • Cleans up after each test (afterEach)
  • Adds explanatory comments inline rather than relying on external context
  • Does not introduce any secrets, auth changes, or database modifications
  • Single file modified: src/middleware.test.ts

No repository standards are violated.


Tool Harness Findings

No tool harness output was provided in the corpus.


CI Check Results

All 11 CI checks passed for commit 80537d77:

Check Result
Tests ✓ success
Typecheck ✓ success
Lint ✓ success
Coverage ✓ success
Build ✓ success
Docker Build ✓ success
Docker Build (MCP) ✓ success
npm audit ✓ success
smoke ✓ success
Database migrations ✓ success
Database integration ✓ success

Unknowns / Needs Verification

None. The PR description provides verification evidence from both vitest 4 and vitest 5 runs, and all CI checks confirm the fix is correct.


Summary

This is a low-risk test-only change that fixes a legitimate test reliability issue introduced by the vitest 5 upgrade. The fix is minimal (24 lines added), well-explained, and verified by CI. No changes to production code.

@joryirving
joryirving merged commit 392960b into main Sep 4, 2026
12 checks passed
@joryirving
joryirving deleted the fix/middleware-csp-tests-pin-node-env branch September 4, 2026 03:57
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