# 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