mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-06-22 12:11:14 +00:00
[AZ-353][AZ-354][AZ-356] Refactor 03 batch 2: harden API surface
AZ-353: Centralize 500 handling via GlobalExceptionHandler / AddProblemDetails / UseExceptionHandler. Sanitized ProblemDetails body carries a generic title, RFC9110 type link, and the request's TraceIdentifier as correlationId; the leaky exception message stays server-side in the ERR log entry. Strip per-endpoint try/catch (Exception) wrappers and the unused ILogger<Program> parameters they served. Preserve the typed ArgumentException catch in CreateRoute (AC-3). The handler maps BadHttpRequestException back to its framework-supplied StatusCode so model-binding / malformed-body failures stay 4xx instead of being promoted to 500. AZ-354: Extract CorsConfigurationValidator (pure static helpers) and wire it into Program.cs. Production with empty CorsConfig:AllowedOrigins and no CorsConfig:AllowAnyOrigin opt-in now throws InvalidOperationException at host startup. Development keeps the permissive default but logs a warning post-build. Adds the explicit CorsConfig:AllowAnyOrigin escape hatch. AZ-356: GetSatelliteTilesByMgrs and UploadImage now return Results.Problem(StatusCode 501) with ProblemDetails. Added .ProducesProblem(501) so swagger.json documents the not-implemented status. Tests: SatelliteProvider.Tests now references SatelliteProvider.Api (downward, idiomatic) so unit tests can reach the new helpers. +9 CorsConfigurationValidator unit tests, +3 GlobalExceptionHandler unit tests, +3 StubAndErrorContractTests integration tests (added to smoke + full suites). 58/58 unit + 5/5 smoke + 3/3 stub-contract pass. Code review verdict: PASS. Batch report: _docs/03_implementation/batch_08_report.md. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
# Batch Report
|
||||
|
||||
**Batch**: 8 (refactor 03-code-quality-refactoring · Phase 1 — critical defensive fixes, part 2/2)
|
||||
**Tasks**: AZ-356, AZ-354, AZ-353
|
||||
**Date**: 2026-05-10
|
||||
**Total Story Points**: 7 (2 + 2 + 3)
|
||||
|
||||
## Task Results
|
||||
|
||||
| Task | Status | Files Modified | Tests | AC Coverage | Issues |
|
||||
|------|--------|---------------|-------|-------------|--------|
|
||||
| AZ-356 Stub endpoints return 501 | Done | 1 (Program.cs handlers + OpenAPI) | 2 new integration | 3/3 ACs | None |
|
||||
| AZ-354 Strict CORS by default | Done | 1 svc helper + 1 Program.cs hook | 9 new unit | 4/4 ACs | None |
|
||||
| AZ-353 Sanitize 5xx via IExceptionHandler | Done | 1 svc class + Program.cs rewire + per-endpoint catch removal | 3 new unit + 1 new integration | 4/4 ACs | None |
|
||||
|
||||
## Files Changed
|
||||
|
||||
### Source
|
||||
- `SatelliteProvider.Api/GlobalExceptionHandler.cs` — NEW (AZ-353)
|
||||
- `SatelliteProvider.Api/CorsConfigurationValidator.cs` — NEW (AZ-354)
|
||||
- `SatelliteProvider.Api/Program.cs` — usings + CORS validator wiring + warn-after-build + ExceptionHandler/ProblemDetails registration + UseExceptionHandler middleware + 501 stubs + per-endpoint try/catch stripping (AZ-353/354/356)
|
||||
|
||||
### Tests
|
||||
- `SatelliteProvider.Tests/CorsConfigurationValidatorTests.cs` — NEW (AZ-354, 9 tests)
|
||||
- `SatelliteProvider.Tests/GlobalExceptionHandlerTests.cs` — NEW (AZ-353, 3 tests)
|
||||
- `SatelliteProvider.Tests/SatelliteProvider.Tests.csproj` — added `ProjectReference` to Api so unit tests can reach the new classes
|
||||
- `SatelliteProvider.IntegrationTests/StubAndErrorContractTests.cs` — NEW (AZ-356 AC-1, AZ-353 AC-3, 3 tests)
|
||||
- `SatelliteProvider.IntegrationTests/Program.cs` — added `StubAndErrorContractTests.RunAll` to smoke + full
|
||||
|
||||
## AC Test Coverage: All covered
|
||||
|
||||
| Task | AC | Test |
|
||||
|------|----|------|
|
||||
| AZ-353 | AC-1 (5xx body sanitized) | `GlobalExceptionHandlerTests.TryHandleAsync_WritesSanitizedProblemDetailsAndReturnsTrue_AC1` (asserts response body has generic title + correlationId, not the leaky exception message) |
|
||||
| AZ-353 | AC-2 (server log has full exception + correlationId) | `GlobalExceptionHandlerTests.TryHandleAsync_LogsFullExceptionWithCorrelationId_AC2` |
|
||||
| AZ-353 | AC-3 (4xx paths preserved) | `GlobalExceptionHandlerTests.TryHandleAsync_BadHttpRequestException_HonorsFrameworkStatusAndDoesNotErrorLog_AC3` (unit) + `StubAndErrorContractTests.CreateRoute_InvalidPayload_Returns400_AZ353_AC3` (integration; ArgumentException → 400) + smoke `SecurityTests.SEC-01..04` (regression check that 4xx framework paths still produce 4xx) |
|
||||
| AZ-353 | AC-4 (tests stay green) | smoke green |
|
||||
| AZ-354 | AC-1 (Production refuses to start without origins) | `CorsConfigurationValidatorTests.EnsureSafeForEnvironment_ProductionWithEmptyOriginsAndNoOptIn_Throws_AC1` |
|
||||
| AZ-354 | AC-2 (Development warns but starts) | `CorsConfigurationValidatorTests.EnsureSafeForEnvironment_NonProductionWithEmptyOrigins_DoesNotThrow_AC2` (Theory: Development/Staging/Local) + smoke (compose-managed `ASPNETCORE_ENVIRONMENT=Development` runs warn-after-build path; smoke is green) |
|
||||
| AZ-354 | AC-3 (explicit opt-in works) | `CorsConfigurationValidatorTests.EnsureSafeForEnvironment_ProductionWithExplicitAllowAnyOrigin_DoesNotThrow_AC3` |
|
||||
| AZ-354 | AC-4 (tests stay green) | smoke green |
|
||||
| AZ-356 | AC-1 (both stubs return 501) | `StubAndErrorContractTests.StubMgrs_Returns501` + `StubAndErrorContractTests.StubUpload_Returns501` |
|
||||
| AZ-356 | AC-2 (OpenAPI marks not-implemented) | `.ProducesProblem(StatusCodes.Status501NotImplemented)` annotations in `Program.cs`; verified by inspecting the route registration |
|
||||
| AZ-356 | AC-3 (tests stay green) | smoke green |
|
||||
|
||||
## Code Review Verdict: PASS
|
||||
|
||||
### Phase 2 (Spec Compliance)
|
||||
- All ACs satisfied with executed tests.
|
||||
- `BadHttpRequestException` carve-out added to GlobalExceptionHandler — required by AC-3 (4xx paths preserved). Without it, the handler would have promoted SEC-01..04 framework binding errors from 400 to 500.
|
||||
|
||||
### Phase 3 (Code Quality)
|
||||
- `CorsConfigurationValidator`: pure static class (no I/O, no state) — allowed under coderule.
|
||||
- `GlobalExceptionHandler`: instance class with injected logger; private static helper `WriteClientErrorAsync` is pure HTTP serialization — allowed.
|
||||
- Per-endpoint try/catch removed for 7 of 7 affected handlers; the `CreateRoute` typed `ArgumentException` catch is intentionally preserved per AC-3. Endpoint signatures lost the `ILogger<Program> logger` parameter where it became unused.
|
||||
|
||||
### Phase 4 (Security)
|
||||
- `application/problem+json` content type set explicitly (override `WriteAsJsonAsync` default).
|
||||
- Sanitized 500 body removes server-internal text (validated by `..._WritesSanitizedProblemDetailsAndReturnsTrue_AC1` which uses a connection-string-shaped exception message and asserts the password literal does NOT appear in the response).
|
||||
- Strict CORS in Production is the deliverable.
|
||||
|
||||
### Phase 5 (Performance)
|
||||
- No hot-path changes.
|
||||
|
||||
### Phase 6 (Cross-Task Consistency)
|
||||
- All three tasks edit the same Program.cs in different sections (CORS / DI / pipeline / endpoints) without conflict.
|
||||
- The single `using SatelliteProvider.Api;` directive serves all three new classes.
|
||||
|
||||
### Phase 7 (Architecture Compliance)
|
||||
- All new files live under `SatelliteProvider.Api/**` (Api OWNS).
|
||||
- `SatelliteProvider.Tests` now references `SatelliteProvider.Api` — this is a downward (test → top-of-stack) reference, which is idiomatic for unit-testing API-internal helpers. Tests project remains the only consumer of Api types outside Api itself.
|
||||
|
||||
## Auto-Fix Attempts: 1 (one re-run cycle to honor BadHttpRequestException StatusCode)
|
||||
## Stuck Agents: None
|
||||
|
||||
## Tracker Status (post-batch)
|
||||
|
||||
| Task | Pre-batch | Post-batch (after commit) |
|
||||
|------|-----------|---------------------------|
|
||||
| AZ-356 | In Progress | → In Testing |
|
||||
| AZ-354 | In Progress | → In Testing |
|
||||
| AZ-353 | In Progress | → In Testing |
|
||||
|
||||
## Phase 1 Summary (Batches 7+8)
|
||||
|
||||
| Batch | Tasks | SP | Outcome |
|
||||
|-------|-------|---:|---------|
|
||||
| 7 | AZ-351 / AZ-352 / AZ-363 | 5 | PASS |
|
||||
| 8 | AZ-356 / AZ-354 / AZ-353 | 7 | PASS |
|
||||
|
||||
Phase 1 complete: 6 tasks, 12 SP, 0 blockers. All Critical-severity defensive fixes landed.
|
||||
|
||||
## Next Batch
|
||||
|
||||
**Batch 9** (Phase 2 — correctness): AZ-359 (consolidate RegionService catch ladder, 3 SP), AZ-357 (drop tile Version concept + new migration, 5 SP), AZ-362 (idempotent POST contract, 3 SP, depends on AZ-353 ✓). Total 11 SP.
|
||||
|
||||
## Commit
|
||||
|
||||
`[AZ-353][AZ-354][AZ-356] Refactor 03 batch 2: harden API surface` (commit hash recorded post-commit).
|
||||
Reference in New Issue
Block a user