From b16004ccd33f731ead2808b6779ddbfe6aa0906d Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Fri, 21 Aug 2026 11:18:27 +0200 Subject: [PATCH 1/4] fix(helm): preflight Agent Sandbox APIs Signed-off-by: Evan Lezar --- architecture/compute-runtimes.md | 4 +++- deploy/helm/openshell/README.md | 8 ++++++++ deploy/helm/openshell/README.md.gotmpl | 7 +++++++ .../templates/agent-sandbox-preflight.yaml | 11 +++++++++++ .../tests/agent_sandbox_preflight_test.yaml | 12 ++++++++++++ deploy/helm/openshell/values.yaml | 10 ++++++++++ docs/kubernetes/setup.mdx | 13 +++++++++++++ tasks/helm.toml | 4 ++-- 8 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 deploy/helm/openshell/templates/agent-sandbox-preflight.yaml create mode 100644 deploy/helm/openshell/tests/agent_sandbox_preflight_test.yaml diff --git a/architecture/compute-runtimes.md b/architecture/compute-runtimes.md index 207008bb36..96d97f91e3 100644 --- a/architecture/compute-runtimes.md +++ b/architecture/compute-runtimes.md @@ -336,7 +336,9 @@ chart deploys the gateway and sandbox runtime integration. The default gateway workload is a StatefulSet for SQLite-backed single-replica installs. External database-backed installs can render a Deployment with `workload.kind=deployment`; HA deployments must point `server.externalDbSecret` at an operator-managed -PostgreSQL database. +PostgreSQL database. Agent Sandbox CRDs and controller lifecycle remain +operator-owned; the chart can optionally preflight for a served supported API +but does not install the cluster-scoped dependency. Standalone local deployments start the gateway with a selected runtime such as Docker, Podman, or VM. The CLI can register multiple gateways and switch between them without changing the sandbox architecture. diff --git a/deploy/helm/openshell/README.md b/deploy/helm/openshell/README.md index 93dab354b6..817900e2d2 100644 --- a/deploy/helm/openshell/README.md +++ b/deploy/helm/openshell/README.md @@ -17,6 +17,13 @@ The Kubernetes Agent Sandbox CRDs and controller must be installed on the cluste kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/latest/download/manifest.yaml ``` +The chart does not install this cluster-scoped dependency. By default, it +fails before creating gateway resources when the cluster serves neither +supported Sandbox API (`agents.x-k8s.io/v1beta1` or +`agents.x-k8s.io/v1alpha1`). Disable the check with +`agentSandbox.preflight.enabled=false` for offline `helm template` rendering, +where Helm cannot discover cluster APIs. + ## Install on Kubernetes ```shell @@ -153,6 +160,7 @@ add `ci/values-spire.yaml` to the OpenShell release values files. | Key | Type | Default | Description | |-----|------|---------|-------------| | affinity | object | `{}` | Affinity rules for the gateway pod. | +| agentSandbox.preflight.enabled | bool | `true` | Check the live cluster for a supported Agent Sandbox API before rendering gateway resources. Disable only for offline rendering and linting. | | certManager.caSecretName | string | `"openshell-ca-tls"` | Secret created for the intermediate CA (Certificate with isCA: true). | | certManager.certificateDuration | string | `"8760h"` | Duration for cert-manager-issued certificates. | | certManager.certificateRenewBefore | string | `"720h"` | Renewal window for cert-manager-issued certificates. | diff --git a/deploy/helm/openshell/README.md.gotmpl b/deploy/helm/openshell/README.md.gotmpl index 0242d8118c..b3dd63e083 100644 --- a/deploy/helm/openshell/README.md.gotmpl +++ b/deploy/helm/openshell/README.md.gotmpl @@ -17,6 +17,13 @@ The Kubernetes Agent Sandbox CRDs and controller must be installed on the cluste kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/latest/download/manifest.yaml ``` +The chart does not install this cluster-scoped dependency. By default, it +fails before creating gateway resources when the cluster serves neither +supported Sandbox API (`agents.x-k8s.io/v1beta1` or +`agents.x-k8s.io/v1alpha1`). Disable the check with +`agentSandbox.preflight.enabled=false` for offline `helm template` rendering, +where Helm cannot discover cluster APIs. + ## Install on Kubernetes ```shell diff --git a/deploy/helm/openshell/templates/agent-sandbox-preflight.yaml b/deploy/helm/openshell/templates/agent-sandbox-preflight.yaml new file mode 100644 index 0000000000..83a742f670 --- /dev/null +++ b/deploy/helm/openshell/templates/agent-sandbox-preflight.yaml @@ -0,0 +1,11 @@ +{{/* +SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +SPDX-License-Identifier: Apache-2.0 +*/}} +{{- if .Values.agentSandbox.preflight.enabled }} +{{- $v1beta1 := or (.Capabilities.APIVersions.Has "agents.x-k8s.io/v1beta1") (.Capabilities.APIVersions.Has "agents.x-k8s.io/v1beta1/Sandbox") }} +{{- $v1alpha1 := or (.Capabilities.APIVersions.Has "agents.x-k8s.io/v1alpha1") (.Capabilities.APIVersions.Has "agents.x-k8s.io/v1alpha1/Sandbox") }} +{{- if not (or $v1beta1 $v1alpha1) }} +{{- fail "Agent Sandbox is required but neither agents.x-k8s.io/v1beta1 nor agents.x-k8s.io/v1alpha1 is served by this cluster. Install the Agent Sandbox CRDs and controller before deploying OpenShell; see deploy/helm/openshell/README.md. Set agentSandbox.preflight.enabled=false only for offline rendering." }} +{{- end }} +{{- end }} diff --git a/deploy/helm/openshell/tests/agent_sandbox_preflight_test.yaml b/deploy/helm/openshell/tests/agent_sandbox_preflight_test.yaml new file mode 100644 index 0000000000..45ab2e76b9 --- /dev/null +++ b/deploy/helm/openshell/tests/agent_sandbox_preflight_test.yaml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +suite: Agent Sandbox preflight +templates: + - templates/agent-sandbox-preflight.yaml + +tests: + - it: fails clearly by default without a supported Agent Sandbox API + asserts: + - failedTemplate: + errorPattern: "Agent Sandbox is required but neither agents.x-k8s.io/v1beta1 nor agents.x-k8s.io/v1alpha1 is served" diff --git a/deploy/helm/openshell/values.yaml b/deploy/helm/openshell/values.yaml index 33337c768e..b4b14ef9d3 100644 --- a/deploy/helm/openshell/values.yaml +++ b/deploy/helm/openshell/values.yaml @@ -133,6 +133,16 @@ service: # -- Gateway metrics service port. metricsPort: 9090 +# Agent Sandbox is a cluster-scoped prerequisite for the Kubernetes compute +# driver. OpenShell deliberately does not install its CRDs or controller. +# Enable this check for live Helm installs to fail before creating gateway +# resources when neither supported Sandbox API is served. Disable it for +# offline `helm template` and lint workflows, which cannot discover APIs. +agentSandbox: + preflight: + # -- Check the live cluster for a supported Agent Sandbox API before rendering gateway resources. Disable only for offline rendering and linting. + enabled: true + # Pod restart behavior and health probe tuning. podLifecycle: # -- Grace period, in seconds, before Kubernetes terminates the gateway pod. diff --git a/docs/kubernetes/setup.mdx b/docs/kubernetes/setup.mdx index d305cb0f8a..221f935eb6 100644 --- a/docs/kubernetes/setup.mdx +++ b/docs/kubernetes/setup.mdx @@ -38,6 +38,19 @@ kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/lates This creates the `agent-sandbox-system` namespace, installs the `sandboxes.agents.x-k8s.io` CRD, and starts the controller. +The Helm chart checks for a supported Agent Sandbox API before it creates +gateway resources. This preflight is enabled by default. Disable it only for +offline `helm template` rendering, where Helm cannot discover cluster APIs: + +```shell +helm template openshell oci://ghcr.io/nvidia/openshell/helm-chart \ + --version \ + --set agentSandbox.preflight.enabled=false +``` + +The chart does not install or upgrade the cluster-scoped Agent Sandbox CRDs or +controller. + **Air-gapped clusters:** mirror the manifest above and the `registry.k8s.io/agent-sandbox/agent-sandbox-controller` image referenced inside it to your internal registry, then point the manifest's image reference at your mirror before applying. You will also need to mirror the OpenShell gateway and sandbox images — see the chart's `image.repository` value for the gateway and `server.sandboxImage` / `server.supervisorImage` for the sandbox runtime. diff --git a/tasks/helm.toml b/tasks/helm.toml index dd5128ef64..33a61c022c 100644 --- a/tasks/helm.toml +++ b/tasks/helm.toml @@ -30,12 +30,12 @@ run = """ helm dependency build deploy/helm/openshell echo "--- helm lint: defaults ---" echo "values files: deploy/helm/openshell/values.yaml" - helm lint deploy/helm/openshell + helm lint deploy/helm/openshell --set agentSandbox.preflight.enabled=false for f in deploy/helm/openshell/ci/values-*.yaml; do variant=$(basename "$f" .yaml | sed 's/values-//') echo "--- helm lint: $variant ---" echo "values files: deploy/helm/openshell/values.yaml, $f" - helm lint deploy/helm/openshell -f "$f" + helm lint deploy/helm/openshell -f "$f" --set agentSandbox.preflight.enabled=false done echo "All variants passed." """ From 22e9812bcad211d34c7390a0b09ca4fccbe91879 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Fri, 21 Aug 2026 11:44:52 +0200 Subject: [PATCH 2/4] test(kubernetes): share Agent Sandbox setup Signed-off-by: Evan Lezar --- .agents/skills/test-release-canary/SKILL.md | 2 ++ .github/workflows/release-canary.yml | 6 +++++ e2e/support/install-agent-sandbox.sh | 16 ++++++++++++ e2e/with-kube-gateway.sh | 29 ++------------------- 4 files changed, 26 insertions(+), 27 deletions(-) create mode 100644 e2e/support/install-agent-sandbox.sh diff --git a/.agents/skills/test-release-canary/SKILL.md b/.agents/skills/test-release-canary/SKILL.md index 8d5d6d157e..5e8bbf394c 100644 --- a/.agents/skills/test-release-canary/SKILL.md +++ b/.agents/skills/test-release-canary/SKILL.md @@ -89,6 +89,8 @@ The `kubernetes` job can be reproduced on any machine with Docker and `mise inst ```shell kind create cluster --name release-canary-local +bash e2e/support/install-agent-sandbox.sh + helm install openshell oci://ghcr.io/nvidia/openshell/helm-chart \ --version 0.0.0-dev \ --namespace openshell --create-namespace \ diff --git a/.github/workflows/release-canary.yml b/.github/workflows/release-canary.yml index 799e5e971e..f77637eef2 100644 --- a/.github/workflows/release-canary.yml +++ b/.github/workflows/release-canary.yml @@ -214,7 +214,10 @@ jobs: RELEASE_NAME: openshell RELEASE_NAMESPACE: openshell KIND_GATEWAY_NAME: kind + AGENT_SANDBOX_VERSION: v0.5.0 steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Install Helm uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1 @@ -224,6 +227,9 @@ jobs: cluster_name: ${{ env.KIND_CLUSTER_NAME }} wait: 120s + - name: Install Agent Sandbox controller + run: bash e2e/support/install-agent-sandbox.sh + - name: Install OpenShell Helm chart from GHCR OCI run: | set -euo pipefail diff --git a/e2e/support/install-agent-sandbox.sh b/e2e/support/install-agent-sandbox.sh new file mode 100644 index 0000000000..012c9053f2 --- /dev/null +++ b/e2e/support/install-agent-sandbox.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +# Install the upstream Agent Sandbox CRDs and controller. Pass any kubectl +# context arguments (for example, --context kind-e2e) as script arguments. +set -euo pipefail + +agent_sandbox_version="${AGENT_SANDBOX_VERSION:-v0.5.0}" +echo "Installing agent-sandbox CRDs and controller (${agent_sandbox_version})..." +agent_sandbox_base="https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${agent_sandbox_version}" +kubectl "$@" apply -f "${agent_sandbox_base}/manifest.yaml" +kubectl "$@" wait --for=condition=Established \ + crd/sandboxes.agents.x-k8s.io --timeout=120s +kubectl "$@" -n agent-sandbox-system rollout status \ + deployment/agent-sandbox-controller --timeout=300s diff --git a/e2e/with-kube-gateway.sh b/e2e/with-kube-gateway.sh index f6d0efc4ec..c92e9dd3e5 100755 --- a/e2e/with-kube-gateway.sh +++ b/e2e/with-kube-gateway.sh @@ -103,28 +103,6 @@ kctl() { kubectl --context "${KUBE_CONTEXT}" "$@" } -wait_for_agent_sandbox_crd() { - local deadline - local established - - deadline=$(( $(date +%s) + 120 )) - while [ "$(date +%s)" -lt "${deadline}" ]; do - if kctl get crd/sandboxes.agents.x-k8s.io >/dev/null 2>&1; then - established="$(kctl get crd/sandboxes.agents.x-k8s.io \ - -o 'jsonpath={.status.conditions[?(@.type=="Established")].status}' \ - 2>/dev/null || true)" - if [ "${established}" = "True" ]; then - return 0 - fi - fi - sleep 2 - done - - echo "Timed out waiting for agent-sandbox Sandbox CRD to become Established" >&2 - kctl get crd/sandboxes.agents.x-k8s.io -o yaml >&2 || true - return 1 -} - helmctl() { helm --kube-context "${KUBE_CONTEXT}" "$@" } @@ -676,11 +654,8 @@ fi # The Kubernetes compute driver creates and watches Sandbox CRs reconciled # by the upstream agent-sandbox-controller. Without the CRD + controller, # every gateway K8s call 404s and CreateSandbox never produces a Pod. -echo "Installing agent-sandbox CRDs and controller (${AGENT_SANDBOX_VERSION})..." -_agent_sandbox_base="https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}" -kctl apply -f "${_agent_sandbox_base}/manifest.yaml" -wait_for_agent_sandbox_crd -kctl -n agent-sandbox-system rollout status deployment/agent-sandbox-controller --timeout=300s +AGENT_SANDBOX_VERSION="${AGENT_SANDBOX_VERSION}" \ + bash "${ROOT}/e2e/support/install-agent-sandbox.sh" --context "${KUBE_CONTEXT}" ACTIVE_CREDENTIAL_DRIVER="${OPENSHELL_E2E_CREDENTIAL_DRIVER:-kubernetes-secrets}" if [ "${OPENSHELL_E2E_CREDENTIAL_DRIVERS:-0}" = "1" ] \ From e8354a1fb406efa0f80868b8e10554678a8be33c Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Fri, 21 Aug 2026 14:50:40 +0200 Subject: [PATCH 3/4] fix(e2e): wait for Agent Sandbox CRD status Signed-off-by: Evan Lezar --- e2e/support/install-agent-sandbox.sh | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/e2e/support/install-agent-sandbox.sh b/e2e/support/install-agent-sandbox.sh index 012c9053f2..7b33a53eea 100644 --- a/e2e/support/install-agent-sandbox.sh +++ b/e2e/support/install-agent-sandbox.sh @@ -7,10 +7,32 @@ set -euo pipefail agent_sandbox_version="${AGENT_SANDBOX_VERSION:-v0.5.0}" + +wait_for_agent_sandbox_crd() { + local deadline + local established + + deadline=$(( $(date +%s) + 120 )) + while [ "$(date +%s)" -lt "${deadline}" ]; do + if kubectl "$@" get crd/sandboxes.agents.x-k8s.io >/dev/null 2>&1; then + established="$(kubectl "$@" get crd/sandboxes.agents.x-k8s.io \ + -o 'jsonpath={.status.conditions[?(@.type=="Established")].status}' \ + 2>/dev/null || true)" + if [ "${established}" = "True" ]; then + return 0 + fi + fi + sleep 2 + done + + echo "Timed out waiting for agent-sandbox Sandbox CRD to become Established" >&2 + kubectl "$@" get crd/sandboxes.agents.x-k8s.io -o yaml >&2 || true + return 1 +} + echo "Installing agent-sandbox CRDs and controller (${agent_sandbox_version})..." agent_sandbox_base="https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${agent_sandbox_version}" kubectl "$@" apply -f "${agent_sandbox_base}/manifest.yaml" -kubectl "$@" wait --for=condition=Established \ - crd/sandboxes.agents.x-k8s.io --timeout=120s +wait_for_agent_sandbox_crd "$@" kubectl "$@" -n agent-sandbox-system rollout status \ deployment/agent-sandbox-controller --timeout=300s From c2bf9725ad96dffd184da35db4a375d6bba561a4 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Fri, 21 Aug 2026 16:21:46 +0200 Subject: [PATCH 4/4] ci(canary): sparse-checkout sandbox helper Signed-off-by: Evan Lezar --- .github/workflows/release-canary.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-canary.yml b/.github/workflows/release-canary.yml index f77637eef2..937e774db7 100644 --- a/.github/workflows/release-canary.yml +++ b/.github/workflows/release-canary.yml @@ -216,7 +216,13 @@ jobs: KIND_GATEWAY_NAME: kind AGENT_SANDBOX_VERSION: v0.5.0 steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Checkout Agent Sandbox helper + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + sparse-checkout: | + e2e/support/install-agent-sandbox.sh + sparse-checkout-cone-mode: false + persist-credentials: false - name: Install Helm uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1