Files
git.stella-ops.org/docs/airgap/controller-scaffold.md
StellaOps Bot ce1f282ce0
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
up
2025-12-11 08:20:15 +02:00

3.9 KiB

AirGap Controller Scaffold (Draft) - PREP-AIRGAP-CTL-56-001/002/57-001/57-002/58-001

Status: Draft (2025-11-20) Owners: AirGap Controller Guild / Observability Guild / AirGap Time Guild / DevOps Guild Scope: Define the baseline project skeleton, APIs, telemetry, and staleness fields needed to unblock controller tasks 56-001 through 58-001.

1) Project layout

  • Project: src/AirGap/StellaOps.AirGap.Controller (net10.0, minimal API host).
  • Tests: tests/AirGap/StellaOps.AirGap.Controller.Tests with xunit + deterministic time provider.
  • Shared contracts: DTOs under Endpoints/Contracts, domain state under Domain/AirGapState.cs.
  • Persistence: in-memory state store only (no external DB dependency). Postgres-backed persistence will follow in a later sprint.
  • Tests: run entirely in-memory; no Mongo/OpenSSL shims required.

2) State model

  • In-memory state record per tenant: id (const singleton), tenant_id, sealed (bool), policy_hash, time_anchor (nullable), last_transition_at (UTC), staleness_budget_seconds (int?, optional per bundle), notes.
  • In-memory cache with monotonic timestamp to avoid stale reads; cache invalidated on transitions.
  • Persistence roadmap: swap in a Postgres-backed store with equivalent singleton and tenant scoping; Mongo wiring has been removed.

3) Endpoints (56-002 baseline)

  • GET /system/airgap/status -> returns current state + staleness summary:
    • {sealed, policy_hash, time_anchor:{source, anchored_at, drift_seconds}, staleness:{age_seconds, warning_seconds, breach_seconds, seconds_remaining}, last_transition_at}.
  • POST /system/airgap/seal -> body {policy_hash, time_anchor?, staleness_budget_seconds?}; requires Authority scopes airgap:seal + effective:write.
  • POST /system/airgap/unseal -> requires airgap:seal.
  • Validation: reject seal if missing policy_hash or time anchor when platform requires sealed mode.

4) Telemetry (57-002)

  • Structured logs: airgap.sealed, airgap.unsealed, airgap.status.read with tenant_id, policy_hash, time_anchor_source, drift_seconds.
  • Metrics (Prometheus/OpenTelemetry): counters airgap_seal_total, airgap_unseal_total, airgap_startup_blocked_total; gauges airgap_time_anchor_age_seconds, airgap_staleness_budget_seconds.
  • Timeline events (Observability stream): airgap.sealed, airgap.unsealed with correlation_id.

Startup diagnostics wiring (57-001)

  • Config section AirGap:Startup now drives sealed-mode startup validation:
    • TenantId (default default).
    • EgressAllowlist (array; required when sealed).
    • Trust:RootJsonPath, Trust:SnapshotJsonPath, Trust:TimestampJsonPath (all required when sealed; parsed via TUF validator).
    • Rotation:ActiveKeys, Rotation:PendingKeys, Rotation:ApproverIds (base64-encoded keys; dual approval enforced when pending keys exist).
  • Failures raise sealed-startup-blocked:<reason> and increment airgap_startup_blocked_total{reason}.

5) Staleness & time (58-001)

  • Staleness computation: drift_seconds = now_utc - time_anchor.anchored_at; seconds_remaining = max(0, staleness_budget_seconds - drift_seconds).
  • Time anchors accept Roughtime or RFC3161 token parsed via AirGap Time component (imported service).
  • Status response includes drift and remaining budget; sealed mode refuses to run if budget exceeded.

6) Determinism & offline rules

  • No external network calls; time source injected IClock seeded in tests.
  • All timestamps RFC3339 UTC; responses sorted properties (serializer config).

7) Open decisions

  • Final scopes list (Authority) for status read vs seal/unseal.
  • Whether to require dual authorization for seal (two-man rule) in sealed environments.
  • Retention/rotation policy for airgap_state audit trail (append-only vs mutation).

8) Handoff

This document satisfies PREP-AIRGAP-CTL-56-001 through 58-001. Update once Authority scopes and time-anchor token format are finalized; then promote to v1 schema doc and wire tests accordingly.