Files
git.stella-ops.org/docs/operations/runbooks/concelier-airgap-bundle-deploy.md
master 3a95f315bd feat(airgap): multi-source import (server path, URL, file upload) with overlay UX
Import now supports three sources: server-side path (USB/NFS volumes),
backend URL download, and browser file upload. Export/import workflows
refactored from routed pages to overlay dialogs. Docs updated with
volume mount instructions and source comparison table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:33:21 +03:00

3.3 KiB

Concelier Air-Gap Bundle Deploy Runbook (CONCELIER-AIRGAP-56-003)

Status: draft · 2025-11-24 Scope: deploy sealed-mode Concelier evidence bundles using deterministic NDJSON + manifest/entry-trace outputs.

Inputs

  • Bundle: concelier-airgap.ndjson
  • Manifest: bundle.manifest.json
  • Entry trace: bundle.entry-trace.json
  • Hashes: SHA256 recorded in manifest and entry-trace; verify before import.

Preconditions

  • Concelier WebService running with concelier:features:airgap enabled.
  • No external egress; only local file system allowed for bundle path.
  • PostgreSQL indexes applied (advisory_observations, advisory_linksets tables).
  • Import volume mounted: The Concelier container must have the import staging directory mounted. In Docker Compose this is configured via STELLAOPS_AIRGAP_IMPORT_DIR (defaults to ./airgap-import on the host, mounted read-only at /var/lib/concelier/import inside the container).

Import Volume Setup (Docker Compose)

The Concelier service mounts an import staging volume for air-gapped bundle ingestion. Bundles placed on the host at $STELLAOPS_AIRGAP_IMPORT_DIR are visible inside the container at /var/lib/concelier/import/.

# Default: ./airgap-import relative to the compose directory
mkdir -p devops/compose/airgap-import

# Override: point to USB, NFS mount, or any host directory
export STELLAOPS_AIRGAP_IMPORT_DIR=/media/usb/stellaops-bundles
docker compose -f docker-compose.stella-ops.yml up -d concelier

The volume is mounted read-only — the Concelier service reads and validates bundles but never modifies the staging directory. The environment variable CONCELIER_IMPORT__STAGINGROOT tells the service where to find staged bundles inside the container.

UI Console Import

The Feeds & Airgap console (Ops → Operations → Feeds & Airgap → Airgap Bundles → Import) supports three import sources:

Source Description Volume needed?
Server Path Path inside the container (e.g. /var/lib/concelier/import/bundle.tar.gz). Zero browser transfer. Yes
URL Internal URL the backend downloads directly. No
File Upload Browser drag-and-drop for small bundles. No

For large bundles (GB+), use Server Path or URL — never browser upload.

Steps

  1. Stage the bundle onto the import volume (or transfer to the offline controller host).
  2. Verify hashes:
    sha256sum concelier-airgap.ndjson | diff - <(jq -r .bundleSha256 bundle.manifest.json)
    jq -r '.[].sha256' bundle.entry-trace.json | nl | sed 's/\t/:/' > entry.hashes
    paste -d' ' <(cut -d: -f1 entry.hashes) <(cut -d: -f2 entry.hashes)
    
  3. Import:
    curl -sSf -X POST \
      -H 'Content-Type: application/x-ndjson' \
      --data-binary @concelier-airgap.ndjson \
      http://localhost:5000/internal/airgap/import
    
  4. Validate import:
    curl -sSf http://localhost:5000/internal/airgap/status | jq
    
  5. Record evidence:
    • Store manifest + entry-trace alongside TRX/logs in artifacts/airgap/<date>/.

Determinism notes

  • NDJSON ordering is lexicographic; do not re-sort downstream.
  • Entry-trace hashes must match post-transfer; any mismatch aborts import.

Rollback

  • Delete imported batch by bundleId from advisory_observations and advisory_linksets (requires DBA approval); rerun import after fixing hash.