# Static Analysis (Cycle 9) **Date**: 2026-06-25 **Mode**: Delta scan **Scope**: AZ-1074 + AZ-1075 gRPC surface. Cycle-8 baseline remains authoritative for REST validators. **Files in scope**: - `SatelliteProvider.Api/Grpc/RouteTileDeliveryGrpcService.cs` (new) - `SatelliteProvider.Api/Program.cs` (`AddGrpc`, `MapGrpcService`, message size limits) - `SatelliteProvider.Services.RouteManagement/TileProvision/RouteTileDeliveryOrchestrator.cs` (validation hardening) - `SatelliteProvider.GrpcContracts/tile_provision.proto` + generated stubs - `SatelliteProvider.IntegrationTests/RouteTileDeliveryGrpcTests.cs`, `GrpcTestHelpers.cs` - `SatelliteProvider.IntegrationTests/Dockerfile` (linux/amd64, aspnet runtime) - `docker-compose.tests.yml` (self-contained test stack) **Method**: End-to-end read of new files; grep for hardcoded secrets; trace auth middleware order; compare gRPC validation bounds vs REST `CreateRouteRequestValidator`. ## Findings ### F-AZ1074-1 — Unbounded gRPC request collections enable authenticated DoS (Medium / A04) — **RESOLVED in cycle 9 (Step-14 follow-up)** - **Location**: `RouteTileDeliveryOrchestrator.ValidateJob` (pre-fix). - **Description**: `DeliverRouteTiles` accepted unbounded `waypoints`, `geofences`, and `client_tiles` protobuf repeated fields. REST `POST /api/satellite/route` caps `points` at 500 and `geofences.polygons` at 50 (cycle-8 F-AZ809-1 fix); gRPC had no equivalent caps before cycle 9 Step 14. - **Impact**: Medium. Auth-gated (`[Authorize]` on `RouteTileDeliveryGrpcService`; JWT metadata required). Authenticated operator could force large CPU/memory work in `RouteTileExpander.Expand` and `ClientTileCatalog.IndexByZxy`. - **Resolution**: Added `MaxWaypoints = 500`, `MaxGeofencePolygons = 50`, `MaxClientTiles = 5000` (inventory cap parity) to `ValidateJob`. Unit test `DeliverAsync_TooManyWaypoints_Throws` added. ### F-AZ1074-2 — Internal exception message echoed to gRPC client (Low / A09) — **RESOLVED in cycle 9 (Step-14 follow-up)** - **Location**: `RouteTileDeliveryGrpcService.cs:55-58` (pre-fix). - **Description**: Generic `catch (Exception)` wrote `ex.Message` into stream `DeliveryError.Message` — parallel to cycle-7 F-AZ795-1 (REST ProblemDetails path). - **Impact**: Low. Auth-gated. Could leak internal exception text to authenticated clients. - **Resolution**: Client message replaced with generic `"An internal error occurred."`; full exception still logged server-side. ## Pass areas (cycle-9 delta) | Area | Result | |------|--------| | SQL injection | N/A — no new raw SQL | | Hardcoded secrets | None in new files | | gRPC auth | `[Authorize]` + `UseAuthentication`/`UseAuthorization` before `MapGrpcService` | | JWT on gRPC | Integration tests pass Bearer token via metadata — matches REST contract | | Message size limits | `MaxReceiveMessageSize = 16 MiB`, `MaxSendMessageSize = 64 MiB` configured | | Protobuf parsing | Bounded by Kestrel/gRPC message limits; collection caps added post-audit | | Test fixtures | `GrpcTestHelpers` uses env-resolved JWT via `JwtTestHelpers.MintAuthenticated` — no embedded secrets | ## Verdict **PASS_WITH_WARNINGS** at audit time (1 Medium open → **resolved in Step-14 follow-up**). Post-fix delta: **PASS** for cycle-9 new code.