[AZ-317] [AZ-318] C11 upload-side: flight-state gate + per-flight key

Batch 38 (cycle 1) lands the two upload-side prerequisites the
upcoming AZ-319 TileUploader needs to authenticate per-flight
sessions against the parent suite's D-PROJ-2 ingest contract.

AZ-317 FlightStateGate:
- confirm_on_ground() defence-in-depth gate atop ADR-004 process
  isolation; fail-closed for UNKNOWN, IN_FLIGHT, TAKING_OFF,
  LANDING, and source-failure (mapped to UNKNOWN with original
  exception preserved on __cause__).
- ERROR log on refusal, INFO log on pass, single source call per
  invocation (no polling, no retry).

AZ-318 PerFlightKeyManager:
- Per-flight ephemeral Ed25519 keypair via the project-pinned
  cryptography library; sign(payload) -> 64-byte Ed25519 signature.
- Best-effort zeroisation of a project-controlled bytearray mirror
  on end_session; OpenSSL-side buffer freed via dropped reference.
- __del__ safety net with WARN log if end_session was missed.
- start_session emits FDR kind=c11.upload.session.key.public so the
  safety officer can correlate flights with key fingerprints.
- record_signature_rejection emits FDR + ERROR log on parent-suite
  ingest rejection (security-critical, never silently dropped).

Shared C11 plumbing:
- TileManagerError parent + 3 subclasses (FlightStateNotOnGroundError,
  SessionNotActiveError, SignatureRejectedError envelope).
- FlightStateSignal (str, Enum) and PublicKeyFingerprint DTOs.
- FlightStateSource Protocol on c11_tile_manager.interface.
- runtime_root.c11_factory factories for both new services.
- Two new FDR kinds registered in fdr_client.records central
  KNOWN_PAYLOAD_KEYS; AZ-272 schema-roundtrip fixtures added in
  lockstep so the central test stays green.

Tests: 26 new + 2 fixture additions; full suite 1384 passed, 80
skipped (documented Docker / Tier-2 / CUDA gates).

Code review: PASS_WITH_WARNINGS — 2 Low findings documented in
_docs/03_implementation/reviews/batch_38_review.md (dev-host vs
operator-workstation perf bound; spec text named StrEnum but
project pins Python 3.10).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-13 05:48:52 +03:00
parent ca0430a44d
commit cde237e236
16 changed files with 1936 additions and 8 deletions
@@ -0,0 +1,78 @@
"""C11 TileManager composition-root factories (AZ-317, AZ-318).
Wires the upload-side services that have landed:
* :func:`build_flight_state_gate` (AZ-317) — adapts an injected
``FlightStateSource`` (typically an E-C8 FC adapter wrapper) into
the C11 ``FlightStateGate``.
* :func:`build_per_flight_key_manager` (AZ-318) — wires the AZ-273
:class:`FdrClient` and the project ``Clock`` strategy into the
ephemeral signing-key manager.
Composition root is the ONLY layer permitted to import from
``components.c11_tile_manager`` (per ``module-layout.md`` Rule 9 +
the AZ-270 lint).
"""
from __future__ import annotations
from typing import TYPE_CHECKING
from gps_denied_onboard.components.c11_tile_manager import (
FlightStateGate,
FlightStateSource,
PerFlightKeyManager,
)
from gps_denied_onboard.fdr_client import FdrClient, make_fdr_client
from gps_denied_onboard.logging import get_logger
if TYPE_CHECKING:
from gps_denied_onboard.clock import Clock
from gps_denied_onboard.config.schema import Config
__all__ = [
"build_flight_state_gate",
"build_per_flight_key_manager",
]
_C11_GATE_LOGGER = "c11_tile_manager.flight_state_gate"
_C11_SIGNING_LOGGER = "c11_tile_manager.signing_key"
_C11_SIGNING_PRODUCER_ID = "c11_tile_manager.signing_key"
def build_flight_state_gate(*, source: FlightStateSource) -> FlightStateGate:
"""Construct a wired :class:`FlightStateGate` (AZ-317).
The ``source`` argument is the consumer-side cut over E-C8's FC
adapter; the composition root supplies a concrete adapter wrapping
the actual C8 instance once E-C8 ships. Until then operator
tooling tests inject a fake source that returns a fixed signal.
"""
logger = get_logger(_C11_GATE_LOGGER)
return FlightStateGate(source=source, logger=logger)
def build_per_flight_key_manager(
config: Config,
*,
clock: Clock,
fdr_client: FdrClient | None = None,
) -> PerFlightKeyManager:
"""Construct a wired :class:`PerFlightKeyManager` (AZ-318).
``fdr_client`` defaults to the project's cached singleton via
:func:`make_fdr_client` so the operator binary's composition root
does not need to thread it through every factory. Tests override
by supplying :class:`FakeFdrSink` directly.
"""
if fdr_client is None:
fdr_client = make_fdr_client(_C11_SIGNING_PRODUCER_ID, config)
logger = get_logger(_C11_SIGNING_LOGGER)
return PerFlightKeyManager(
fdr_client=fdr_client,
logger=logger,
clock=clock,
)