mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-21 10:11:12 +00:00
bf13549b32
ci/woodpecker/push/02-build-push Pipeline failed
- Enhanced `.env.example` with detailed CMake build flags and replay-mode strategy flags for development and CI environments. - Updated `.gitignore` to include a new deploy rollback bookmark. - Revised `_docs/_autodev_state.md` to reflect the current task status and steps. - Added new lessons to `_docs/LESSONS.md` regarding testing and architectural improvements. - Documented changes in `_docs/02_document/deployment/ci_cd_pipeline.md` to reflect the relaxed OpenCV version pin. - Updated test data documentation in `_docs/02_document/tests/test-data.md` to clarify fixture usage and paths. This commit continues the cycle-1 documentation sync and addresses various configuration updates for improved clarity and functionality.
98 lines
6.4 KiB
Markdown
98 lines
6.4 KiB
Markdown
# Security Tests
|
||
|
||
These tests cover the security-relevant AC and the Mode B revisions that introduced explicit security gates: D-CROSS-CVE-1 (OpenCV CVE pin), D-C8-9 (MAVLink 2.0 message signing), AC-NEW-7 (cache poisoning), and RESTRICT-SAT-1 / AC-8.1 (no in-flight Service calls).
|
||
|
||
### NFT-SEC-01: Cache-poisoning safety budget
|
||
|
||
**Summary**: Validates AC-NEW-7 — across all onboard tiles written, `P(geo-misalign > 30 m) < 1%` and `P(> 100 m) < 0.1%`. Multi-flight statistics constrained — PARTIAL with current single-flight fixture (see traceability matrix).
|
||
**Traces to**: AC-NEW-7, Mode B Fact #105 (Service voting layer external dependency), D-PROJ-2
|
||
|
||
**Steps**:
|
||
|
||
| Step | Consumer Action | Expected Response |
|
||
|------|----------------|------------------|
|
||
| 1 | Run 3 trial flights against `derkachi-fixture` with synthetic over-confidence injection (deflate covariance ×1.5, ×2, ×3) | Each flight produces mid-flight tiles uploaded to `mock-suite-sat-service` |
|
||
| 2 | After each flight, the mock service records each received tile's quality metadata + onboard-asserted geo-alignment vs the GT-derived geo-alignment | Per-tile mis-alignment captured |
|
||
| 3 | Across all uploaded tiles, compute `P(misalign > 30 m)` and `P(misalign > 100 m)` | Statistic computed |
|
||
| 4 | Independently observe Suite Sat Service voting-layer behavior (mock) — verify mock-side gate refuses `trusted basemap` promotion when ingest votes don't agree | Voting contract assertion (per D-PROJ-2) |
|
||
|
||
**Pass criteria** (PARTIAL):
|
||
- `P(misalign > 30 m) < 1%`, `P(misalign > 100 m) < 0.1%` across the available trial flights.
|
||
- PARTIAL annotation: AC text expects ≥100 flights — escalates D-PROJ-3 fixture acquisition + D-PROJ-2 contract verification.
|
||
|
||
---
|
||
|
||
### NFT-SEC-02: No in-flight Service calls (network egress isolation)
|
||
|
||
**Summary**: Validates RESTRICT-SAT-1 / AC-8.1 — the SUT MUST NOT reach an external satellite provider during a flight. All cache reads come from the local cache.
|
||
**Traces to**: RESTRICT-SAT-1, AC-8.1
|
||
|
||
**Steps**:
|
||
|
||
| Step | Consumer Action | Expected Response |
|
||
|------|----------------|------------------|
|
||
| 1 | Start the SUT with `e2e-net` configured `internal: true` (no external connectivity at the network layer) | SUT comes up; tile cache reads succeed |
|
||
| 2 | Run 5 min of Derkachi replay | All tile lookups served from local cache |
|
||
| 3 | Read SUT egress counter (Docker network stats) | 0 packets out to non-`e2e-net` destinations |
|
||
| 4 | Inspect SUT log for any "external Service call attempted" event | 0 events (proving the SUT didn't even try) |
|
||
| 5 | Defense-in-depth: temporarily flip `internal: false` AND blackhole DNS, re-run | Same — 0 egress attempts; no failed-DNS errors |
|
||
|
||
**Pass criteria**: 0 packets to non-`e2e-net` destinations; no "Service call attempted" log entry.
|
||
|
||
---
|
||
|
||
### NFT-SEC-03: MAVLink 2.0 message signing on AP wired channel
|
||
|
||
**Summary**: Validates D-C8-9 — AP-side rejects unsigned MAVLink GPS_INPUT messages on the signed channel; SUT-emitted (signed) messages pass; SBOM dump confirms passkey configuration.
|
||
**Traces to**: D-C8-9 (Plan-phase decision), Mode B Fact #109 (CVE-2026-1579 mitigation)
|
||
|
||
**Steps**:
|
||
|
||
| Step | Consumer Action | Expected Response |
|
||
|------|----------------|------------------|
|
||
| 1 | Start `ardupilot-plane-sitl` with signing enabled and the test passkey loaded | Signing enabled |
|
||
| 2 | Inject an UNSIGNED `GPS_INPUT` from `mavproxy-listener` (i.e. a non-SUT origin) | AP rejects the message; rejection logged in AP STATUSTEXT |
|
||
| 3 | Inject a SIGNED `GPS_INPUT` with the SUT's signing key | AP accepts |
|
||
| 4 | Inject a SIGNED `GPS_INPUT` with a DIFFERENT key | AP rejects |
|
||
| 5 | Run the SUT's SBOM-dump CI step | SBOM declares the MAVLink signing module + passkey configuration entry present |
|
||
|
||
**Pass criteria**: AP rejection of unsigned + wrong-key; AP acceptance of correct-signed; SBOM declares signing.
|
||
|
||
**Note**: iNav-side is NOT subject to this test — Mode B Fact #109 documents the asymmetry as accepted residual risk (no MAVLink signing in iNav firmware per Source #129).
|
||
|
||
---
|
||
|
||
### NFT-SEC-04: OpenCV CVE-2025-53644 mitigation (≥4.12.0 pin)
|
||
|
||
**Summary**: Validates D-CROSS-CVE-1 — the pinned OpenCV ≥4.12.0 either decodes the CVE-2025-53644 PoC JPEG safely or rejects it; no crash, no buffer overflow.
|
||
**Traces to**: D-CROSS-CVE-1, Mode B Fact #112
|
||
|
||
**Steps**:
|
||
|
||
| Step | Consumer Action | Expected Response |
|
||
|------|----------------|------------------|
|
||
| 1 | Build the SUT image with AddressSanitizer (ASan) instrumentation enabled (separate CI build) | Instrumented binary |
|
||
| 2 | Push `cve-jpeg-fixture` to every code path that uses OpenCV imread/imdecode: nav-camera frame source (C1), satellite tile thumbnail re-load (C4), tile cache import (C6) | Each path either decodes cleanly OR returns a graceful error |
|
||
| 3 | Observe ASan output | 0 buffer-overflow / use-after-free / uninitialized-read reports |
|
||
| 4 | Observe SUT process exit code | Process does NOT crash; if rejection path taken, exit code is 0 + error logged |
|
||
| 5 | CI step: lint the lockfile / pyproject.toml / requirements.txt for the OpenCV version pin | Pin asserts `opencv-python>=4.11.0.86,<4.12` (cycle-1 relaxation per `_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md`; original target was `>=4.12.0` and will replay once gtsam ships numpy-2 wheels) |
|
||
|
||
**Pass criteria**: ASan clean; no crash; pinned version satisfies the cycle-1 floor `opencv-python>=4.11.0.86,<4.12` (D-CROSS-CVE-1 follow-up open). The leftover-replay condition lifts the floor back to `>=4.12.0` once upstream constraints clear.
|
||
|
||
---
|
||
|
||
### NFT-SEC-05: Egress-blocked + DNS-blackholed defense-in-depth
|
||
|
||
**Summary**: Defense-in-depth complement to NFT-SEC-02 — verifies that even if the network policy were misconfigured, the SUT does not call out to public DNS / known satellite-provider hosts.
|
||
**Traces to**: RESTRICT-SAT-1 (defense-in-depth)
|
||
|
||
**Steps**:
|
||
|
||
| Step | Consumer Action | Expected Response |
|
||
|------|----------------|------------------|
|
||
| 1 | Configure SUT container with iptables OUTPUT DROP except `e2e-net` AND DNS blackholed via `--dns 0.0.0.0` | SUT comes up |
|
||
| 2 | Run Derkachi replay | All operations succeed; 0 outbound DNS queries (verified via tcpdump on egress) |
|
||
| 3 | Inspect SUT for hardcoded provider hostnames (e.g. `*.googleapis.com`, `*.maxar.com`, `*.mapbox.com`, `*.azaion.com` for the runtime path) | grep finds zero references in compiled binary's strings table for runtime-path code |
|
||
|
||
**Pass criteria**: 0 DNS queries during replay; 0 provider hostname references in runtime path.
|