diff --git a/.agents/skills/debug-openshell-cluster/SKILL.md b/.agents/skills/debug-openshell-cluster/SKILL.md index b65bf26d2..ecc5aff7f 100644 --- a/.agents/skills/debug-openshell-cluster/SKILL.md +++ b/.agents/skills/debug-openshell-cluster/SKILL.md @@ -138,13 +138,14 @@ kubectl -n openshell rollout status statefulset/openshell Look for failed installs, unexpected values, missing namespace, wrong image tag, TLS settings that do not match the registered endpoint, and scheduling failures. -For HA or PostgreSQL-backed installs, also check the service-binding Secret and -bundled PostgreSQL workload: +For HA or PostgreSQL-backed installs, also check the external database Secret +referenced by `server.externalDbSecret` and the PostgreSQL workload if the test +or operator deployed one in-cluster: ```bash -kubectl -n openshell get secret -l app.kubernetes.io/instance=openshell -kubectl -n openshell get statefulset,pod,pvc -l app.kubernetes.io/instance=openshell -kubectl -n openshell logs statefulset/openshell-postgres --tail=200 +kubectl -n openshell get secret openshell-ha-pg -o yaml +kubectl -n openshell get deployment,service,pod -l app.kubernetes.io/name=openshell-e2e-postgres +kubectl -n openshell logs deployment/openshell-e2e-postgres --tail=200 ``` Check required Helm deployment secrets: diff --git a/.agents/skills/helm-dev-environment/SKILL.md b/.agents/skills/helm-dev-environment/SKILL.md index 58efbfef8..878d6e4da 100644 --- a/.agents/skills/helm-dev-environment/SKILL.md +++ b/.agents/skills/helm-dev-environment/SKILL.md @@ -66,9 +66,10 @@ generates mTLS secrets on first install. Envoy Gateway opt-in; see the Optional The gateway Service uses ClusterIP. Access is via Envoy Gateway (port `8080`) or `kubectl port-forward`. -**HA test deploy** (two gateway replicas + bundled PostgreSQL): uncomment +**HA test deploy** (two gateway replicas + external PostgreSQL Secret): uncomment `#- ci/values-high-availability.yaml` in `deploy/helm/openshell/skaffold.yaml`, -then run `mise run helm:skaffold:run` or `mise run helm:skaffold:dev`. +create the Secret named `openshell-ha-pg` with a `uri` key, then run +`mise run helm:skaffold:run` or `mise run helm:skaffold:dev`. ### TLS behaviour @@ -203,7 +204,7 @@ mise run helm:k3s:status | `deploy/helm/openshell/ci/values-skaffold.yaml` | Dev overrides (image pull policy, TLS disabled for local Skaffold) | | `deploy/helm/openshell/ci/values-cert-manager.yaml` | cert-manager PKI overlay (opt-in; disables pkiInitJob) | | `deploy/helm/openshell/ci/values-gateway.yaml` | Envoy Gateway GRPCRoute + Gateway overlay | -| `deploy/helm/openshell/ci/values-high-availability.yaml` | HA test overlay (`replicaCount: 2` with bundled PostgreSQL) | +| `deploy/helm/openshell/ci/values-high-availability.yaml` | HA test overlay (`replicaCount: 2` with external PostgreSQL Secret) | | `deploy/helm/openshell/ci/values-keycloak.yaml` | Keycloak OIDC overlay | | `deploy/helm/openshell/ci/values-tls-disabled.yaml` | Lint-only: TLS + auth disabled (reverse-proxy edge termination) | | `deploy/kube/manifests/envoy-gateway-openshell.yaml` | GatewayClass for Envoy Gateway (`mise run helm:gateway:apply`) | diff --git a/.github/actions/release-helm-oci/action.yml b/.github/actions/release-helm-oci/action.yml index 57c901a17..7c3b5d05e 100644 --- a/.github/actions/release-helm-oci/action.yml +++ b/.github/actions/release-helm-oci/action.yml @@ -71,14 +71,6 @@ runs: exit 1 fi - - name: Build chart dependencies - env: - CHART_DIR: ${{ steps.prep.outputs.chart_dir }} - shell: bash - run: | - set -euo pipefail - helm dependency build "${CHART_DIR}" - - name: Package Helm chart env: CHART_DIR: ${{ steps.prep.outputs.chart_dir }} diff --git a/.github/workflows/branch-e2e.yml b/.github/workflows/branch-e2e.yml index 9a67f9c20..8a9e7fe29 100644 --- a/.github/workflows/branch-e2e.yml +++ b/.github/workflows/branch-e2e.yml @@ -122,6 +122,7 @@ jobs: image-tag: ${{ github.sha }} job-name: Kubernetes HA E2E (Rust smoke) extra-helm-values: deploy/helm/openshell/ci/values-high-availability.yaml + external-postgres-secret: openshell-ha-pg core-e2e-result: name: Core E2E result diff --git a/.github/workflows/e2e-kubernetes-test.yml b/.github/workflows/e2e-kubernetes-test.yml index 8596d285b..ee9caac6f 100644 --- a/.github/workflows/e2e-kubernetes-test.yml +++ b/.github/workflows/e2e-kubernetes-test.yml @@ -27,6 +27,11 @@ on: required: false type: string default: "" + external-postgres-secret: + description: "Create an ephemeral external PostgreSQL fixture and write its URI to this Secret" + required: false + type: string + default: "" mise-version: description: "mise version to install on the bare Kubernetes e2e runner" required: false @@ -111,6 +116,7 @@ jobs: env: OPENSHELL_E2E_KUBE_CONTEXT: kind-${{ env.KIND_CLUSTER_NAME }} OPENSHELL_E2E_KUBE_EXTRA_VALUES: ${{ inputs.extra-helm-values }} + OPENSHELL_E2E_KUBE_EXTERNAL_POSTGRES_SECRET: ${{ inputs.external-postgres-secret }} IMAGE_TAG: ${{ inputs.image-tag }} OPENSHELL_REGISTRY: ghcr.io/nvidia/openshell run: mise run --no-deps --skip-deps e2e:kubernetes diff --git a/architecture/compute-runtimes.md b/architecture/compute-runtimes.md index b70a2fccc..ef6f6dc5a 100644 --- a/architecture/compute-runtimes.md +++ b/architecture/compute-runtimes.md @@ -86,7 +86,9 @@ runtime still owns GPU device injection. ## Deployment Shape -Kubernetes deployments use the Helm chart under `deploy/helm/openshell`. +Kubernetes deployments use the Helm chart under `deploy/helm/openshell`. The +chart deploys the gateway and sandbox runtime integration, but HA deployments +must point `server.externalDbSecret` at an operator-managed PostgreSQL database. 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/Chart.lock b/deploy/helm/openshell/Chart.lock deleted file mode 100644 index b079e8e6e..000000000 --- a/deploy/helm/openshell/Chart.lock +++ /dev/null @@ -1,6 +0,0 @@ -dependencies: -- name: postgresql - repository: oci://registry-1.docker.io/bitnamicharts - version: 18.6.7 -digest: sha256:e4df764483edb0695ac56dd4e27eb3a225a9c0b0ef52a8b60e3e0b51e36153ab -generated: "2026-05-28T18:05:12.507876-04:00" diff --git a/deploy/helm/openshell/Chart.yaml b/deploy/helm/openshell/Chart.yaml index 69693662b..06608adb3 100644 --- a/deploy/helm/openshell/Chart.yaml +++ b/deploy/helm/openshell/Chart.yaml @@ -11,9 +11,3 @@ type: application # empty), so a released chart automatically pulls the matching gateway and supervisor images. version: 0.0.0 appVersion: "0.0.0" -dependencies: - - name: postgresql - version: 18.6.7 - repository: oci://registry-1.docker.io/bitnamicharts - condition: postgres.enabled - alias: postgres diff --git a/deploy/helm/openshell/README.md b/deploy/helm/openshell/README.md index ab5b6eb45..343985f6f 100644 --- a/deploy/helm/openshell/README.md +++ b/deploy/helm/openshell/README.md @@ -56,7 +56,7 @@ See [`values.yaml`](values.yaml) for source defaults. Selected overlays: - [`ci/values-gateway.yaml`](ci/values-gateway.yaml) - gateway-only configuration - [`ci/values-cert-manager.yaml`](ci/values-cert-manager.yaml) - cert-manager integration - [`ci/values-keycloak.yaml`](ci/values-keycloak.yaml) - Keycloak OIDC integration -- [`ci/values-high-availability.yaml`](ci/values-high-availability.yaml) - HA gateway test overlay with bundled PostgreSQL +- [`ci/values-high-availability.yaml`](ci/values-high-availability.yaml) - CI overlay for multi-replica external PostgreSQL testing ### Database backend @@ -65,12 +65,15 @@ By default, OpenShell uses SQLite: ```yaml server: dbUrl: "sqlite:/var/openshell/openshell.db" -postgres: - enabled: false ``` #### External PostgreSQL +Use external PostgreSQL when the gateway should connect to a database managed +outside this chart. The OpenShell chart does not deploy a database; install +PostgreSQL separately using the chart, operator, or managed service that fits +your environment, then pass the connection URI through a Secret. + Create a Secret containing the PostgreSQL connection URI if one does not already exist: @@ -87,18 +90,6 @@ helm install openshell oci://ghcr.io/nvidia/openshell/helm-chart --version \ - --set postgres.enabled=true -``` - -To set an explicit password, add `--set postgres.auth.password=my-secret-password`. - #### OpenShift Append these flags to any of the PostgreSQL commands above for OpenShift: @@ -159,12 +150,6 @@ JWT signing Secret. | podLabels | object | `{}` | Extra labels to add to the gateway pod. | | podLifecycle.terminationGracePeriodSeconds | int | `5` | Grace period, in seconds, before Kubernetes terminates the gateway pod. | | podSecurityContext.fsGroup | int | `1000` | fsGroup assigned to the gateway pod. | -| postgres.auth.database | string | `"openshell"` | | -| postgres.auth.password | string | `""` | | -| postgres.auth.username | string | `"openshell"` | | -| postgres.enabled | bool | `false` | Deploy the bundled Bitnami PostgreSQL subchart. | -| postgres.primary.persistence.enabled | bool | `true` | | -| postgres.serviceBindings.enabled | bool | `true` | | | probes.liveness.failureThreshold | int | `3` | Liveness probe failure threshold before the container is restarted. | | probes.liveness.initialDelaySeconds | int | `2` | Liveness probe initial delay, in seconds. | | probes.liveness.periodSeconds | int | `5` | Liveness probe period, in seconds. | @@ -176,7 +161,7 @@ JWT signing Secret. | probes.startup.failureThreshold | int | `30` | Startup probe failure threshold before the container is killed. | | probes.startup.periodSeconds | int | `2` | Startup probe period, in seconds. | | probes.startup.timeoutSeconds | int | `1` | Startup probe timeout, in seconds. | -| replicaCount | int | `1` | Number of OpenShell gateway replicas. | +| replicaCount | int | `1` | Number of OpenShell gateway replicas. Values greater than 1 require server.externalDbSecret because the default SQLite backend is per pod. | | resources | object | `{}` | Gateway pod resource requests and limits. | | sandboxServiceAccount.annotations | object | `{}` | Annotations to add to the generated sandbox service account. | | sandboxServiceAccount.create | bool | `true` | Create a service account for sandbox pods. | diff --git a/deploy/helm/openshell/README.md.gotmpl b/deploy/helm/openshell/README.md.gotmpl index 5fc4019e8..7b70d4b80 100644 --- a/deploy/helm/openshell/README.md.gotmpl +++ b/deploy/helm/openshell/README.md.gotmpl @@ -56,7 +56,7 @@ See [`values.yaml`](values.yaml) for source defaults. Selected overlays: - [`ci/values-gateway.yaml`](ci/values-gateway.yaml) - gateway-only configuration - [`ci/values-cert-manager.yaml`](ci/values-cert-manager.yaml) - cert-manager integration - [`ci/values-keycloak.yaml`](ci/values-keycloak.yaml) - Keycloak OIDC integration -- [`ci/values-high-availability.yaml`](ci/values-high-availability.yaml) - HA gateway test overlay with bundled PostgreSQL +- [`ci/values-high-availability.yaml`](ci/values-high-availability.yaml) - CI overlay for multi-replica external PostgreSQL testing ### Database backend @@ -65,12 +65,15 @@ By default, OpenShell uses SQLite: ```yaml server: dbUrl: "sqlite:/var/openshell/openshell.db" -postgres: - enabled: false ``` #### External PostgreSQL +Use external PostgreSQL when the gateway should connect to a database managed +outside this chart. The OpenShell chart does not deploy a database; install +PostgreSQL separately using the chart, operator, or managed service that fits +your environment, then pass the connection URI through a Secret. + Create a Secret containing the PostgreSQL connection URI if one does not already exist: @@ -87,18 +90,6 @@ helm install openshell oci://ghcr.io/nvidia/openshell/helm-chart --version \ - --set postgres.enabled=true -``` - -To set an explicit password, add `--set postgres.auth.password=my-secret-password`. - #### OpenShift Append these flags to any of the PostgreSQL commands above for OpenShift: diff --git a/deploy/helm/openshell/ci/values-high-availability.yaml b/deploy/helm/openshell/ci/values-high-availability.yaml index 5ccb79a77..ba439cfbf 100644 --- a/deploy/helm/openshell/ci/values-high-availability.yaml +++ b/deploy/helm/openshell/ci/values-high-availability.yaml @@ -1,24 +1,10 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -# CI/dev overlay for exercising the gateway with more than one replica. -# SQLite is not suitable for HA because each replica has its own pod volume, so -# this overlay enables the bundled PostgreSQL dependency added by the chart. +# CI/dev overlay for exercising the gateway with more than one replica. SQLite +# is not suitable for HA because each replica has its own pod volume, so this +# overlay expects the caller to provide a PostgreSQL Secret named openshell-ha-pg. replicaCount: 2 -global: - security: - # The mirror serves the same pinned Bitnami PostgreSQL digest, but Bitnami's - # chart verification treats non-Docker-Hub registries as unrecognized. - allowInsecureImages: true - -postgres: - enabled: true - # Keep the HA CI/dev overlay off Docker Hub's unauthenticated pull path. - # The Bitnami subchart defaults to registry-1.docker.io/bitnami/postgresql:latest. - image: - registry: mirror.gcr.io - repository: bitnami/postgresql - digest: sha256:7651d7f24aad83fe68a222f7f20eded10d325c96ebee285ca5bf8162eddcba64 - auth: - password: openshell-ha-ci +server: + externalDbSecret: openshell-ha-pg diff --git a/deploy/helm/openshell/skaffold.yaml b/deploy/helm/openshell/skaffold.yaml index 9a056238a..8a4037429 100644 --- a/deploy/helm/openshell/skaffold.yaml +++ b/deploy/helm/openshell/skaffold.yaml @@ -97,7 +97,7 @@ deploy: #- ci/values-keycloak.yaml # To enable the Gateway API HTTPRoute (requires Envoy Gateway above): #- ci/values-gateway.yaml - # To test HA gateway behavior with bundled PostgreSQL: + # To test multi-replica external PostgreSQL behavior: #- ci/values-high-availability.yaml setValueTemplates: image.repository: '{{.IMAGE_REPO_openshell_gateway}}' diff --git a/deploy/helm/openshell/templates/_helpers.tpl b/deploy/helm/openshell/templates/_helpers.tpl index a8e7ac721..5876be542 100644 --- a/deploy/helm/openshell/templates/_helpers.tpl +++ b/deploy/helm/openshell/templates/_helpers.tpl @@ -102,37 +102,6 @@ Namespace where sandbox pods are created. An explicit {{- .Values.server.sandboxNamespace | default .Release.Namespace -}} {{- end }} -{{/* -Fully qualified name of the PostgreSQL subchart, mirroring the Bitnami -common.names.fullname template so we stay in sync when users set -postgres.fullnameOverride or postgres.nameOverride. -*/}} -{{- define "openshell.postgresFullname" -}} -{{- if .Values.postgres.fullnameOverride -}} -{{- .Values.postgres.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default "postgres" .Values.postgres.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end }} - -{{/* -Name of the Secret holding the PostgreSQL connection URI. -- server.externalDbSecret set: use it verbatim (always wins) -- postgres.enabled=true: derive from Bitnami service-binding naming convention -*/}} -{{- define "openshell.dbSecretName" -}} -{{- if .Values.server.externalDbSecret -}} -{{- .Values.server.externalDbSecret -}} -{{- else -}} -{{- printf "%s-svcbind-custom-user" (include "openshell.postgresFullname" .) -}} -{{- end -}} -{{- end }} - {{/* Name of the Secret holding gateway-minted sandbox JWT signing material. */}} @@ -174,3 +143,15 @@ init-container {{- printf "%s://%s.%s.svc.cluster.local:%d" $scheme (include "openshell.fullname" .) .Release.Namespace (int .Values.service.port) -}} {{- end -}} {{- end }} + +{{/* +Validate chart values that Helm would otherwise accept silently. +*/}} +{{- define "openshell.validateValues" -}} +{{- if and (hasKey .Values "postgres") (kindIs "map" .Values.postgres) (hasKey .Values.postgres "enabled") -}} +{{- fail "postgres.enabled was removed; the OpenShell chart no longer deploys PostgreSQL. Provision PostgreSQL separately and set server.externalDbSecret to a Secret containing a PostgreSQL URI." -}} +{{- end -}} +{{- if and (gt (int (default 1 .Values.replicaCount)) 1) (not .Values.server.externalDbSecret) -}} +{{- fail "replicaCount > 1 requires server.externalDbSecret; multiple gateway replicas cannot share the default per-pod SQLite database." -}} +{{- end -}} +{{- end }} diff --git a/deploy/helm/openshell/templates/gateway-config.yaml b/deploy/helm/openshell/templates/gateway-config.yaml index f46547c3f..cd21bee2f 100644 --- a/deploy/helm/openshell/templates/gateway-config.yaml +++ b/deploy/helm/openshell/templates/gateway-config.yaml @@ -9,8 +9,8 @@ still override anything in this file. One value is intentionally NOT rendered here: - server.dbUrl → passed via OPENSHELL_DB_URL env var (from Secret) - when postgres.enabled=true or server.externalDbSecret - is set, otherwise --db-url arg for SQLite + when server.externalDbSecret is set, otherwise + --db-url arg for SQLite */}} apiVersion: v1 kind: ConfigMap diff --git a/deploy/helm/openshell/templates/statefulset.yaml b/deploy/helm/openshell/templates/statefulset.yaml index d56c06355..e6cb1037e 100644 --- a/deploy/helm/openshell/templates/statefulset.yaml +++ b/deploy/helm/openshell/templates/statefulset.yaml @@ -1,8 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -{{- if and .Values.postgres.enabled (not .Values.postgres.serviceBindings.enabled) (not .Values.server.externalDbSecret) }} -{{- fail "postgres.serviceBindings.enabled must be true when using bundled PostgreSQL" }} -{{- end }} +{{- include "openshell.validateValues" . }} apiVersion: apps/v1 kind: StatefulSet metadata: @@ -56,16 +54,16 @@ spec: args: - --config - /etc/openshell/gateway.toml - {{- if not (or .Values.postgres.enabled .Values.server.externalDbSecret) }} + {{- if not .Values.server.externalDbSecret }} - --db-url - {{ .Values.server.dbUrl | quote }} {{- end }} env: - {{- if or .Values.postgres.enabled .Values.server.externalDbSecret }} + {{- if .Values.server.externalDbSecret }} - name: OPENSHELL_DB_URL valueFrom: secretKeyRef: - name: {{ include "openshell.dbSecretName" . }} + name: {{ .Values.server.externalDbSecret }} key: uri {{- end }} # All gateway settings live in the ConfigMap-backed TOML file diff --git a/deploy/helm/openshell/tests/gateway_config_test.yaml b/deploy/helm/openshell/tests/gateway_config_test.yaml index 6b14fe12a..393d59a37 100644 --- a/deploy/helm/openshell/tests/gateway_config_test.yaml +++ b/deploy/helm/openshell/tests/gateway_config_test.yaml @@ -170,98 +170,32 @@ tests: path: spec.template.spec.containers[0].args content: "sqlite:/var/openshell/openshell.db" - - it: does not pass --db-url in args when postgres.enabled is true + - it: fails when legacy postgres.enabled is set template: templates/statefulset.yaml set: postgres.enabled: true - postgres.auth.password: test-pw asserts: - - notContains: - path: spec.template.spec.containers[0].args - content: "--db-url" - - - it: does not pass --db-url in args when externalDbSecret is set - template: templates/statefulset.yaml - set: - server.externalDbSecret: my-pg-secret - asserts: - - notContains: - path: spec.template.spec.containers[0].args - content: "--db-url" - - - it: references Bitnami service-binding Secret when postgres.enabled is true - template: templates/statefulset.yaml - set: - postgres.enabled: true - postgres.auth.password: test-pw - asserts: - - contains: - path: spec.template.spec.containers[0].env - content: - name: OPENSHELL_DB_URL - valueFrom: - secretKeyRef: - name: openshell-postgres-svcbind-custom-user - key: uri - - - it: respects postgres.fullnameOverride for bundled service-binding Secret - template: templates/statefulset.yaml - set: - postgres.enabled: true - postgres.auth.password: test-pw - postgres.fullnameOverride: my-pg - asserts: - - contains: - path: spec.template.spec.containers[0].env - content: - name: OPENSHELL_DB_URL - valueFrom: - secretKeyRef: - name: my-pg-svcbind-custom-user - key: uri - - - it: respects postgres.nameOverride for bundled service-binding Secret - template: templates/statefulset.yaml - set: - postgres.enabled: true - postgres.auth.password: test-pw - postgres.nameOverride: pgdb - asserts: - - contains: - path: spec.template.spec.containers[0].env - content: - name: OPENSHELL_DB_URL - valueFrom: - secretKeyRef: - name: openshell-pgdb-svcbind-custom-user - key: uri + - failedTemplate: + errorPattern: "postgres.enabled was removed" - - it: fails when serviceBindings is disabled with bundled postgres + - it: fails when multiple replicas use the default SQLite database template: templates/statefulset.yaml set: - postgres.enabled: true - postgres.serviceBindings.enabled: false + replicaCount: 2 asserts: - failedTemplate: - errorMessage: "postgres.serviceBindings.enabled must be true when using bundled PostgreSQL" + errorPattern: "replicaCount > 1 requires server.externalDbSecret" - - it: allows serviceBindings disabled when externalDbSecret is set + - it: does not pass --db-url in args when externalDbSecret is set template: templates/statefulset.yaml set: - postgres.enabled: true - postgres.serviceBindings.enabled: false - server.externalDbSecret: my-external-secret + server.externalDbSecret: my-pg-secret asserts: - - contains: - path: spec.template.spec.containers[0].env - content: - name: OPENSHELL_DB_URL - valueFrom: - secretKeyRef: - name: my-external-secret - key: uri + - notContains: + path: spec.template.spec.containers[0].args + content: "--db-url" - - it: references externalDbSecret when set without postgres.enabled + - it: references externalDbSecret when set template: templates/statefulset.yaml set: server.externalDbSecret: my-pg-secret @@ -275,18 +209,19 @@ tests: name: my-pg-secret key: uri - - it: externalDbSecret overrides bundled secret when both are set + - it: renders HA external database configuration from the CI overlay template: templates/statefulset.yaml - set: - postgres.enabled: true - postgres.auth.password: test-pw - server.externalDbSecret: my-external-secret + values: + - ../ci/values-high-availability.yaml asserts: + - equal: + path: spec.replicas + value: 2 - contains: path: spec.template.spec.containers[0].env content: name: OPENSHELL_DB_URL valueFrom: secretKeyRef: - name: my-external-secret + name: openshell-ha-pg key: uri diff --git a/deploy/helm/openshell/values.yaml b/deploy/helm/openshell/values.yaml index f0cd43c73..91faeec28 100644 --- a/deploy/helm/openshell/values.yaml +++ b/deploy/helm/openshell/values.yaml @@ -3,7 +3,8 @@ # Default values for OpenShell -# -- Number of OpenShell gateway replicas. +# -- Number of OpenShell gateway replicas. Values greater than 1 require +# server.externalDbSecret because the default SQLite backend is per pod. replicaCount: 1 image: @@ -257,28 +258,6 @@ server: # issuer uses a non-public CA (e.g. OpenShift ingress, private PKI). caConfigMapName: "" -# Bundled PostgreSQL backing store (Bitnami subchart). -# Set enabled=true to deploy a PostgreSQL instance alongside the gateway. -# For external PostgreSQL, leave enabled=false and set server.externalDbSecret -# to a pre-existing Secret containing a `uri` key. -postgres: - # -- Deploy the bundled Bitnami PostgreSQL subchart. - enabled: false - # Values below configure the bundled Bitnami PostgreSQL subchart - # (aliased as "postgres" in Chart.yaml). The subchart uses these to - # initialise the PostgreSQL instance. - auth: - username: openshell - password: "" - database: openshell - # Bitnami service-binding Secrets — must stay true. The gateway reads - # the connection URI from the subchart-managed Secret. - serviceBindings: - enabled: true - primary: - persistence: - enabled: true - # NetworkPolicy restricting SSH ingress on sandbox pods to the gateway only. networkPolicy: # -- Create a NetworkPolicy restricting SSH ingress on sandbox pods to the gateway. diff --git a/docs/kubernetes/setup.mdx b/docs/kubernetes/setup.mdx index b21321143..78c685dd6 100644 --- a/docs/kubernetes/setup.mdx +++ b/docs/kubernetes/setup.mdx @@ -136,7 +136,9 @@ The most commonly changed values are: | Value | Purpose | |---|---| | `image.repository` / `image.tag` | Gateway container image. Defaults to `ghcr.io/nvidia/openshell/gateway:latest`. | +| `replicaCount` | Number of gateway replicas. Leave at `1` unless you are explicitly testing multi-replica behavior. | | `server.sandboxNamespace` | Namespace where sandbox pods are created. Defaults to the Helm release namespace when left empty. | +| `server.externalDbSecret` | Secret containing a PostgreSQL connection URI in the `uri` key. Use when the database is managed outside the chart. | | `server.sandboxImage` | Default sandbox image used when a sandbox does not specify one. | | `server.sandboxImagePullSecrets` | Image pull secrets attached to sandbox pods. Referenced Secrets must exist in the sandbox namespace. | | `server.grpcEndpoint` | Endpoint that sandbox supervisors use to call back to the gateway. Must be reachable from inside the cluster. | diff --git a/e2e/kubernetes/postgres-fixture.yaml b/e2e/kubernetes/postgres-fixture.yaml new file mode 100644 index 000000000..390145145 --- /dev/null +++ b/e2e/kubernetes/postgres-fixture.yaml @@ -0,0 +1,77 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +apiVersion: v1 +kind: ServiceAccount +metadata: + name: openshell-e2e-postgres + labels: + app.kubernetes.io/name: openshell-e2e-postgres +--- +apiVersion: v1 +kind: Secret +metadata: + name: openshell-e2e-postgres-credentials + labels: + app.kubernetes.io/name: openshell-e2e-postgres +type: Opaque +stringData: + password: openshell-e2e-postgres +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: openshell-e2e-postgres + labels: + app.kubernetes.io/name: openshell-e2e-postgres +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: openshell-e2e-postgres + template: + metadata: + labels: + app.kubernetes.io/name: openshell-e2e-postgres + spec: + serviceAccountName: openshell-e2e-postgres + containers: + - name: postgres + image: mirror.gcr.io/library/postgres:17.10-alpine3.23@sha256:979c4379dd698aba0b890599a6104e082035f98ef31d9b9291ec22f2b13059ca + imagePullPolicy: IfNotPresent + env: + - name: POSTGRES_USER + value: openshell + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: openshell-e2e-postgres-credentials + key: password + - name: POSTGRES_DB + value: openshell + ports: + - name: postgres + containerPort: 5432 + readinessProbe: + exec: + command: + - /bin/sh + - -ec + - pg_isready -U openshell -d openshell + initialDelaySeconds: 3 + periodSeconds: 3 + timeoutSeconds: 2 + failureThreshold: 20 +--- +apiVersion: v1 +kind: Service +metadata: + name: openshell-e2e-postgres + labels: + app.kubernetes.io/name: openshell-e2e-postgres +spec: + selector: + app.kubernetes.io/name: openshell-e2e-postgres + ports: + - name: postgres + port: 5432 + targetPort: postgres diff --git a/e2e/rust/e2e-openshift.sh b/e2e/rust/e2e-openshift.sh index 588a5572e..3abd81855 100755 --- a/e2e/rust/e2e-openshift.sh +++ b/e2e/rust/e2e-openshift.sh @@ -7,7 +7,6 @@ # Prerequisites: # - oc CLI authenticated to an OpenShift cluster # - helm 3.x installed -# - Chart dependencies built (helm dependency build deploy/helm/openshell) # # Usage: # mise run e2e:openshift @@ -15,6 +14,7 @@ set -euo pipefail +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" CHART_PATH="${CHART_PATH:-./deploy/helm/openshell}" NAMESPACE="openshell" RELEASE="openshell" @@ -23,6 +23,13 @@ WAIT_TIMEOUT="120s" PASSED=0 FAILED=0 SCENARIOS=() +EXTERNAL_PG_SECRET="my-pg-credentials" +EXTERNAL_PG_SERVICE="openshell-e2e-postgres" +EXTERNAL_PG_SERVICE_ACCOUNT="openshell-e2e-postgres" +EXTERNAL_PG_PASSWORD="openshell-e2e-postgres" +EXTERNAL_PG_DATABASE="openshell" +EXTERNAL_PG_USERNAME="openshell" +EXTERNAL_PG_MANIFEST="${ROOT}/e2e/kubernetes/postgres-fixture.yaml" while [[ $# -gt 0 ]]; do case $1 in @@ -61,6 +68,30 @@ cleanup_release() { oc delete pvc -n "$NAMESPACE" -l "app.kubernetes.io/instance=$RELEASE" --wait=false 2>/dev/null || true } +deploy_external_pg() { + local pg_uri + + log "Deploying standalone PostgreSQL as external database..." + oc create serviceaccount "$EXTERNAL_PG_SERVICE_ACCOUNT" -n "$NAMESPACE" 2>/dev/null || true + oc adm policy add-scc-to-user anyuid -z "$EXTERNAL_PG_SERVICE_ACCOUNT" -n "$NAMESPACE" >/dev/null + + oc apply -n "$NAMESPACE" -f "$EXTERNAL_PG_MANIFEST" + oc rollout status "deployment/${EXTERNAL_PG_SERVICE}" -n "$NAMESPACE" --timeout="$WAIT_TIMEOUT" + + pg_uri="postgresql://${EXTERNAL_PG_USERNAME}:${EXTERNAL_PG_PASSWORD}@${EXTERNAL_PG_SERVICE}.${NAMESPACE}.svc.cluster.local:5432/${EXTERNAL_PG_DATABASE}" + log "Creating existing Secret with PostgreSQL credentials..." + oc delete secret "$EXTERNAL_PG_SECRET" -n "$NAMESPACE" --ignore-not-found >/dev/null 2>&1 || true + oc create secret generic "$EXTERNAL_PG_SECRET" -n "$NAMESPACE" \ + --from-literal=uri="$pg_uri" +} + +cleanup_external_pg() { + oc delete -n "$NAMESPACE" -f "$EXTERNAL_PG_MANIFEST" --ignore-not-found 2>/dev/null || true + oc delete secret "$EXTERNAL_PG_SECRET" -n "$NAMESPACE" --ignore-not-found 2>/dev/null || true + oc adm policy remove-scc-from-user anyuid -z "$EXTERNAL_PG_SERVICE_ACCOUNT" \ + -n "$NAMESPACE" 2>/dev/null || true +} + verify_gateway() { local scenario="$1" if wait_for_ready "app.kubernetes.io/name=openshell,app.kubernetes.io/instance=$RELEASE" "$WAIT_TIMEOUT"; then @@ -105,73 +136,30 @@ helm install "$RELEASE" "$CHART_PATH" -n "$NAMESPACE" \ verify_gateway "$SCENARIO" cleanup_release -# --- scenario 2: Bundled PostgreSQL ------------------------------------------- - -SCENARIO="Bundled PostgreSQL" -log "Testing: $SCENARIO" -cleanup_release - -helm install "$RELEASE" "$CHART_PATH" -n "$NAMESPACE" \ - "${OPENSHIFT_FLAGS[@]}" \ - --set postgres.enabled=true - -# Wait for postgres to be ready first -log "Waiting for bundled PostgreSQL..." -wait_for_ready "app.kubernetes.io/name=postgres,app.kubernetes.io/instance=$RELEASE" "$WAIT_TIMEOUT" || true - -verify_gateway "$SCENARIO" -cleanup_release - -# --- scenario 3: External PostgreSQL with existing Secret ------------------- +# --- scenario 2: External PostgreSQL with existing Secret ------------------- SCENARIO="External PostgreSQL (externalDbSecret)" log "Testing: $SCENARIO" cleanup_release -# Deploy a standalone Bitnami PostgreSQL as the "external" database -EXTERNAL_PG_RELEASE="pg-external" -EXTERNAL_PG_PASSWORD="ext-test-password" -EXTERNAL_PG_DATABASE="openshell" -EXTERNAL_PG_USERNAME="openshell" - -log "Deploying standalone PostgreSQL as external database..." -helm install "$EXTERNAL_PG_RELEASE" oci://registry-1.docker.io/bitnamicharts/postgresql \ - -n "$NAMESPACE" \ - --set auth.username="$EXTERNAL_PG_USERNAME" \ - --set auth.password="$EXTERNAL_PG_PASSWORD" \ - --set auth.database="$EXTERNAL_PG_DATABASE" \ - --set primary.podSecurityContext.fsGroup=null \ - --set primary.containerSecurityContext.runAsUser=null \ - --wait --timeout "$WAIT_TIMEOUT" 2>/dev/null || true - -wait_for_ready "app.kubernetes.io/name=postgresql,app.kubernetes.io/instance=$EXTERNAL_PG_RELEASE" "$WAIT_TIMEOUT" || true - -EXTERNAL_PG_HOST="${EXTERNAL_PG_RELEASE}-postgresql.${NAMESPACE}.svc.cluster.local" -EXTERNAL_PG_URI="postgresql://${EXTERNAL_PG_USERNAME}:${EXTERNAL_PG_PASSWORD}@${EXTERNAL_PG_HOST}:5432/${EXTERNAL_PG_DATABASE}" - -# Create the existing Secret with the uri key -log "Creating existing Secret with PostgreSQL credentials..." -oc create secret generic my-pg-credentials -n "$NAMESPACE" \ - --from-literal=uri="$EXTERNAL_PG_URI" \ - 2>/dev/null || true +deploy_external_pg # Install OpenShell pointing at the existing Secret helm install "$RELEASE" "$CHART_PATH" -n "$NAMESPACE" \ "${OPENSHIFT_FLAGS[@]}" \ - --set server.externalDbSecret=my-pg-credentials + --set server.externalDbSecret="$EXTERNAL_PG_SECRET" verify_gateway "$SCENARIO" # Cleanup external postgres and secret cleanup_release -helm uninstall "$EXTERNAL_PG_RELEASE" -n "$NAMESPACE" --wait 2>/dev/null || true -oc delete secret my-pg-credentials -n "$NAMESPACE" 2>/dev/null || true -oc delete pvc -n "$NAMESPACE" -l "app.kubernetes.io/instance=$EXTERNAL_PG_RELEASE" --wait=false 2>/dev/null || true +cleanup_external_pg # --- teardown --------------------------------------------------------------- log "Removing SCC binding and namespace" oc adm policy remove-scc-from-user privileged -z "${RELEASE}-sandbox" -n "$NAMESPACE" 2>/dev/null || true +cleanup_external_pg oc delete ns "$NAMESPACE" --wait=false 2>/dev/null || true # --- summary ---------------------------------------------------------------- diff --git a/e2e/with-kube-gateway.sh b/e2e/with-kube-gateway.sh index 39ba899db..bea1c01d3 100755 --- a/e2e/with-kube-gateway.sh +++ b/e2e/with-kube-gateway.sh @@ -30,9 +30,15 @@ # # Database backend scenarios: # Set OPENSHELL_E2E_KUBE_DB_SCENARIOS=1 to run the test command against -# three database configurations (SQLite, bundled PostgreSQL, external -# PostgreSQL with existingSecret). When unset, the default single-install -# behavior is unchanged. +# the supported database configurations: SQLite and external PostgreSQL +# with an existing Secret. When unset, the default single-install behavior +# is unchanged. +# +# External PostgreSQL fixture: +# Set OPENSHELL_E2E_KUBE_EXTERNAL_POSTGRES_SECRET to create an ephemeral +# PostgreSQL Deployment and a matching Secret with a `uri` key before +# installing OpenShell. This is used by HA CI so the gateway can run multiple +# replicas without requiring the OpenShell chart to own a database. set -euo pipefail @@ -66,7 +72,13 @@ PORTFORWARD_LOG="${WORKDIR}/portforward.log" PORTFORWARD_HEALTH_PID="" PORTFORWARD_HEALTH_LOG="${WORKDIR}/portforward-health.log" HELM_INSTALLED=0 -EXTERNAL_PG_DEPLOYED=0 +EXTERNAL_PG_FIXTURE_DEPLOYED=0 +EXTERNAL_PG_FIXTURE_SECRET="" +EXTERNAL_PG_FIXTURE_MANIFEST="${ROOT}/e2e/kubernetes/postgres-fixture.yaml" +EXTERNAL_PG_FIXTURE_SERVICE="openshell-e2e-postgres" +EXTERNAL_PG_FIXTURE_USER="openshell" +EXTERNAL_PG_FIXTURE_PASSWORD="openshell-e2e-postgres" +EXTERNAL_PG_FIXTURE_DATABASE="openshell" # Isolate CLI/SDK gateway metadata from the developer's real config. export XDG_CONFIG_HOME="${WORKDIR}/config" @@ -80,19 +92,41 @@ helmctl() { helm --kube-context "${KUBE_CONTEXT}" "$@" } -chart_without_dependencies() { - local src="${ROOT}/deploy/helm/openshell" - local dst="${WORKDIR}/helm-chart-no-deps" - - rm -rf "${dst}" - cp -a "${src}" "${dst}" - rm -rf "${dst}/charts" "${dst}/Chart.lock" - awk ' - /^dependencies:[[:space:]]*$/ { skip = 1; next } - skip && /^[^[:space:]-]/ { skip = 0 } - !skip { print } - ' "${src}/Chart.yaml" >"${dst}/Chart.yaml" - printf '%s\n' "${dst}" +deploy_postgres_fixture() { + local secret_name="$1" + local pg_uri + + echo "Deploying external PostgreSQL fixture ${EXTERNAL_PG_FIXTURE_SERVICE}..." + if ! kctl get namespace "${NAMESPACE}" >/dev/null 2>&1; then + kctl create namespace "${NAMESPACE}" + fi + + kctl -n "${NAMESPACE}" apply -f "${EXTERNAL_PG_FIXTURE_MANIFEST}" + EXTERNAL_PG_FIXTURE_DEPLOYED=1 + EXTERNAL_PG_FIXTURE_SECRET="${secret_name}" + + kctl -n "${NAMESPACE}" rollout status "deployment/${EXTERNAL_PG_FIXTURE_SERVICE}" --timeout=120s + + pg_uri="postgresql://${EXTERNAL_PG_FIXTURE_USER}:${EXTERNAL_PG_FIXTURE_PASSWORD}@${EXTERNAL_PG_FIXTURE_SERVICE}.${NAMESPACE}.svc.cluster.local:5432/${EXTERNAL_PG_FIXTURE_DATABASE}" + kctl -n "${NAMESPACE}" delete secret "${secret_name}" \ + --ignore-not-found >/dev/null 2>&1 || true + kctl -n "${NAMESPACE}" create secret generic "${secret_name}" \ + --from-literal=uri="${pg_uri}" +} + +cleanup_postgres_fixture() { + local secret_name="$1" + + [ -n "${KUBE_CONTEXT}" ] || return 0 + [ -n "${NAMESPACE}" ] || return 0 + + kctl -n "${NAMESPACE}" delete -f "${EXTERNAL_PG_FIXTURE_MANIFEST}" \ + --ignore-not-found >/dev/null 2>&1 || true + kctl -n "${NAMESPACE}" delete secret "${secret_name}" \ + --ignore-not-found >/dev/null 2>&1 || true + + EXTERNAL_PG_FIXTURE_DEPLOYED=0 + EXTERNAL_PG_FIXTURE_SECRET="" } cleanup() { @@ -134,13 +168,8 @@ cleanup() { fi fi - if [ "${EXTERNAL_PG_DEPLOYED}" = "1" ] && [ -n "${KUBE_CONTEXT}" ] && [ -n "${NAMESPACE}" ]; then - helmctl uninstall pg-external --namespace "${NAMESPACE}" --wait \ - --timeout 60s >/dev/null 2>&1 || true - kctl -n "${NAMESPACE}" delete secret my-pg-credentials \ - --ignore-not-found >/dev/null 2>&1 || true - kctl delete pvc -n "${NAMESPACE}" \ - -l "app.kubernetes.io/instance=pg-external" --wait=false >/dev/null 2>&1 || true + if [ "${EXTERNAL_PG_FIXTURE_DEPLOYED}" = "1" ]; then + cleanup_postgres_fixture "${EXTERNAL_PG_FIXTURE_SECRET}" fi if [ "${HELM_INSTALLED}" = "1" ] && [ -n "${KUBE_CONTEXT}" ] && [ -n "${NAMESPACE}" ]; then @@ -200,45 +229,20 @@ scenario_cleanup_release() { } scenario_deploy_external_pg() { - local pg_host pg_uri echo "==> Deploying standalone PostgreSQL as external database..." - helmctl install pg-external oci://registry-1.docker.io/bitnamicharts/postgresql \ - --namespace "${NAMESPACE}" \ - --set auth.username=openshell \ - --set auth.password=ext-test-password \ - --set auth.database=openshell \ - --wait --timeout 120s 2>/dev/null || true - EXTERNAL_PG_DEPLOYED=1 - - kctl -n "${NAMESPACE}" wait pod \ - -l "app.kubernetes.io/name=postgresql,app.kubernetes.io/instance=pg-external" \ - --for=condition=Ready --timeout=120s || true - - pg_host="pg-external-postgresql.${NAMESPACE}.svc.cluster.local" - pg_uri="postgresql://openshell:ext-test-password@${pg_host}:5432/openshell" - - echo "==> Creating Secret with PostgreSQL URI..." - kctl -n "${NAMESPACE}" create secret generic my-pg-credentials \ - --from-literal=uri="${pg_uri}" \ - 2>/dev/null || true + deploy_postgres_fixture my-pg-credentials } scenario_cleanup_external_pg() { echo "==> Cleaning up external PostgreSQL..." - helmctl uninstall pg-external --namespace "${NAMESPACE}" --wait \ - --timeout 60s 2>/dev/null || true - kctl -n "${NAMESPACE}" delete secret my-pg-credentials \ - --ignore-not-found >/dev/null 2>&1 || true - kctl delete pvc -n "${NAMESPACE}" \ - -l "app.kubernetes.io/instance=pg-external" --wait=false 2>/dev/null || true - EXTERNAL_PG_DEPLOYED=0 + cleanup_postgres_fixture my-pg-credentials } # Run a single DB-backend scenario: install chart → port-forward → run tests → cleanup. # Usage: run_scenario "label" "type" [extra --set flags...] -# type: sqlite | bundled-pg | external-pg +# type: sqlite | external-pg run_scenario() { - local scenario_label="$1" scenario_type="$2" + local scenario_label="$1" shift 2 local scenario_exit=0 @@ -259,13 +263,6 @@ run_scenario() { --wait --timeout 5m HELM_INSTALLED=1 - if [ "${scenario_type}" = "bundled-pg" ]; then - echo "Waiting for bundled PostgreSQL to become ready..." - kctl -n "${NAMESPACE}" wait pod \ - -l "app.kubernetes.io/name=postgres,app.kubernetes.io/instance=${RELEASE_NAME}" \ - --for=condition=Ready --timeout=120s || true - fi - LOCAL_PORT="$(e2e_pick_port)" echo "Starting kubectl port-forward svc/openshell ${LOCAL_PORT}:8080..." kctl -n "${NAMESPACE}" port-forward "svc/openshell" \ @@ -545,7 +542,6 @@ if [ -n "${HOST_GATEWAY_IP}" ]; then fi helm_values_args=(--values "${ROOT}/deploy/helm/openshell/ci/values-skaffold.yaml") -helm_extra_values_enabled=0 if [ -n "${OPENSHELL_E2E_KUBE_EXTRA_VALUES:-}" ]; then IFS=':' read -r -a extra_values_files <<< "${OPENSHELL_E2E_KUBE_EXTRA_VALUES}" for values_file in "${extra_values_files[@]}"; do @@ -554,13 +550,10 @@ if [ -n "${OPENSHELL_E2E_KUBE_EXTRA_VALUES:-}" ]; then values_file="${ROOT}/${values_file}" fi helm_values_args+=(--values "${values_file}") - helm_extra_values_enabled=1 done fi if [ "${OPENSHELL_E2E_KUBE_DB_SCENARIOS:-0}" = "1" ]; then - helm dependency build "${ROOT}/deploy/helm/openshell" - # --- Multi-scenario mode: test all database backends --- DB_PASSED=0 DB_FAILED=0 @@ -570,10 +563,6 @@ if [ "${OPENSHELL_E2E_KUBE_DB_SCENARIOS:-0}" = "1" ]; then run_scenario "SQLite (default)" sqlite \ "${helm_extra_args[@]}" - run_scenario "Bundled PostgreSQL" bundled-pg \ - "${helm_extra_args[@]}" \ - --set postgres.enabled=true - scenario_deploy_external_pg run_scenario "External PostgreSQL (externalDbSecret)" external-pg \ "${helm_extra_args[@]}" \ @@ -596,17 +585,13 @@ if [ "${OPENSHELL_E2E_KUBE_DB_SCENARIOS:-0}" = "1" ]; then fi else # --- Single-install mode (default, existing behavior) --- - helm_dependency_args=() - if [ "${helm_extra_values_enabled}" = "1" ]; then - chart_dir="${ROOT}/deploy/helm/openshell" - helm_dependency_args=(--dependency-update) - else - chart_dir="$(chart_without_dependencies)" + if [ -n "${OPENSHELL_E2E_KUBE_EXTERNAL_POSTGRES_SECRET:-}" ]; then + deploy_postgres_fixture "${OPENSHELL_E2E_KUBE_EXTERNAL_POSTGRES_SECRET}" fi + echo "Installing Helm chart (release=${RELEASE_NAME}, namespace=${NAMESPACE}, tag=${IMAGE_TAG_VALUE})..." - helmctl install "${RELEASE_NAME}" "${chart_dir}" \ + helmctl install "${RELEASE_NAME}" "${ROOT}/deploy/helm/openshell" \ --namespace "${NAMESPACE}" --create-namespace \ - "${helm_dependency_args[@]}" \ "${helm_values_args[@]}" \ --set "fullnameOverride=openshell" \ --set "image.repository=${REGISTRY_VALUE}/gateway" \ diff --git a/tasks/helm.toml b/tasks/helm.toml index f25dadb09..31788088a 100644 --- a/tasks/helm.toml +++ b/tasks/helm.toml @@ -26,7 +26,6 @@ hide = true description = "Lint the openshell Helm chart (defaults + all CI configuration variants)" run = """ set -e - helm dependency build deploy/helm/openshell echo "--- helm lint: defaults ---" echo "values files: deploy/helm/openshell/values.yaml" helm lint deploy/helm/openshell @@ -46,7 +45,6 @@ run = """ if ! helm plugin list | grep -q unittest; then helm plugin install https://github.com/helm-unittest/helm-unittest --verify=false fi - helm dependency build deploy/helm/openshell helm unittest deploy/helm/openshell """ diff --git a/tasks/test.toml b/tasks/test.toml index 51f24f1be..c80225e4f 100644 --- a/tasks/test.toml +++ b/tasks/test.toml @@ -90,7 +90,7 @@ description = "Run Rust CLI e2e tests against an OpenShell gateway deployed on K run = "e2e/rust/e2e-kubernetes.sh" ["e2e:kubernetes:db"] -description = "Run Kubernetes e2e with all database backend scenarios (SQLite, bundled PostgreSQL, external PostgreSQL with existingSecret)" +description = "Run Kubernetes e2e with all database backend scenarios (SQLite and external PostgreSQL with existingSecret)" env = { OPENSHELL_E2E_KUBE_DB_SCENARIOS = "1" } run = "e2e/rust/e2e-kubernetes.sh"