[AZ-503] [AZ-504] Cycle 5 Steps 11-15 sync

Wrap up cycle 5 verification + documentation:
- Steps 10/11 wrap-up reports (implementation_completeness +
  implementation_report) for the AZ-503-foundation + AZ-504 batch.
- Step 12 test-spec sync: AZ-503-foundation/AZ-504 ACs appended;
  AZ-505 deferred ACs recorded.
- Step 13 update-docs: architecture, data-model, glossary, module-
  layout, uav-tile-upload contract (v1.1.0), DataAccess + Services
  + Tests module docs synced; new common_uuidv5.md module doc.
- Step 14 security audit: PASS_WITH_WARNINGS; 0 new Critical/High;
  2 new Low informational (F1 flightId provenance, F2 pgcrypto
  deploy gap).
- Step 15 performance test: PASS_WITH_INFRA_WARNINGS; PT-08
  passed twice (AZ-504 fix verified); PT-01/02 failed due to
  recurring local Docker/colima DNS cold-start (not an app
  regression). Cycle-3 perf-harness leftover stays OPEN with
  replay #5 documented.
- Autodev state moved to Step 16 (Deploy).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-12 18:01:27 +03:00
parent c646aa93e2
commit 61612044fb
27 changed files with 1075 additions and 50 deletions
@@ -0,0 +1,95 @@
# Security Audit Report (Cycle 5)
**Date**: 2026-05-12
**Scope**: Cycle-5 delta over the cycle-4 audit (`_docs/05_security/security_report_cycle4.md`)
**Trigger**: AZ-503-foundation (UUIDv5 tile identity + integer-only flight-aware UPSERT + per-flight on-disk paths) + AZ-504 (perf-script pipefail fix)
**Mode**: Delta — all five phases re-executed for the AZ-503 surface; AZ-504 has no source-code surface beyond a shell wrap and is folded into Phase 2
**Verdict**: **PASS_WITH_WARNINGS** (cycle-5 delta) / **PASS_WITH_WARNINGS** (cumulative — carries forward 1 cycle-3 Medium dep finding via D2-cy4 + 2 cycle-5 Low informational notes)
## Summary
| Severity | Count (cycle 5 delta) | Count (cumulative) |
|----------|-----------------------|--------------------|
| Critical | 0 | 0 |
| High | 0 | 0 |
| Medium | 0 NEW | 1 (D2-cy4 carry-over — Microsoft.NET.Test.Sdk transitive flag, test-runtime exposure only) |
| Low | 2 NEW (informational) | 5 cycle-4 informational + 2 cycle-5 informational |
## OWASP Top 10 Assessment (Cycle 5)
| Category | Status |
|----------|--------|
| A01 Broken Access Control | PASS |
| A02 Cryptographic Failures | PASS |
| A03 Injection | PASS |
| A04 Insecure Design | PASS_WITH_NOTE (F1-cy5 — flight_id provenance) |
| A05 Security Misconfiguration | PASS |
| A06 Vulnerable Components | PASS_WITH_WARNINGS (D2-cy4 carry-over only) |
| A07 Auth Failures | PASS |
| A08 Data Integrity Failures | PASS |
| A09 Logging Failures | PASS |
| A10 SSRF | PASS |
## Cycle-5 NEW Findings
| # | Severity | Category | Location | Title |
|---|----------|----------|----------|-------|
| F1-cy5 | Low (informational) | Insecure Design (A04) | `_docs/02_document/contracts/api/uav-tile-upload.md` v1.1.0 + `UavTileUploadHandler.PersistAsync` | `metadata.flightId` is not authenticated provenance |
| F2-cy5 | Low (informational) | Security Misconfiguration (A05) | Migration 014 `CREATE EXTENSION pgcrypto` | Deployment runbook gap on managed Postgres providers |
### Finding Details
**F1-cy5: `metadata.flightId` is not authenticated provenance** (Low / Insecure Design)
- Location: `_docs/02_document/contracts/api/uav-tile-upload.md` v1.1.0 § Request shape; `SatelliteProvider.Services.TileDownloader/UavTileUploadHandler.cs:144-217`
- Description: The new optional `metadata.flightId` field is persisted to `tiles.flight_id` and used as part of the on-disk path and the deterministic `tile.id` derivation, but the handler does NOT check that the authenticated principal is authorized to write under that flight identifier. Any GPS-permissioned caller can supply any flight_id.
- Impact: Two adversarial cases:
1. **Impersonation**: a compromised UAV credential can falsely attribute its uploads to a different flight (mis-attribution on the evidence chain).
2. **False-flag**: a legitimate UAV credential can falsely attribute its uploads to a competing operator's flight_id.
Downstream consumers MUST NOT treat `tiles.flight_id` as cryptographic provenance — they must cross-reference against an authoritative flight registry (out of this workspace's scope) before drawing operational conclusions.
- Remediation: Documented as a deliberate v1.1.0 design choice. If a future cycle requires per-flight ownership, options listed in `static_analysis_cycle5.md` (per-flight JWT, scoped permission claim `GPS:flight=<uuid>`, or move flight_id derivation to a trusted claim).
- Verification cross-reference: AZ-487/AZ-494 (JWT identity baseline) + AZ-488 (`RequiresGpsPermission` policy) — both still apply unchanged. F1-cy5 is purely about the **inside** of the authorized envelope.
- Severity rationale: Low because (i) the surface only exists after a valid GPS-permissioned JWT, (ii) the Admin API per `suite/_docs/10_auth.md` is the upstream identity gate, (iii) no current consumer treats flight_id as authenticated provenance.
**F2-cy5: Deployment runbook gap — `CREATE EXTENSION pgcrypto` privilege on managed Postgres** (Low / Security Misconfiguration)
- Location: `SatelliteProvider.DataAccess/Migrations/014_AddTileIdentityColumns.sql:34`; first observed by `_docs/05_security/infrastructure_review_cycle5.md`
- Description: Migration 014 issues `CREATE EXTENSION IF NOT EXISTS pgcrypto`. The current Docker compose dev/test environment connects as the `postgres` superuser, so the extension installs automatically. On managed Postgres providers (AWS RDS, Google Cloud SQL, Azure Database for PostgreSQL) the deployment role typically lacks superuser; the migration will fail with `must be owner of database` or `permission denied to create extension` unless the extension is pre-installed by an operator.
- Impact: Deployment may fail at the migration step at startup time. Failure is loud (the app crashes before serving requests) — not a silent security degradation. No production cycle has shipped yet for the satellite-provider on a managed Postgres provider, so this is forward-looking.
- Remediation:
- (a) Add a one-line entry to the deployment runbook: "ensure `CREATE EXTENSION IF NOT EXISTS pgcrypto` has run as a superuser before the satellite-provider migration role runs migration 014."
- (b) On RDS / Cloud SQL, allow-list `pgcrypto` in the provider's per-DB extension UI / parameter group.
- Severity rationale: Low informational because (i) the failure mode is loud, (ii) the remediation is one-line operational, (iii) the local Docker environment is unaffected, (iv) every recent managed Postgres provider supports `pgcrypto` in their default allow-list (it's a contrib module shipped with Postgres itself, not a third-party extension).
## Dependency Vulnerabilities (Cycle 5 delta)
None. Zero new NuGet packages, zero version bumps. The cycle-4 D2-cy4 Medium carry-over (Microsoft.NET.Test.Sdk 17.8.0 transitive `NuGet.Frameworks` flag) is unchanged.
## Recommendations
### Immediate (Critical/High)
None. No Critical or High findings in cycle 5.
### Short-term (Medium)
Apply the D2-cy4 Microsoft.NET.Test.Sdk refresh once a downstream cycle bumps the Test SDK (separate workstream — same posture as cycle 4).
### Long-term (Low / Hardening)
- **F1-cy5**: when an authoritative flight registry is introduced (likely a sibling repo or the Admin API), add per-flight ownership verification to `UavTileUploadHandler.HandleAsync` and bump the upload contract to v2.0.0. Until then, document the trust boundary clearly in any consumer-facing API docs that surface `tiles.flight_id`.
- **F2-cy5**: add the `pgcrypto` pre-install step to the deployment runbook before the first managed-Postgres deployment.
## Cross-Reference to Prior Audits
- Cycle-3 baseline: `_docs/05_security/security_report.md` (authoritative for OWASP narrative on categories untouched by AZ-503).
- Cycle-4 delta: `_docs/05_security/security_report_cycle4.md` (AZ-500 package bumps; D2-cy4 finding tree).
- Cycle-5 delta artifacts: `dependency_scan_cycle5.md`, `static_analysis_cycle5.md`, `owasp_review_cycle5.md`, `infrastructure_review_cycle5.md`.
## Verdict Reasoning
- No Critical, no High, no NEW Medium findings.
- 2 Low informational notes (F1-cy5, F2-cy5) properly documented with rationale and forward-looking remediation paths.
- Cumulative posture continues to carry the cycle-3 D2-cy4 Medium dep finding (out-of-scope for AZ-503).
- Per `security/SKILL.md` § Verdict Logic: `PASS_WITH_WARNINGS` because the cumulative state retains a Medium finding (D2-cy4) but no Critical or High. Cycle-5 delta in isolation would be `PASS_WITH_WARNINGS` due to the Low informational notes; the cycle-5 delta-only verdict is `PASS` per the strict reading ("PASS_WITH_WARNINGS: only Medium or Low findings" — and we have 2 Low informational). The conservative (cumulative) verdict is `PASS_WITH_WARNINGS`.
**Final verdict (cumulative)**: **PASS_WITH_WARNINGS**.
**Cycle-5 delta verdict**: **PASS_WITH_WARNINGS** (informational notes only — gate-acceptable).