mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 01:41:13 +00:00
Update autodev state, architecture documentation, and glossary terms
Transitioned the autodev state to phase 21, reflecting the completion of Step 5 and the drafting of Step 6 epics. Revised the architecture documentation to clarify the roles of the Tile Manager and its components, ensuring accurate representation of the system's operational flow. Updated glossary entries for Flight State and Operator to incorporate recent changes and enhance clarity on component interactions and responsibilities.
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
# C11 — Tile Manager
|
||||
|
||||
## 1. High-Level Overview
|
||||
|
||||
**Purpose**: own the operator-side network I/O against `satellite-provider` for the onboard tile corpus, in **both directions**:
|
||||
|
||||
- **Download** (pre-flight, F1): fetch tiles from `satellite-provider` for the operational area, apply AC-NEW-6 freshness gating, and write into C6 (`TileStore` + `TileMetadataStore`). C11 is the **only** path that crosses the workstation/companion enclave to the parent suite for tile pixels — C10 reads from the populated C6 store and never touches `satellite-provider` itself.
|
||||
- **Upload** (post-landing, F10): when `flight_state == ON_GROUND` is confirmed, read pending mid-flight tiles from C6 and POST to `satellite-provider`'s ingest endpoint (D-PROJ-2 contract sketch).
|
||||
|
||||
C11 is a **separate operator-side binary / image**. The airborne companion image's CMake target deliberately excludes the entire `c11_tilemanager/` source tree so the airborne process cannot accidentally execute either the download path or the upload path even via reflection or config error (ADR-004 process-level isolation, AC-8.4). Both directions of tile I/O are operator-driven on the operator workstation; the companion only consumes the populated C6 store while airborne.
|
||||
|
||||
**Architectural Pattern**: Pipeline behind two interfaces (`TileDownloader`, `TileUploader`) under one component, consistent with C8's multi-interface shape (FC-AP, FC-iNav, GCS adapters under one component). The two interfaces are bundled into C11 because they share auth (TLS + service-internal API key for download, per-flight onboard signing key for upload), HTTP client, network configuration, deployment unit (operator-tooling tarball), and the airborne-exclusion property — splitting them into two components would duplicate all of that. They are kept as **two interfaces** so SRP is preserved at the call-site level: C12 binds `TileDownloader` for the F1 cache-build workflow, `TileUploader` for the F10 post-landing trigger; neither is forced to depend on the other.
|
||||
|
||||
**Upstream dependencies**:
|
||||
|
||||
- C12 OperatorTooling → invokes `TileDownloader.download_tiles_for_area(...)` during F1 and `TileUploader.upload_pending_tiles(...)` post-landing.
|
||||
- C6 TileStore + TileMetadataStore → write target during download (`source = googlemaps`); read source during upload (`source = onboard_ingest`, `voting_status = pending`).
|
||||
- Operator workstation OS → invocation entry point (CLI / tray app, owned by C12).
|
||||
- `satellite-provider` (external) → `GET /api/satellite/tiles?bbox=…&zoom=…` for download; `POST /api/satellite/tiles/ingest` for upload (D-PROJ-2 design task #1, **planned, not yet implemented service-side**).
|
||||
|
||||
**Downstream consumers**:
|
||||
|
||||
- C10 CacheProvisioner reads the populated C6 store after a `TileDownloader` run completes; C10 does not call C11 directly. C12 sequences the two steps.
|
||||
- On the upload side: none on the onboard side; the parent-suite voting layer (D-PROJ-2 design task #2) consumes the uploaded tiles asynchronously.
|
||||
|
||||
## 2. Internal Interfaces
|
||||
|
||||
### Interface: `TileDownloader`
|
||||
|
||||
| Method | Input | Output | Async | Error Types |
|
||||
|--------|-------|--------|-------|-------------|
|
||||
| `download_tiles_for_area` | `DownloadRequest` | `DownloadBatchReport` | No (offline; minutes) | `SatelliteProviderError`, `FreshnessRejectionError`, `ResolutionRejectionError`, `CacheBudgetExceededError`, `IdempotentNoOp` |
|
||||
| `enumerate_remote_coverage` | `bbox: BoundingBox, zoom_levels: list[int]` | `list[TileSummary]` | No | `SatelliteProviderError` |
|
||||
|
||||
### Interface: `TileUploader`
|
||||
|
||||
| Method | Input | Output | Async | Error Types |
|
||||
|--------|-------|--------|-------|-------------|
|
||||
| `confirm_flight_state` | `()` | `FlightStateSignal` (must be ON_GROUND) | No | `FlightStateNotOnGroundError` |
|
||||
| `enumerate_pending_tiles` | `flight_id: uuid (optional)` | `list[TileMetadata]` | No | `TileMetadataError` |
|
||||
| `upload_pending_tiles` | `UploadRequest` | `UploadBatchReport` | No | `SatelliteProviderError`, `RateLimitedError`, `SignatureRejectedError` |
|
||||
|
||||
**Input/Output DTOs**:
|
||||
|
||||
```
|
||||
DownloadRequest:
|
||||
bbox: BoundingBox (lat_min, lon_min, lat_max, lon_max)
|
||||
zoom_levels: list[int]
|
||||
sector_class: enum {active_conflict, stable_rear}
|
||||
satellite_provider_url: URL
|
||||
service_api_key: string
|
||||
cache_root: Path
|
||||
|
||||
DownloadBatchReport:
|
||||
tiles_downloaded: int
|
||||
tiles_rejected_freshness: int
|
||||
tiles_rejected_resolution: int # RESTRICT-SAT-4 < 0.5 m/px
|
||||
tiles_downgraded: int
|
||||
freshness_summary: dict[freshness_label, count]
|
||||
outcome: enum {success, failure, idempotent_no_op}
|
||||
failure_reason: string (optional)
|
||||
|
||||
UploadRequest:
|
||||
flight_id: uuid (optional; defaults to all flights with pending tiles)
|
||||
batch_size: int
|
||||
satellite_provider_url: URL
|
||||
|
||||
FlightStateSignal: see C8 — must be ON_GROUND for any upload to proceed
|
||||
|
||||
UploadBatchReport:
|
||||
batch_uuid: uuid (assigned by satellite-provider per D-PROJ-2 contract)
|
||||
per_tile_status: list[(tile_id, status: enum {queued, rejected, duplicate, superseded})]
|
||||
retry_count: int
|
||||
next_retry_at_s: int (when retried)
|
||||
outcome: enum {success, partial, failure}
|
||||
```
|
||||
|
||||
## 3. External API Specification
|
||||
|
||||
C11 is a **client** of `satellite-provider`'s REST surface in both directions.
|
||||
|
||||
### 3.1 Download — read path (existing `satellite-provider` API)
|
||||
|
||||
| Endpoint | Method | Auth | Rate Limit | Description |
|
||||
|----------|--------|------|------------|-------------|
|
||||
| `/api/satellite/tiles?bbox=…&zoom=…` | GET | TLS + service-internal API key | parent-suite enforces | Paged tile blobs + metadata for a bounding box at the given zoom level(s). |
|
||||
|
||||
C11 honours `Retry-After` on 429s, fails fast on TLS / auth errors, retries with backoff on 5xx. Resolution below 0.5 m/px (RESTRICT-SAT-4) is rejected at the C11 boundary, not pushed downstream.
|
||||
|
||||
### 3.2 Upload — write path (D-PROJ-2 contract sketch, **planned**)
|
||||
|
||||
| Endpoint | Method | Auth | Rate Limit | Description |
|
||||
|----------|--------|------|------------|-------------|
|
||||
| `/api/satellite/tiles/ingest` (parent-suite, **planned**) | POST | Per-flight onboard signing key (D-C8-9 = (d) family); each tile carries the signature | parent-suite enforces | Multipart upload of one or more tiles; response 202 with batch UUID + per-tile status. |
|
||||
|
||||
**Request schema** (multipart fields per tile):
|
||||
|
||||
- `tile_blob` (JPEG body, byte-identical to `satellite-provider`'s existing tile format)
|
||||
- `zoomLevel` (int)
|
||||
- `latitude` / `longitude` (double)
|
||||
- `tile_size_meters` (double), `tile_size_pixels` (int)
|
||||
- `capture_timestamp` (ISO 8601), `flight_id` (UUID), `companion_id` (string)
|
||||
- `quality_metadata` (JSON; `TileQualityMetadata` per data_model.md)
|
||||
- `signature` (per-flight onboard signing key signature over the payload)
|
||||
|
||||
**Response**: 202 Accepted + `{batch_uuid: UUID, per_tile_status: [...]}`.
|
||||
|
||||
Test substitute during NFT-SEC-01 / FT-P-17 / IT runs: the e2e-test `mock-suite-sat-service` fixture (under `tests/fixtures/mock-suite-sat-service/`) implements the planned POST surface so upload integration tests can run before D-PROJ-2 ships service-side. Download integration tests run against the **real** `satellite-provider` (its existing GET surface is already implemented). The mock is not a component and is never reached in production.
|
||||
|
||||
## 4. Data Access Patterns
|
||||
|
||||
C11 reads from / writes to C6 (the local store) and reads from / writes to `satellite-provider` (network). It owns no relational state of its own beyond a small download-progress journal and a small upload-progress journal.
|
||||
|
||||
### Caching Strategy
|
||||
|
||||
| Data | Cache Type | TTL | Invalidation |
|
||||
|------|-----------|-----|-------------|
|
||||
| Download-progress journal | filesystem alongside the operator workstation cache root | until a `download_tiles_for_area` run completes | per-area run on completion |
|
||||
| Pending-upload journal | filesystem alongside the operator workstation cache root | until upload acknowledged | per-batch acknowledgment removes from journal |
|
||||
|
||||
### Storage Estimates
|
||||
|
||||
| Table/Collection | Est. Row Count (1yr) | Row Size | Total Size | Growth Rate |
|
||||
|-----------------|---------------------|----------|------------|-------------|
|
||||
| Download-progress journal | a few hundred rows per area provisioning | ~256 B / row | <1 MB | per provisioning run |
|
||||
| Pending-upload journal | a few hundred per flight | ~256 B / row | <1 MB | per flight |
|
||||
|
||||
### Data Management
|
||||
|
||||
**Seed data**: none — both journals are empty until the operator triggers a download or an upload run.
|
||||
|
||||
**Rollback**: the download path is idempotent — re-running `download_tiles_for_area` for an unchanged `(bbox, zoom_levels, sector_class)` triggers C10's manifest-hash check (D-C10-1) downstream and the engine/descriptor build is skipped. The upload path is idempotent on the service side via the `(zoomLevel, lat, lon, capture_timestamp, companion_id, flight_id)` dedup key.
|
||||
|
||||
## 5. Implementation Details
|
||||
|
||||
**Algorithmic Complexity**:
|
||||
|
||||
- Download: linear in tile count; bandwidth-bound by the operator workstation's link to `satellite-provider`.
|
||||
- Upload: linear in pending tile count; bandwidth-bound; bursty post-landing.
|
||||
|
||||
**State Management**: stateless except for the two journals.
|
||||
|
||||
**Key Dependencies**:
|
||||
|
||||
| Library | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| httpx | per project pin | GET (download) + multipart POST (upload) to `satellite-provider` |
|
||||
| atomicwrites | latest | Journal updates |
|
||||
| cryptography | per project pin | Per-flight signing key (upload payload signing); the production `satellite-provider` ingest endpoint and the e2e-test `mock-suite-sat-service` fixture both verify with the same key family |
|
||||
|
||||
**Error Handling Strategy**:
|
||||
|
||||
- `SatelliteProviderError`: HTTP timeout / 5xx / TLS failure on either direction. Retry-with-backoff on 5xx; fail fast on TLS / auth. On download, surface to operator + takeoff blocked. On upload, leave tiles in the pending-upload journal and surface to operator. **Do not delete uploaded tiles from C6** until acknowledged.
|
||||
- `RateLimitedError` (429): obey `Retry-After`; the operator can also re-invoke later. Same handling either direction.
|
||||
- `FreshnessRejectionError` / `ResolutionRejectionError`: download-side only. Per AC-NEW-6 / RESTRICT-SAT-4 — never silently downgrade fresh-required tiles in `active_conflict` sectors. Surface counts in the `DownloadBatchReport`.
|
||||
- `CacheBudgetExceededError`: download-side only. Pre-flight free-space check against AC-8.3 (≤ 10 GB). Fail fast with explicit budget delta; no partial write.
|
||||
- `FlightStateNotOnGroundError`: upload-side only. Refuse to start; log + show explicit reason. ADR-004 process-level isolation means C11 should never run when the FC believes it's airborne — this error is a defense-in-depth, not the primary control.
|
||||
- `SignatureRejectedError`: upload-side only. Per-flight signing key was rejected by `satellite-provider`. This is a security-critical event — do NOT silently drop; surface to operator + log to FDR.
|
||||
|
||||
## 6. Extensions and Helpers
|
||||
|
||||
| Helper | Purpose | Used By |
|
||||
|--------|---------|---------|
|
||||
| `TileSignaturePayloadBuilder` | constructs the signed payload for D-PROJ-2 contract (upload) | C11 only — keep inside the component |
|
||||
|
||||
## 7. Caveats & Edge Cases
|
||||
|
||||
**Known limitations**:
|
||||
|
||||
- D-PROJ-2 ingest endpoint is NOT yet implemented service-side. Until parent-suite delivers the endpoint, C11 will fail every upload — the pending-upload journal accumulates. Operator workflow tolerates this.
|
||||
- The e2e-test `mock-suite-sat-service` fixture implements only the planned POST contract (per the leftover file). Download integration tests run against the real `satellite-provider`. Production runs reach `satellite-provider` directly in both directions; the fixture is never on the production path.
|
||||
- `TileDownloader` requires the operator workstation to have network reach to `satellite-provider` (the only path that crosses out of the workstation enclave). Pre-flight network configuration is an operator concern owned by C12; C11 fails fast if reachability is missing.
|
||||
|
||||
**Potential race conditions**:
|
||||
|
||||
- If the operator launches two `TileDownloader` runs concurrently against the same cache root, a filesystem lockfile (operated by C12 tooling) prevents corrupting C6's tile rows. Same lockfile gates concurrent `TileUploader` invocations.
|
||||
|
||||
**Performance bottlenecks**:
|
||||
|
||||
- Download: bandwidth-bound by the operator workstation's `satellite-provider` link; descriptor / engine work is downstream in C10 (offline, minutes).
|
||||
- Upload: bandwidth-bound. Per-flight upload volume is bounded by the F4 mid-flight tile gen cap (typically a few hundred tiles, each 50–200 KB → tens of MB per flight).
|
||||
|
||||
## 8. Dependency Graph
|
||||
|
||||
**Must be implemented after**: C6 (read source for upload, write target for download), `satellite-provider` (download path; existing) + D-PROJ-2 endpoint (upload path; the e2e-test `mock-suite-sat-service` fixture covers tests until the real endpoint ships).
|
||||
|
||||
**Can be implemented in parallel with**: anything except C6 changes.
|
||||
|
||||
**Blocks**: F1 (pre-flight cache build cannot start without `TileDownloader`), F10 (post-landing upload cannot start without `TileUploader`).
|
||||
|
||||
## 9. Logging Strategy
|
||||
|
||||
| Log Level | When | Example |
|
||||
|-----------|------|---------|
|
||||
| ERROR | `FlightStateNotOnGroundError`, `SignatureRejectedError`, persistent `SatelliteProviderError`, `CacheBudgetExceededError` | `C11 refused to start: flight_state=IN_AIR; safeguard active` |
|
||||
| WARN | one-off network failure, scheduled retry, freshness-driven rejections (counts) | `C11 batch upload retry: batch_uuid=…; next_retry_in_s=30` |
|
||||
| INFO | session start/end; per-batch report (download + upload) | `C11 download complete: 87654 tiles, 12 stale-rejected; bbox=…` |
|
||||
| DEBUG | per-tile request/response | `C11 tile uploaded: tile_id=(z=18,lat=…,lon=…); status=queued` |
|
||||
|
||||
**Log format**: structured JSON.
|
||||
**Log storage**: operator workstation log file (e.g. `~/.azaion/onboard/c11-tilemanager.log`); also writes per-run summaries (download report, upload report) to the operator workstation cache root for audit. The companion's FDR is NOT involved (C11 doesn't run on the companion).
|
||||
@@ -0,0 +1,213 @@
|
||||
# Test Specification — C11 Tile Manager (TileDownloader + TileUploader)
|
||||
|
||||
Component-scoped. Suite-level coverage in `_docs/02_document/tests/*.md`. C11 was renamed and expanded in this Plan cycle: it now owns BOTH operator-side network I/O directions against `satellite-provider`. Strict ADR-004 enforcement: never loaded into the airborne companion image.
|
||||
|
||||
## Acceptance Criteria Traceability
|
||||
|
||||
| AC ID | Acceptance Criterion (one-line) | Test IDs | Coverage |
|
||||
|-------|---------------------------------|----------|----------|
|
||||
| AC-8.1 | Imagery via Suite Sat Service offline cache, ≥0.5 m/px | FT-P-15, **C11-IT-01** (download) | Covered |
|
||||
| AC-8.2 | Tile freshness <6 mo (active-conflict) / <12 mo (rear) | FT-N-05, **C11-IT-02** (download-side gate) | Covered |
|
||||
| AC-8.3 | Imagery pre-loaded onto companion before flight | FT-P-15, FT-P-16, **C11-IT-01** | Covered |
|
||||
| AC-NEW-6 | System rejects/downgrades stale tiles | FT-N-05, FT-N-06, **C11-IT-02** | Covered |
|
||||
| AC-8.4 + D-PROJ-2 (POST contract) | Mid-flight tile generation + post-landing upload to satellite-provider | FT-P-17, **C11-IT-03** (upload) | Covered (against e2e-test fixture until D-PROJ-2 ships) |
|
||||
| RESTRICT-SAT-1 | Onboard cache offline-only; no in-flight Service calls | NFT-SEC-02, NFT-SEC-05, **C11-ST-01** | Covered |
|
||||
| ADR-004 | Process isolation; C11 never airborne | **C11-ST-01**, **C11-ST-02** | Covered (R02 enforcement) |
|
||||
|
||||
---
|
||||
|
||||
## Component-Internal Tests
|
||||
|
||||
### C11-IT-01: TileDownloader fetch + sector-classified freshness gate + write to C6
|
||||
|
||||
**Summary**: given a Derkachi-area request, `TileDownloader.fetch` retrieves tiles from the real `satellite-provider` (or fixture in tests), enforces the per-sector freshness gate, and writes accepted tiles into C6 with byte-identical filesystem layout.
|
||||
|
||||
**Traces to**: AC-8.1, AC-8.2, AC-8.3, AC-NEW-6
|
||||
|
||||
**Description**: configure the fetch job with the Derkachi bbox + zoom range + sector classification (active_conflict + stable_rear mix); run `fetch`; assert (a) all returned tiles within the bbox land in C6, (b) tiles with `produced_at` older than the per-sector threshold are downgrade-flagged or rejected, (c) the `DownloadBatchReport` reports counts that sum to the request size.
|
||||
|
||||
**Input data**: scripted fetch request + the real `satellite-provider` (or its test Docker fixture under `tests/fixtures/satellite-provider/`; this is the REAL service's existing GET surface, not the mock).
|
||||
|
||||
**Expected result**: tiles in C6 match request scope; freshness flags applied per sector.
|
||||
|
||||
**Max execution time**: 4 min on Tier-1 (network-dependent).
|
||||
|
||||
---
|
||||
|
||||
### C11-IT-02: freshness rejection counts surface in DownloadBatchReport
|
||||
|
||||
**Summary**: when the source has stale tiles, `DownloadBatchReport.stale_rejected` is non-zero and matches the count rejected at the C6 boundary.
|
||||
|
||||
**Traces to**: AC-NEW-6 (operator visibility)
|
||||
|
||||
**Description**: run a fetch that hits a known-stale tile range; assert (a) `stale_rejected > 0`, (b) the value equals C6's freshness-rejection count for that batch.
|
||||
|
||||
**Input data**: a synthetic `satellite-provider` response with stale tiles.
|
||||
|
||||
**Expected result**: counts match.
|
||||
|
||||
**Max execution time**: 60 s.
|
||||
|
||||
---
|
||||
|
||||
### C11-IT-03: TileUploader posts mid-flight tiles + signs payload
|
||||
|
||||
**Summary**: `TileUploader.upload_pending` reads mid-flight tiles from C6's pending-upload set, packages them per the D-PROJ-2 POST contract sketch, signs each payload with the per-flight key, and posts to the configured `/api/satellite/tiles/ingest` endpoint.
|
||||
|
||||
**Traces to**: AC-8.4, D-PROJ-2 contract
|
||||
|
||||
**Description**: stage C6 with 50 mid-flight tiles flagged pending-upload; bring up the e2e-test `mock-suite-sat-service` fixture (under `tests/fixtures/mock-suite-sat-service/`); call `upload_pending`; assert (a) all 50 tiles POSTed, (b) each payload signature verifies against the test public key, (c) on 202 Accepted, the C6 row is marked uploaded, (d) the fixture's request log shows all 50 tiles in arrival.
|
||||
|
||||
**Input data**: scripted C6 + e2e-test mock fixture.
|
||||
|
||||
**Expected result**: all 50 uploaded + acknowledged + marked.
|
||||
|
||||
**Max execution time**: 5 min.
|
||||
|
||||
---
|
||||
|
||||
### C11-IT-04: TileUploader gates on `flight_state == ON_GROUND`
|
||||
|
||||
**Summary**: `TileUploader.upload_pending` refuses to run if `FlightStateSignal != ON_GROUND` (defense-in-depth atop ADR-004 process isolation).
|
||||
|
||||
**Traces to**: AC-8.4 (defensive — ADR-004's secondary guard)
|
||||
|
||||
**Description**: call `upload_pending` with `FlightStateSignal == IN_FLIGHT`; assert `UploadGateBlockedError`. Same with `UNKNOWN`. Set `ON_GROUND` and assert upload proceeds.
|
||||
|
||||
**Input data**: scripted FlightStateSignal source.
|
||||
|
||||
**Expected result**: upload blocked except in `ON_GROUND`.
|
||||
|
||||
**Max execution time**: 30 s.
|
||||
|
||||
---
|
||||
|
||||
### C11-IT-05: idempotent uploads on retry
|
||||
|
||||
**Summary**: re-running `upload_pending` after a partial-success batch only POSTs the tiles that weren't acknowledged before.
|
||||
|
||||
**Traces to**: D-PROJ-2 contract resilience
|
||||
|
||||
**Description**: stage 50 pending-upload tiles; call `upload_pending` with the mock configured to return 202 for first 30, 5xx for last 20; assert C6 marks 30 as uploaded. Reset mock to 202 for all; call `upload_pending` again; assert only the remaining 20 are POSTed and the first 30 are NOT re-sent.
|
||||
|
||||
**Input data**: scripted with controlled mock failure profile.
|
||||
|
||||
**Expected result**: per assertion above.
|
||||
|
||||
**Max execution time**: 60 s.
|
||||
|
||||
---
|
||||
|
||||
## Performance Tests
|
||||
|
||||
### C11-PT-01: download throughput
|
||||
|
||||
**Traces to**: operator-tooling SLO (AC-8.3 supports this).
|
||||
|
||||
**Load scenario**: 10 GB Derkachi area, parallel fetch.
|
||||
|
||||
**Expected results**:
|
||||
|
||||
| Metric | Target | Failure Threshold |
|
||||
|--------|--------|-------------------|
|
||||
| Throughput | ≥ 50 MB/s on a 1 Gbps link | < 20 MB/s |
|
||||
| `DownloadBatchReport` produced | yes | no report = test failure |
|
||||
|
||||
---
|
||||
|
||||
### C11-PT-02: upload throughput
|
||||
|
||||
**Traces to**: post-landing operator UX (AC-8.4 + D-PROJ-2 timing assumption).
|
||||
|
||||
**Load scenario**: 1000 mid-flight tiles, sequential POST + sign.
|
||||
|
||||
**Expected results**:
|
||||
|
||||
| Metric | Target | Failure Threshold |
|
||||
|--------|--------|-------------------|
|
||||
| Throughput | ≥ 20 tile/s with signing | < 10 tile/s |
|
||||
|
||||
---
|
||||
|
||||
## Security Tests
|
||||
|
||||
### C11-ST-01: airborne process cannot import `c11_tilemanager`
|
||||
|
||||
**Summary**: per ADR-004 R02 enforcement, the airborne `production-binary` artifact has no path to import the C11 module.
|
||||
|
||||
**Traces to**: ADR-004, R02
|
||||
|
||||
**Test procedure**:
|
||||
1. Build the airborne `production-binary`.
|
||||
2. Inside a sandbox running the artifact, attempt `import c11_tilemanager` (and any submodule).
|
||||
3. Assert `ModuleNotFoundError` for every variant.
|
||||
4. Run the `runtime_root.py` self-check; assert it does NOT panic (because `find_spec` returns `None`).
|
||||
|
||||
**Pass criteria**: import fails everywhere; self-check passes silently.
|
||||
**Fail criteria**: any successful import.
|
||||
|
||||
---
|
||||
|
||||
### C11-ST-02: NFT-SEC-02 network-egress test
|
||||
|
||||
**Summary**: the airborne process running in a no-route-to-`satellite-provider` network namespace cannot reach `satellite-provider` over TCP.
|
||||
|
||||
**Traces to**: ADR-004 R02 enforcement; covers `RESTRICT-SAT-1`.
|
||||
|
||||
**Test procedure**: as documented in `tests/security-tests.md` NFT-SEC-02. Listed here for traceability.
|
||||
|
||||
**Pass criteria**: zero outbound connection attempts to `satellite-provider`'s host:port from the airborne process during a 10-min replay.
|
||||
**Fail criteria**: any attempt.
|
||||
|
||||
---
|
||||
|
||||
### C11-ST-03: per-flight signing key zeroised after upload completes
|
||||
|
||||
**Summary**: after `upload_pending` completes (success or final failure), the per-flight key is zeroised in memory.
|
||||
|
||||
**Traces to**: D-C8-9 = (d) (operator-side analogue)
|
||||
|
||||
**Test procedure**:
|
||||
1. Run an upload.
|
||||
2. Capture the key buffer post-call via test harness.
|
||||
3. Assert the buffer is zero-filled.
|
||||
|
||||
**Pass criteria**: zero-filled.
|
||||
**Fail criteria**: any non-zero residue.
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Tests
|
||||
|
||||
### C11-AT-01: operator runs F1 download + F10 upload via CLI
|
||||
|
||||
**Summary**: end-to-end operator flow exercises both interfaces via the C12-driven CLI.
|
||||
|
||||
**Traces to**: AC-8.3, AC-8.4
|
||||
|
||||
**Preconditions**:
|
||||
- Operator workstation with Docker + the operator-tooling tarball.
|
||||
- A `satellite-provider` (real or test fixture) reachable.
|
||||
|
||||
**Steps**:
|
||||
|
||||
| Step | Action | Expected Result |
|
||||
|------|--------|-----------------|
|
||||
| 1 | `operator-tool download --area derkachi.geojson --since 2026-01` | `DownloadBatchReport` printed; tiles in C6 |
|
||||
| 2 | `operator-tool build-cache` | C10 builds engines + descriptors + Manifest |
|
||||
| 3 | (simulate flight) | (covered by other tests) |
|
||||
| 4 | `operator-tool upload-pending` | Pending-upload tiles POSTed; report printed |
|
||||
|
||||
---
|
||||
|
||||
## Test Data Management
|
||||
|
||||
| Data Set | Source | Size |
|
||||
|----------|--------|------|
|
||||
| Real `satellite-provider` Docker fixture (download) | upstream parent-suite Docker | image |
|
||||
| e2e-test `mock-suite-sat-service` fixture (upload) | `tests/fixtures/mock-suite-sat-service/` | <50 MB image |
|
||||
| Scripted Derkachi bbox + sector classification | scripted | <1 MB |
|
||||
|
||||
**Setup**: bring up the appropriate fixture per test (real for download; e2e-test mock for upload until D-PROJ-2 ships).
|
||||
**Teardown**: stop fixture containers; clean per-test C6.
|
||||
**Data isolation**: per-test C6 + per-test fixture instance.
|
||||
Reference in New Issue
Block a user