refactor(ui): rename the extension framework to App Extensions and install an ordered array #8723
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: CI Build | |
| on: | |
| push: | |
| branches: [main, "release/**"] | |
| paths-ignore: | |
| - "**/*.md" | |
| pull_request: | |
| branches: [main, "release/**"] | |
| paths-ignore: | |
| - "**/*.md" | |
| workflow_dispatch: | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| # Cache key components for better organization | |
| CACHE_KEY_PREFIX: kagent-v2 | |
| BRANCH_CACHE_KEY: ${{ github.head_ref || github.ref_name }} | |
| # Consistent builder configuration | |
| BUILDX_BUILDER_NAME: kagent-builder-v0.23.0 | |
| BUILDX_VERSION: v0.23.0 | |
| jobs: | |
| setup: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| cache-key: ${{ steps.cache-key.outputs.key }} | |
| steps: | |
| - name: Generate cache keys | |
| id: cache-key | |
| run: | | |
| # Generate branch-based cache key | |
| BRANCH_KEY="${CACHE_KEY_PREFIX}-${BRANCH_CACHE_KEY}" | |
| echo "key=${BRANCH_KEY}" >> $GITHUB_OUTPUT | |
| echo "::notice title=Cache Key::Branch: ${BRANCH_KEY}" | |
| test-e2e: | |
| needs: | |
| - setup | |
| env: | |
| VERSION: v0.0.1-test | |
| SUBSTRATE_VERSION: 0.0.20 | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Initialize Environment | |
| uses: ./.github/actions/initialize-environment | |
| - name: Allow unprivileged user namespaces | |
| # Ubuntu 24.04 (ubuntu-latest) enables AppArmor-based restrictions on | |
| # unprivileged user namespaces by default, which causes bubblewrap | |
| # to fail with EPERM on unshare(CLONE_NEWUSER) | |
| # See https://github.com/openai/codex/issues/14919 | |
| run: | | |
| sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 || true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| with: | |
| name: ${{ env.BUILDX_BUILDER_NAME }} | |
| version: ${{ env.BUILDX_VERSION }} | |
| platforms: linux/amd64 | |
| use: "true" | |
| driver-opts: network=host | |
| - name: Set up Helm | |
| uses: azure/setup-helm@v5.0.1 | |
| with: | |
| version: v3.18.0 | |
| - name: Install Kind | |
| id: kind | |
| uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc | |
| with: | |
| install_only: true | |
| - name: Create Kind cluster | |
| run: | | |
| make create-kind-cluster | |
| - name: Install Agent Substrate | |
| run: | | |
| curl -fsSL -o kubectl-ate "https://github.com/kagent-dev/substrate/releases/download/v${SUBSTRATE_VERSION}/kubectl-ate-linux-amd64" | |
| chmod +x kubectl-ate | |
| helm upgrade --install substrate-crds oci://ghcr.io/kagent-dev/substrate/helm/substrate-crds --version "${SUBSTRATE_VERSION}" --namespace ate-system --create-namespace | |
| helm upgrade --install substrate oci://ghcr.io/kagent-dev/substrate/helm/substrate --version "${SUBSTRATE_VERSION}" --namespace ate-system --set-string 'atelet.extraArgs[0]=--localhost-registry-replacement=kind-registry:5000' | |
| ./kubectl-ate --context kind-kagent admin make-ca-pool --ca-id=1 --name=service-dns-ca-pool --secret-namespace=podcertificate-controller-system | |
| ./kubectl-ate --context kind-kagent admin make-ca-pool --ca-id=1 --name=pod-identity-ca-pool --secret-namespace=podcertificate-controller-system | |
| ./kubectl-ate --context kind-kagent admin make-jwt-pool --key-id=1 --name=actor-id-jwt-pool --secret-namespace=ate-system | |
| ./kubectl-ate --context kind-kagent admin make-ca-pool --ca-id=1 --name=actor-id-ca-pool --secret-namespace=ate-system | |
| actor_id_ca_root="$(kubectl get secret actor-id-ca-pool -n ate-system -o jsonpath='{.data.pool}' | base64 --decode | jq -r '.CAs[0].RootCertificateDER' | base64 --decode | openssl x509 -inform der -outform pem)" | |
| kubectl create secret generic actor-id-ca-certs -n ate-system --from-literal=ca.crt="${actor_id_ca_root}" | |
| kubectl create configmap ate-api-authentication -n ate-system --from-literal=authentication.yaml=$'actorIdentityJWTProvider: kubernetes\njwtProviders:\n- name: kubernetes\n issuer: https://kubernetes.default.svc\n audiences: [api.ate-system.svc]\n certificateAuthorityFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt\n discoveryTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token\n' | |
| helm upgrade substrate oci://ghcr.io/kagent-dev/substrate/helm/substrate --version "${SUBSTRATE_VERSION}" --namespace ate-system --reuse-values --wait --timeout 5m | |
| - name: Install Kagent | |
| id: install-kagent | |
| env: | |
| OPENAI_API_KEY: fake | |
| BUILDX_BUILDER_NAME: ${{ env.BUILDX_BUILDER_NAME }} | |
| KMCP_ENABLED: "false" | |
| KAGENT_HELM_EXTRA_ARGS: >- | |
| --cleanup-on-fail=false | |
| --set ui.replicas=0 | |
| --set kagent-tools.enabled=false | |
| --set grafana-mcp.enabled=false | |
| --set controller.substrate.enabled=true | |
| --set controller.substrate.ateApiEndpoint=dns:///api.ate-system.svc:443 | |
| --set controller.substrate.atenetRouterURL=http://atenet-router.ate-system.svc:80 | |
| --set controller.substrate.defaultWorkerPool.name=kagent-default | |
| --set substrateWorkerPool.create=true | |
| --set substrateWorkerPool.replicas=1 | |
| --set-string substrateWorkerPool.ateomImage=ghcr.io/kagent-dev/substrate/ateom-gvisor:v${{ env.SUBSTRATE_VERSION }} | |
| DOCKER_BUILD_ARGS: >- | |
| --cache-from=type=gha,scope=${{ needs.setup.outputs.cache-key }}-e2e | |
| --cache-from=type=gha,scope=${{ env.CACHE_KEY_PREFIX }}-main-e2e | |
| --cache-to=type=gha,scope=${{ needs.setup.outputs.cache-key }}-e2e,mode=max | |
| --platform=linux/amd64 | |
| --push | |
| run: | | |
| echo "Cache key: ${{ needs.setup.outputs.cache-key }}" | |
| make build-controller build-golang-adk | |
| make helm-install-provider | |
| kubectl rollout status deployment/kagent-controller -n kagent --timeout=120s | |
| kubectl wait --for=condition=Ready pod -l app.kubernetes.io/component=controller -n kagent --timeout=120s | |
| - name: Run e2e tests | |
| if: success() | |
| working-directory: go | |
| run: | | |
| RUNTIME_DIGEST=$(docker buildx imagetools inspect "localhost:5001/kagent-dev/kagent/golang-adk:${VERSION}" | awk '$1 == "Digest:" { print $2; exit }') | |
| test -n "$RUNTIME_DIGEST" | |
| export KAGENT_E2E_RUNTIME_IMAGE="localhost:5001/kagent-dev/kagent/golang-adk@${RUNTIME_DIGEST}" | |
| envsubst < core/test/e2e/manifests/lifecycle.yaml.tmpl | kubectl apply -f - | |
| for _ in $(seq 1 60); do | |
| READY=$(kubectl get agenttemplate smoke -n kagent -o jsonpath='{.status.harnesses[?(@.harness=="kagent")].conditions[?(@.type=="Ready")].status}') | |
| if [ "$READY" = True ]; then break; fi | |
| sleep 5 | |
| done | |
| test "$READY" = True | |
| export KAGENT_GRPC_URL="$(kubectl get svc -n kagent kagent-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'):8084" | |
| echo "KAGENT_GRPC_URL: $KAGENT_GRPC_URL" | |
| go test -v github.com/kagent-dev/kagent/go/core/test/e2e -failfast -shuffle=on | |
| - name: fail print info | |
| if: failure() | |
| run: | | |
| echo "::error::Failed to run e2e tests" | |
| echo "::error::Kubectl get pods -n kagent" | |
| kubectl describe pods -n kagent | |
| echo "::error::Kubectl get events -n kagent" | |
| kubectl get events -n kagent | |
| echo "::error::Kubectl get Harnesses and AgentTemplates -n kagent" | |
| kubectl get harnesses,agenttemplates -n kagent | |
| echo "::error::Kubectl logs -n kagent deployment/kagent-controller" | |
| kubectl logs -n kagent deployment/kagent-controller | |
| kubectl get pods,actortemplates,workerpools -A | |
| echo "::error::Substrate logs" | |
| kubectl logs -n ate-system -l app --all-containers --prefix --tail=200 || true | |
| kubectl logs -n ate-system -l app --all-containers --prefix --previous --tail=200 || true | |
| kubectl logs -n kagent -l ate.dev/worker-pool --all-containers --prefix --tail=200 || true | |
| kubectl logs -n kagent -l ate.dev/worker-pool --all-containers --prefix --previous --tail=200 || true | |
| query-contraction-check: | |
| name: Query Contraction Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| with: | |
| # Full history + tags so the previous release's queries can be read. | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Version resolution | |
| run: ./scripts/version-resolution_test.sh | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go/go.mod | |
| cache: true | |
| cache-dependency-path: go/go.sum | |
| - name: Previous-release queries vs current schema | |
| run: make -C go check-query-contraction | |
| proto-check: | |
| name: Protobuf Contract Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go/go.mod | |
| cache: true | |
| cache-dependency-path: go/go.sum | |
| - name: Lint and generate protobuf contracts | |
| run: make proto-check | |
| - name: Check protobuf compatibility | |
| run: make proto-breaking | |
| upgrade-tests: | |
| needs: | |
| - setup | |
| env: | |
| VERSION: v0.0.1-test | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # adjacent: the same-line latest published version, including prereleases | |
| # — only meaningful on a release branch and skipped on main. | |
| upgrade-from: [adjacent] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| with: | |
| # Full history + tags so the version resolvers can derive the | |
| # upgrade-from release, and so the local action below is on disk. | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Prepare upgrade test environment | |
| id: prep | |
| uses: ./.github/actions/upgrade-test-setup | |
| with: | |
| upgrade-from: ${{ matrix.upgrade-from }} | |
| - name: Run upgrade tests | |
| if: steps.prep.outputs.skip != 'true' | |
| env: | |
| OPENAI_API_KEY: fake | |
| BUILDX_BUILDER_NAME: ${{ env.BUILDX_BUILDER_NAME }} | |
| KAGENT_HELM_EXTRA_ARGS: --cleanup-on-fail=false | |
| DOCKER_BUILD_ARGS: >- | |
| --cache-from=type=gha,scope=${{ needs.setup.outputs.cache-key }}-e2e | |
| --cache-from=type=gha,scope=${{ env.CACHE_KEY_PREFIX }}-main-e2e | |
| --platform=linux/amd64 | |
| --push | |
| run: | | |
| make run-upgrade-tests UPGRADE_FROM_VERSION="${{ steps.prep.outputs.version }}" | |
| - name: fail print info | |
| if: failure() && steps.prep.outputs.skip != 'true' | |
| run: | | |
| echo "::error::Failed to run upgrade tests" | |
| kubectl describe pods -n kagent | |
| kubectl get events -n kagent | |
| kubectl logs -n kagent deployment/kagent-controller || true | |
| rolling-upgrade-tests: | |
| needs: | |
| - setup | |
| env: | |
| VERSION: v0.0.1-test | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # adjacent: the same-line latest published version, including prereleases | |
| # — only meaningful on a release branch and skipped on main. | |
| upgrade-from: [adjacent] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| with: | |
| # Full history + tags so the version resolvers can derive the | |
| # upgrade-from release, and so the local action below is on disk. | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Prepare upgrade test environment | |
| id: prep | |
| uses: ./.github/actions/upgrade-test-setup | |
| with: | |
| upgrade-from: ${{ matrix.upgrade-from }} | |
| - name: Run rolling upgrade tests | |
| if: steps.prep.outputs.skip != 'true' | |
| env: | |
| OPENAI_API_KEY: fake | |
| BUILDX_BUILDER_NAME: ${{ env.BUILDX_BUILDER_NAME }} | |
| KAGENT_HELM_EXTRA_ARGS: --cleanup-on-fail=false | |
| DOCKER_BUILD_ARGS: >- | |
| --cache-from=type=gha,scope=${{ needs.setup.outputs.cache-key }}-e2e | |
| --cache-from=type=gha,scope=${{ env.CACHE_KEY_PREFIX }}-main-e2e | |
| --platform=linux/amd64 | |
| --push | |
| run: | | |
| make run-rolling-upgrade-tests UPGRADE_FROM_VERSION="${{ steps.prep.outputs.version }}" | |
| - name: fail print info | |
| if: failure() && steps.prep.outputs.skip != 'true' | |
| run: | | |
| echo "::error::Failed to run rolling upgrade tests" | |
| kubectl describe pods -n kagent | |
| kubectl get events -n kagent | |
| kubectl logs -n kagent deployment/kagent-controller || true | |
| go-unit-tests: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go/go.mod | |
| cache: true | |
| cache-dependency-path: go/go.sum | |
| - name: Run Go unit tests | |
| working-directory: go | |
| env: | |
| # Runners are ephemeral, so Ryuk's leaked-container cleanup buys nothing, | |
| # and its single session-scoped reaper is contended by the parallel package | |
| # processes of `go test ./...`, intermittently timing out the Postgres tests. | |
| TESTCONTAINERS_RYUK_DISABLED: "true" | |
| run: | | |
| make setup-envtest | |
| export KUBEBUILDER_ASSETS="$(make -s envtest-path)" | |
| go test -race -skip 'TestE2E.*' -v ./... | |
| helm-unit-tests: | |
| env: | |
| VERSION: v0.0.1-test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Helm | |
| uses: azure/setup-helm@v5.0.1 | |
| with: | |
| version: v3.18.0 | |
| # Install unittest plugin | |
| - name: Install unittest plugin | |
| run: | | |
| helm plugin install https://github.com/helm-unittest/helm-unittest | |
| - name: Chart init | |
| run: | | |
| make helm-version | |
| - name: Run helm unit tests | |
| run: | | |
| helm unittest helm/kagent | |
| helm unittest helm/tools/grafana-mcp | |
| ui-tests: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version-file: ui/.nvmrc | |
| # Before any cache step that shells out to yarn: the pinned version in | |
| # ui/package.json "packageManager" is Yarn 4, and without corepack the shim | |
| # on the runner is a different one that cannot read this lock file. | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Cache Yarn downloads | |
| uses: actions/cache@v4 | |
| with: | |
| path: ui/.yarn/cache | |
| key: yarn-${{ runner.os }}-${{ hashFiles('ui/yarn.lock') }} | |
| restore-keys: yarn-${{ runner.os }}- | |
| - name: Install dependencies | |
| working-directory: ./ui | |
| run: yarn install --immutable | |
| - name: Typecheck | |
| working-directory: ./ui | |
| run: yarn typecheck | |
| - name: Run lint | |
| working-directory: ./ui | |
| run: yarn lint | |
| - name: Run unit tests | |
| working-directory: ./ui | |
| run: yarn test | |
| # Both engines the suite declares. Installing only one leaves that project | |
| # failing to launch, which reads as a broken app rather than a missing browser. | |
| - name: Install Playwright browsers | |
| working-directory: ./ui | |
| run: yarn playwright install --with-deps chromium firefox | |
| - name: Run browser tests | |
| working-directory: ./ui | |
| run: yarn test:pw | |
| # This job builds the Docker images for the controller, UI, ADKs, and CLI on arm64. | |
| build: | |
| needs: setup | |
| env: | |
| VERSION: v0.0.1-test | |
| strategy: | |
| matrix: | |
| image: | |
| - controller | |
| - ui | |
| - kagent-adk | |
| - cli | |
| - golang-adk | |
| runs-on: ubuntu-latest | |
| services: | |
| registry: | |
| image: registry:2 | |
| ports: | |
| - 5001:5000 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v4 | |
| with: | |
| platforms: linux/amd64,linux/arm64 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| with: | |
| name: ${{ env.BUILDX_BUILDER_NAME }} | |
| platforms: linux/amd64,linux/arm64 | |
| version: ${{ env.BUILDX_VERSION }} | |
| use: "true" | |
| driver-opts: network=host | |
| - name: Run make build | |
| env: | |
| BUILDX_BUILDER_NAME: ${{ env.BUILDX_BUILDER_NAME }} | |
| DOCKER_BUILD_ARGS: >- | |
| --cache-from=type=gha,scope=${{ needs.setup.outputs.cache-key }}-${{ matrix.image }} | |
| --cache-from=type=gha,scope=${{ env.CACHE_KEY_PREFIX }}-main-${{ matrix.image }} | |
| --cache-to=type=gha,scope=${{ needs.setup.outputs.cache-key }}-${{ matrix.image }},mode=max | |
| --platform=linux/amd64,linux/arm64 | |
| --push | |
| DOCKER_REPO: "${{ github.repository_owner }}/kagent" | |
| DOCKER_BUILDER: "docker buildx build" | |
| run: make build-${{ matrix.image }} | |
| working-directory: ./ | |
| go-lint: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go/go.mod | |
| cache: true | |
| cache-dependency-path: go/go.sum | |
| - name: golangci-lint | |
| working-directory: go | |
| run: make lint | |
| python-test: | |
| env: | |
| OPENAI_API_KEY: fake | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python-version: ["3.11", "3.12", "3.13"] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Install python | |
| run: uv python install ${{ matrix.python-version }} | |
| - name: Sync dependencies | |
| working-directory: ./python | |
| run: uv sync --all-extras | |
| - name: Generate test certificates | |
| working-directory: ./python | |
| run: make generate-test-certs | |
| - name: Run tests | |
| working-directory: ./python | |
| run: make test | |
| python-lint: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Install python | |
| run: uv python install 3.11 | |
| - name: Verify uv.lock matches pyproject.toml | |
| working-directory: ./python | |
| run: uv lock --check | |
| - name: Sync dependencies | |
| working-directory: ./python | |
| run: uv sync --all-extras | |
| - name: Run ruff linter | |
| working-directory: ./python | |
| run: uv run ruff check | |
| - name: Run ruff format check | |
| working-directory: ./python | |
| run: | | |
| if ! uv run ruff format --diff .; then | |
| echo "Ruff formatting issues detected. Please run 'uv run ruff format' locally to fix formatting issues." | |
| exit 1 | |
| fi | |
| manifests-check: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go/go.mod | |
| cache: true | |
| cache-dependency-path: go/go.sum | |
| - name: Generate controller manifests | |
| run: make controller-manifests | |
| - name: Check for uncommitted changes | |
| run: | | |
| if ! git diff --exit-code; then | |
| echo "::error::Controller manifests are out of date!" | |
| echo "::error::Please run 'make controller-manifests' and commit the changes." | |
| echo "" | |
| echo "The following files have differences:" | |
| git diff --name-only | |
| echo "" | |
| echo "Diff details:" | |
| git diff | |
| exit 1 | |
| fi | |
| echo "✓ Controller manifests are up to date" |