name: Validate Helm chart on: push: paths: - infra/helm/** - .github/workflows/helm-chart.yml pull_request: paths: - infra/helm/** - .github/workflows/helm-chart.yml permissions: contents: read jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: azure/setup-helm@v4 with: version: v3.17.3 - name: Lint chart run: helm lint infra/helm/medical-chatbot - name: Render default and production manifests run: | helm template default infra/helm/medical-chatbot > /tmp/default.yaml helm template production infra/helm/medical-chatbot \ --values infra/helm/medical-chatbot/values-prod.yaml \ > /tmp/production.yaml grep -q 'ANSWER_MODEL_ID: "qwen.qwen3-next-80b-a3b"' /tmp/production.yaml grep -q 'RERANK_ENABLED: "true"' /tmp/production.yaml grep -q 'checksum/runtime-config:' /tmp/production.yaml # The practice cluster is only evidence for the production migration # while it renders the same behavioural contract as production, so both # of its releases are asserted here rather than trusted by review. - name: Render practice manifests run: | helm template medical-chatbot-app infra/helm/medical-chatbot \ --values infra/helm/medical-chatbot/values-practice.yaml \ > /tmp/practice-app.yaml helm template medical-chatbot-data infra/helm/medical-chatbot \ --values infra/helm/medical-chatbot/values-practice-data.yaml \ > /tmp/practice-data.yaml # Behavioural parity with the audited production runtime contract. grep -q 'ANSWER_MODEL_ID: "qwen.qwen3-next-80b-a3b"' /tmp/practice-app.yaml grep -q 'ANSWER_PROVIDER: "bedrock-converse"' /tmp/practice-app.yaml grep -q 'EMBEDDING_PROVIDER: "cohere-v4"' /tmp/practice-app.yaml grep -q 'EMBEDDING_DIMENSIONS: "1024"' /tmp/practice-app.yaml grep -q 'EVIDENCE_MINIMUM_SCORE: "0.12"' /tmp/practice-app.yaml grep -q 'RERANK_ENABLED: "true"' /tmp/practice-app.yaml grep -q 'AWS_REGION: "us-east-1"' /tmp/practice-app.yaml grep -q 'checksum/runtime-config:' /tmp/practice-app.yaml grep -q 'host: readytochat.realvuxbaro.me' /tmp/practice-app.yaml # The app release must own neither data StatefulSet: PostgreSQL and # Qdrant belong to the data release, so an app-side sync failure or # prune can never delete the corpus or the query history. Only those # two use volumeClaimTemplates — the observability PVCs are the app # release's own and are expected here. # # `set -e` ignores a command whose status is inverted with `!`, so # every must-NOT-contain assertion is written as an explicit exit. refute() { if grep -q "$2" "$1"; then echo "::error::$1 must not contain: $2" exit 1 fi } refute /tmp/practice-app.yaml 'volumeClaimTemplates' grep -q 'medical-chatbot-data-medical-chatbot-qdrant' /tmp/practice-app.yaml # ...and the data release must own nothing else. refute /tmp/practice-data.yaml 'medical-chatbot-data-medical-chatbot-ai-service' refute /tmp/practice-data.yaml 'kind: Ingress' grep -q 'volumeClaimTemplates' /tmp/practice-data.yaml