PASS_WITH_WARNINGS. Zero Critical / High. New cycle-8 findings: - F-AZ809-1 (Medium / A04 Insecure Design): unbounded geofences.polygons enables an authenticated DoS on POST /api/satellite/route. Cap candidate: 50 or 500. - F-AZ810-1 (Low / A09): JsonException.Message echoed in UavUploadValidationFilter (new instance of cycle-7 F-AZ795-1 pattern in a second code path). - F-AZ810-2 (Low / Informational): UavTileMetadata.CapturedAt typed DateTime not DateTimeOffset; freshness window drifts in non-UTC dev environments. Zero impact in UTC-deployed prod. Carry-overs (cycle 7): F-AZ795-1, F-AZ795-2, D-AZ795-1 still open. Cycle 4 D2-cy4 still open (test-runtime Medium). Cycle-8 architectural wins recorded: per-endpoint validation reached 100% coverage; three approved validation paths formalised; OSM wire-format normalisation under strict mode (AZ-812); UAV-handler defence-in-depth retained. Highest-priority cycle-9 follow-up: F-AZ809-1 polygon cap. Co-authored-by: Cursor <cursoragent@cursor.com>
6.2 KiB
Infrastructure & Configuration Review (Cycle 8)
Date: 2026-05-23 Mode: Delta scan Scope: Cycle-8 changes to deployment configs, CI/CD files, environment templates, and shell scripts only.
Cycle-8 Infrastructure-Layer Diff
Computed via git diff --name-only 865dfdb..b763da3 (cycle-7 tip → cycle-8 tip), filtered to infrastructure-relevant paths:
| File | Diff summary | Security relevance |
|---|---|---|
Dockerfile, Dockerfile.tests, Dockerfile.api (and any image-build file) |
NOT modified | None — cycle 8 did not touch any image build. |
docker-compose.yml, docker-compose.tests.yml, docker-compose.prod.yml (and any orchestration file) |
NOT modified | None — cycle 8 did not touch any compose file. |
.woodpecker.yml, .github/workflows/** (and any CI/CD pipeline definition) |
NOT modified | None — cycle 8 added no automated pipeline changes. |
.env, .env.example, .env.tests (and any environment template) |
NOT modified | None — cycle 8 read no new env vars (every cycle-8 validator and filter is pure code; FluentValidation 12.0.0 has no config knobs). |
appsettings.json, appsettings.Development.json, appsettings.tests.json |
NOT modified | None — cycle 8 added no new configuration sections. The pre-existing UavQualityConfig section is unchanged. |
scripts/probe_latlon_validation.sh |
NEW manual probe script for AZ-811 | Reviewed in static_analysis_cycle8.md § Test Code Review § scripts/probe_*_validation.sh. ✓ |
scripts/probe_region_validation.sh |
NEW manual probe script for AZ-808 | Reviewed in static_analysis_cycle8.md § Test Code Review § scripts/probe_*_validation.sh. ✓ |
scripts/probe_route_validation.sh |
NEW manual probe script for AZ-809 | Reviewed in static_analysis_cycle8.md § Test Code Review § scripts/probe_*_validation.sh. ✓ |
scripts/probe_upload_validation.sh |
NEW manual probe script for AZ-810 | Reviewed in static_analysis_cycle8.md § Test Code Review § scripts/probe_*_validation.sh. ✓ |
scripts/run-performance-tests.sh |
Modified — diff is exclusively the AZ-812 wire-format rename (?Latitude=…&Longitude=…&ZoomLevel=… → ?lat=…&lon=…&zoom=… across query strings, and {"latitude":…,"longitude":…} → {"lat":…,"lon":…} across JSON bodies in PT-01 through PT-08 invocations) |
No new credentials, no new shell-injection surface. The change is a forced wire-update made necessary by AZ-812's contract rename. ✓ |
.vscode/launch.json, .vscode/tasks.json, README.md |
Modified — developer-tooling artifacts | Out of scope for security audit (not deployed; do not affect runtime). |
Probe Shell Scripts — Common Safety Posture
All four new probe_*_validation.sh scripts follow the same defensive pattern (verified per static_analysis_cycle8.md):
#!/usr/bin/env bashwithset -euo pipefailat the top — fail-fast on undefined vars, broken pipes, command failures.API_URL="${API_URL:-https://localhost:8080}"default;JWT="${JWT:-}"with an explicitif [[ -z "${JWT}" ]]; then echo "ERROR: set JWT env var to a bearer token. …"; exit 2; figuard.curl -kused (justified — the dev cert is self-signed; the scripts target localhost in dev/test only — documented in each script's header).- Hand-built JSON payloads via shell variable interpolation — values are integer / quoted strings only, no caller-supplied shell strings.
- No embedded secrets, no hardcoded
$JWT, no.envreads.
Identical posture to the cycle-7 probe_inventory_validation.sh. ✓
Container & Image Security — Carried Forward Unchanged
| Check | Status (carried from cycle 5/6/7) | Cycle-8 impact |
|---|---|---|
Non-root container user (Dockerfile USER directive) |
Already in effect | None — no Dockerfile change. |
| Minimal base image (alpine/distroless/etc.) | The API image uses the .NET 10 SDK base — same as cycle 7; image hardening is still owned by a separate, unscheduled follow-up task. | None. |
| No secrets in build args | Verified cycle 5; no Dockerfile change in cycle 7 or 8 |
None. |
| Health checks | Compose healthcheck block on Postgres unchanged |
None. |
CI/CD Security — Carried Forward Unchanged
| Check | Status | Cycle-8 impact |
|---|---|---|
| Secrets management (env vars / vault, not pipeline literals) | Existing pattern preserved | None. |
| No credentials in pipeline definitions | .woodpecker.yml untouched in cycle 8 |
None. |
| Artifact signing | Existing posture (none — owned by a separate operational improvement track) | None. |
| Dependency-audit step in pipeline | Existing posture (manual audit per dependency_scan_cycle*.md; no automated dotnet list package --vulnerable in CI due to the build-hang issue noted in AGENTS.md) |
None. |
Environment & Secrets
.env.example— not modified in cycle 8. The cycle-8 code reads no new env vars.appsettings.Development.json— not modified in cycle 8.appsettings.json— production template; unchanged in cycle 8.- The cycle-7 host-port change (
5432:5432→5433:5432) is preserved through cycle 8; not relevant to production exposure (production containers run on a private docker network without host-port mapping per the existing deployment model).
Cycle-7 + Earlier Carry-overs
No infrastructure-layer carry-overs from earlier cycles. The cycle-2 UavQualityConfig-derived KestrelServerOptions.Limits.MaxRequestBodySize = 500 MiB (set in Program.cs:41-43) is noted in owasp_review_cycle8.md § A05 as a configuration choice that contributed to the F-AZ809-1 exploit-math worst case, but it is not itself an infrastructure-layer finding — the value is correct for the UAV upload endpoint, and the proper fix is per-endpoint size narrowing (a code change, not an infra change).
Verdict (Phase 4)
PASS — zero new infrastructure-layer findings.
The four new probe scripts are dev/test only, env-driven, fail-fast under set -euo pipefail, and contain no embedded credentials. The single perf-script update is a wire-rename diff with no security impact. Cycle 8 made no Docker, compose, CI, env-template, or appsettings changes.