Files
clean-architecture-backend-…/docs/superpowers/plans/2026-08-02-web-security-boundary.md
T
DongHyeonkaandClaude Opus 5 5f10b791d3 chore: record pre-existing uncommitted repository state
Snapshot of the in-flight state that already existed, identically, in both
this worktree and the main checkout before this session began: the initial
HTTP Client platform implementation (previously untracked), the redis-lab
removal, and the JPA / object-storage / notification integration work.

Kept separate from this session's HTTP Client review response, which lands
in the following commit, so the two bodies of work stay reviewable apart.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 16:48:43 +09:00

3.1 KiB

Web Security Boundary Implementation Plan

Execution: Follow test-driven development and request an independent read-only review before advancing to Redis session/CSRF.

Goal: Make JWT/JWKS and CORS filter-boundary behavior hermetic, release-blocking, and impossible to skip silently.

Architecture: Tests remain in inbound-web, use only existing dependencies, and cross the real Spring Security filter chain. A tagged Gradle task isolates them from the ordinary unit suite.

Tech Stack: Java 21, Spring Boot 4.0.0, Spring Security 7, Nimbus JOSE JWT, JDK HttpServer, MockMvc, Gradle 9.

Task 1: Dedicated No-Skip Test Gate

Files:

  • Modify: src/adapter/inbound/web/build.gradle

  • Register webSecurityBoundaryTest over sourceSets.test with tag inclusion, no-discovery failure, no up-to-date reuse, UTC, and a root-suite skipped-count guard.

  • Exclude security-boundary from ordinary test and require the dedicated task from check.

  • Confirm 13 tagged tests are discovered with zero skips and no dependency/lock entry is added.

Task 2: JWT/JWKS RED Contracts

Files:

  • Create: src/adapter/inbound/web/src/test/java/dev/caskeleton/adapter/inbound/web/auth/JwtJwksSecurityFilterIntegrationTest.java

  • Add a loopback OIDC discovery/JWKS server with request counters and deterministic 503 mode.

  • Add RS256 token generation using ephemeral keys and conspicuous secret sentinels.

  • Prove lazy startup and valid bearer-to-principal conversion.

  • Prove exact expiry, issuer, audience, signature, unknown-kid, and JWKS-outage envelopes/headers.

  • Prove same-context recovery after a first-request JWKS 503 and prove mismatched discovery metadata reaches the safe 500 INTERNAL_AUTH_MISCONFIGURATION filter boundary.

  • Run the dedicated task and record RED: unknown kid was classified as signature failure and a first-request JWKS 503 escaped as JwtDecoderInitializationException/AuthenticationServiceException.

Task 3: CORS RED Contracts

Files:

  • Create: src/adapter/inbound/web/src/test/java/dev/caskeleton/adapter/inbound/web/auth/CorsSecurityFilterIntegrationTest.java

  • Prove approved credentialed preflight bypasses bearer authentication and emits exact headers.

  • Prove denied origin, disabled CORS, wildcard-without-credentials, and approved actual-origin behavior.

  • Assert bounded Vary behavior and no reflection of an unapproved sentinel origin.

  • Run the dedicated task: all five CORS filter-boundary contracts passed without production changes.

Task 4: Minimal Production Fixes and Verification

  • If RED exposes a production mismatch, change only the owning classifier/security configuration and keep stable error-code/header contracts intact.
  • Run webSecurityBoundaryTest, ordinary inbound-web test, module static analysis, check, dependency-lock verification, architecture verification, and git diff --check.
  • Request an independent read-only review; add the requested same-context recovery and non-I/O initialization-failure contracts, and bind the loopback server to an explicit IPv4 address.