AZ-495 (1 SP): formalize the modules-only documentation convention for the WebApi component. _docs/02_document/module-layout.md now carries an explicit Documentation Layout section anchoring WebApi docs at modules/api_program.md; the components/06_web_api/ folder is intentionally absent. .cursor/skills/new-task/SKILL.md Step 4 directs future agents at the correct path. Cycle-1 + cycle-2 F1 findings in the two batch-review files are marked RESOLVED with back-reference to AZ-495. Cycle-2 retrospective decision-item list F1 updated. AZ-496 (2 SP): bump Microsoft.AspNetCore.OpenApi and JwtBearer in SatelliteProvider.Api.csproj from 8.0.21 to 8.0.25, closing CVE- 2026-26130 (SignalR DoS - not reachable in this app, but the runtime patch is the recommended hardening per cycle-1 D1 + cycle-2 D3). SatelliteProvider.Tests.csproj has no direct JwtBearer reference - it consumes JwtBearer transitively via ProjectReference to Api, so no edit needed there. Dockerfiles use floating mcr.microsoft.com/ dotnet/aspnet:8.0 / sdk:8.0 / runtime:8.0 tags which auto-resolve to >= 8.0.25 on rebuild. Security artifacts (dependency_scan.md, security_report.md) and current-state docs (module-layout.md, architecture.md, modules/api_program.md, modules/tests_unit.md) updated to reflect 8.0.25. Batch report + code review report (verdict PASS_WITH_WARNINGS with 2 Low findings, neither blocking) written under _docs/03_implementation. Test suite gate deferred to Step 16 (Final Test Run) per implement skill convention. Patch-level bump within .NET 8 LTS; regression risk very low. Co-authored-by: Cursor <cursoragent@cursor.com>
6.2 KiB
Code Review Report — Batch 01 cycle 2
Batch: AZ-487 (JWT validation baseline) Date: 2026-05-11 Verdict: PASS_WITH_WARNINGS
Findings
| # | Severity | Category | File:Line | Title |
|---|---|---|---|---|
| 1 | Low | Style | _docs/02_document/components/01_web_api/description.md | Task spec referenced a doc path that does not exist in the codebase |
| 2 | Low | Security | SatelliteProvider.Api/appsettings.Development.json | Dev-only JWT secret placeholder is committed (intentional per spec) |
Finding Details
F1: Task spec referenced a doc path that does not exist in the codebase (Low / Style) — RESOLVED in cycle 3 (AZ-495)
- Location:
_docs/02_document/components/01_web_api/description.md(referenced; does not exist) - Description: The AZ-487 task spec lists
_docs/02_document/components/01_web_api/description.mdas a doc to update. The codebase's component-doc folders are01_common,02_data_access,03_tile_downloader,04_region_processing,05_route_management— there is no01_web_apifolder. The WebApi component's documentation lives in_docs/02_document/modules/api_program.md. - Suggestion: Either (a) create the missing folder with a brief stub that defers to
api_program.md, or (b) update the task spec for AZ-488 to point atmodules/api_program.mdand acknowledge that WebApi has nocomponents/*folder. This batch chose (b) — updatedarchitecture.md§ Architecture Vision + § Security Architecture andmodules/api_program.md. Surface to user for a doc-organization decision. - Task: AZ-487
- Resolution (AZ-495, cycle 3): Option B formalized as canonical convention.
_docs/02_document/module-layout.md§ Documentation Layout now explicitly states WebApi has nocomponents/*folder; documentation anchor ismodules/api_program.md. The.cursor/skills/new-task/SKILL.mdStep 4 (Codebase Analysis) directs future agents at the correct path. Finding will not recur.
F2: Dev-only JWT secret placeholder is committed (Low / Security)
- Location:
SatelliteProvider.Api/appsettings.Development.json - Description: The dev placeholder
DEV-ONLY-DO-NOT-USE-IN-PROD-replace-with-real-secret-via-JWT_SECRET-env-var(78 bytes) is committed to the repo. Anyone with read access could mint a token signed with that secret. The mitigations (per task spec) are: (i) only loaded whenASPNETCORE_ENVIRONMENT=Development, (ii) theJWT_SECRETenv var overrides it whenever set, (iii) the placeholder text itself signals it must be replaced. - Suggestion: Accept as-is for dev ergonomics; production environments must set
JWT_SECRET(validated inscripts/run-tests.shand at startup). Document on the README that this dev placeholder is intentional. - Task: AZ-487
Phase Notes
Phase 1 — Context Loading
- Task spec read:
_docs/02_tasks/todo/AZ-487_jwt_validation_baseline.md - Suite contract referenced:
suite/_docs/10_auth.md(consumed via implementation, not modified) - Module layout, architecture doc, existing test patterns reviewed.
Phase 2 — Spec Compliance
All 8 acceptance criteria have at least one automated test:
| AC | Description | Test |
|---|---|---|
| AC-1 | Anonymous → 401 | JwtIntegrationTests.AnonymousRequest_To_AnyEndpoint_Returns401 |
| AC-2 | Expired → 401 | JwtIntegrationTests.ExpiredToken_Returns401 |
| AC-3 | Invalid signature → 401 | JwtIntegrationTests.InvalidSignature_Returns401 |
| AC-4 | Valid token reaches handler | JwtIntegrationTests.ValidToken_Returns200_OnHealthyEndpoint |
| AC-5 | Missing/short secret → fail fast | AuthenticationServiceCollectionExtensionsTests.AddSatelliteJwt_ThrowsOnMissingSecret/Empty/Short |
| AC-6 | HttpContext.User exposes claims |
JwtTokenFactoryTests.Create_WithExtraClaims_PropagatesClaimsThroughValidation (exercises same JwtSecurityTokenHandler.ValidateToken path JwtBearer uses to populate HttpContext.User) |
| AC-7 | Swagger Authorize button | JwtIntegrationTests.SwaggerDocument_AdvertisesBearerSecurityScheme (OpenAPI document declares Bearer security scheme) |
| AC-8 | All existing tests pass | Verified at Step 11 (test-run gate); shared HttpClient attaches default Bearer token in IntegrationTests/Program.cs |
Contract verification: AZ-487 is a consumer of suite/_docs/10_auth.md. The implementation matches the consumed contract (HS256, ≥32-byte HMAC key, no issuer/audience validation, expiration required).
Phase 3 — Code Quality
- New code follows SRP (
AuthenticationServiceCollectionExtensionsdoes one thing). - Tests follow AAA pattern with explicit comments (matches project style).
- No bare catches introduced. The pre-existing empty catch in
IntegrationTests/Program.cs::WaitForApiReadyis out of scope (pre-existing, not modified). - No comments narrating obvious code.
Phase 4 — Security Quick-Scan
- No SQL/command-injection vectors introduced.
- No sensitive data in logs (error messages mention secret length, not value).
- Dev placeholder secret: see F2.
Phase 5 — Performance Scan
- JWT validation per request is microsecond-scale HMAC + claims parsing; no I/O, no caching needed (per NFR).
- No N+1, no unbounded fetches, no new blocking calls.
Phase 6 — Cross-Task Consistency
Single-task batch; not applicable.
Phase 7 — Architecture Compliance
- All new code in
SatelliteProvider.Api/Authentication/— owned by the WebApi component permodule-layout.md. - Imports stay within the allowed dependency table (
Microsoft.AspNetCore.Authentication.JwtBearer,Microsoft.IdentityModel.Tokensare external NuGet packages, not other components). - Test code lives under
SatelliteProvider.Tests/andSatelliteProvider.IntegrationTests/(separate test projects per layout rule 5). - No new cross-sibling ProjectReferences. No new cyclic dependencies. No duplicate cross-component symbols.
Baseline Delta
_docs/02_document/architecture_compliance_baseline.md is not present in the repo; baseline delta section omitted.
Verdict Rationale
Two Low findings, both already accepted in the task spec or surfacable as doc-organization decisions. No Critical, High, or Medium findings. Verdict: PASS_WITH_WARNINGS — proceed to commit per implement skill Step 10.