[AZ-563] Decompose blackbox tests into AZ-564..574 task specs

Step 5 of autodev existing-code flow. Epic AZ-563 plus 11 atomic
tasks covering all 67 test scenarios from
_docs/02_document/tests/* exactly once:

- AZ-564 test infrastructure (xUnit + Docker + mock JWKS + dataseed)
- AZ-565..568 functional positive (FT-P-01..22)
- AZ-569..570 functional negative (FT-N-01..16)
- AZ-571 security (NFT-SEC-01..10)
- AZ-572 resilience (NFT-RES-01..06)
- AZ-573 resource limits (NFT-RES-LIM-01..06)
- AZ-574 performance (NFT-PERF-*)

_dependencies_table.md records the cross-check vs traceability
matrix (22 + 16 + 29 = 67 scenarios, no overlaps, no gaps; deferred
items remain deferred per matrix). All task headers carry their
Jira IDs (tracker: jira). Autodev state advanced to Step 6
(Implement Tests).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-14 21:13:53 +03:00
parent 637f41c51c
commit cf632d9e2e
13 changed files with 703 additions and 2 deletions
@@ -0,0 +1,52 @@
# Security tests (NFT-SEC-01..10)
**Task**: AZ-571
**Name**: Security tests
**Description**: Implement xUnit tests for all 10 security scenarios: JWT signature mismatch, expired, cross-policy DATASET/ANN, anonymous-access denials, error envelope no-stack-leak, path traversal in image/thumbnail GETs, token claim tampering, CORS preflight, alg-confusion `alg=HS256` forgery.
**Complexity**: 5 points
**Dependencies**: AZ-564 (test infrastructure)
**Component**: Blackbox Tests → Security
**Tracker**: jira
**Epic**: AZ-563
## Scenarios Covered
| Test ID | Source | What it asserts |
|---------|--------|-----------------|
| NFT-SEC-01 | `_docs/02_document/tests/security-tests.md` | JWT signed with key NOT in JWKS. HTTP 401. |
| NFT-SEC-02 | same | JWT expired. HTTP 401. |
| NFT-SEC-03 | same | DATASET token → `POST /annotations`. HTTP 403. |
| NFT-SEC-04 | same | ANN token → `PUT /settings/*`. HTTP 403. |
| NFT-SEC-05 | same | Anonymous access to non-public endpoints. Only `/health` is anonymous; everything else returns 401 without auth. |
| NFT-SEC-06 | same | Error envelope under Production env mode does NOT leak stack traces. |
| NFT-SEC-07 | same | Path traversal in image / thumbnail GET routes. `../etc/passwd` style payloads return 400/404, never 200 with foreign content. |
| NFT-SEC-08 | same | Token claim modification (signature breaks). HTTP 401. |
| NFT-SEC-09 | same | CORS preflight respects `CorsConfig:AllowedOrigins` allow-list under Production. |
| NFT-SEC-10 | same | Algorithm confusion — token forged with `alg=HS256` using the published ES256 public key as the HMAC secret. HTTP 401. |
## System Under Test Boundary
- HTTP only.
- Token variants minted via `TokenMinter.MintToken(claim, overrides)`.
- NFT-SEC-06 requires the SUT to be re-booted with `ASPNETCORE_ENVIRONMENT=Production` (and a Production-safe CORS config). This is a separate compose profile or test class with its own `SutRestartFixture`.
- NFT-SEC-09 requires a second SUT boot under Production with `CorsConfig__AllowedOrigins__0: https://app.azaion.local`. Asserts ACAO is exactly that one origin.
## Acceptance Criteria
**AC-1: Every scenario passes per its spec.**
**AC-2: NFT-SEC-10 explicitly verifies algorithm pinning**
Given a token forged with `alg=HS256` and the published ES256 public key as the HMAC secret,
When the runner presents it to `POST /annotations`,
Then HTTP 401 is returned and the error envelope contains "Bearer error=invalid_token" in `WWW-Authenticate`.
**AC-3: NFT-SEC-06 verifies no stack leak**
Given `ASPNETCORE_ENVIRONMENT=Production`,
When a request triggers a 500-class error,
Then the response body's error envelope contains only the safe error code and message — no `stackTrace`, no `innerException`, no file paths.
## Constraints
- AAA pattern.
- `[Trait("traces_to", "AC-F-50, AC-F-51, AC-F-52, SW-05, ENV-06")]` plus per-test specific traces.
- Production-env tests run in a dedicated test class with its own fixture (no leak between Production and E2ETest boots).