Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/workflows/release-airgap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Release — air-gapped bundle

# Builds the offline install bundle (all runtime images + Helm chart + installer),
# cosign-signs its SHA256SUMS (keyless via GitHub OIDC), and attaches the tarball to
# the GitHub Release. Runs only on version tags (the build pulls every image, so it
# is deliberately release-scoped, not per-PR).

on:
push:
tags: ["v*.*.*"]
workflow_dispatch:
inputs:
version:
description: "Bundle version (e.g. v0.1.0)"
required: true

permissions:
contents: write # upload the bundle as a release asset
id-token: write # cosign keyless OIDC signing

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false

jobs:
bundle:
name: Build → Sign → Attach
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4

- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
cache-dependency-glob: "uv.lock"

- run: uv sync --all-packages

- name: Set up Helm
uses: azure/setup-helm@v4

- name: Install cosign
uses: sigstore/cosign-installer@v3

- name: Resolve version
id: ver
run: |
version="${{ github.event.inputs.version }}"
[ -n "$version" ] || version="${GITHUB_REF_NAME}"
echo "version=${version}" >> "$GITHUB_OUTPUT"

- name: Build + sign bundle
run: uv run ragctl airgap build --version "${{ steps.ver.outputs.version }}" --sign

- name: Verify bundle (content hash)
run: uv run ragctl airgap verify dist/airgap.tar.gz

- name: Inspect bundle
run: uv run ragctl airgap inspect dist/airgap.tar.gz

- name: Attach bundle to the release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
files: dist/airgap.tar.gz
24 changes: 17 additions & 7 deletions TRACKER.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@
| | |
|---|---|
| **Last updated** | 2026-06-08 |
| **Current phase** | Phase 6 — Governance & Tenancy (**8 / 10 steps**) |
| **Overall** | **72 / 84 steps** — Phases 0–5 complete |
| **Next action** | **Step 6.9Air-gapped install bundle**: signed tarball with all images + Helm chart; offline bootstrap; cosign verification. |
| **Current phase** | Phase 6 — Governance & Tenancy (**9 / 10 steps**) |
| **Overall** | **73 / 84 steps** — Phases 0–5 complete |
| **Next action** | **Step 6.10Compliance posture**: SOC 2 Type II control mapping; GDPR data-residency config; data-retention policies. |

**Recently shipped**

