name: Validate # Validates the Kubernetes manifests against the real agent-sandbox CRD # schema (server-side dry-run on a throwaway kind cluster), runs the gateway # unit tests + lint, and builds/smoke-tests the gateway image without a # cluster. Runs on every PR and on pushes to main. on: pull_request: push: branches: [main] permissions: contents: read jobs: validate-manifests: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Create kind cluster uses: helm/kind-action@1544676c07bb3570fcb70166beaa07c4528fd4aa # v1.15.1 with: version: v0.33.0 cluster_name: dsh-validate - name: Install agent-sandbox (extensions) run: | VERSION=v1.0.7 kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${VERSION}/sandbox-with-extensions.yaml kubectl wait --for=condition=Established crd/sandboxtemplates.extensions.agents.x-k8s.io --timeout=180s kubectl wait --for=condition=Established crd/sandboxwarmpools.extensions.agents.x-k8s.io --timeout=180s kubectl wait --for=condition=Established crd/sandboxclaims.extensions.agents.x-k8s.io --timeout=180s kubectl wait --for=condition=Established crd/sandboxes.agents.x-k8s.io --timeout=180s - name: Validate manifests (server dry-run) run: | set -euo pipefail kubectl create namespace dsh-demo for f in examples/dsh-agents-as-a-service/*.yaml; do echo "== $f ==" kubectl apply --dry-run=server -f "$f" done kubectl apply --dry-run=server -f deploy/k8s/sandbox-template.yaml echo "all manifests validated" gateway-tests: # The gateway lives in examples/dsh-agents-as-a-service/gateway/. Its # runtime pins and dev pins are kept separate so the image only ships # requirements.txt while CI installs both files. name: Gateway unit tests and lint runs-on: ubuntu-latest defaults: run: working-directory: examples/dsh-agents-as-a-service/gateway steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" cache: pip cache-dependency-path: | examples/dsh-agents-as-a-service/gateway/requirements.txt examples/dsh-agents-as-a-service/gateway/requirements-dev.txt - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt -r requirements-dev.txt - name: Lint (ruff) run: python -m ruff check . - name: Run gateway unit tests run: python -m pytest -v gateway-image: # No cluster and no real credentials: the gateway must start and answer # /healthz with a dummy kubeconfig, which catches broken imports, missing # runtime deps, and an unresponsive ASGI entrypoint. name: Build and smoke-test gateway image runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Build gateway image run: | docker build \ -t dsh-aaas-gateway:ci \ examples/dsh-agents-as-a-service/gateway/ - name: Smoke-test /healthz without a cluster run: | set -euo pipefail cat > /tmp/kubeconfig <<'EOF' apiVersion: v1 kind: Config clusters: - name: dummy cluster: server: https://127.0.0.1:6443 insecure-skip-tls-verify: true contexts: - name: dummy context: cluster: dummy user: dummy users: - name: dummy user: {} current-context: dummy EOF docker run -d --name gateway-smoke \ -p 18080:8080 \ -e NAMESPACE=dsh-demo \ -e POOL=dsh-pool \ -e KUBECONFIG=/tmp/kubeconfig \ -v /tmp/kubeconfig:/tmp/kubeconfig:ro \ dsh-aaas-gateway:ci trap 'docker logs gateway-smoke || true; docker rm -f gateway-smoke || true' EXIT code="" for _ in $(seq 1 30); do code=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:18080/healthz || true) [ "$code" = "200" ] && break sleep 1 done if [ "$code" != "200" ]; then echo "gateway /healthz returned '$code' instead of 200" >&2 exit 1 fi echo "gateway image healthy: GET /healthz -> 200"