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

74 lines
3.3 KiB
Markdown

# 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/`.
```bash
# 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:
```bash
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:
```bash
curl -sSf -X POST \
-H 'Content-Type: application/x-ndjson' \
--data-binary @concelier-airgap.ndjson \
http://localhost:5000/internal/airgap/import
```
4) Validate import:
```bash
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.