Sealed Install Enforcement Contract
Currency check 2026-10-07: owner paths/source placement verified against
3238bd511a37e199ae99d4f17be2f13eabec8dd7. The supported boundary isPlatform posture custody and OfflineKit carrier custody(src/Platform/StellaOps.Platform.WebService/Endpoints/EnvironmentStateEndpoints.cs). Re-verify the host mount and owning endpoint extension together. This is source verification; deployment and broader audit coverage are separate evidence. Other dated findings retain their stated dates. Re-verify:rg -n "MapGroup|Map.*Endpoints|AddHostedService" src/Platform/StellaOps.Platform.WebService/Endpoints/EnvironmentStateEndpoints.cs, then inspect the endpoint extension or library pointer cited at the operation.
Supported implementation
The proposed TaskRunner sealed_install flag and pre-execution enforcer were never shipped as written. The retained design is unsupported. Current posture, egress and import behavior below does not implement that pack flag.
Posture is held by Platform, exchange custody by OfflineKit, and imported content by the service that owns the domain. The Controller/Time predecessor hosts, their HTTP DTOs and their telemetry meters are withdrawn source. There is no replacement standalone time service to deploy.
| Concern | Supported surface and owner |
|---|---|
| Posture custody | Platform GET/PUT /api/v1/platform/environment-state/{stateClass}/{scope}; classes airgap-seal and time-anchor, default CLI scope installation |
| Seal/unseal/status | stella airgap seal, stella airgap unseal, stella airgap status declare/read Platform state with no local marker fallback |
| Verified time declaration | stella airgap time-anchor declare --token anchor.tsr --trust-roots tsa-chain.pem; verification precedes declaration |
| Time readback | stella airgap time-anchor status --trust-roots tsa-chain.pem re-verifies the stored proof against supplied roots |
| Carrier import/validation | OfflineKit POST /api/offlinekit/v1/import, POST /api/offlinekit/v1/validate |
| Custody and part state | OfflineKit GET /api/offlinekit/v1/status, GET /api/offlinekit/v1/manifest |
| Re-offer a failed/superseded part | POST /api/offlinekit/v1/imports/{importId}/parts/{domain}/activate; activated is terminal |
Platform stores opaque JSON and enforces class custody, not air-gap semantics. Its read policy accepts envstate:read or the air-gap status grant; declaring airgap-seal needs envstate:airgap-seal:write (the recorded airgap:seal grant is accepted by that custody policy), and time-anchor needs envstate:time-anchor:write. OfflineKit import/validate use airgap:import; custody status/manifest use airgap:status:read. Check the current Authority and Platform policy registrations before assigning grants.
AirGapSealInterpreter and AirGapTimeAnchorInterpreter in src/__Libraries/StellaOps.AirGap.Policy/StellaOps.AirGap.Policy/Posture/ distinguish Declared, NotDeclared and Unreadable. Missing/unreadable state is not a measured sealed/unsealed result; an absent anchor is not fresh. Consumers read their environment-state replica so a Platform outage does not force a cross-service posture read.
RFC3161 verification is the library under src/OfflineKit/__Libraries/StellaOps.AirGap.Time.Verification/. The CLI writer checks the token signature and supplied trust chain without certificate downloads or revocation checking, and records revocationChecked: false. Roughtime remains an enum member but has no current verifier. Consumers re-verify stored proof with the public trust purpose timestamp-authority; a declared timestamp alone is not verification evidence.
For sealed import, OfflineKitImportPostureGate refuses a missing, unreadable or breached trusted time anchor with 409. Warning age admits with a warning. Unsealed/undeclared posture admits; an unreadable posture replica admits with a warning, as implemented. A verified carrier means custody, not activation: each part is offered to its registered owner. Unsupported parts report PART_ACTIVATOR_NOT_REGISTERED; owner activation can fail while custody remains verified.
AirGap:Egress and the in-process IEgressPolicy interpreter govern outbound calls. Sealing state is a declaration, not firewall proof. Apply and verify network controls using the Compose/host tooling in the current sealing guide. Egress policy is a sealed-mode gate, not an SSRF control.
Source pointers:
src/Platform/StellaOps.Platform.WebService/Endpoints/EnvironmentStateEndpoints.cssrc/CLI/StellaOps.Cli/Commands/CommandHandlers.AirGap.cssrc/CLI/StellaOps.Cli/Commands/CommandHandlers.AirGap.TimeAnchor.cssrc/OfflineKit/StellaOps.OfflineKit.WebService/Endpoints/OfflineKitEndpoints.cssrc/OfflineKit/StellaOps.OfflineKit.WebService/Imports/OfflineKitImportPostureGate.cs
Operator references
Historical TaskRunner sealed-install design and 2026-05-30 reconciliation (superseded 2026-09-14)
The remainder records the predecessor implementation or unlanded design at the dates stated in its text. All routes, host names, source paths, DTOs, metrics and examples in this section are historical comparison, including sentences that originally said “current” or “today”. They are not instructions for the consolidated estate. The supported section and owner source above supersede them. Do not rebuild or deploy a predecessor from these examples.
Status: SUPERSEDED — NOT IMPLEMENTED AS WRITTEN Version: 1.0.0 (historical) Last Updated: 2025-12-06 (last reconciled against source 2026-05-30) Owner: AirGap Controller Guild Originally Unblocked: TASKRUN-AIRGAP-57-001, TASKRUN-AIRGAP-58-001 (both in the now-deleted TaskRunner service)
[!WARNING] Reconciliation note (2026-05-30). This contract was authored against a
TaskRunnerservice that has since been deleted from the monorepo. There is nosrc/TaskRunner/directory, andStellaOps.Auth.Abstractions/StellaOpsScopes.cs(lines 755-758) records that thetaskrunner:*scopes were “REMOVED (service deleted, constants kept for DB/migration backward compat).” The archived sprintdocs-archive/implplan/SPRINT_0157_0001_0001_taskrunner_i.mdshows tasks TASKRUN-AIRGAP-57-001/58-001 were marked DONE insidesrc/TaskRunner/StellaOps.TaskRunner, but that code no longer ships.Concretely, none of the following exist anywhere in
src/: asealed_installpack-manifest flag, aSealedInstallEnforcerclass, aSealedRequirements/SealedInstallViolationtype, or the error codes / exit codes / env vars described below. The pseudo-code, JSON schemas, decision matrices, and CLI flows in this document are aspirational / historical and do not reflect shipped behaviour.What does ship today (see §8):
- AirGap Controller —
GET/POST /system/airgap/{status,seal,unseal,verify}(src/AirGap/StellaOps.AirGap.Controller), gated on the three catalogued scopesairgap:status:read/airgap:seal/airgap:import(/verifysharesairgap:status:read).- Policy Engine sealed-mode —
SealedModeService(src/Policy/StellaOps.Policy.Engine/AirGap/, contractCONTRACT-SEALED-MODE-004), the real fail-closed enforcement gated onIEgressPolicy.IsSealed.stella airgapCLI —import,seal,unseal,status,time-anchor,export-evidencesubcommands (registered insrc/Cli/StellaOps.Cli/Commands/CommandFactory.cs;AirGapCommandGroup.csis a non-wired legacy group nothing constructs from the command line). (Currency update 2026-09-02, SPRINT_20260722_025 OK-5:seal/unsealnow exist and declare posture in Platform’s environment-state custodian — the sentence previously here recording their absence is superseded. There is still nostella pack …group at all — deleted 2026-09-14, SPRINT_20260914_003 JEF-4.)The remainder of this document (§§1-7) is retained for historical context. Treat it as a DRAFT design that was never landed in its specified form; consult §8 for the implemented surface. For the authoritative, reconciled sealed-mode contract, see Sealed Mode (
CONTRACT-SEALED-MODE-004).
Overview
This contract was intended to define sealed-install enforcement semantics for StellaOps air-gapped deployments: when a pack or task declared sealed_install: true, a Task Runner would refuse to execute if the environment was not properly sealed.
[!NOTE] NOT IMPLEMENTED. No
sealed_installflag is honoured by any shipping service. The Task Runner that would have enforced it has been removed. See §8 for the sealed-mode enforcement that actually ships (Policy EngineSealedModeService+ AirGap Controller egress policy).
Architecture
┌─────────────────────────────────────────────────────────────────────────────┐
│ Sealed Install Enforcement Flow │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Task Pack │ │ Task Runner │ │ AirGap │ │
│ │ │────>│ │────>│ Controller │ │
│ │ sealed_ │ │ Enforcement │ │ │ │
│ │ install:true │ │ Check │ │ /status │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ Decision Matrix │ │
│ │ │ │
│ │ Pack: sealed Env: sealed │ │
│ │ ────────────── ──────────── │ │
│ │ true true → RUN │ │
│ │ true false → DENY │ │
│ │ false true → RUN │ │
│ │ false false → RUN │ │
│ └──────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
1. Pack Declaration (DRAFT — not implemented)
[!WARNING] The
sealed_installmanifest flag andsealed_requirementsblock below do not exist in any shipping pack manifest schema. A repo-wide search forsealed_install/SealedInstallinsrc/returns no matches. This section is a never-landed design.
1.1 Sealed Install Flag
Packs declare their sealed requirement in the pack manifest:
{
"pack_id": "compliance-scan-airgap",
"version": "1.0.0",
"name": "Air-Gap Compliance Scanner",
"sealed_install": true,
"sealed_requirements": {
"min_bundle_version": "2025.10.0",
"max_advisory_staleness_hours": 168,
"require_time_anchor": true,
"allowed_offline_duration_hours": 720
}
}
1.2 Sealed Requirements Schema
{
"type": "object",
"properties": {
"sealed_install": {
"type": "boolean",
"default": false,
"description": "If true, pack MUST run in sealed environment"
},
"sealed_requirements": {
"type": "object",
"properties": {
"min_bundle_version": {
"type": "string",
"description": "Minimum air-gap bundle version"
},
"max_advisory_staleness_hours": {
"type": "integer",
"minimum": 1,
"default": 168,
"description": "Maximum age of advisory data in hours"
},
"require_time_anchor": {
"type": "boolean",
"default": true,
"description": "Require valid time anchor"
},
"allowed_offline_duration_hours": {
"type": "integer",
"minimum": 1,
"default": 720,
"description": "Maximum allowed offline duration"
},
"require_signature_verification": {
"type": "boolean",
"default": true,
"description": "Require bundle signature verification"
}
}
}
}
}
2. Environment Detection (DRAFT — see §8 for the real API)
2.1 Sealed Mode Status API
[!WARNING] INCORRECT — the path, scope, and response shape below do not match the implementation. The real endpoint is
GET /system/airgap/status(not/api/v1/airgap/status), it requires theairgap:status:readscope, and it returnsAirGapStatusResponse— see §8.1 for the actual contract. None of the fieldsmode,sealed_at,sealed_by,bundle_version,bundle_digest,last_advisory_update,advisory_staleness_hours,egress_blocked, ornetwork_policyexist in the shipping response. Air-gap staleness is expressed in seconds against aStalenessBudget(Warning/Breach), not in “advisory staleness hours”, and is tracked per content kind viaContentStaleness.
The original (unimplemented) design had the Task Runner query the AirGap Controller as follows:
GET /api/v1/airgap/status # NOT IMPLEMENTED — real path is GET /system/airgap/status
Response (speculative shape — does not match AirGapStatusResponse):
{
"sealed": true,
"mode": "sealed",
"sealed_at": "2025-12-01T00:00:00Z",
"sealed_by": "ops-admin@company.com",
"bundle_version": "2025.10.0",
"bundle_digest": "sha256:abc123...",
"last_advisory_update": "2025-12-01T00:00:00Z",
"advisory_staleness_hours": 120,
"time_anchor": {
"timestamp": "2025-12-01T00:00:00Z",
"signature": "base64...",
"valid": true,
"expires_at": "2025-12-31T00:00:00Z"
},
"egress_blocked": true,
"network_policy": "deny-all"
}
2.2 Detection Heuristics
[!WARNING] NOT IMPLEMENTED. There is no heuristic sealed-mode detector. Sealed state is determined deterministically: the AirGap Controller persists explicit seal/unseal state per tenant (
AirGapState.Sealed), and the Policy Engine readsIEgressPolicy.IsSealed(true iffEgressPolicyMode.Sealed). There is no DNS/port-probing fallback, noAIRGAP_MODEenv var consumed by this path, no/etc/stellaops/sealedsentinel file, and no “0.7 heuristic score” anywhere insrc/.
The original design proposed the following fallback heuristics (none of which ship):
| Heuristic | Weight | Indicates |
|---|---|---|
| No external DNS resolution | High | Sealed |
| Blocked ports 80, 443 | High | Sealed |
| AIRGAP_MODE=sealed env var | High | Sealed |
| /etc/stellaops/sealed file exists | Medium | Sealed |
| No internet connectivity | Medium | Sealed |
| Local-only registry configured | Low | Sealed |
Combined heuristic score threshold: 0.7 to consider environment sealed.
3. Enforcement Logic (DRAFT — illustrative pseudo-code only)
[!WARNING] NOT IMPLEMENTED. The
SealedInstallEnforcer,EnforcementResult,SealedRequirements,SealedInstallViolation, andRequirementViolationtypes below do not exist insrc/. No service performs amin_bundle_version/max_advisory_staleness_hours/require_time_anchorpre-execution check against a pack flag. The closest shipping enforcement isSealedModeService.EnforceBundleImportAsync(src/Policy/StellaOps.Policy.Engine/AirGap/SealedModeService.cs), which gates bundle import (not pack execution) onIEgressPolicy.IsSealedand time-anchor staleness, returningSealedModeEnforcementResult(Allowed, Reason, Remediation). The pseudo-code below is retained only to convey the original intent.
3.1 Pre-Execution Check
// ILLUSTRATIVE / NOT IMPLEMENTED — no such type exists in src/
public sealed class SealedInstallEnforcer
{
public async Task<EnforcementResult> EnforceAsync(
TaskPack pack,
CancellationToken ct = default)
{
// If pack doesn't require sealed install, allow
if (!pack.SealedInstall)
{
return EnforcementResult.Allowed("Pack does not require sealed install");
}
// Get environment sealed status
var status = await _airgapController.GetStatusAsync(ct);
// Core check: environment must be sealed
if (!status.Sealed)
{
return EnforcementResult.Denied(
"SEALED_INSTALL_VIOLATION",
"Pack requires sealed environment but environment is not sealed",
new SealedInstallViolation
{
PackId = pack.PackId,
RequiredSealed = true,
ActualSealed = false,
Recommendation = "Activate sealed mode with: stella airgap seal"
});
}
// Check sealed requirements
if (pack.SealedRequirements != null)
{
var violations = ValidateRequirements(pack.SealedRequirements, status);
if (violations.Any())
{
return EnforcementResult.Denied(
"SEALED_REQUIREMENTS_VIOLATION",
"Sealed requirements not met",
violations);
}
}
return EnforcementResult.Allowed("Sealed install requirements satisfied");
}
private List<RequirementViolation> ValidateRequirements(
SealedRequirements requirements,
SealedModeStatus status)
{
var violations = new List<RequirementViolation>();
// Bundle version check
if (requirements.MinBundleVersion != null)
{
if (Version.Parse(status.BundleVersion) < Version.Parse(requirements.MinBundleVersion))
{
violations.Add(new RequirementViolation
{
Requirement = "min_bundle_version",
Expected = requirements.MinBundleVersion,
Actual = status.BundleVersion,
Message = $"Bundle version {status.BundleVersion} < required {requirements.MinBundleVersion}"
});
}
}
// Advisory staleness check
if (status.AdvisoryStalenessHours > requirements.MaxAdvisoryStalenessHours)
{
violations.Add(new RequirementViolation
{
Requirement = "max_advisory_staleness_hours",
Expected = requirements.MaxAdvisoryStalenessHours.ToString(),
Actual = status.AdvisoryStalenessHours.ToString(),
Message = $"Advisory data is {status.AdvisoryStalenessHours}h old, max allowed is {requirements.MaxAdvisoryStalenessHours}h"
});
}
// Time anchor check
if (requirements.RequireTimeAnchor && (status.TimeAnchor == null || !status.TimeAnchor.Valid))
{
violations.Add(new RequirementViolation
{
Requirement = "require_time_anchor",
Expected = "valid time anchor",
Actual = status.TimeAnchor?.Valid.ToString() ?? "missing",
Message = "Valid time anchor required but not present"
});
}
return violations;
}
}
3.2 Decision Matrix
Pack sealed_install | Environment Sealed | Bundle Valid | Advisories Fresh | Result |
|---|---|---|---|---|
true | true | true | true | ✅ RUN |
true | true | true | false | ⚠️ WARN + RUN (if within grace) |
true | true | false | * | ❌ DENY |
true | false | * | * | ❌ DENY |
false | true | * | * | ✅ RUN |
false | false | * | * | ✅ RUN |
3.3 Grace Period Handling
For advisory staleness, a grace period can be configured:
# etc/taskrunner.yaml
enforcement:
sealed_install:
staleness_grace_period_hours: 24
staleness_warning_threshold_hours: 120
deny_on_staleness: true # or false for warn-only
4. Refusal Semantics (DRAFT — codes below do not exist)
[!WARNING] NOT IMPLEMENTED. The error code
SEALED_INSTALL_VIOLATION(andSEALED_REQUIREMENTS_VIOLATION,BUNDLE_VERSION_VIOLATION,ADVISORY_STALENESS_VIOLATION,TIME_ANCHOR_VIOLATION,SIGNATURE_VERIFICATION_VIOLATION) and the CLI exit codes 40-44 below appear nowhere insrc/. The shipping sealed-mode error codes are theSealedModeErrorCodes.*constants used bySealedModeService(e.g. staleness-breach / staleness-warning); the AirGap Controllerverifyendpoint returns aVerifyResponse(Valid, Reason)rather than a coded error envelope.
4.1 Error Response
When enforcement denies execution (speculative shape — not emitted by any service):
{
"error": {
"code": "SEALED_INSTALL_VIOLATION",
"message": "Pack requires sealed environment but environment is not sealed",
"details": {
"pack_id": "compliance-scan-airgap",
"pack_version": "1.0.0",
"sealed_install_required": true,
"environment_sealed": false,
"violations": [],
"recommendation": "Activate sealed mode with: stella airgap seal"
}
},
"status": "rejected",
"rejected_at": "2025-12-06T10:00:00Z"
}
4.2 CLI Exit Codes
| Code | Name | Description |
|---|---|---|
| 40 | SEALED_INSTALL_VIOLATION | Pack requires sealed but environment is not |
| 41 | BUNDLE_VERSION_VIOLATION | Bundle version below minimum |
| 42 | ADVISORY_STALENESS_VIOLATION | Advisory data too stale |
| 43 | TIME_ANCHOR_VIOLATION | Time anchor missing or invalid |
| 44 | SIGNATURE_VERIFICATION_VIOLATION | Bundle signature verification failed |
4.3 Audit Logging
All enforcement decisions are logged:
{
"event_type": "sealed_install_enforcement",
"timestamp": "2025-12-06T10:00:00Z",
"pack_id": "compliance-scan-airgap",
"pack_version": "1.0.0",
"decision": "denied",
"reason": "SEALED_INSTALL_VIOLATION",
"environment": {
"sealed": false,
"bundle_version": null,
"advisory_staleness_hours": null
},
"user": "task-runner-service",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000"
}
5. Integration Points (DRAFT — TaskRunner deleted)
[!WARNING] NOT IMPLEMENTED. The
src/TaskRunner/service that hosted this integration has been removed from the monorepo, so the execution-pipeline hook below has no host. The CLI commands shown (stella pack run …, “Activate sealed mode:stella airgap seal”) do not exist — the realstella airgapgroup exposes onlyexport,import,diff,status, andjobs(src/Cli/StellaOps.Cli/Commands/AirGapCommandGroup.cs); seal/unseal are HTTP-only operations on the AirGap Controller.
5.1 Task Runner Integration
// NOT IMPLEMENTED — TaskRunner service removed; no such pipeline exists
// In TaskRunner execution pipeline
public async Task<TaskResult> ExecuteAsync(TaskPack pack, TaskContext context)
{
// Pre-execution enforcement
var enforcement = await _sealedInstallEnforcer.EnforceAsync(pack);
if (!enforcement.Allowed)
{
await _auditLogger.LogEnforcementDenialAsync(pack, enforcement);
return TaskResult.Rejected(enforcement);
}
// Continue with execution
return await _executor.ExecuteAsync(pack, context);
}
5.2 CLI Integration
# Check sealed status before running pack
$ stella pack run … # NEVER SHIPPED: the Task Pack verb group was deleted 2026-09-14 (SPRINT_20260914_003 JEF-4)
Error: Sealed install violation
Pack 'compliance-scan-airgap' requires a sealed environment.
Current environment:
Sealed: false
To resolve:
1. Import an air-gap bundle: stella airgap import <bundle.tar.gz>
2. Activate sealed mode: stella airgap seal
3. Verify status: stella airgap status
Exit code: 40
6. Configuration (DRAFT — keys/vars below not honoured)
[!WARNING] NOT IMPLEMENTED. The
etc/taskrunner.yamlenforcement.sealed_install.*keys and the env varsAIRGAP_MODE,AIRGAP_CONTROLLER_URL, andSEALED_INSTALL_BYPASSare not consumed by any shipping service (noSEALED_INSTALL_BYPASSor sealed-install enforcement config reader exists insrc/). Real sealed-mode behaviour is configured through the egress policy (EgressPolicy.Options,EgressPolicyMode) and the AirGap Controller startup options (AirGapStartupOptions); staleness is configured viaStalenessBudget(Warning/Breach seconds) on the seal request, not via hour-based grace periods.
6.1 Task Runner Configuration
# etc/taskrunner.yaml
enforcement:
sealed_install:
enabled: true
# Staleness handling
staleness_grace_period_hours: 24
staleness_warning_threshold_hours: 120
deny_on_staleness: true
# Fallback detection
use_heuristic_detection: true
heuristic_threshold: 0.7
# Logging
log_all_decisions: true
audit_retention_days: 365
6.2 Environment Variables
| Variable | Description | Default |
|---|---|---|
AIRGAP_MODE | Force sealed mode detection | — |
AIRGAP_CONTROLLER_URL | AirGap controller endpoint | http://localhost:8080 |
SEALED_INSTALL_BYPASS | Bypass enforcement (dev only) | false |
7. Tasks Unblocked (historical — service since deleted)
This contract originally unblocked the tasks below. They were marked DONE inside the src/TaskRunner/StellaOps.TaskRunner service (see docs-archive/implplan/SPRINT_0157_0001_0001_taskrunner_i.md), which has since been removed from the monorepo. The delivered code therefore no longer ships.
| Task ID | Description | Status |
|---|---|---|
| TASKRUN-AIRGAP-57-001 | Sealed install enforcement | ❌ Removed with TaskRunner service |
| TASKRUN-AIRGAP-58-001 | Sealed install CLI integration | ❌ Removed with TaskRunner service |
8. Actual Implementation (as of 2026-05-30)
This section documents the sealed-mode enforcement that actually ships, replacing the aspirational §§1-7 above.
8.1 AirGap Controller HTTP API
Source: src/AirGap/StellaOps.AirGap.Controller/Endpoints/AirGapEndpoints.cs. All routes are under the /system/airgap group and resolve the tenant from the stellaops:tenant/tid claim or x-tenant-id header.
| Method & Path | Scope (policy) | Handler / Contract |
|---|---|---|
GET /system/airgap/status | airgap:status:read (AirGapPolicies.StatusRead) | Returns AirGapStatusResponse |
POST /system/airgap/seal | airgap:seal (AirGapPolicies.Seal) | Body SealRequest; returns AirGapStatusResponse |
POST /system/airgap/unseal | airgap:seal (AirGapPolicies.Seal) | Returns AirGapStatusResponse |
POST /system/airgap/verify | airgap:status:read (AirGapPolicies.Verify) | Body VerifyRequest; returns VerifyResponse(Valid, Reason) |
Canonical scope constants live in StellaOps.Auth.Abstractions/StellaOpsScopes.cs: AirgapStatusRead = "airgap:status:read", AirgapSeal = "airgap:seal", AirgapImport = "airgap:import". There is no airgap:verify scope: the AirGapPolicies.Verify policy asserts AirgapStatusRead (Program.cs:59-69), because verification is a read-only integrity check.
AirGapStatusResponse(Endpoints/Contracts/AirGapStatusResponse.cs):
{
"tenantId": "default",
"sealed": true,
"policyHash": "sha256:…",
"timeAnchor": {
"anchorTime": "2025-12-01T00:00:00Z",
"source": "roughtime",
"format": "…",
"signatureFingerprint": "…",
"tokenDigest": "…"
},
"staleness": {
"ageSeconds": 432000,
"warningSeconds": 3600,
"breachSeconds": 7200,
"isWarning": false,
"isBreach": true
},
"driftSeconds": 432000,
"driftBaselineSeconds": 0,
"secondsRemaining": 0,
"contentStaleness": {
"advisories": { "ageSeconds": 0, "secondsRemaining": 7200, "isWarning": false, "isBreach": false }
},
"lastTransitionAt": "2025-12-01T00:00:00Z",
"evaluatedAt": "2025-12-06T10:00:00Z"
}
SealRequest(Endpoints/Contracts/SealRequest.cs) carries a required policyHash, an optional timeAnchor (StellaOps.AirGap.Time.Models.TimeAnchor), an optional stalenessBudget (StalenessBudget(WarningSeconds, BreachSeconds), default 3600/7200), and an optional per-content contentBudgets map.
8.2 Policy Engine sealed-mode (CONTRACT-SEALED-MODE-004)
Source: src/Policy/StellaOps.Policy.Engine/AirGap/ (SealedModeService, SealedModeModels, ISealedModeService). This is the real fail-closed enforcement primitive:
IsSealeddelegates toIEgressPolicy.IsSealed(src/AirGap/StellaOps.AirGap.Policy/), which istrueiffEgressPolicyMode.Sealed.SealAsync/UnsealAsyncpersist aPolicyPackSealedStateper tenant (policy hash, time anchor, staleness budget, last-transition timestamp).EvaluateStalenessAsynccompares wall clock againstTimeAnchor.AnchorTimeusingStalenessBudget(Warning/Breach seconds) — there is no hour-based “advisory staleness” concept.EnforceBundleImportAsyncreturnsSealedModeEnforcementResult(Allowed, Reason, Remediation): allows when not sealed; in sealed mode blocks bundle import on a staleness breach (SealedModeErrorCodes.StalenessBreach) and warns onSealedModeErrorCodes.StalenessWarning. Note this gates bundle import, not pack/task execution.VerifyBundleAsyncreturns DSSE/TUF/Merkle validity viaIPolicyPackBundleTrustVerifier, refusing to mark a bundle valid when no verifier is configured.
8.3 CLI surface
Source: src/Cli/StellaOps.Cli/Commands/AirGapCommandGroup.cs. The stella airgap group exposes:
| Command | Purpose |
|---|---|
stella airgap export | Export a sealed knowledge snapshot (advisories/VEX/policies/trust-roots, optional DSSE sign, time anchor). |
stella airgap import <bundle> | Import a snapshot; --verify-only, --force, --trust-policy, --max-age-hours, --quarantine-on-failure. |
stella airgap diff <base> <target> | Compare two knowledge snapshots. |
stella airgap status | Show current air-gap state and staleness (text/json). |
stella airgap jobs {export,import,list} | Manage HLC job-sync bundles for offline scenarios. |
There is no stella airgap seal / stella airgap unseal command and no stella pack … group at all (deleted 2026-09-14, SPRINT_20260914_003 JEF-4). Sealing/unsealing is performed through the HTTP API described in §8.1.
Host note, 2026-09-14. §8.1 is named for the
airgap-controllerdeployable, which retired 2026-09-11 (SPRINT_20260722_025 OK-5) and is frozen atsrc/__Obsoleted/AirGap/StellaOps.AirGap.Controller/. The section heading is left unchanged because four in-document links anchor to it. The/system/airgap/*paths it documents are still served — live probe 2026-09-14 returns 401 with an error body naming"service":"policy-engine"— and sealed-posture custody now lives in Platform’splatform.environment_state(/api/v1/platform/environment-state/{stateClass}/{scope}, also 401 live). Read §8.1 as the contract, not as a statement about which container answers it.
9. Changelog
| Date | Version | Change |
|---|---|---|
| 2025-12-06 | 1.0.0 | Initial contract with enforcement logic, decision matrix, CLI integration. |
| 2026-05-30 | 1.0.0 (reconciled) | Source reconciliation: marked SUPERSEDED / NOT IMPLEMENTED. TaskRunner service deleted; no sealed_install flag, SealedInstallEnforcer, or coded exit codes exist. Corrected status-API path/scope/shape and CLI surface; added §8 documenting the shipping AirGap Controller API, Policy Engine SealedModeService, and stella airgap CLI. |
Related Contracts
- Sealed Mode (
CONTRACT-SEALED-MODE-004) — the authoritative, reconciled sealed-mode contract (AirGap Controller API, egress policy, staleness, time anchoring). Read this instead for current behaviour. - Mirror Bundle Contract — bundle format for sealed import.
- Verification Policy Contract — attestation verification.
