Files
git.stella-ops.org/docs/contracts/sealed-install-enforcement.md
StellaOps Bot f6c22854a4
Some checks failed
AOC Guard CI / aoc-verify (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Findings Ledger CI / build-test (push) Has been cancelled
Findings Ledger CI / migration-validation (push) Has been cancelled
Findings Ledger CI / generate-manifest (push) Has been cancelled
mock-dev-release / package-mock-release (push) Has been cancelled
feat(api): Add Policy Registry API specification
- Introduced OpenAPI specification for the StellaOps Policy Registry API, covering endpoints for verification policies, policy packs, snapshots, violations, overrides, sealed mode operations, and advisory staleness tracking.
- Defined schemas, parameters, and responses for comprehensive API documentation.

chore(scanner): Add global usings for scanner analyzers

- Created GlobalUsings.cs to simplify namespace usage across analyzer libraries.

feat(scanner): Implement Surface Service Collection Extensions

- Added SurfaceServiceCollectionExtensions for dependency injection registration of surface analysis services.
- Included methods for adding surface analysis, surface collectors, and entry point collectors to the service collection.
2025-12-06 20:52:23 +02:00

14 KiB

Sealed Install Enforcement Contract

Status: APPROVED Version: 1.0.0 Last Updated: 2025-12-06 Owner: AirGap Controller Guild Unblocks: TASKRUN-AIRGAP-57-001, TASKRUN-AIRGAP-58-001

Overview

This contract defines the sealed install enforcement semantics for StellaOps air-gapped deployments. When a pack or task declares sealed_install: true, the Task Runner MUST refuse to execute if the environment is not properly sealed.

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

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

2.1 Sealed Mode Status API

The Task Runner queries the AirGap Controller to determine sealed status:

GET /api/v1/airgap/status

Response:

{
  "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

If the AirGap Controller is unavailable, the Task Runner uses fallback heuristics:

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

3.1 Pre-Execution Check

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

4.1 Error Response

When enforcement denies execution:

{
  "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

5.1 Task Runner Integration

// 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

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

This contract unblocks:

Task ID Description Status
TASKRUN-AIRGAP-57-001 Sealed install enforcement contract UNBLOCKED
TASKRUN-AIRGAP-58-001 Sealed install CLI integration UNBLOCKED

8. Changelog

Date Version Change
2025-12-06 1.0.0 Initial contract with enforcement logic, decision matrix, CLI integration