Add new features and tests for AirGap and Time modules
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Introduced `SbomService` tasks documentation.
- Updated `StellaOps.sln` to include new projects: `StellaOps.AirGap.Time` and `StellaOps.AirGap.Importer`.
- Added unit tests for `BundleImportPlanner`, `DsseVerifier`, `ImportValidator`, and other components in the `StellaOps.AirGap.Importer.Tests` namespace.
- Implemented `InMemoryBundleRepositories` for testing bundle catalog and item repositories.
- Created `MerkleRootCalculator`, `RootRotationPolicy`, and `TufMetadataValidator` tests.
- Developed `StalenessCalculator` and `TimeAnchorLoader` tests in the `StellaOps.AirGap.Time.Tests` namespace.
- Added `fetch-sbomservice-deps.sh` script for offline dependency fetching.
This commit is contained in:
master
2025-11-20 23:29:54 +02:00
parent 65b1599229
commit 79b8e53441
182 changed files with 6660 additions and 1242 deletions

View File

@@ -0,0 +1,38 @@
# Bundle Catalog & Items Repositories (prep for AIRGAP-IMP-57-001)
## Scope
- Deterministic storage for offline bundle metadata with tenant isolation (RLS) and stable ordering.
- Ready for Mongo-backed implementation while providing in-memory deterministic reference behavior.
## Schema (logical)
- `bundle_catalog`:
- `tenant_id` (string, PK part, RLS partition)
- `bundle_id` (string, PK part)
- `digest` (hex string)
- `imported_at_utc` (datetime)
- `content_paths` (array of strings, sorted ordinal)
- `bundle_items`:
- `tenant_id` (string, PK part, RLS partition)
- `bundle_id` (string, PK part)
- `path` (string, PK part)
- `digest` (hex string)
- `size_bytes` (long)
## Implementation delivered (2025-11-20)
- In-memory repositories enforcing tenant isolation and deterministic ordering:
- `InMemoryBundleCatalogRepository` (upsert + list ordered by `bundle_id`).
- `InMemoryBundleItemRepository` (bulk upsert + list ordered by `path`).
- Models: `BundleCatalogEntry`, `BundleItem`.
- Tests cover upsert overwrite semantics, tenant isolation, and deterministic ordering (`tests/AirGap/StellaOps.AirGap.Importer.Tests/InMemoryBundleRepositoriesTests.cs`).
## Migration notes (for Mongo/SQL backends)
- Create compound unique indexes on (`tenant_id`, `bundle_id`) for catalog; (`tenant_id`, `bundle_id`, `path`) for items.
- Enforce RLS by always scoping queries to `tenant_id` and validating it at repository boundary (as done in in-memory reference impl).
- Keep paths lowercased or use ordinal comparisons to avoid locale drift; sort before persistence to preserve determinism.
## Next steps
- Implement Mongo-backed repositories mirroring the deterministic behavior and indexes above.
- Wire repositories into importer service/CLI once storage provider is selected.
## Owners
- AirGap Importer Guild.

View File

@@ -0,0 +1,45 @@
# 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`.
## 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 cache with monotonic timestamp to avoid stale reads; cache invalidated on transitions.
## 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:{seconds_remaining?, budget_seconds?}, 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`; gauges `airgap_time_anchor_drift_seconds`, `airgap_staleness_budget_seconds`.
- Timeline events (Observability stream): `airgap.sealed`, `airgap.unsealed` with correlation_id.
## 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.

View File

