- Implemented comprehensive tests for verdict artifact generation to ensure deterministic outputs across various scenarios, including identical inputs, parallel execution, and change ordering. - Created helper methods for generating sample verdict inputs and computing canonical hashes. - Added tests to validate the stability of canonical hashes, proof spine ordering, and summary statistics. - Introduced a new PowerShell script to update SHA256 sums for files, ensuring accurate hash generation and file integrity checks.
101 lines
3.6 KiB
Markdown
101 lines
3.6 KiB
Markdown
# AirGap Controller
|
|
|
|
The AirGap Controller is the tenant-scoped state keeper for sealed-mode operation. It records whether an installation is sealed, what policy hash is active, which time anchor is in force, and what staleness budgets apply.
|
|
|
|
For workflow context, start at `docs/airgap/overview.md` and `docs/airgap/airgap-mode.md`.
|
|
|
|
## Responsibilities
|
|
|
|
- Maintain the current AirGap state per tenant (sealed/unsealed, policy hash, time anchor, staleness budgets).
|
|
- Provide a deterministic, auditable status snapshot for operators and automation.
|
|
- Enforce sealed/unsealed transitions via Authority scopes.
|
|
- Emit telemetry signals suitable for dashboards and forensics timelines.
|
|
|
|
Non-goals:
|
|
|
|
- Bundle signature validation and import staging (owned by the importer; see `docs/airgap/importer.md`).
|
|
- Cryptographic signing (Signer/Attestor).
|
|
|
|
## API
|
|
|
|
Base route group: `/system/airgap` (requires authorization).
|
|
|
|
### `GET /system/airgap/status`
|
|
|
|
Required scope: `airgap:status:read`
|
|
|
|
Response: `AirGapStatusResponse` (current state + staleness evaluation).
|
|
|
|
Notes:
|
|
|
|
- Tenant routing uses `x-tenant-id` (defaults to `default` if absent).
|
|
- `driftSeconds` and `secondsRemaining` are derived from the active time anchor and staleness budget evaluation.
|
|
- `contentStaleness` contains per-category staleness evaluations (clients should treat keys as case-insensitive).
|
|
|
|
### `POST /system/airgap/seal`
|
|
|
|
Required scope: `airgap:seal`
|
|
|
|
Body: `SealRequest`
|
|
|
|
- `policyHash` (required): binds the sealed state to a specific policy revision.
|
|
- `timeAnchor` (optional): time anchor record (from the AirGap Time service).
|
|
- `stalenessBudget` (optional): default staleness budget.
|
|
- `contentBudgets` (optional): per-category staleness budgets (e.g., `advisories`, `vex`, `scanner`).
|
|
|
|
Behavior:
|
|
|
|
- Rejects requests missing `policyHash` (`400 { \"error\": \"policy_hash_required\" }`).
|
|
- Records the sealed state and returns an updated status snapshot.
|
|
|
|
### `POST /system/airgap/unseal`
|
|
|
|
Required scope: `airgap:seal`
|
|
|
|
Behavior:
|
|
|
|
- Clears the sealed state and returns an updated status snapshot.
|
|
- Staleness is returned as `Unknown` after unseal (clients should treat this as "not applicable").
|
|
|
|
### `POST /system/airgap/verify`
|
|
|
|
Required scope: `airgap:verify`
|
|
|
|
Purpose: verify replay / bundle verification requests against the currently active AirGap state.
|
|
|
|
## State model (per tenant)
|
|
|
|
Canonical fields captured by the controller (see `src/AirGap/StellaOps.AirGap.Controller`):
|
|
|
|
- `tenantId`
|
|
- `sealed`
|
|
- `policyHash` (nullable)
|
|
- `timeAnchor` (`TimeAnchor`, may be `Unknown`)
|
|
- `stalenessBudget` (`StalenessBudget`)
|
|
- `contentBudgets` (`Dictionary<string, StalenessBudget>`)
|
|
- `driftBaselineSeconds` (baseline used to keep drift evaluation stable across transitions)
|
|
- `lastTransitionAt` (UTC)
|
|
|
|
Determinism requirements:
|
|
|
|
- Use UTC timestamps only.
|
|
- Use ordinal comparisons for keys and stable serialization settings for JSON responses.
|
|
- Never infer state from wall-clock behavior other than the injected `TimeProvider`.
|
|
|
|
## Telemetry
|
|
|
|
The controller emits:
|
|
|
|
- Structured logs: `airgap.status.read`, `airgap.sealed`, `airgap.unsealed`, `airgap.verify` (include `tenant_id`, `policy_hash`, and drift/staleness).
|
|
- Metrics: `airgap_seal_total`, `airgap_unseal_total`, `airgap_status_read_total`, and gauges for drift/budget/remaining seconds.
|
|
- Timeline events (optional): `airgap.sealed`, `airgap.unsealed`, `airgap.staleness.warning`, `airgap.staleness.breach`.
|
|
|
|
## References
|
|
|
|
- `docs/airgap/overview.md`
|
|
- `docs/airgap/sealed-startup-diagnostics.md`
|
|
- `docs/airgap/staleness-and-time.md`
|
|
- `docs/airgap/time-api.md`
|
|
- `docs/airgap/importer.md`
|
|
|