Files
gps-denied-onboard/e2e/docker/docker-compose.test.yml
T
Oleksandr Bezdieniezhnykh 6ce31587d4 [autodev] fix Tier-1 e2e docker harness drift
Bugs found during Step 11 (Run Tests) functional gate:

1. e2e/docker/docker-compose.test.yml referenced docker/Dockerfile
   (doesn't exist). Renamed to docker/companion-tier1.Dockerfile.

2. fdr-output volume declared tmpfs size=64g, which requires actual host
   RAM. Docker Desktop on macOS has only ~3.8 GiB; tmpfs alloc fails.
   Switched to a plain named volume (the SUT enforces the 64 GB cap
   internally per NFT-LIM-02; the volume-layer cap was belt-and-
   suspenders only). Documented the overlay2+xfs override path for CI
   runners that support it.

3. Added e2e-results/ to .gitignore (runtime output dir created by
   the bind-mount).

These bugs predate this session; the harness had never been bench-tested
end-to-end. Surfacing them was the actual outcome of running test-run.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 19:12:16 +03:00

148 lines
5.1 KiB
YAML

# Tier-1 docker-compose entrypoint for the gps-denied-onboard blackbox e2e harness.
#
# Spec sources (single source of truth):
# _docs/02_document/tests/environment.md § Docker Environment
# _docs/02_tasks/todo/AZ-406_test_infrastructure.md
#
# Layout note: AZ-406 introduces this file; later test-task batches may add
# per-scenario override files alongside it (e.g. negative path injectors).
# This base file MUST stay self-contained — every override is purely additive.
#
# Build context (`build.context: ../..`) is the repo root, so the SUT image
# build sees `src/`, `cpp/`, `docker/Dockerfile`, and `pyproject.toml`.
services:
gps-denied-onboard:
build:
context: ../..
dockerfile: docker/companion-tier1.Dockerfile
args:
BUILD_VINS_MONO: "OFF"
image: gps-denied-onboard:e2e
networks: [e2e-net]
volumes:
- tile-cache-fixture:/var/azaion/tile-cache:ro
- fdr-output:/var/azaion/fdr
environment:
ONBOARD_FC_ADAPTER: ${FC_ADAPTER:-ardupilot}
ONBOARD_VIO_STRATEGY: ${VIO_STRATEGY:-okvis2}
MAVLINK_SIGNING_PASSKEY_FILE: /run/secrets/mavlink_passkey
secrets:
- mavlink_passkey
depends_on:
- mock-suite-sat-service
healthcheck:
test: ["CMD", "python", "-c", "from gps_denied_onboard.healthcheck import check; check()"]
interval: 5s
retries: 12
ardupilot-plane-sitl:
image: ardupilot/ardupilot-sitl:plane-stable
networks: [e2e-net]
command: ["--vehicle=ArduPlane", "--gps-type=14"]
environment:
# GPS_TYPE=14 selects MAV (external positioning) per ArduPilot SITL params.
AP_PARAM_GPS_TYPE: "14"
inav-sitl:
image: inavflight/inav-sitl:9.0.0
networks: [e2e-net]
# iNav SITL exposes MSP on TCP 5760 (UART1) per docs/SITL/SITL.md
mock-suite-sat-service:
build: ../fixtures/mock-suite-sat
image: mock-suite-sat-service:e2e
networks: [e2e-net]
environment:
MOCK_SUITE_SAT_AUDIT_PATH: /audit
volumes:
- mock-audit:/audit
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request, sys; sys.exit(0 if urllib.request.urlopen('http://localhost:8080/mock/health', timeout=2).status==200 else 1)"]
interval: 5s
retries: 12
mavproxy-listener:
image: ardupilot/mavproxy:latest
networks: [e2e-net]
command:
- "--master=udp:0.0.0.0:14551"
- "--logfile=/var/log/tlogs/${RUN_ID:-local}.tlog"
- "--out=udp:e2e-runner:14552"
volumes:
- tlog-output:/var/log/tlogs
e2e-runner:
build: ../runner
image: gps-denied-onboard-e2e-runner:latest
networks: [e2e-net]
environment:
RUN_ID: ${RUN_ID:-local}
FC_ADAPTER: ${FC_ADAPTER:-ardupilot}
VIO_STRATEGY: ${VIO_STRATEGY:-okvis2}
TIER: tier1-docker
MAVLINK_PASSKEY_PATH: /test-fixtures/secrets/mavlink-test-passkey.txt
MOCK_SUITE_SAT_URL: http://mock-suite-sat-service:8080
AP_SITL_HOST: ardupilot-plane-sitl
INAV_SITL_HOST: inav-sitl
MAVPROXY_LISTENER_HOST: mavproxy-listener
volumes:
- ../../_docs/00_problem/input_data:/test-data:ro
- ../../_docs/00_problem/input_data/expected_results:/expected:ro
- ../fixtures:/test-fixtures:ro
- ../tests:/test-suite:ro
- fdr-output:/fdr:ro
- tlog-output:/tlogs:ro
- e2e-results:/e2e-results
- mock-audit:/mock-audit:ro
command:
- "pytest"
- "/test-suite"
- "--csv=/e2e-results/run-${RUN_ID:-local}/report.csv"
- "--csv-columns=test_id,test_name,traces_to,fc_adapter,vio_strategy,tier,started_at_utc,execution_time_ms,result,error_message,evidence_paths"
- "--evidence-out=/e2e-results/run-${RUN_ID:-local}/evidence"
depends_on:
gps-denied-onboard:
condition: service_healthy
mock-suite-sat-service:
condition: service_healthy
ardupilot-plane-sitl:
condition: service_started
inav-sitl:
condition: service_started
mavproxy-listener:
condition: service_started
networks:
e2e-net:
driver: bridge
# CRITICAL: enforces RESTRICT-SAT-1 / NFT-SEC-02 / NFT-SEC-05 at the network layer.
# The SUT, mock, runner, and SITLs can talk to each other but none of them can
# reach the public internet (no DNS, no egress). The e2e-runner verifies this
# at runtime by attempting a TCP connect to 1.1.1.1:443 (AC-5).
internal: true
volumes:
# Size cap follows AC-NEW-3: each FDR file ≤ 64 GB. The volume layer cap is
# belt-and-suspenders; the SUT enforces the cap internally per NFT-LIM-02.
# `--storage-opt size=64g` requires overlay2 with xfs backing on the host —
# most CI runners and macOS Docker Desktop hosts lack that combination, so
# this base file uses the documented fallback (a plain named volume) and
# relies on the SUT-internal cap. CI runners with overlay2+xfs can override
# via a docker-compose.override.yml that re-introduces the tmpfs driver_opts.
fdr-output: {}
tile-cache-fixture: {}
tlog-output: {}
mock-audit: {}
e2e-results:
driver: local
driver_opts:
type: none
device: ${PWD}/../../e2e-results
o: bind
secrets:
mavlink_passkey:
file: ./secrets/mavlink_passkey