up
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

This commit is contained in:
StellaOps Bot
2025-12-11 08:20:15 +02:00
parent b8b493913a
commit ce1f282ce0
65 changed files with 5481 additions and 1803 deletions

View File

@@ -1,43 +1,26 @@
# AirGap Controller Scaffold (Draft) PREP-AIRGAP-CTL-56-001/002/57-001/57-002/58-001
# 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
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 store by default; Mongo store activates when `AirGap:Mongo:ConnectionString` is set.
- Tests: Mongo2Go-backed store tests live under `tests/AirGap`; see `tests/AirGap/README.md` for OpenSSL shim note.
- 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
- Persistent document `airgap_state` (Mongo):
- `id` (const `singleton`), `tenant_id`, `sealed` (bool), `policy_hash`, `time_anchor` (nullable), `last_transition_at` (UTC), `staleness_budget_seconds` (int?, optional per bundle), `notes`.
- Index on `{tenant_id}`; unique on `singleton` within tenant.
- 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.
### Mongo wiring (optin)
- Config section:
```json
"AirGap": {
"Mongo": {
"ConnectionString": "mongodb://localhost:27017",
"Database": "stellaops_airgap",
"Collection": "airgap_state"
}
}
```
- The DI extension `AddAirGapController` chooses Mongo when `ConnectionString` is present; otherwise falls back to in-memory.
- Collection index: unique on `{tenant_id, id}` to enforce singleton per tenant.
- 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:
- `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`.
- `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)