@@ -0,0 +1,38 @@
# AirGap Importer Scaffold (prep for AIRGAP-IMP-56-001/56-002/58-002)
## Scope for prep
- Provide minimal project and test scaffolds so downstream implementation can wire DSSE, TUF, Merkle validation, and audit logging without redoing structure.
- Capture trust-root inputs required (bundle path, signing keys, allowed algorithms, validity window).
## What landed (2025-11-20)
- New project: `src/AirGap/StellaOps.AirGap.Importer/StellaOps.AirGap.Importer.csproj` (net10.0, deterministic-only dependencies).
- Planning layer: `BundleImportPlanner` emits deterministic plan steps and early validation reasons (`bundle-path-required`, `trust-roots-required`, `invalid-trust-window`).
- Contracts: `TrustRootConfig` record carries root bundle path, trusted key fingerprints, allowed algorithms, and optional validity window.
- Validation shape: `BundleValidationResult` centralises success/failure reasons for replay/capture.
- Tests: `tests/AirGap/StellaOps.AirGap.Importer.Tests` validate planner behavior without external feeds.
## Updates (2025-11-20)
- Added DSSE verifier (RSA-PSS/SHA256) with PAE encoding + trusted key fingerprint checks.
- Added TUF metadata validator (root/snapshot/timestamp) with hash consistency guard.
- Added deterministic Merkle root calculator for bundle object staging.
- Expanded tests for DSSE, TUF, Merkle helpers.
- Added trust store + root rotation policy (dual approval) and import validator that coordinates DSSE/TUF/Merkle/rotation checks.
## Next implementation hooks
- Replace placeholder plan with actual DSSE + TUF verifiers; keep step ordering stable.
- Feed trust roots from sealed-mode config and Evidence Locker bundles (once available) before allowing imports.
- Record audit trail for each plan step (success/failure) and a Merkle root of staged content.
## Determinism/air-gap posture
- No network dependencies; only BCL used.
- Tests use cached local NuGet feed (`local-nugets/`).
- Plan steps are ordered list; do not reorder without bumping downstream replay expectations.
## How to consume
```bash
# run tests offline once feed is hydrated
DOTNET_NOLOGO=1 dotnet test tests/AirGap/StellaOps.AirGap.Importer.Tests/StellaOps.AirGap.Importer.Tests.csproj --no-build
```
## Owners
- AirGap Importer Guild / Security Guild (per sprint 0510).

View File

@@ -0,0 +1,32 @@
# AirGap Sealed-Mode Startup Diagnostics (prep for AIRGAP-CTL-57-001/57-002)
## Goal
Prevent services from running when sealed-mode requirements are unmet and emit auditable diagnostics + telemetry.
## Pre-flight checks
1) `airgap_state` indicates `sealed=true`.
2) Egress allowlist configured (non-empty or explicitly `[]`).
3) Trust root bundle + TUF metadata present and unexpired.
4) Time anchor available (see `TimeAnchor` schema) and staleness budget not exceeded.
5) Pending root rotations either applied or flagged with approver IDs.
## On failure
- Abort host startup with structured error code: `AIRGAP_STARTUP_MISSING_<ITEM>`.
- Emit structured log fields: `airgap.startup.check`, `status=failure`, `reason`, `bundlePath`, `trustRootVersion`, `timeAnchorDigest`.
- Increment counter `airgap_startup_blocked_total{reason}` and gauge `airgap_time_anchor_age_seconds` if anchor missing/stale.
## Telemetry hooks
- Trace event `airgap.startup.validation` with attributes: `sealed`, `allowlist.count`, `trust_roots.count`, `time_anchor.age_seconds`, `rotation.pending`.
- Timeline events (for 57-002): `airgap.sealed` and `airgap.unsealed` include startup validation results and pending rotations.
## Integration points
- Controller: run checks during `IHostApplicationLifetime.ApplicationStarted` before exposing endpoints.
- Importer: reuse `ImportValidator` to ensure bundles + trust rotation are valid before proceeding.
- Time component: provide anchor + staleness calculations to the controller checks.
## Artefacts
- This document (deterministic guardrails for startup diagnostics).
- Code references: `src/AirGap/StellaOps.AirGap.Importer/Validation/*` for trust + bundle validation primitives; `src/AirGap/StellaOps.AirGap.Time/*` for anchors.
## Owners
- AirGap Controller Guild · Observability Guild.

View File

@@ -59,6 +59,7 @@ AirGap Time calculates drift = `now(monotonic) - anchor.issued_at` and exposes:
- Ensure deterministic JSON serialization (UTC ISO-8601 timestamps, sorted keys).
- Test vectors located under `src/AirGap/StellaOps.AirGap.Time/fixtures/`.
- For offline testing, simulate monotonic clock via `ITestClock` to avoid system clock drift in CI.
- Staleness calculations use `StalenessCalculator` + `StalenessBudget`/`StalenessEvaluation` (see `src/AirGap/StellaOps.AirGap.Time/Services` and `.Models`); warning/breach thresholds must be non-negative and warning ≤ breach.
## 7. References

