Sealed Install Enforcement Contract

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 TaskRunner service that has since been deleted from the monorepo. There is no src/TaskRunner/directory, and StellaOps.Auth.Abstractions/StellaOpsScopes.cs (lines 755-758) records that the taskrunner:* scopes were “REMOVED (service deleted, constants kept for DB/migration backward compat).” The archived sprint docs-archive/implplan/SPRINT_0157_0001_0001_taskrunner_i.md shows tasks TASKRUN-AIRGAP-57-001/58-001 were marked DONE inside src/TaskRunner/StellaOps.TaskRunner, but that code no longer ships.

Concretely, none of the following exist anywhere in src/: a sealed_install pack-manifest flag, a SealedInstallEnforcer class, a SealedRequirements/SealedInstallViolation type, 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 ControllerGET/POST /system/airgap/{status,seal,unseal,verify} (src/AirGap/StellaOps.AirGap.Controller), gated on the three catalogued scopes airgap:status:read / airgap:seal / airgap:import (/verify shares airgap:status:read).
  • Policy Engine sealed-modeSealedModeService (src/Policy/StellaOps.Policy.Engine/AirGap/, contract CONTRACT-SEALED-MODE-004), the real fail-closed enforcement gated on IEgressPolicy.IsSealed.
  • stella airgap CLIexport, import, diff, status, jobs subcommands (src/Cli/StellaOps.Cli/Commands/AirGapCommandGroup.cs). There is no stella airgap seal / unseal command and no stella pack run command.

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_install flag 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 Engine SealedModeService + 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_install manifest flag and sealed_requirements block below do not exist in any shipping pack manifest schema. A repo-wide search for sealed_install / SealedInstall in src/ 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 the airgap:status:read scope, and it returns AirGapStatusResponse — see §8.1 for the actual contract. None of the fields mode, sealed_at, sealed_by, bundle_version, bundle_digest, last_advisory_update, advisory_staleness_hours, egress_blocked, or network_policy exist in the shipping response. Air-gap staleness is expressed in seconds against a StalenessBudget (Warning/Breach), not in “advisory staleness hours”, and is tracked per content kind via ContentStaleness.

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 reads IEgressPolicy.IsSealed (true iff EgressPolicyMode.Sealed). There is no DNS/port-probing fallback, no AIRGAP_MODE env var consumed by this path, no /etc/stellaops/sealed sentinel file, and no “0.7 heuristic score” anywhere in src/.

The original design proposed the following fallback heuristics (none of which ship):

HeuristicWeightIndicates
No external DNS resolutionHighSealed
Blocked ports 80, 443HighSealed
AIRGAP_MODE=sealed env varHighSealed
/etc/stellaops/sealed file existsMediumSealed
No internet connectivityMediumSealed
Local-only registry configuredLowSealed

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, and RequirementViolation types below do not exist in src/. No service performs a min_bundle_version / max_advisory_staleness_hours / require_time_anchor pre-execution check against a pack flag. The closest shipping enforcement is SealedModeService.EnforceBundleImportAsync (src/Policy/StellaOps.Policy.Engine/AirGap/SealedModeService.cs), which gates bundle import (not pack execution) on IEgressPolicy.IsSealed and time-anchor staleness, returning SealedModeEnforcementResult(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_installEnvironment SealedBundle ValidAdvisories FreshResult
truetruetruetrue✅ RUN
truetruetruefalse⚠️ WARN + RUN (if within grace)
truetruefalse*❌ DENY
truefalse**❌ DENY
falsetrue**✅ RUN
falsefalse**✅ 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 (and SEALED_REQUIREMENTS_VIOLATION, BUNDLE_VERSION_VIOLATION, ADVISORY_STALENESS_VIOLATION, TIME_ANCHOR_VIOLATION, SIGNATURE_VERIFICATION_VIOLATION) and the CLI exit codes 40-44 below appear nowhere in src/. The shipping sealed-mode error codes are the SealedModeErrorCodes.* constants used by SealedModeService (e.g. staleness-breach / staleness-warning); the AirGap Controller verify endpoint returns a VerifyResponse(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

CodeNameDescription
40SEALED_INSTALL_VIOLATIONPack requires sealed but environment is not
41BUNDLE_VERSION_VIOLATIONBundle version below minimum
42ADVISORY_STALENESS_VIOLATIONAdvisory data too stale
43TIME_ANCHOR_VIOLATIONTime anchor missing or invalid
44SIGNATURE_VERIFICATION_VIOLATIONBundle 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 real stella airgap group exposes only export, import, diff, status, and jobs (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 compliance-scan-airgap

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.yaml enforcement.sealed_install.* keys and the env vars AIRGAP_MODE, AIRGAP_CONTROLLER_URL, and SEALED_INSTALL_BYPASS are not consumed by any shipping service (no SEALED_INSTALL_BYPASS or sealed-install enforcement config reader exists in src/). Real sealed-mode behaviour is configured through the egress policy (EgressPolicy.Options, EgressPolicyMode) and the AirGap Controller startup options (AirGapStartupOptions); staleness is configured via StalenessBudget (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

VariableDescriptionDefault
AIRGAP_MODEForce sealed mode detection
AIRGAP_CONTROLLER_URLAirGap controller endpointhttp://localhost:8080
SEALED_INSTALL_BYPASSBypass 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 IDDescriptionStatus
TASKRUN-AIRGAP-57-001Sealed install enforcement❌ Removed with TaskRunner service
TASKRUN-AIRGAP-58-001Sealed 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 & PathScope (policy)Handler / Contract
GET /system/airgap/statusairgap:status:read (AirGapPolicies.StatusRead)Returns AirGapStatusResponse
POST /system/airgap/sealairgap:seal (AirGapPolicies.Seal)Body SealRequest; returns AirGapStatusResponse
POST /system/airgap/unsealairgap:seal (AirGapPolicies.Seal)Returns AirGapStatusResponse
POST /system/airgap/verifyairgap: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:

8.3 CLI surface

Source: src/Cli/StellaOps.Cli/Commands/AirGapCommandGroup.cs. The stella airgap group exposes:

CommandPurpose
stella airgap exportExport 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 statusShow 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 run command. Sealing/unsealing is performed through the AirGap Controller HTTP API (§8.1).

9. Changelog

DateVersionChange
2025-12-061.0.0Initial contract with enforcement logic, decision matrix, CLI integration.
2026-05-301.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.