From 19d6e3af9f47304e560dd298c36c2ffc116ce8e0 Mon Sep 17 00:00:00 2001 From: Deep Kumar Singh Kushwah Date: Wed, 10 Jun 2026 02:57:18 +0530 Subject: [PATCH] feat(release): rag-platform PyPI meta + release.yml fans one tag to every channel (Step 7.7) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Meet the 7.7 bar — one-command install per channel, all artifacts signed + SBOM-attested — by adding a server meta-package and a release path that fans one tag out to every channel with the same signing posture the gateway image had. - packaging/rag-platform/: PyPI meta-distribution pinning the workspace component dists (pip install rag-platform). Existing agentcontextos SDK scope kept (no rename to ragplatform). - .github/workflows/release.yml: on a vX.Y.Z tag, publish PyPI (OIDC Trusted Publishing for meta + SDK), npm (@agentcontextos/sdk, provenance), the admin-ui image (cosign + SBOM), and the Helm chart to OCI (cosign). Alongside docker.yml (gateway image) + release-airgap.yml on the same tag. - apps/admin-ui/Dockerfile: Next.js standalone image. - packaging/README.md channels matrix + docs/guides/packaging-distribution.md + ADR-0049. Deferred: Go/Java/.NET SDK publish; worker/eval-runner images (single-process today). Verified: release.yml + pricing parse, pyproject (16 deps), 216 links. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/release.yml | 131 ++++++++++++++++++++ TRACKER.md | 18 ++- apps/admin-ui/Dockerfile | 28 +++++ docs/README.md | 2 + docs/adr/ADR-0049-packaging-distribution.md | 62 +++++++++ docs/guides/packaging-distribution.md | 57 +++++++++ packaging/README.md | 39 ++++++ packaging/rag-platform/README.md | 15 +++ packaging/rag-platform/pyproject.toml | 57 +++++++++ 9 files changed, 405 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 apps/admin-ui/Dockerfile create mode 100644 docs/adr/ADR-0049-packaging-distribution.md create mode 100644 docs/guides/packaging-distribution.md create mode 100644 packaging/README.md create mode 100644 packaging/rag-platform/README.md create mode 100644 packaging/rag-platform/pyproject.toml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..5a6dd98 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,131 @@ +name: Release + +# Tag-triggered distribution. On a `vX.Y.Z` tag this publishes the user-facing +# install channels; docker.yml (gateway image) and release-airgap.yml (offline +# bundle) fire on the same tag, so one tag fans out to every channel. +on: + push: + tags: ["v*.*.*"] + workflow_dispatch: + inputs: + dry_run: + description: "Build artifacts but skip publishing" + type: boolean + default: true + +permissions: + contents: read + +env: + REGISTRY: ghcr.io + +jobs: + pypi: + name: PyPI (rag-platform + SDK) + runs-on: ubuntu-22.04 + permissions: + id-token: write # PyPI Trusted Publishing (OIDC) — no API token + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - run: pip install build + - name: Build meta-distribution + SDK + run: | + python -m build --outdir dist-pypi packaging/rag-platform + python -m build --outdir dist-pypi sdks/python + - name: Publish to PyPI + if: ${{ github.event_name == 'push' || !inputs.dry_run }} + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist-pypi + + npm: + name: npm (@agentcontextos/sdk) + runs-on: ubuntu-22.04 + permissions: + id-token: write # npm provenance + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-node@v4 + with: + node-version: 20 + registry-url: "https://registry.npmjs.org" + - working-directory: sdks/typescript + run: | + npm ci + npm run build + - name: Publish (with provenance) + if: ${{ github.event_name == 'push' || !inputs.dry_run }} + working-directory: sdks/typescript + run: npm publish --provenance --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + admin-ui-image: + name: Container — admin-ui (sign + SBOM) + runs-on: ubuntu-22.04 + permissions: + packages: write + id-token: write # cosign keyless OIDC + env: + IMAGE_NAME: ${{ github.repository_owner }}/agentcontextos/admin-ui + steps: + - uses: actions/checkout@v6 + - run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> "$GITHUB_ENV" + - uses: docker/setup-buildx-action@v4 + - uses: docker/login-action@v4 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - id: meta + uses: docker/metadata-action@v6 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,prefix=sha- + - id: build + uses: docker/build-push-action@v7 + with: + context: . + file: apps/admin-ui/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + - uses: sigstore/cosign-installer@v3 + - name: Sign (keyless) + run: cosign sign --yes "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}" + - name: SBOM + uses: anchore/sbom-action@v0 + with: + image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} + artifact-name: admin-ui.spdx.json + format: spdx-json + + helm-oci: + name: Helm chart → OCI (sign) + runs-on: ubuntu-22.04 + permissions: + packages: write + id-token: write # cosign keyless OIDC + steps: + - uses: actions/checkout@v6 + - uses: azure/setup-helm@v4 + - uses: sigstore/cosign-installer@v3 + - name: Package + push + sign + run: | + echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login "${REGISTRY}" -u "${{ github.actor }}" --password-stdin + repo="oci://${REGISTRY}/$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')/agentcontextos/charts" + helm package infra/helm/rag-platform --destination . + chart="$(ls rag-platform-*.tgz)" + out="$(helm push "${chart}" "${repo}" 2>&1)"; echo "${out}" + digest="$(echo "${out}" | awk '/Digest:/ {print $2}')" + name="$(helm show chart infra/helm/rag-platform | awk '/^name:/{print $2}')" + cosign sign --yes "${REGISTRY}/$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')/agentcontextos/charts/${name}@${digest}" diff --git a/TRACKER.md b/TRACKER.md index 00b44b7..60ae7f9 100644 --- a/TRACKER.md +++ b/TRACKER.md @@ -14,12 +14,13 @@ | | | |---|---| | **Last updated** | 2026-06-10 | -| **Current phase** | Phase 7 — Pilot, Harden, GA (**6 / 10 steps**) — Phases 0–6 ✅ complete | -| **Overall** | **80 / 84 steps** — Phases 0–6 complete | -| **Next action** | **Step 7.7 — Packaging & distribution**: PyPI `rag-platform`, npm `@ragplatform/sdk`, GHCR images (cosign + SBOM), Helm OCI repo, air-gap bundle per release; one-command install per channel; release workflow. | +| **Current phase** | Phase 7 — Pilot, Harden, GA (**7 / 10 steps**) — Phases 0–6 ✅ complete | +| **Overall** | **81 / 84 steps** — Phases 0–6 complete | +| **Next action** | **Step 7.8 — Support, SLAs, on-call**: support tiers (Community/Pro/Business/Enterprise); SLA targets; incident response + postmortem template; per-alert runbooks; public status page; PagerDuty tie-in. | **Recently shipped** +- **7.7** ✅ Packaging & distribution — **one-command install per channel** + **one tag fans out to every channel**. New `rag-platform` PyPI **meta-package** (`packaging/rag-platform/`) pins the workspace component dists for a reproducible `pip install rag-platform`; the existing `agentcontextos` SDK scope is kept (no rename). A new `release.yml` publishes PyPI (OIDC Trusted Publishing) + npm (`@agentcontextos/sdk`, provenance) + the **admin-ui image** (new `apps/admin-ui/Dockerfile`, cosign + SBOM) + the Helm chart → **OCI** (cosign), alongside the existing `docker.yml` (gateway image, cosign + SBOM) and `release-airgap.yml` — all keyed off the same `vX.Y.Z` tag. Deferred: Go/Java/.NET SDK publish, worker/eval-runner images (single-process today). [ADR-0049](docs/adr/ADR-0049-packaging-distribution.md) [#180](https://github.com/officialCodeWork/AgentContextOS/pull/180) - **7.6** ✅ Marketplace listings — listing artifacts for AWS / Azure / GCP under a new `marketplace/` (approval + procurement stay an external per-cloud process, like the 7.3 pentest). **One canonical `pricing.yaml`** (tiers + usage-metered dimensions whose ids match the Step 7.9 metering signals) + **one shared `listing-content.md`** mapped to all three clouds, so listings can't drift and prices reconcile with metering. Each per-cloud spec maps the model to that cloud's billing primitives and **reuses existing delivery** (Helm / AMI / air-gap bundle / GHCR — no new packaging); per-cloud submission checklists + a procurement acceptance test in the guide. [ADR-0048](docs/adr/ADR-0048-marketplace-listings.md) [#179](https://github.com/officialCodeWork/AgentContextOS/pull/179) - **7.5** ✅ Documentation site — a **Docusaurus 3** app (`website/`) that serves the repo `docs/` tree **in place** (single source of truth; `markdown.format: 'detect'` renders hand-written `.md` as CommonMark). The **REST API reference** (`docs/reference/rest-api.md`) is **generated + drift-gated** from `dist/openapi.json` by `scripts/gen_api_reference.py` (`task docs:api`) — never hand-edited. Doc honesty is a `tests/docs/` suite (every `ragctl` / `/v1/` reference in a quickstart must be real) + `lychee` offline link-check + `codespell`, wired into a new `docs` CI workflow. Deferred: Algolia search, versioned docs, the deploy workflow. [ADR-0047](docs/adr/ADR-0047-documentation-site.md) [#178](https://github.com/officialCodeWork/AgentContextOS/pull/178) - **7.4** ✅ Design-partner pilots — the pilot program shipped as a **repo-backed machine** (signing the referenceable partners is the external GTM deliverable, like the 7.3 pentest): an operator runbook + five fill-in templates (`docs/pilots/`), a **customer-support/KB kit** (`docs/pilots/customer-support/` — sample corpus with synthetic PII + a planted injection probe; domain-calibrated criteria), and **`ragctl pilot`** (`onboard` renders the per-tenant config + checklist; `report` assembles a weekly-KPI dashboard + **PASS/FAIL** verdict from the platform's own feedback / drift / cost signal components — the same ones behind `GET /v1/status/*`). KPIs are **pulled, not self-reported**. A worked case study runs it end-to-end on the kit with real `ragctl pilot report` output (satisfaction **+0.733**, **0/5** drift, cost **ok** → **PASS**) + the PII-redaction + injection-blocked security demo. No `dist`/SPI/config change. [#174](https://github.com/officialCodeWork/AgentContextOS/pull/174) @@ -810,7 +811,7 @@ New ground — the only prior crypto was HMAC signing. The V1 plan calls for en | 7.4 | Design partner onboarding | ✅ | [#174](https://github.com/officialCodeWork/AgentContextOS/pull/174) — repo-backed pilot program: operator runbook + 5 templates (`docs/pilots/`) + ADR-0046; **customer-support/KB kit** (corpus w/ PII + planted injection probe; domain criteria); **`ragctl pilot`** `onboard` + `report` (weekly KPIs + PASS/FAIL verdict from feedback/drift/cost signal components, KPIs pulled not self-reported); worked case study (real `pilot report` → PASS). Signing partners = external GTM item | | 7.5 | Documentation site | ✅ | [#178](https://github.com/officialCodeWork/AgentContextOS/pull/178) — Docusaurus app (`website/`) serving `docs/` in place; **generated + drift-gated REST API reference** from `dist/openapi.json`; `tests/docs/` quickstart-honesty suite + `lychee`/`codespell`; `docs` CI workflow; `task docs:api`/`docs:build` | | 7.6 | Marketplace listings | ✅ | [#179](https://github.com/officialCodeWork/AgentContextOS/pull/179) — `marketplace/` listing artifacts (AWS/Azure/GCP); one canonical `pricing.yaml` (dims = 7.9 metering signals) + shared listing copy mapped to all three; reuse Helm/AMI/airgap/GHCR delivery; submission checklists + procurement test; approval = external process | -| 7.7 | Packaging & distribution | ⏳ | PyPI publish (`rag-platform`), npm publish (`@ragplatform/sdk`), Docker Hub images | +| 7.7 | Packaging & distribution | ✅ | [#180](https://github.com/officialCodeWork/AgentContextOS/pull/180) — `rag-platform` PyPI meta-package; `release.yml` fans one tag out to PyPI/npm/GHCR(admin-ui)/Helm-OCI (cosign-keyless + SPDX SBOM + OIDC/provenance) alongside `docker.yml`+`release-airgap.yml`; `apps/admin-ui/Dockerfile`; channels matrix + guide | | 7.8 | Support & SLA | ⏳ | Support tiers defined; SLA dashboards; PagerDuty integration; runbooks | | 7.9 | Billing integration | ⏳ | Stripe metered billing; usage export API; invoice generation | | 7.10 | GA cutover | ⏳ | `main` tag `v1.0.0`; release notes; all Phase 7 exit gates passed | @@ -866,6 +867,14 @@ New ground — the only prior crypto was HMAC signing. The V1 plan calls for en - **Reuse existing delivery — no new packaging.** AWS (SaaS + AMI), Azure (SaaS + managed app), GCP (SaaS + K8s app) each map the model to that cloud's billing primitives and deploy via the existing Helm chart (`infra/`) + air-gap bundle (6.9) + GHCR/OCI artifacts (7.7). The per-cloud Marketplace wrappers (packer AMI, Azure ARM, GCP `schema.yaml`) are thin shells, skeletoned. - **Scope:** `marketplace/` (canonical pricing + shared copy + three per-cloud specs + checklists) + the process guide. No code / `dist` change. **Deferred:** the Marketplace wrapper artifacts, the procurement/metering API integrations, and the actual submissions/approvals (external). Pure docs/manifests, link-checked. [ADR-0048](docs/adr/ADR-0048-marketplace-listings.md), [guides/marketplace-listings.md](docs/guides/marketplace-listings.md). +### 7.7 — Packaging & distribution ✅ [#180](https://github.com/officialCodeWork/AgentContextOS/pull/180) + +- The acceptance bar — **one-command install from every channel, all artifacts signed + SBOM-attested** — met by adding a server meta-package + a release path that fans one tag out to every channel with the same signing posture the gateway image already had. +- **`rag-platform` PyPI meta-package** (`packaging/rag-platform/`) pins the workspace component distributions, so `pip install rag-platform==X` resolves a reproducible server stack (optional backends + cloud KMS as extras). The `agentcontextos` SDK stays a separate, lighter dist; **the existing `agentcontextos` / `@agentcontextos/sdk` scope is kept — no rename** (the plan's aspirational `ragplatform` names would break existing consumers). +- **One tag → every channel.** A `vX.Y.Z` tag triggers `docker.yml` (gateway image, cosign + SBOM, already shipped), the new **`release.yml`** (PyPI Trusted Publishing for the meta + SDK · npm with provenance · the **admin-ui** image via a new `apps/admin-ui/Dockerfile`, cosign + SBOM · the Helm chart pushed to **OCI** + cosign-signed), and `release-airgap.yml` (signed offline bundle). Kept as separate workflows so each re-runs independently. +- **Signed + SBOM, keyless.** cosign keyless (GitHub OIDC) for images + chart, SPDX SBOM per image, OIDC Trusted Publishing for PyPI, `--provenance` for npm, cosign-over-`SHA256SUMS` for the air-gap bundle — no long-lived registry tokens. +- **Scope:** the meta-package + `release.yml` + the admin-ui Dockerfile + a channels-matrix `packaging/README.md` + the guide. **Deferred:** publishing the generated Go/Java/.NET SDKs; separate `worker`/`eval-runner` images (single gateway process today; `core` is a library, not an image); the one-time trusted-publisher / GHCR setup + first publish (external). [ADR-0049](docs/adr/ADR-0049-packaging-distribution.md), [guides/packaging-distribution.md](docs/guides/packaging-distribution.md). + --- ## PR & Branch History @@ -1019,6 +1028,7 @@ Complete log of every PR. Routine Dependabot bumps are grouped; everything else | [#177](https://github.com/officialCodeWork/AgentContextOS/pull/177) | 2026-06-10 | feat(admin-ui): wire dashboard + audit page to live data; clearer trace help | | [#178](https://github.com/officialCodeWork/AgentContextOS/pull/178) | 2026-06-10 | feat(docs): Docusaurus documentation site + generated API reference + doc-tests (Step 7.5) | | [#179](https://github.com/officialCodeWork/AgentContextOS/pull/179) | 2026-06-10 | docs(marketplace): AWS/Azure/GCP listing artifacts + canonical pricing model (Step 7.6) | +| [#180](https://github.com/officialCodeWork/AgentContextOS/pull/180) | 2026-06-10 | feat(release): rag-platform PyPI meta + release.yml (PyPI/npm/Helm-OCI/admin-ui image) (Step 7.7) | | #78–#80, #116–#118 | Open | Dependabot bumps — awaiting merge | | #81 | Closed | Dependabot bump — superseded | diff --git a/apps/admin-ui/Dockerfile b/apps/admin-ui/Dockerfile new file mode 100644 index 0000000..9c3d0ce --- /dev/null +++ b/apps/admin-ui/Dockerfile @@ -0,0 +1,28 @@ +# Admin console image — Next.js standalone output (next.config.ts: output:'standalone'). +# Build context is the repo root: docker build -f apps/admin-ui/Dockerfile . +FROM node:20-bookworm-slim AS deps +WORKDIR /app +COPY apps/admin-ui/package.json apps/admin-ui/package-lock.json* apps/admin-ui/pnpm-lock.yaml* ./ +RUN if [ -f pnpm-lock.yaml ]; then corepack enable && pnpm i --frozen-lockfile; \ + elif [ -f package-lock.json ]; then npm ci; \ + else npm install; fi + +FROM node:20-bookworm-slim AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY apps/admin-ui/ ./ +RUN npm run build + +# Minimal runtime: just the standalone server + static assets, non-root. +FROM node:20-bookworm-slim AS runner +WORKDIR /app +ENV NODE_ENV=production +ENV PORT=3100 +RUN addgroup --system --gid 1001 nodejs \ + && adduser --system --uid 1001 nextjs +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +USER nextjs +EXPOSE 3100 +CMD ["node", "server.js"] diff --git a/docs/README.md b/docs/README.md index f90e64a..6d836ab 100644 --- a/docs/README.md +++ b/docs/README.md @@ -134,6 +134,7 @@ | [design-partner-pilots.md](guides/design-partner-pilots.md) | Design-partner pilot runbook (Step 7.4): the pilot lifecycle (qualify → onboard → run → review → graduate); roles; onboarding as a configured deployment; **signed success criteria** (quality/latency/integration/security) each tied to a platform signal; the **weekly KPI** dashboard pulled from `GET /v1/status/{metrics,feedback,drift,cost,health}` + the eval harness (assembled by `ragctl pilot report`); the intake → triage → incorporate → close feedback loop; acceptance (≥ 3 consecutive green weeks · 3 referenceable tenants) + the case study; the in-repo-machine vs external-GTM split | | [documentation-site.md](guides/documentation-site.md) | The documentation site (Step 7.5): the Docusaurus app under `website/` that serves `docs/` in place; running/building it; the generated REST API reference; the CI gates (API-ref drift · quickstart doc-tests · spell-check · `lychee` link-check · site build); adding docs | | [marketplace-listings.md](guides/marketplace-listings.md) | Cloud marketplace listings (Step 7.6): what's in-repo (`marketplace/` — one canonical `pricing.yaml` + shared listing copy + per-cloud AWS/Azure/GCP specs) vs the external approval/procurement process; reusing the Helm/AMI/airgap/GHCR delivery; the submission checklists + the procurement acceptance test | +| [packaging-distribution.md](guides/packaging-distribution.md) | Packaging & distribution (Step 7.7): the one-command install per channel (PyPI `rag-platform`, npm `@agentcontextos/sdk`, GHCR images, Helm OCI, air-gap); how one `vX.Y.Z` tag fans out across `docker.yml` + `release.yml` + `release-airgap.yml`; cosign-keyless + SPDX SBOM + OIDC/provenance signing; verification commands | | [curl-quickstart.md](guides/curl-quickstart.md) | 🥈 Curl-able RAG (Step 3.1): 5-minute walkthrough from `curl` to gateway response, including ingest, query, generate, OpenAPI | | [grpcurl-quickstart.md](guides/grpcurl-quickstart.md) | gRPC quickstart (Step 3.2): 5-minute walkthrough using `grpcurl` against the in-process server — health check, list corpora, server-streaming query, structured errors | | [mcp-quickstart.md](guides/mcp-quickstart.md) | MCP quickstart (Step 3.3): 5-minute walkthrough — `ragctl mcp-query`, running the stdio server, mounting `@ragplatform/mcp` in Claude Desktop, the three tools, error shape | @@ -200,6 +201,7 @@ broken, and what to fix before committing to the next phase. | [ADR-0045-red-team-security.md](adr/ADR-0045-red-team-security.md) | Decision (Step 7.3, Phase-7 hardening): turn the governance stack into an **adversarial probe gate** (injection / PII / ACL / tenant-escape) + close the injection gap. New **`rag-injection`** package: a pluggable `InjectionDetector` (dependency-free `HeuristicInjectionDetector`, attack-grammar regexes) + `PromptInjectionGuard.inspect` that drops hijack chunks, paired with the `INJECTION_RESISTANT_SYSTEM_PROMPT` so untrusted context is **fenced data in the user turn, never a system-trust position** (fixes the OpenAI-chat surface that injected context as a `system` turn); wired on `/v1/query` + `/v1/chat/completions` + MCP; off by default (`cfg.injection`). Deterministic CI gate: a ≥ 500 known + ≥ 500 generated corpus (`eval/redteam_v0/`) at **≥ 95 % block** + a **false-positive bound** + the no-system-position invariant end-to-end; building it *hardened the detector*. PII-egress probe over `PiiPolicyEngine` (zero leakage, second-detector verified); `redteam` marker + `redteam-gate` CI job; `pip-audit` is the CVE gate. Injection types are internal (no attacker signal, `dist` untouched). Deferred/process: the external pentest, a real ML classifier behind the seam; rejected a core SPI, surfacing the verdict, tuning to a circular 100 % | | [ADR-0046-design-partner-pilots.md](adr/ADR-0046-design-partner-pilots.md) | Decision (Step 7.4): ship the pilot **machine** in-repo (runbook + templates + per-vertical kits + a `ragctl pilot` KPI reader) while the partner **relationships** stay an external GTM deliverable (like the 7.3 pentest); each success criterion (quality / latency / integration / security) maps to a platform signal (eval / feedback / drift / cost / metrics / compliance) so KPIs are **pulled, not self-reported**; sliced 7.4a–d, leading with customer-support/KB, the framework vertical-extensible; no new package / core type / governed SPI call / `dist` change — the report reads existing status endpoints; rejected a pure-external motion, self-reported KPIs, a `rag-pilot` package, one generic kit | | [ADR-0047-documentation-site.md](adr/ADR-0047-documentation-site.md) | Decision (Step 7.5): publish docs via **Docusaurus** sourcing the repo `docs/` tree **in place** (single source of truth, no copy); `markdown.format: 'detect'` so hand-written `.md` renders as CommonMark; the **REST API reference is generated + drift-gated** from `dist/openapi.json` (a committed file, not a build-time plugin); doc honesty is a `tests/docs/` suite (every `ragctl` / `/v1/` reference is real) + `lychee` + `codespell`; rejected MkDocs, copying `docs/`, an OpenAPI plugin | +| [ADR-0049-packaging-distribution.md](adr/ADR-0049-packaging-distribution.md) | Decision (Step 7.7): a `rag-platform` PyPI **meta-package** pins the workspace component dists (one-command server install); keep the existing `agentcontextos` SDK scope (no rename); **one `vX.Y.Z` tag fans out** to PyPI/npm/GHCR/Helm-OCI/air-gap across `docker.yml` + a new `release.yml` + `release-airgap.yml`; cosign-keyless + SPDX SBOM + OIDC/provenance everywhere; deferred Go/Java/.NET publish + worker/eval-runner images; rejected a `ragplatform` rename + one mega-workflow | | [ADR-0048-marketplace-listings.md](adr/ADR-0048-marketplace-listings.md) | Decision (Step 7.6): one canonical `marketplace/pricing.yaml` (metered dims = the Step 7.9 signals) + one shared listing copy mapped to all three clouds, so listings can't drift and prices reconcile with metering; **reuse existing delivery** (Helm / AMI / airgap / GHCR) — the per-cloud Marketplace wrappers are thin shells; approval + procurement are documented external process, not a faked status; rejected per-cloud pricing, custom packaging, encoding a "live" status | | [ADR-0042-compliance-posture.md](adr/ADR-0042-compliance-posture.md) | Decision (Step 6.10, Phase-6 capstone): add the three compliance pieces on top of the controls the platform already ships (audit/ACL/PII/BYOK/SSO/quotas). New `rag-compliance` package (config-free, like rag-feedback/rag-drift): `RetentionEnforcer` drives tenant-scoped `purge_*`; `compliance_posture`/`residency_ok` are pure. **Retention is a capability on the existing stores, not a new SPI** — non-abstract `purge_before`/`purge_tenant` (default no-op) on Feedback/Provenance, with `dry_run` in the SPI so a preview counts-without-deleting uniformly (ProvenanceStore has no `list`). **Audit is never purged in place** (the hash chain would break) — audit retention is the 6.6b WORM export; `audit_days` is advisory. **Right-to-erasure is always-on, tenant-self-service, two-flag** — `POST /v1/compliance/erase` erases the *calling* tenant's data (scope from the principal, never the body), dry-run by default, delete needs `dry_run=false` AND `confirm=true`. **Residency = declared per tenant + enforced at ingest** (`tenants[].data_region` vs `cfg.compliance.region` → 403), opt-in, a single-deployment assertion not multi-region routing. **The SOC 2 / GDPR mapping is a doc backed by a live posture** (`GET /v1/status/compliance` reports which controls are on, so the mapping is checkable). Deferred: subject-level (vs tenant-level) erasure, an admin retention-sweep endpoint, multi-region routing, automated audit-evidence bundles; rejected purging the audit chain, a `Purgeable` SPI mixin, a static doc with no live backing | | [ADR-0041-airgap-bundle.md](adr/ADR-0041-airgap-bundle.md) | Decision (Step 6.9): ship the platform as one signed, self-contained offline bundle (all runtime images + Helm chart + config + installer). Integrity reuses the WORM-export pattern (6.6b): a standard `SHA256SUMS` whose hash is pinned as `manifest.content_hash` is the **hard gate** — verifiable with nothing but `sha256sum`, no network/cosign — and a cosign signature **over `SHA256SUMS`** adds authenticity; the *same* `SHA256SUMS` drives the Python verifier and the standalone shell installer so they can't diverge. The shell/pwsh `install.{sh,ps1}` (shipped inside the bundle) need only docker+helm (air-gap hosts lack uv/the workspace); `ragctl airgap` holds the typed/tested build+verify logic (pure core separated from a stubbable docker/helm/cosign subprocess seam; `--dry-run` = a verifiable bundle minus image blobs, so the path is testable with no Docker). Digest-pinned manifest-driven image set (`infra/airgap/images.txt` + the chart-derived gateway image); key-based cosign is the air-gap recommendation (keyless needs Rekor + an identity policy), keyless is the connected-release path (`release-airgap.yml` on tags). Deferred: ctr/podman load, registry re-tag/push, multi-arch selection, bundling backend charts, TUF-rooted offline keyless verify; rejected `oras`/OCI (no registry to pull from in an air-gap), a second HMAC scheme (cosign already the signer), a pure-shell build (would escape mypy/tests) | diff --git a/docs/adr/ADR-0049-packaging-distribution.md b/docs/adr/ADR-0049-packaging-distribution.md new file mode 100644 index 0000000..023bbeb --- /dev/null +++ b/docs/adr/ADR-0049-packaging-distribution.md @@ -0,0 +1,62 @@ +# ADR-0049 — Packaging & distribution: a meta-package + one tag fans out to every channel + +**Status:** Accepted +**Date:** 2026-06-10 +**Step:** 7.7 — Packaging & distribution (Phase 7 — Pilot, Harden, GA) +**Related:** [guides/packaging-distribution.md](../guides/packaging-distribution.md), [packaging/](../../packaging/README.md), [3.7 SDK generation](ADR-0016-sdk-generation.md), [6.9 air-gap bundle](ADR-0041-airgap-bundle.md), [7.6 marketplace listings](ADR-0048-marketplace-listings.md), [planning/phases/phase-7-pilot-ga.md](../../planning/phases/phase-7-pilot-ga.md) + +## Context + +Step 7.7 wants one-command install from every channel (PyPI, npm, container images, +Helm OCI, air-gap), all artifacts signed + SBOM-attested. The repo already has the +gateway image build with cosign + SBOM (`docker.yml`), the air-gapped bundle +(`release-airgap.yml`), the SDKs under `sdks/` (`agentcontextos` / `@agentcontextos/sdk`), +and the Helm chart (`infra/helm/rag-platform`). The gap is a server meta-package and +a release path that publishes the remaining channels with the same signing posture. + +## Decision + +**1. `rag-platform` is the PyPI meta-distribution.** `packaging/rag-platform/` pins +the workspace component distributions (gateway + governance/retrieval/reliability +packages + `ragctl`), so `pip install rag-platform==X` resolves a reproducible +server stack; optional backends + cloud KMS are extras. The `agentcontextos` SDK +stays a separate, lighter dist. + +**2. Keep the existing `agentcontextos` scope.** The plan's aspirational +`ragplatform` names are *not* adopted — the SDKs already shipped as `agentcontextos` +/ `@agentcontextos/sdk` (ADR-0016); renaming would break existing consumers. Only +the *server meta* is the new `rag-platform` PyPI name. + +**3. One tag fans out to every channel.** A `vX.Y.Z` tag triggers three workflows: +`docker.yml` (gateway image), the new `release.yml` (PyPI Trusted Publishing for the +meta + SDK · npm with provenance · admin-ui image with cosign + SBOM · Helm chart to +OCI with cosign), and `release-airgap.yml` (signed offline bundle). Keeping them +separate (not one mega-workflow) means each can run / be re-run independently. + +**4. Signed + SBOM everywhere, keyless.** cosign keyless (GitHub OIDC) for images + +the Helm chart, SPDX SBOMs per image, OIDC Trusted Publishing for PyPI, `--provenance` +for npm, cosign-over-`SHA256SUMS` for the air-gap bundle — no long-lived registry +tokens. + +## Consequences + +- New `packaging/` (the `rag-platform` meta + a channels matrix), `release.yml`, + and an `apps/admin-ui/Dockerfile` (Next.js standalone) for a second signed image. +- A single tag produces a fully-signed, SBOM-attested release across PyPI, npm, + GHCR, Helm OCI, and the air-gap bundle. +- **Deferred:** publishing the generated Go / Java / .NET SDKs; separate `worker` / + `eval-runner` images (the platform is a single gateway process today; `core` is a + library, not an image); the actual first publish (needs the PyPI/npm trusted-publisher + + GHCR config, an external one-time setup). + +## Alternatives considered + +- **Rename everything to `ragplatform`.** Rejected — the SDKs already ship as + `agentcontextos`; renaming breaks consumers for no benefit. Only the server meta + takes the descriptive `rag-platform` name. +- **One mega release workflow.** Rejected — `docker.yml` and `release-airgap.yml` + already exist and are independently useful; `release.yml` orchestrates only the + remaining channels, and all key off the same tag. +- **Publish every workspace package as a top-level `pip install`.** Rejected as the + primary UX — the meta-package is the one-command install; components publish + underneath it. diff --git a/docs/guides/packaging-distribution.md b/docs/guides/packaging-distribution.md new file mode 100644 index 0000000..f77030f --- /dev/null +++ b/docs/guides/packaging-distribution.md @@ -0,0 +1,57 @@ +# Guide: packaging & distribution (Step 7.7) + +Every channel AgentContextOS ships through, the one-command install for each, and +how a single release tag publishes them all — signed and SBOM-attested. + +## One-command install per channel + +| Channel | Install | +|---------|---------| +| PyPI (server) | `pip install rag-platform` (or `"rag-platform[all]"`) | +| PyPI (SDK) | `pip install agentcontextos` | +| npm (SDK) | `npm i @agentcontextos/sdk` | +| Container (gateway) | `docker pull ghcr.io/officialcodework/agentcontextos/rag-gateway:vX` | +| Container (admin-ui) | `docker pull ghcr.io/officialcodework/agentcontextos/admin-ui:vX` | +| Helm (OCI) | `helm install rag oci://ghcr.io/officialcodework/agentcontextos/charts/rag-platform --version X` | +| Air-gap | download the release bundle, run `install.sh` (Step 6.9) | + +The [`rag-platform`](../../packaging/rag-platform/README.md) PyPI meta-package pins +the workspace component distributions, so `pip install rag-platform==X` resolves a +reproducible server stack. SDKs live under [`sdks/`](../../sdks). + +## One tag → every channel + +Pushing a `vX.Y.Z` tag fans out across three tag-triggered workflows: + +| Workflow | Publishes | +|----------|-----------| +| `docker.yml` | gateway image → GHCR (cosign keyless + SPDX SBOM) | +| `release.yml` | PyPI (`rag-platform` + `agentcontextos`, OIDC Trusted Publishing) · npm (`@agentcontextos/sdk`, provenance) · admin-ui image (cosign + SBOM) · Helm chart → OCI (cosign) | +| `release-airgap.yml` | signed offline bundle → GitHub Release asset | + +```bash +git tag v1.0.0 +git push origin v1.0.0 # → all three workflows run +``` + +## Signing + SBOM + +- **Container images** — cosign **keyless** (GitHub OIDC), plus an SPDX SBOM per image. + Verify: `cosign verify --certificate-identity-regexp '...' --certificate-oidc-issuer https://token.actions.githubusercontent.com`. +- **Helm chart** — cosign keyless over the pushed OCI digest. +- **PyPI** — OIDC Trusted Publishing provenance (no long-lived token). +- **npm** — `--provenance` (links the published tarball to the build). +- **Air-gap bundle** — cosign over `SHA256SUMS` (Step 6.9). + +## What's deferred + +- Publishing the Go / Java / .NET SDKs (generated under `sdks/`) via their language + toolchains. +- Separate `worker` / `eval-runner` images — the platform is a single gateway + process today; those split out post-GA. `core` is a library (PyPI), not an image. + +## See also + +- [packaging/](../../packaging/README.md) — the channels matrix + meta-package +- [ADR-0049](../adr/ADR-0049-packaging-distribution.md) — the packaging decision +- [airgap-install.md](airgap-install.md) — the offline bundle (Step 6.9) diff --git a/packaging/README.md b/packaging/README.md new file mode 100644 index 0000000..342ff2c --- /dev/null +++ b/packaging/README.md @@ -0,0 +1,39 @@ +# packaging — distribution channels (Step 7.7) + +Every supported way to install AgentContextOS, and where each is published from. +The goal (Step 7.7 acceptance): **one-command install from every channel, all +artifacts signed + SBOM-attested.** + +## Channels + +| Channel | One-command install | Published by | Signed / SBOM | +|---------|--------------------|--------------|---------------| +| **PyPI** (server) | `pip install rag-platform` | `release.yml` (PyPI Trusted Publishing, OIDC) | sdist/wheel via OIDC provenance | +| **PyPI** (SDK) | `pip install agentcontextos` | `release.yml` | OIDC provenance | +| **npm** (SDK) | `npm i @agentcontextos/sdk` | `release.yml` (npm provenance) | npm provenance | +| **Container** (gateway) | `docker pull ghcr.io/officialcodework/agentcontextos/rag-gateway:vX` | `docker.yml` | cosign (keyless) + SPDX SBOM | +| **Container** (admin-ui) | `docker pull ghcr.io/officialcodework/agentcontextos/admin-ui:vX` | `release.yml` | cosign (keyless) + SPDX SBOM | +| **Helm** (OCI) | `helm install rag oci://ghcr.io/officialcodework/agentcontextos/charts/rag-platform --version X` | `release.yml` | cosign (keyless) | +| **Air-gap bundle** | `install.sh` from the release asset | `release-airgap.yml` | cosign over `SHA256SUMS` | + +Other SDKs (Go / Java / .NET) are generated under [`../sdks/`](../sdks) and +published by their language toolchains (deferred to the release-engineering pass). + +## What runs on a release tag (`v*.*.*`) + +``` +git tag v1.0.0 && git push --tags + ├── docker.yml → gateway image (build · push · cosign · SBOM) + ├── release.yml → PyPI · npm · admin-ui image · Helm OCI chart + └── release-airgap.yml → signed offline bundle → GitHub Release asset +``` + +All three are tag-triggered, so a single tag fans out to every channel. See +[docs/guides/packaging-distribution.md](../docs/guides/packaging-distribution.md) +and [ADR-0049](../docs/adr/ADR-0049-packaging-distribution.md). + +## The meta-package + +[`rag-platform/`](rag-platform/) is the PyPI meta-distribution — it pins the +workspace component distributions so `pip install rag-platform==X` resolves a +reproducible server stack. diff --git a/packaging/rag-platform/README.md b/packaging/rag-platform/README.md new file mode 100644 index 0000000..b10bd38 --- /dev/null +++ b/packaging/rag-platform/README.md @@ -0,0 +1,15 @@ +# rag-platform + +The PyPI meta-distribution for [AgentContextOS](https://github.com/officialCodeWork/AgentContextOS) — +a production-grade, multi-tenant RAG platform. + +```bash +pip install rag-platform # full self-hosted server stack + ragctl +pip install "rag-platform[all]" # + optional backend drivers + cloud KMS +``` + +This package pins the component distributions published from the uv workspace on +the same release tag (the gateway, every governance / retrieval / reliability +package, and the `ragctl` CLI). See +[docs/guides/packaging-distribution.md](https://github.com/officialCodeWork/AgentContextOS/blob/main/docs/guides/packaging-distribution.md) +for every distribution channel (PyPI, npm, container images, Helm OCI, air-gap). diff --git a/packaging/rag-platform/pyproject.toml b/packaging/rag-platform/pyproject.toml new file mode 100644 index 0000000..d2d9797 --- /dev/null +++ b/packaging/rag-platform/pyproject.toml @@ -0,0 +1,57 @@ +# rag-platform — the PyPI meta-distribution. +# +# `pip install rag-platform` installs the full self-hosted server stack (the +# gateway + every governance / retrieval / reliability package + ragctl). It +# pins the component distributions (published from the uv workspace on the same +# release tag); optional backends + cloud KMS providers are extras. +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "rag-platform" +version = "0.10.0" +description = "AgentContextOS — production-grade, multi-tenant RAG platform (meta-distribution)." +readme = "README.md" +requires-python = ">=3.12" +license = { text = "Apache-2.0" } +authors = [{ name = "AgentContextOS" }] +keywords = ["rag", "retrieval", "llm", "vector-search", "multi-tenant"] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python :: 3.12", + "License :: OSI Approved :: Apache Software License", + "Topic :: Scientific/Engineering :: Artificial Intelligence", +] + +# Core server stack — the gateway pulls most of these transitively, but they are +# pinned explicitly so `rag-platform==X` resolves a fully-reproducible stack. +dependencies = [ + "rag-core==0.10.0", + "rag-config==0.10.0", + "rag-observability==0.10.0", + "rag-policy==0.10.0", + "rag-backends==0.10.0", + "rag-retrieval==0.10.0", + "rag-ingest==0.10.0", + "rag-guard==0.10.0", + "rag-breaker==0.10.0", + "rag-quota==0.10.0", + "rag-provenance==0.10.0", + "rag-feedback==0.10.0", + "rag-drift==0.10.0", + "rag-injection==0.10.0", + "rag-gateway==0.10.0", + "ragctl==0.10.0", +] + +[project.optional-dependencies] +# Optional backend drivers + cloud KMS providers (extras, not in the base install). +backends = ["rag-backends[pgvector,qdrant,redis,s3]==0.10.0"] +kms = ["rag-backends[kms-aws,kms-gcp,kms-azure,kms-vault]==0.10.0"] +all = ["rag-platform[backends,kms]"] + +[project.urls] +Homepage = "https://github.com/officialCodeWork/AgentContextOS" +Documentation = "https://docs.agentcontextos.io" +Source = "https://github.com/officialCodeWork/AgentContextOS"