View File

@@ -0,0 +1,35 @@
# AirGap Time Anchor Scaffold (prep for AIRGAP-TIME-57-001)
## Scope for prep
- Provide a deterministic parsing surface for signed time tokens (Roughtime, RFC3161) so staleness calculations and telemetry wiring can start without full crypto yet.
## What landed (2025-11-20)
- New project: `src/AirGap/StellaOps.AirGap.Time/StellaOps.AirGap.Time.csproj` (net10.0), BCL-only.
- Model: `TimeAnchor` canonical record (anchor time, source, format, signature fingerprint placeholder, token digest).
- Parser: `TimeTokenParser` with deterministic SHA-256 digest derivation and structured success/failure reasons.
- Result envelope: `TimeAnchorValidationResult` and `TimeTokenFormat` enum.
- Tests: `tests/AirGap/StellaOps.AirGap.Time.Tests` cover empty-token failure and digest production for Roughtime tokens.
## Updates (2025-11-20)
- Added staleness calculator (`StalenessCalculator`) and budgets/evaluation models to derive warning/breach states deterministically.
- Added `TimeAnchorLoader` to ingest hex-encoded tokens from fixtures; sample tokens placed under `src/AirGap/StellaOps.AirGap.Time/fixtures/`.
- Added `TimeStatusService` + `InMemoryTimeAnchorStore` for per-tenant anchor/budget status + staleness; tests in `TimeStatusServiceTests`.
- Added verification pipeline (`TimeVerificationService`) with stub Roughtime/RFC3161 verifiers requiring trust roots; loader now verifies using trust roots.
- Added API surface `/api/v1/time/status` (plus POST `/api/v1/time/anchor`) via `TimeStatusController` and web host wiring.
## Next implementation hooks
- Plug real Roughtime and RFC3161 decoders, verifying against trust roots supplied via sealed-mode config.
- Persist `TimeAnchor` rows under controller/importer once schema is final; emit telemetry counters/alerts.
- Replace placeholder signature fingerprint with actual signer fingerprint post-verification.
## Determinism/air-gap posture
- Parser avoids wall-clock; anchor time derived deterministically from token digest until real parser is wired.
- No network calls; uses cached NuGet (`local-nugets/`) for tests.
## How to consume
```bash
DOTNET_NOLOGO=1 dotnet test tests/AirGap/StellaOps.AirGap.Time.Tests/StellaOps.AirGap.Time.Tests.csproj --no-build
```
## Owners
- AirGap Time Guild (per sprint 0510).

View File

@@ -0,0 +1,21 @@
# Time Anchor Verification Gap (AIRGAP-TIME-57-001 follow-up)
## Status (2025-11-20)
- Parser: stubbed for Roughtime/RFC3161 with deterministic digest + derived anchor time.
- Staleness: calculator + budgets landed; loader accepts hex fixtures.
- Verification: pipeline exists (`TimeVerificationService`) with stub verifiers; still needs real crypto using guild-provided trust roots.
## Whats missing
- Roughtime parser: parse signed responses, extract `timestamp`, `radius`, `verifier` public key; verify signature.
- RFC3161 parser: decode ASN.1 TimeStampToken, verify signer chain against provided trust roots, extract nonce/ts.
- Trust roots: final format (JWK vs PEM) and key IDs to align with `TrustRootConfig`/Time service.
## Proposed plan
1) Receive finalized token format + trust-root bundle from Time Guild.
2) Implement format-specific verifiers with validating tests using provided fixtures.
3) Expose `/api/v1/time/status` returning anchor metadata + staleness; wire telemetry counters/alerts per sealed diagnostics doc.
## Owners
- AirGap Time Guild (format decision + trust roots)
- AirGap Importer Guild (bundle delivery of anchors)
- Observability Guild (telemetry wiring)