Skip to content

feat(airgap): signed offline install bundle — ragctl airgap (Step 6.9) - #161

Merged
officialCodeWork merged 1 commit into
mainfrom
build/phase-6/step-6.9-airgap-bundle
Jun 8, 2026
Merged

feat(airgap): signed offline install bundle — ragctl airgap (Step 6.9)#161
officialCodeWork merged 1 commit into
mainfrom
build/phase-6/step-6.9-airgap-bundle

Conversation

@officialCodeWork

Copy link
Copy Markdown
Owner

Summary

Step 6.9 — Air-gapped install bundle: a signed tarball with all images + the Helm chart, an offline bootstrap, and cosign verification. New ragctl airgap command + standalone installer.

  • One self-contained artifact for networks with no registry / internet: all runtime images (docker save) + the packaged Helm chart (helm package) + an example rag.yaml + a standalone installer, in one .tar.gz.
  • Integrity reuses the WORM-export pattern (6.6b): a standard SHA256SUMS — verifiable with nothing but sha256sum -c, no network / no cosign — whose hash is pinned as manifest.content_hash is the hard tamper-evidence gate; a cosign signature over SHA256SUMS adds authenticity when present. The same SHA256SUMS drives both the Python verifier and the standalone shell installer, so they can't diverge.
  • Standalone install.{sh,ps1} (shipped inside every bundle) need only docker + helm (+ optional cosign / sha256sum) — no Python workspace, the genuinely air-gap-appropriate entry point: verify → docker loadhelm upgrade --install.
  • Typed, tested logic in ragctl airgap (build/inspect/verify/install): a pure core (BundleManifest, render_sha256sums, content_hash, verify_bundle) separated from a stubbable docker/helm/cosign subprocess seam. --dry-run produces a complete, verifiable bundle minus the image blobs, so the path is testable with no Docker.
  • Digest-pinned, manifest-driven image set (infra/airgap/images.txt); the gateway image is derived from the chart's image.repository + --version. Key-based cosign is the air-gap recommendation (keyless needs Rekor + an identity policy); keyless is the connected-release path — release-airgap.yml builds + signs + attaches the tarball to the GitHub Release on v* tags. task airgap:build / build-dry / verify.

Deferred: ctr/podman load (docker only), registry re-tag/push, multi-arch selection, bundling the backend charts (chart deploys the gateway; backends stay external), TUF-rooted offline keyless verify.

Documentation

Test plan

  • Unit: parse_image_list, sha256_file, render_sha256sums/content_hash, build_manifest, verify_bundle (ok / tamper / added-file / no-checksums), tarball round-trip, chart helpers
  • Signature paths: keyless (advisory) / key-verified / key-mismatch / sign-invokes-cosign (stubbed subprocess)
  • CLI (CliRunner on a --dry-run bundle): buildinspectverify exit 0; tamper → verify exit 1; install rejects a dry-run bundle
  • Standalone install.sh: bash -n + --verify-only exercised against a real bundle (clean + tampered)
  • ruff, mypy --strict (321 files), RAG001, full pytest (excl integration), schema/openapi/proto-drift (dist untouched), policy-coverage, log-schema

🤖 Generated with Claude Code

Ship the platform as one signed, self-contained artifact for networks
with no registry / internet: all runtime container images (docker save),
the packaged Helm chart (helm package), an example rag.yaml, and a
standalone offline installer.

- Integrity mirrors the WORM audit export (6.6b): a standard SHA256SUMS
  (verifiable with `sha256sum -c` — no network, no cosign) whose hash is
  pinned as manifest.content_hash is the hard tamper-evidence gate; a
  cosign signature over SHA256SUMS adds authenticity when present. The
  same SHA256SUMS drives both the Python verifier and the standalone
  shell installer, so they can never diverge.
- scripts/airgap_install.{sh,ps1} (shipped inside every bundle as
  install.{sh,ps1}) need only docker+helm (+ optional cosign/sha256sum) —
  no Python workspace, the genuinely air-gap-appropriate entry point:
  verify -> docker load -> helm upgrade --install.
- ragctl airgap build/inspect/verify/install holds the typed, mypy-strict,
  unit-tested logic — a pure core (BundleManifest, render_sha256sums,
  content_hash, verify_bundle) separated from a stubbable docker/helm/
  cosign subprocess seam. --dry-run produces a complete, verifiable
  bundle minus the image blobs, so the whole path is testable with no
  Docker.
- infra/airgap/images.txt is the digest-pinned, manifest-driven image set
  (third-party backends); the gateway image is derived from the chart's
  image.repository + --version (always release-versioned). Key-based
  cosign is the air-gap recommendation; keyless is the connected-release
  path (release-airgap.yml on v* tags, attaches the tarball to the GitHub
  Release). task airgap:build / build-dry / verify.

~17 tests (manifest / hashing / tamper detection / tarball round-trip /
signature paths via stubbed cosign / CLI on a dry-run bundle); the shell
installer is bash -n + --verify-only exercised. All gates green: ruff,
mypy --strict (321 files), RAG001, full pytest (excl integration),
schema/openapi/proto-drift (dist untouched), policy-coverage, log-schema.

Docs: docs/reference/airgap.md, docs/architecture/airgap-bundle.md,
docs/guides/airgap-install.md, docs/adr/ADR-0041-airgap-bundle.md,
docs/README.md. TRACKER: 6.9 done (73/84).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@officialCodeWork
officialCodeWork merged commit b5856e2 into main Jun 8, 2026
12 of 17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant