mount trusted CA bundle in runner pods #3679
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Push Component Docker Images | |
| on: | |
| push: | |
| branches: [main, alpha] | |
| paths: | |
| - '.github/workflows/components-build-deploy.yml' | |
| - 'components/manifests/**' | |
| - 'components/runners/**' | |
| - 'components/operator/**' | |
| - 'components/backend/**' | |
| - 'components/frontend/**' | |
| - 'components/public-api/**' | |
| - 'components/ambient-api-server/**' | |
| pull_request: | |
| branches: [main, alpha] | |
| paths: | |
| - '.github/workflows/components-build-deploy.yml' | |
| - 'components/manifests/**' | |
| - 'components/runners/**' | |
| - 'components/operator/**' | |
| - 'components/backend/**' | |
| - 'components/frontend/**' | |
| - 'components/public-api/**' | |
| - 'components/ambient-api-server/**' | |
| workflow_dispatch: | |
| inputs: | |
| components: | |
| description: 'Components to build (comma-separated: frontend,backend,operator,ambient-runner,state-sync,public-api,ambient-api-server) - leave empty for all' | |
| required: false | |
| type: string | |
| default: '' | |
| concurrency: | |
| group: components-build-deploy-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| build-matrix: | |
| if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository | |
| runs-on: ubuntu-latest | |
| permissions: {} | |
| outputs: | |
| build-matrix: ${{ steps.matrix.outputs.build-matrix }} | |
| merge-matrix: ${{ steps.matrix.outputs.merge-matrix }} | |
| steps: | |
| - name: Build component matrices | |
| id: matrix | |
| run: | | |
| ALL_COMPONENTS='[ | |
| {"name":"frontend","context":"./components/frontend","image":"quay.io/ambient_code/vteam_frontend","dockerfile":"./components/frontend/Dockerfile"}, | |
| {"name":"backend","context":"./components/backend","image":"quay.io/ambient_code/vteam_backend","dockerfile":"./components/backend/Dockerfile"}, | |
| {"name":"operator","context":"./components/operator","image":"quay.io/ambient_code/vteam_operator","dockerfile":"./components/operator/Dockerfile"}, | |
| {"name":"ambient-runner","context":"./components/runners/ambient-runner","image":"quay.io/ambient_code/vteam_claude_runner","dockerfile":"./components/runners/ambient-runner/Dockerfile"}, | |
| {"name":"state-sync","context":"./components/runners/state-sync","image":"quay.io/ambient_code/vteam_state_sync","dockerfile":"./components/runners/state-sync/Dockerfile"}, | |
| {"name":"public-api","context":"./components/public-api","image":"quay.io/ambient_code/vteam_public_api","dockerfile":"./components/public-api/Dockerfile"}, | |
| {"name":"ambient-api-server","context":"./components/ambient-api-server","image":"quay.io/ambient_code/vteam_api_server","dockerfile":"./components/ambient-api-server/Dockerfile"} | |
| ]' | |
| SELECTED="${{ github.event.inputs.components }}" | |
| if [ -n "$SELECTED" ]; then | |
| FILTERED=$(echo "$ALL_COMPONENTS" | jq -c --arg sel "$SELECTED" '[.[] | select(.name as $n | $sel | split(",") | map(gsub("^\\s+|\\s+$";"")) | index($n))]') | |
| else | |
| FILTERED="$ALL_COMPONENTS" | |
| fi | |
| echo "build-matrix=$(echo "$FILTERED" | jq -c '.')" >> $GITHUB_OUTPUT | |
| echo "merge-matrix=$(echo "$FILTERED" | jq -c '[.[] | {name, image}]')" >> $GITHUB_OUTPUT | |
| echo "Components to build:" | |
| echo "$FILTERED" | jq -r '.[].name' | |
| build: | |
| needs: build-matrix | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| issues: read | |
| id-token: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # IMPORTANT: suffix values must match the hardcoded suffixes in | |
| # merge-manifests. Update both together if arches change. | |
| arch: | |
| - runner: ubuntu-latest | |
| platform: linux/amd64 | |
| suffix: amd64 | |
| - runner: ubuntu-24.04-arm | |
| platform: linux/arm64 | |
| suffix: arm64 | |
| component: ${{ fromJSON(needs.build-matrix.outputs.build-matrix) }} | |
| runs-on: ${{ matrix.arch.runner }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Quay.io | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: quay.io | |
| username: ${{ secrets.QUAY_USERNAME }} | |
| password: ${{ secrets.QUAY_PASSWORD }} | |
| - name: Log in to Red Hat Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: registry.redhat.io | |
| username: ${{ secrets.REDHAT_USERNAME }} | |
| password: ${{ secrets.REDHAT_PASSWORD }} | |
| - name: Build and push ${{ matrix.component.name }} (${{ matrix.arch.suffix }}) | |
| if: github.event_name != 'pull_request' | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: ${{ matrix.component.context }} | |
| file: ${{ matrix.component.dockerfile }} | |
| platforms: ${{ matrix.arch.platform }} | |
| push: true | |
| tags: ${{ matrix.component.image }}:${{ github.sha }}-${{ matrix.arch.suffix }} | |
| build-args: AMBIENT_VERSION=${{ github.sha }} | |
| cache-from: type=gha,scope=${{ matrix.component.name }}-${{ matrix.arch.suffix }} | |
| cache-to: type=gha,mode=max,scope=${{ matrix.component.name }}-${{ matrix.arch.suffix }} | |
| - name: Build and push ${{ matrix.component.name }} (${{ matrix.arch.suffix }}) for pull request | |
| if: github.event_name == 'pull_request' | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: ${{ matrix.component.context }} | |
| file: ${{ matrix.component.dockerfile }} | |
| platforms: ${{ matrix.arch.platform }} | |
| push: true | |
| tags: ${{ matrix.component.image }}:pr-${{ github.event.pull_request.number }}-${{ matrix.arch.suffix }} | |
| build-args: AMBIENT_VERSION=${{ github.sha }} | |
| cache-from: type=gha,scope=${{ matrix.component.name }}-${{ matrix.arch.suffix }} | |
| cache-to: type=gha,mode=max,scope=${{ matrix.component.name }}-${{ matrix.arch.suffix }} | |
| merge-manifests: | |
| needs: [build-matrix, build] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| id-token: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| component: ${{ fromJSON(needs.build-matrix.outputs.merge-matrix) }} | |
| steps: | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Quay.io | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: quay.io | |
| username: ${{ secrets.QUAY_USERNAME }} | |
| password: ${{ secrets.QUAY_PASSWORD }} | |
| - name: Create multi-arch manifest for ${{ matrix.component.name }} (main) | |
| if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' | |
| # Suffixes (-amd64, -arm64) must match the arch matrix in the build job above. | |
| # Arch-suffixed tags remain in the registry after merging. Clean these up | |
| # via Quay tag expiration policies or a periodic job. | |
| run: | | |
| docker buildx imagetools create \ | |
| -t ${{ matrix.component.image }}:latest \ | |
| -t ${{ matrix.component.image }}:${{ github.sha }} \ | |
| ${{ matrix.component.image }}:${{ github.sha }}-amd64 \ | |
| ${{ matrix.component.image }}:${{ github.sha }}-arm64 | |
| - name: Create multi-arch manifest for ${{ matrix.component.name }} (alpha) | |
| if: github.event_name != 'pull_request' && github.ref == 'refs/heads/alpha' | |
| run: | | |
| docker buildx imagetools create \ | |
| -t ${{ matrix.component.image }}:alpha \ | |
| -t ${{ matrix.component.image }}:${{ github.sha }} \ | |
| ${{ matrix.component.image }}:${{ github.sha }}-amd64 \ | |
| ${{ matrix.component.image }}:${{ github.sha }}-arm64 | |
| - name: Create multi-arch manifest for ${{ matrix.component.name }} (pull request) | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| docker buildx imagetools create \ | |
| -t ${{ matrix.component.image }}:pr-${{ github.event.pull_request.number }} \ | |
| ${{ matrix.component.image }}:pr-${{ github.event.pull_request.number }}-amd64 \ | |
| ${{ matrix.component.image }}:pr-${{ github.event.pull_request.number }}-arm64 | |
| deploy-rhoai-mlflow: | |
| runs-on: ubuntu-latest | |
| needs: [build-matrix] | |
| if: always() && !cancelled() && (github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch') | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Install oc | |
| uses: redhat-actions/oc-installer@v1 | |
| with: | |
| oc_version: 'latest' | |
| - name: Log in to OpenShift Cluster | |
| run: | | |
| oc login ${{ secrets.OPENSHIFT_SERVER }} --token=${{ secrets.OPENSHIFT_TOKEN }} | |
| - name: Deploy Service Mesh operator via OLM | |
| run: | | |
| oc apply -f components/manifests/components/openshift-ai/service-mesh-namespace.yaml | |
| oc apply -f components/manifests/components/openshift-ai/service-mesh-operatorgroup.yaml | |
| oc apply -f components/manifests/components/openshift-ai/service-mesh-subscription.yaml | |
| - name: Deploy RHOAI operator via OLM | |
| run: | | |
| oc apply -f components/manifests/components/openshift-ai/namespace.yaml | |
| oc apply -f components/manifests/components/openshift-ai/operatorgroup.yaml | |
| oc apply -f components/manifests/components/openshift-ai/subscription.yaml | |
| - name: Wait for RHOAI operator to be ready | |
| run: | | |
| echo "Waiting for RHOAI operator CSV to appear..." | |
| for i in $(seq 1 60); do | |
| CSV=$(oc get subscription rhods-operator -n redhat-ods-operator \ | |
| -o jsonpath='{.status.installedCSV}' 2>/dev/null) | |
| if [ -n "$CSV" ]; then | |
| echo "Found CSV: $CSV" | |
| break | |
| fi | |
| if [ "$i" -eq 60 ]; then | |
| echo "::error::RHOAI operator CSV did not appear within timeout" | |
| exit 1 | |
| fi | |
| echo "Attempt $i/60 - CSV not yet available, waiting 10s..." | |
| sleep 10 | |
| done | |
| echo "Waiting for CSV $CSV to succeed..." | |
| oc wait csv "$CSV" -n redhat-ods-operator \ | |
| --for=jsonpath='{.status.phase}'=Succeeded --timeout=600s | |
| - name: Wait for DataScienceCluster v2 API to be available | |
| run: | | |
| echo "Waiting for DataScienceCluster v2 API to be served..." | |
| for i in $(seq 1 60); do | |
| if oc api-resources --api-group=datasciencecluster.opendatahub.io 2>/dev/null | grep -q v2; then | |
| echo "DataScienceCluster v2 API is available" | |
| break | |
| fi | |
| if [ "$i" -eq 60 ]; then | |
| echo "::error::DataScienceCluster v2 API did not become available within timeout" | |
| exit 1 | |
| fi | |
| echo "Attempt $i/60 - v2 API not yet available, waiting 10s..." | |
| sleep 10 | |
| done | |
| - name: Apply DSCInitialization and DataScienceCluster | |
| run: | | |
| oc apply -f components/manifests/components/openshift-ai/dsci.yaml | |
| oc apply -f components/manifests/components/openshift-ai/datasciencecluster.yaml | |
| - name: Wait for MLflow Operator CRD to be available | |
| run: | | |
| echo "Waiting for MLflow CRD to be registered..." | |
| for i in $(seq 1 60); do | |
| if oc get crd mlflows.mlflow.opendatahub.io &>/dev/null; then | |
| echo "MLflow CRD is available" | |
| break | |
| fi | |
| if [ "$i" -eq 60 ]; then | |
| echo "::error::MLflow CRD did not become available within timeout" | |
| exit 1 | |
| fi | |
| echo "Attempt $i/60 - MLflow CRD not yet available, waiting 10s..." | |
| sleep 10 | |
| done | |
| - name: Ensure mlflow database exists in PostgreSQL | |
| run: | | |
| oc exec -n ambient-code deploy/postgresql -- \ | |
| psql -U postgres -tAc \ | |
| "SELECT 1 FROM pg_database WHERE datname = 'mlflow'" | grep -q 1 \ | |
| || oc exec -n ambient-code deploy/postgresql -- \ | |
| psql -U postgres -c "CREATE DATABASE mlflow" | |
| - name: Ensure mlflow-db-credentials secret exists | |
| run: | | |
| echo "Reconciling mlflow-db-credentials from postgresql-credentials..." | |
| DB_USER=$(oc get secret postgresql-credentials -n ambient-code -o jsonpath='{.data.db\.user}' | base64 -d) | |
| DB_PASS=$(oc get secret postgresql-credentials -n ambient-code -o jsonpath='{.data.db\.password}' | base64 -d) | |
| DB_HOST=$(oc get secret postgresql-credentials -n ambient-code -o jsonpath='{.data.db\.host}' | base64 -d) | |
| DB_PORT=$(oc get secret postgresql-credentials -n ambient-code -o jsonpath='{.data.db\.port}' | base64 -d) | |
| ENC_USER=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$DB_USER") | |
| ENC_PASS=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$DB_PASS") | |
| ENCODED_URI="postgresql://${ENC_USER}:${ENC_PASS}@${DB_HOST}.ambient-code.svc.cluster.local:${DB_PORT}/mlflow?sslmode=disable" | |
| oc create namespace redhat-ods-applications --dry-run=client -o yaml | oc apply -f - | |
| oc apply -f - <<EOF | |
| apiVersion: v1 | |
| kind: Secret | |
| metadata: | |
| name: mlflow-db-credentials | |
| namespace: redhat-ods-applications | |
| type: Opaque | |
| stringData: | |
| uri: "${ENCODED_URI}" | |
| EOF | |
| - name: Deploy MLflow instance | |
| run: | | |
| oc apply -f components/manifests/components/openshift-ai/mlflow.yaml | |
| update-rbac-and-crd: | |
| runs-on: ubuntu-latest | |
| needs: [build-matrix, merge-manifests] | |
| if: always() && !cancelled() && (github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch') | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Install oc | |
| uses: redhat-actions/oc-installer@v1 | |
| with: | |
| oc_version: 'latest' | |
| - name: Log in to OpenShift Cluster | |
| run: | | |
| oc login ${{ secrets.OPENSHIFT_SERVER }} --token=${{ secrets.OPENSHIFT_TOKEN }} | |
| - name: Apply RBAC and CRD manifests | |
| run: | | |
| oc apply -k components/manifests/base/crds/ | |
| oc apply -k components/manifests/base/rbac/ | |
| oc apply -f components/manifests/overlays/production/operator-config-openshift.yaml -n ambient-code | |
| - name: Deploy observability stack | |
| run: | | |
| oc apply -k components/manifests/observability/ | |
| deploy-to-openshift: | |
| runs-on: ubuntu-latest | |
| needs: [merge-manifests, update-rbac-and-crd] | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Install oc | |
| uses: redhat-actions/oc-installer@v1 | |
| with: | |
| oc_version: 'latest' | |
| - name: Install kustomize | |
| run: | | |
| curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash | |
| sudo mv kustomize /usr/local/bin/ | |
| kustomize version | |
| - name: Log in to OpenShift Cluster | |
| run: | | |
| oc login ${{ secrets.OPENSHIFT_SERVER }} --token=${{ secrets.OPENSHIFT_TOKEN }} | |
| - name: Update kustomization with SHA image tags | |
| working-directory: components/manifests/overlays/production | |
| run: | | |
| kustomize edit set image quay.io/ambient_code/vteam_frontend:latest=quay.io/ambient_code/vteam_frontend:${{ github.sha }} | |
| kustomize edit set image quay.io/ambient_code/vteam_backend:latest=quay.io/ambient_code/vteam_backend:${{ github.sha }} | |
| kustomize edit set image quay.io/ambient_code/vteam_operator:latest=quay.io/ambient_code/vteam_operator:${{ github.sha }} | |
| kustomize edit set image quay.io/ambient_code/vteam_claude_runner:latest=quay.io/ambient_code/vteam_claude_runner:${{ github.sha }} | |
| kustomize edit set image quay.io/ambient_code/vteam_state_sync:latest=quay.io/ambient_code/vteam_state_sync:${{ github.sha }} | |
| kustomize edit set image quay.io/ambient_code/vteam_api_server:latest=quay.io/ambient_code/vteam_api_server:${{ github.sha }} | |
| kustomize edit set image quay.io/ambient_code/vteam_public_api:latest=quay.io/ambient_code/vteam_public_api:${{ github.sha }} | |
| - name: Validate kustomization | |
| working-directory: components/manifests/overlays/production | |
| run: | | |
| kustomize build . > /dev/null | |
| echo "✅ Kustomization validation passed" | |
| - name: Apply production overlay with kustomize | |
| working-directory: components/manifests/overlays/production | |
| run: | | |
| oc apply -k . -n ambient-code | |
| - name: Update frontend environment variables | |
| run: | | |
| oc set env deployment/frontend -n ambient-code -c frontend \ | |
| GITHUB_APP_SLUG="ambient-code-stage" \ | |
| FEEDBACK_URL="https://forms.gle/7XiWrvo6No922DUz6" | |
| - name: Update operator environment variables | |
| run: | | |
| oc set env deployment/agentic-operator -n ambient-code -c agentic-operator \ | |
| AMBIENT_CODE_RUNNER_IMAGE="quay.io/ambient_code/vteam_claude_runner:${{ github.sha }}" \ | |
| STATE_SYNC_IMAGE="quay.io/ambient_code/vteam_state_sync:${{ github.sha }}" | |
| - name: Pin OPERATOR_IMAGE in operator-config ConfigMap | |
| run: | | |
| oc patch configmap operator-config -n ambient-code --type=merge \ | |
| -p "{\"data\":{\"OPERATOR_IMAGE\":\"quay.io/ambient_code/vteam_operator:${{ github.sha }}\"}}" | |
| - name: Update agent registry ConfigMap with pinned image tags | |
| run: | | |
| REGISTRY=$(oc get configmap ambient-agent-registry -n ambient-code \ | |
| -o jsonpath='{.data.agent-registry\.json}') | |
| REGISTRY=$(echo "$REGISTRY" | sed \ | |
| "s|quay.io/ambient_code/vteam_claude_runner[@:][^\"]*|quay.io/ambient_code/vteam_claude_runner:${{ github.sha }}|g") | |
| REGISTRY=$(echo "$REGISTRY" | sed \ | |
| "s|quay.io/ambient_code/vteam_state_sync[@:][^\"]*|quay.io/ambient_code/vteam_state_sync:${{ github.sha }}|g") | |
| oc patch configmap ambient-agent-registry -n ambient-code --type=merge \ | |
| -p "{\"data\":{\"agent-registry.json\":$(echo "$REGISTRY" | jq -Rs .)}}" | |
| deploy-with-disptach: | |
| runs-on: ubuntu-latest | |
| needs: [merge-manifests, update-rbac-and-crd] | |
| if: github.event_name == 'workflow_dispatch' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Install oc | |
| uses: redhat-actions/oc-installer@v1 | |
| with: | |
| oc_version: 'latest' | |
| - name: Install kustomize | |
| run: | | |
| curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash | |
| sudo mv kustomize /usr/local/bin/ | |
| kustomize version | |
| - name: Log in to OpenShift Cluster | |
| run: | | |
| oc login ${{ secrets.OPENSHIFT_SERVER }} --token=${{ secrets.OPENSHIFT_TOKEN }} | |
| - name: Update kustomization with SHA image tags | |
| working-directory: components/manifests/overlays/production | |
| run: | | |
| kustomize edit set image quay.io/ambient_code/vteam_frontend:latest=quay.io/ambient_code/vteam_frontend:${{ github.sha }} | |
| kustomize edit set image quay.io/ambient_code/vteam_backend:latest=quay.io/ambient_code/vteam_backend:${{ github.sha }} | |
| kustomize edit set image quay.io/ambient_code/vteam_operator:latest=quay.io/ambient_code/vteam_operator:${{ github.sha }} | |
| kustomize edit set image quay.io/ambient_code/vteam_claude_runner:latest=quay.io/ambient_code/vteam_claude_runner:${{ github.sha }} | |
| kustomize edit set image quay.io/ambient_code/vteam_state_sync:latest=quay.io/ambient_code/vteam_state_sync:${{ github.sha }} | |
| kustomize edit set image quay.io/ambient_code/vteam_api_server:latest=quay.io/ambient_code/vteam_api_server:${{ github.sha }} | |
| kustomize edit set image quay.io/ambient_code/vteam_public_api:latest=quay.io/ambient_code/vteam_public_api:${{ github.sha }} | |
| - name: Validate kustomization | |
| working-directory: components/manifests/overlays/production | |
| run: | | |
| kustomize build . > /dev/null | |
| echo "✅ Kustomization validation passed" | |
| - name: Apply production overlay with kustomize | |
| working-directory: components/manifests/overlays/production | |
| run: | | |
| oc apply -k . -n ambient-code | |
| - name: Update frontend environment variables | |
| run: | | |
| oc set env deployment/frontend -n ambient-code -c frontend \ | |
| GITHUB_APP_SLUG="ambient-code-stage" \ | |
| FEEDBACK_URL="https://forms.gle/7XiWrvo6No922DUz6" | |
| - name: Update operator environment variables | |
| run: | | |
| oc set env deployment/agentic-operator -n ambient-code -c agentic-operator \ | |
| AMBIENT_CODE_RUNNER_IMAGE="quay.io/ambient_code/vteam_claude_runner:${{ github.sha }}" \ | |
| STATE_SYNC_IMAGE="quay.io/ambient_code/vteam_state_sync:${{ github.sha }}" | |
| - name: Pin OPERATOR_IMAGE in operator-config ConfigMap | |
| run: | | |
| oc patch configmap operator-config -n ambient-code --type=merge \ | |
| -p "{\"data\":{\"OPERATOR_IMAGE\":\"quay.io/ambient_code/vteam_operator:${{ github.sha }}\"}}" | |
| - name: Update agent registry ConfigMap with pinned image tags | |
| run: | | |
| REGISTRY=$(oc get configmap ambient-agent-registry -n ambient-code \ | |
| -o jsonpath='{.data.agent-registry\.json}') | |
| REGISTRY=$(echo "$REGISTRY" | sed \ | |
| "s|quay.io/ambient_code/vteam_claude_runner[@:][^\"]*|quay.io/ambient_code/vteam_claude_runner:${{ github.sha }}|g") | |
| REGISTRY=$(echo "$REGISTRY" | sed \ | |
| "s|quay.io/ambient_code/vteam_state_sync[@:][^\"]*|quay.io/ambient_code/vteam_state_sync:${{ github.sha }}|g") | |
| oc patch configmap ambient-agent-registry -n ambient-code --type=merge \ | |
| -p "{\"data\":{\"agent-registry.json\":$(echo "$REGISTRY" | jq -Rs .)}}" |