# 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.