- **6.9** ✅ Air-gapped install bundle — `ragctl airgap build`/`inspect`/`verify`/`install`: one signed `.tar.gz` of all runtime images (`docker save`) + the packaged Helm chart + `rag.yaml` + a standalone installer, for networks with no registry / internet. Integrity = a standard `SHA256SUMS` (verifiable with `sha256sum -c`, no cosign/network) pinned as `manifest.content_hash` + an optional cosign signature over it (the 6.6b content-hash + optional-signature pattern); the same `SHA256SUMS` drives the Python verifier and the standalone `install.{sh,ps1}` (need only docker+helm). Typed/tested logic in `ragctl.airgap` (pure core + stubbable docker/helm/cosign seam; `--dry-run` = verifiable bundle minus blobs); digest-pinned manifest-driven image set (`infra/airgap/images.txt`); `task airgap:*`; `release-airgap.yml` on tags — [#161](https://github.com/officialCodeWork/AgentContextOS/pull/161)
- **6.8** ✅ SSO / SCIM — `rag-sso`: `FederatedAuth` (an `Auth` SPI backend over per-tenant `OidcProvider` / `SamlProvider`) federates a bearer token / SAML assertion → `Principal` at the existing `authenticate` seam (group claims → `acl_labels`); dependency-free defaults (stdlib HS256 JWT + `defusedxml` SAML), asymmetric OIDC / XML-DSig behind `[oidc]` / `[saml]` extras; algorithm-allowlist downgrade defense; SCIM 2.0 `ScimService` over the new tenant-scoped `ScimStore` SPI driving `/scim/v2/{Users,Groups}` (per-tenant bearer token); per-tenant IdP on `tenants[].sso`; `cfg.sso` / `cfg.scim`; `GET /v1/status/sso`; PII-free `sso.*` / `scim.*` events; `ragctl sso` / `scim` — [#159](https://github.com/officialCodeWork/AgentContextOS/pull/159)
- **6.7** ✅ BYOK envelope encryption — `KeyManager` SPI + `EncryptingStorage` + `EnvelopeKeyManager` (AES-256-GCM DEK + tenant AAD); `LocalKeyManager` + four cloud KMS providers (`Aws`/`Gcp`/`AzureKeyVault`/`Vault`, behind `[kms-*]` extras); `cfg.kms` + per-tenant key + factory; per-tenant isolation + sealing + tamper-evidence; zero-downtime rotation (`RotatingKeyManager` + `rewrap`); `ragctl kms` — [#155](https://github.com/officialCodeWork/AgentContextOS/pull/155)–[#158](https://github.com/officialCodeWork/AgentContextOS/pull/158)
- **6.6** ✅ Immutable audit log — **6.6a** shared `AuditWriter`/store on `app.state` + `GET /v1/audit` (tenant-scoped, `chain_verified`) + `GET /v1/audit/verify` (whole-log) + `cfg.audit.enabled` ([#153](https://github.com/officialCodeWork/AgentContextOS/pull/153)); **6.6b** `AuditExporter` self-verifying WORM bundle (SHA-256 `content_hash` + HMAC, offline `verify()`), `POST /v1/audit/export` (tenant-scoped) + `ragctl audit`, `cfg.audit.export_secret` ([#154](https://github.com/officialCodeWork/AgentContextOS/pull/154))
Expand Down Expand Up @@ -62,9 +63,9 @@
| 3 | Gateway & Agent Runtime | 11 | **11** | 0 |
| 4 | Reliability | 6 | **6** | 0 |
| 5 | Eval & Observability | 7 | **7** | 0 |
| 6 | Governance & Tenancy | 10 | **8** | 2 |
| 6 | Governance & Tenancy | 10 | **9** | 1 |
| 7 | Pilot, Harden, GA | 10 | 0 | 10 |
| **Total** | | **84** | **72** | **12** |
| **Total** | | **84** | **73** | **11** |

---

Expand Down Expand Up @@ -647,7 +648,7 @@
- **Phase-5 close-out:** Step 5.7 ✅ → **Phase 5 complete (7 / 7)**; deferred items remain documented (per-tenant drift / per-dimension embedding PSI; feedback/breaker/quota Grafana export + Loki-events dashboard; gRPC proto mirror of `corpus_decision` + `experiment`; sequential / multi-metric experiments)
- [reference/experiments.md](docs/reference/experiments.md), [reference/admin-ui.md](docs/reference/admin-ui.md)

## Phase 6 — Governance & Tenancy (Weeks 28–34) 🚧 (2 / 10)
## Phase 6 — Governance & Tenancy (Weeks 28–34) 🚧 (1 / 10)

| Step | Title | Status | Planned deliverables |
|------|-------|:------:|----------------------|
Expand All @@ -659,7 +660,7 @@
| 6.6 | Immutable audit log | ✅ | **6.6a** [#153](https://github.com/officialCodeWork/AgentContextOS/pull/153) — read API `GET /v1/audit` + `GET /v1/audit/verify` + shared store + `cfg.audit`. **6.6b** [#154](https://github.com/officialCodeWork/AgentContextOS/pull/154) — `AuditExporter` signed WORM bundle + `POST /v1/audit/export` + `ragctl audit` |
| 6.7 | BYOK (Bring Your Own Key) | ✅ | **6.7a** ✅ [#155](https://github.com/officialCodeWork/AgentContextOS/pull/155) — `KeyManager` SPI + envelope encryption (`LocalKeyManager`) + `EncryptingStorage` + sealing/isolation/tamper. **6.7b** ✅ [#156](https://github.com/officialCodeWork/AgentContextOS/pull/156) — `cfg.kms` + per-tenant key + `build_key_manager_from_config` factory + `AwsKmsKeyManager`. **6.7c** ✅ [#157](https://github.com/officialCodeWork/AgentContextOS/pull/157) — `GcpKmsKeyManager` / `AzureKeyVaultKeyManager` / `VaultKeyManager` behind `[kms-*]` extras. **6.7d** ✅ [#158](https://github.com/officialCodeWork/AgentContextOS/pull/158) — `RotatingKeyManager` zero-downtime rotation + `rewrap` |
| 6.8 | SSO / SCIM | ✅ | [#159](https://github.com/officialCodeWork/AgentContextOS/pull/159) — `rag-sso`: `FederatedAuth` (`Auth` SPI backend over per-tenant `OidcProvider` / `SamlProvider`) federates a token / assertion → `Principal` at the existing `authenticate` seam (groups → `acl_labels`); stdlib HS256 + `defusedxml` defaults, asymmetric OIDC / XML-DSig behind `[oidc]` / `[saml]` extras; SCIM 2.0 `ScimService` + `ScimStore` SPI → `/scim/v2/*` (per-tenant bearer); `tenants[].sso` + `cfg.sso` / `cfg.scim`; `GET /v1/status/sso`; `ragctl sso` / `scim` |
| 6.9 | Air-gapped install bundle | | Signed tarball with all images + Helm chart; offline bootstrap; cosign verification |
| 6.9 | Air-gapped install bundle | | [#161](https://github.com/officialCodeWork/AgentContextOS/pull/161) — `ragctl airgap build`/`verify`/`install`: signed `.tar.gz` of all images (`docker save`) + Helm chart + config + standalone installer; `SHA256SUMS` content-hash (offline-verifiable) + optional cosign; `infra/airgap/images.txt`; `install.{sh,ps1}`; `task airgap:*`; `release-airgap.yml` |
| 6.10 | Compliance posture | ⏳ | SOC 2 Type II control mapping; GDPR data-residency config; data-retention policies |

### 6.1 — Logical multi-tenancy ✅ [#148](https://github.com/officialCodeWork/AgentContextOS/pull/148)
Expand Down Expand Up @@ -770,6 +771,15 @@ New ground — the only prior crypto was HMAC signing. The V1 plan calls for en
- New core types **`FederatedIdentity` / `SsoProtocol` / `ScimUser` / `ScimGroup`** (+ nested) + **`SsoError`** (401) / **`ScimError`** (400) / **`ScimNotFoundError`** (404) / **`ScimConflictError`** (409); wire types `ScimListResponse` / `ScimPatchOp` / `ScimErrorBody` / `SsoStatusResponse` (`dist/schemas` + `dist/openapi` regenerated); `cfg.sso` / `cfg.scim` / `tenants[].sso` (`dist/rag.schema`); PII-free `sso.*` / `scim.*` events (subject **hashed**, never email / userName); **`ragctl sso`** (list + in-process OIDC demo) + **`ragctl scim`** (in-process provisioning demo)
- **Scope:** verification + provisioning at the boundary. **Deferred:** remote JWKS discovery + rotation (configured static keys only), SAML SP-initiated redirect + metadata, SCIM bulk / `/Me` / ETag, directory-backed deprovisioning at authenticate-time, the admin-console SSO/SCIM card. ~80 new tests (jwt / oidc / saml / federated-auth / scim-service unit; `ScimStore` contract suite; gateway SCIM CRUD + token guard + isolation + disabled-404; SSO status + JWT-through-middleware; `ragctl`). All gates green (ruff, mypy --strict, RAG001, schema/openapi/config-drift, policy-coverage, log-schema/event-registry/PII). [ADR-0040](docs/adr/ADR-0040-sso-scim.md), [reference/sso.md](docs/reference/sso.md), [architecture/sso-scim.md](docs/architecture/sso-scim.md)

### 6.9 — Air-gapped install bundle ✅ [#161](https://github.com/officialCodeWork/AgentContextOS/pull/161)

- Ships 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. Packages what already exists — the gateway image (built from `./Dockerfile`, signed keyless in `docker.yml`) + the chart (0.9) + the runtime image set (`docker-compose`)
- **Integrity = a standard `SHA256SUMS` + optional cosign** (mirrors the 6.6b WORM export). A `content_hash` (SHA-256 over the canonical `SHA256SUMS`) is **always** present for tamper-evidence and is verifiable with nothing but `sha256sum -c` — no network, no cosign — and is pinned in `manifest.json`. 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 disagree; `manifest`/`SHA256SUMS`/`*.sig`/`*.pem` are excluded from the hashed payload
- **Standalone `install.{sh,ps1}` need no Python workspace** — an air-gap host has bash/pwsh + docker + helm (+ maybe cosign / sha256sum), not uv or the repo. Shipped *inside* every bundle, they verify → `docker load images.tar` → `helm upgrade --install`; `ragctl airgap install` is the same flow for operators who have the toolchain. `--verify-only` checks integrity without installing
- **Build/verify logic in `ragctl.airgap`** (under `packages/`, so `mypy --strict` + unit-tested): a **pure** core (`BundleManifest` model, `render_sha256sums` / `content_hash` / `build_manifest` / `verify_bundle`) cleanly separated from the **subprocess seam** (docker / helm / cosign through one `_run` chokepoint). A **`--dry-run`** produces a complete, *verifiable* bundle minus the image blobs, so the whole packaging + verification path is testable with no Docker
- **Digest-pinned, manifest-driven image set:** `infra/airgap/images.txt` lists the third-party images (tags); the build resolves each to its digest into `manifest.json`. The gateway image is added from the chart's `image.repository` + `--version`, so the app image is always release-versioned. **Key-based cosign** is the air-gap recommendation (keyless needs Rekor + a deployment-specific identity policy); the release path (`release-airgap.yml` on `v*` tags) signs keyless and attaches the tarball to the GitHub Release
- **Scope:** docker-based image load + the gateway chart. **Deferred:** `ctr`/podman load, registry re-tag/push, multi-arch selection, bundling the *backend* charts (chart deploys the gateway; backends stay external), TUF-rooted offline keyless verify. `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), shell installer syntax-checked + exercised via `--verify-only`. All gates green (ruff, mypy --strict, RAG001, schema/openapi/config-drift, policy-coverage, log-schema). [ADR-0041](docs/adr/ADR-0041-airgap-bundle.md), [reference/airgap.md](docs/reference/airgap.md), [architecture/airgap-bundle.md](docs/architecture/airgap-bundle.md), [guides/airgap-install.md](docs/guides/airgap-install.md)

---

## Phase 7 — Pilot, Harden, GA (Weeks 34–40) ⏳
Expand Down
20 changes: 20 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,26 @@ tasks:
cmds:
- helm template rag-platform infra/helm/rag-platform/

# ---------------------------------------------------------------------------
# Air-gapped install bundle (Step 6.9)
# ---------------------------------------------------------------------------
airgap:build:
desc: "Build the signed offline install bundle → dist/airgap.tar.gz (needs docker + helm + cosign)"
cmds:
- uv run ragctl airgap build --sign

airgap:build-dry:
desc: "Build a dry-run bundle (no docker/helm/cosign) — preview packaging + verify logic"
cmds:
- uv run ragctl airgap build --dry-run

airgap:verify:
desc: "Verify an air-gapped bundle's content hash + signature (BUNDLE=dist/airgap.tar.gz)"
vars:
BUNDLE: '{{.BUNDLE | default "dist/airgap.tar.gz"}}'
cmds:
- uv run ragctl airgap verify {{.BUNDLE}}

# ---------------------------------------------------------------------------
# Cleanup — platform-specific commands via platforms: key
# ---------------------------------------------------------------------------
Expand Down
Loading
Loading