## Test compose stack for the missions service. ## Naming: post-rename target. Pre-rename code path runs the same compose against the ## existing Azaion.Flights.csproj entrypoint -- tests will be RED until B5-B8 land. ## Documented in _docs/02_document/tests/environment.md. ## ## Post-2026-05-14 drift re-verification: JWT model is ECDSA-SHA256 with JWKS ## fetched from the `admin` service. Tests provide a `jwks-mock` container that ## stands in for `admin` -- it holds a fixed ECDSA P-256 keypair, serves the ## public key as JWKS over HTTPS at `https://jwks-mock/.well-known/jwks.json`, ## and signs test tokens on demand at `https://jwks-mock/sign`. The consumer ## fetches signed tokens from the mock; missions validates them against the ## mock's JWKS. The private key never leaves the mock container. services: postgres-test: image: postgres:16-alpine container_name: missions-postgres-test environment: POSTGRES_DB: azaion POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres-test ports: - "5433:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d azaion"] interval: 1s timeout: 1s retries: 30 networks: - e2e-net tmpfs: ## Ephemeral PG data; recreated per `docker compose down -v`. - /var/lib/postgresql/data jwks-mock: ## Build context populated by Step 6 (Implement Tests). The mock is a tiny ## ASP.NET Core / Python / Node app that: ## - Holds a fixed ECDSA P-256 keypair (in-memory; never exported). ## - Serves `GET /.well-known/jwks.json` over HTTPS with `Cache-Control: ## public, max-age=60` (60s instead of admin's 3600s so tests can observe ## rotation within a single 15-minute CI window). ## - Serves `POST /sign` over HTTPS accepting a claims JSON body and ## returning a signed JWT (ECDSA-SHA256) for test consumption. ## - Supports `POST /rotate-key` to generate a new keypair with a new ## `kid`; the prior public key stays in the JWKS for `OldKeyGraceSeconds` ## to verify the rotation transition (used by NFT-RES-07). ## - Self-signs its TLS certificate; the `missions` container trusts the ## mock's CA via a mounted volume at /etc/ssl/certs/jwks-mock-ca.crt. ## - Image tag: `azaion/jwks-mock:test`. Until built, run-tests.sh prints ## a clear "jwks-mock not yet built" message. build: context: tests/Azaion.Missions.JwksMock dockerfile: Dockerfile container_name: missions-jwks-mock environment: JWT_ISSUER: https://admin-test.azaion.local JWT_AUDIENCE: azaion-edge OLD_KEY_GRACE_SECONDS: 5 healthcheck: test: ["CMD-SHELL", "wget -q --no-check-certificate -O - https://127.0.0.1:8443/.well-known/jwks.json || exit 1"] interval: 2s timeout: 1s retries: 30 networks: - e2e-net missions: build: context: . container_name: missions-sut environment: DATABASE_URL: postgresql://postgres:postgres-test@postgres-test:5432/azaion JWT_ISSUER: https://admin-test.azaion.local JWT_AUDIENCE: azaion-edge JWT_JWKS_URL: https://jwks-mock:8443/.well-known/jwks.json ## Shorten the JWKS cache so NFT-RES-07 + NFT-SEC-11 can observe rotation ## within the 15-minute CI wall-clock budget. Production leaves both ## unset and inherits the library defaults (12h / 5min). JWT_JWKS_AUTO_REFRESH_INTERVAL_SECONDS: "30" JWT_JWKS_REFRESH_INTERVAL_SECONDS: "10" ASPNETCORE_URLS: http://+:8080 ASPNETCORE_ENVIRONMENT: Test ## CORS: Test environment (NOT Production) -- empty allow-list falls back ## to permissive with a PermissiveDefaultWarning log line (per ## CorsConfigurationValidator). Production-gate scenarios (E9 lock test) ## set ASPNETCORE_ENVIRONMENT=Production and assert startup THROWS. ## The jwks-mock CA cert is mounted so missions can validate the mock's ## TLS cert when fetching JWKS over HTTPS. The container ENTRYPOINT runs ## update-ca-certificates on startup so the mounted CA is trusted by the ## OS bundle that .NET HttpClient reads from. volumes: - ./tests/jwks-mock-ca.crt:/usr/local/share/ca-certificates/jwks-mock-ca.crt:ro ports: - "5002:8080" depends_on: postgres-test: condition: service_healthy jwks-mock: condition: service_healthy healthcheck: ## Per AC-7.1, /health is anonymous. Container is "healthy" once /health returns 200. test: ["CMD-SHELL", "wget -q -O - http://127.0.0.1:8080/health || exit 1"] interval: 2s timeout: 1s retries: 30 networks: - e2e-net e2e-consumer: ## Build context placeholder -- populated by Step 6 (Implement Tests) when the ## test csproj is created. Until then, run-tests.sh detects the absence and ## prints a clear "test project not yet created" message. build: context: tests/Azaion.Missions.E2E.Tests dockerfile: Dockerfile container_name: missions-e2e environment: MISSIONS_BASE_URL: http://missions:8080 DB_SIDE_CHANNEL: Host=postgres-test;Port=5432;Database=azaion;Username=postgres;Password=postgres-test ## Consumer fetches test tokens from jwks-mock instead of minting locally: ## the private key never leaves the mock container, so tests can't ## accidentally sign with a key that doesn't match the mock's published JWKS. JWKS_MOCK_SIGN_URL: https://jwks-mock:8443/sign JWT_ISSUER: https://admin-test.azaion.local JWT_AUDIENCE: azaion-edge depends_on: missions: condition: service_healthy jwks-mock: condition: service_healthy volumes: - ./test-results:/app/results - ./tests/jwks-mock-ca.crt:/usr/local/share/ca-certificates/jwks-mock-ca.crt:ro networks: - e2e-net profiles: - test networks: e2e-net: name: missions-e2e-net