Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
154 commits
Select commit Hold shift + click to select a range
fd8129a
fix(helm): sanitise the chart version in the app.kubernetes.io/versio…
teemow Sep 9, 2026
082da58
ci(fork): publish dev images and charts to ghcr.io/<owner> from the p…
teemow Sep 9, 2026
933ec60
ci(fork): retry image builds and keep the matrix running on a single …
teemow Sep 9, 2026
ca672ce
fix(docker): apk upgrade in the Go runtime image
teemow Sep 10, 2026
e24fea4
ci(fork): test and scan the consumed branch, re-pin weekly by workflo…
teemow Sep 10, 2026
5cda7ea
ci(fork): mirror as the App and cancel the runs upstream's files start
teemow Sep 10, 2026
f9e6f43
ci(fork): open the sync's pull requests in this repository, not the p…
teemow Sep 10, 2026
11dec02
build(fork): the charts' Substrate dependencies come from the Giant S…
teemow Sep 10, 2026
78e9501
ci(fork): the e2e cluster runs the Substrate the charts depend on
teemow Sep 10, 2026
19e08d6
ci(fork): the consumed branch is giantswarm
teemow Sep 10, 2026
6567ce3
ci(fork): a tag is a release of the line, vX.Y.Z-gs.N
teemow Sep 10, 2026
60e5567
chore: align files according to platform standards
giantswarm-align-files[bot] Sep 10, 2026
50ab485
fix(helm): keep the kagent-crds CRDs on uninstall (helm.sh/resource-p…
teemow Sep 10, 2026
8accd4f
feat(api): a per-source credential for private git skill and plugin s…
teemow Sep 11, 2026
18df629
ci(fork): stamp the golang-adk digest and SUBSTRATE_VERSION into the …
teemow Sep 12, 2026
f4342d5
feat(helm): controller.agentImage.digest and an optional default Harn…
teemow Sep 12, 2026
82db75b
feat(helm): a ConfigMap of the chart's runtime image references for t…
teemow Sep 12, 2026
20e76aa
build(fork): pin Substrate to the line's release 0.0.27-gs.6 (#18)
teemow Sep 12, 2026
be713ea
build(fork): pin Substrate to the line's release 0.0.27-gs.7 (#20)
teemow Sep 12, 2026
62426f0
fix(helm): label the runtime images ConfigMap for helm-controller to …
teemow Sep 12, 2026
4977848
fix(helm): drop empty-valued matchLabels from the Harness admission s…
teemow Sep 13, 2026
f73735b
fix(adk): load a SKILL.md whose frontmatter carries fields outside th…
teemow Sep 13, 2026
3e9d165
chore(fork): re-pin Substrate to the line's release 0.0.27-gs.9 — the…
teemow Sep 13, 2026
3a8103b
build(fork): pin Substrate to the line's re-pin candidate 0.0.30-dev.…
teemow Sep 14, 2026
cf4dc29
build(fork): pin Substrate to the line's release 0.0.30-gs.1
teemow Sep 14, 2026
2ec1bf5
feat(models): add prompt caching for the Anthropic provider
teemow Sep 10, 2026
807200f
test(adk): deep-copy caller objects in the prompt cache no-mutation t…
teemow Sep 10, 2026
07e3cc9
chore(fork): re-pin Substrate to the line's release 0.0.30-gs.4 — the…
teemow Sep 15, 2026
781cddc
feat(runtime): name the agent and the user on every model call
teemow Sep 19, 2026
57c48d5
ci(fork): publish to gsoci from CircleCI
teemow Sep 19, 2026
04e6cc7
chore(fork): re-pin Substrate to the line's release 0.0.30-gs.5 — the…
teemow Sep 19, 2026
e29a52e
fix(helm): trim every trailing non-alphanumeric from the truncated la…
teemow Sep 19, 2026
4fc6f15
ci(fork): publish through the orb's stock jobs with decoupled versions
teemow Sep 19, 2026
2a1383e
chore(fork): re-pin Substrate to the line's release 1.0.0 — the first…
teemow Sep 19, 2026
0878be5
sync: upstream 7471879 conflicts with carried commit 3999b3b [skip ci…
heraldbot[bot] Sep 21, 2026
781f88e
chore(substrate): pin 1.0.1
QuentinBisson Sep 22, 2026
e525198
feat(helm): the Harness's context compaction from harness.compaction
QuentinBisson Sep 22, 2026
68abaef
chore(fork): upstream pin annotation
QuentinBisson Sep 22, 2026
3ed3405
chore(substrate): pin the Substrate line's dev build of the v0.2.0-be…
QuentinBisson Sep 22, 2026
2afceeb
chore: declare Renovate off on the fork line
teemow Sep 23, 2026
bf45d89
fix(ui): the chat journeys no longer race two tooltips and the reply
teemow Sep 23, 2026
40e6e4f
ci(fork): keep the browser suite's evidence of a failed run
teemow Sep 23, 2026
2981105
chore: align files according to platform standards
giantswarm-align-files[bot] Sep 23, 2026
75ee169
test(ui): count a journey's steps per test, and budget the transcript's
teemow Sep 23, 2026
0e66e3a
test(ui): press a template's own Delete, once its page is there
teemow Sep 23, 2026
017052a
test(ui): press the checkpoints' delete buttons once they have arrived
teemow Sep 23, 2026
a52b01f
ci(fork): keep the evidence of a flaky browser test too
teemow Sep 23, 2026
5ed3887
feat(models): turn a thinking model's reasoning off on Ollama
teemow Sep 23, 2026
6e30032
ci: pin giantswarm/architect orb 10.10.0
teemow Sep 24, 2026
ece3b2d
test(ui): press a transcript's controls once its diagram has landed
teemow Sep 24, 2026
9133d39
test(ui): wait for pressUntil's control before pressing it
teemow Sep 24, 2026
1cec8ff
test(ui): leave the schedules lifecycle through its Back button
teemow Sep 24, 2026
ed52d27
test(ui): one test per claim for a bare build's extension points
teemow Sep 24, 2026
35e7a48
fix(models): stream the Anthropic call behind a non-streaming request
teemow Sep 24, 2026
a761630
chore(substrate): pin the Substrate line's release 1.1.0 (#94)
QuentinBisson Sep 24, 2026
56cea13
chore(fork): upstream pin annotation main@dd3b240
QuentinBisson Sep 25, 2026
d9f1354
sync: re-pin onto upstream f5d9b95 blocked — ci(fork): publish dev im…
heraldbot[bot] Sep 28, 2026
6ca98fc
feat(api): Agent.spec.egress — HTTP(S) origins an Agent may reach
QuentinBisson Oct 5, 2026
93f278b
feat(harness): forward the caller's credential on MCP calls from the …
QuentinBisson Oct 5, 2026
4be3e50
feat(harness): run Claude Code as the image's unprivileged user when …
QuentinBisson Sep 26, 2026
01df098
feat(translator): the claude Harness asks Substrate for the capabilit…
QuentinBisson Sep 28, 2026
6f7cd16
fix(harness): let the unprivileged Claude traverse the durable direct…
QuentinBisson Sep 28, 2026
dc6acf4
fix(harness): start the unprivileged Claude with no supplementary groups
QuentinBisson Sep 28, 2026
2ffd7a7
fix(harness): hand Claude's trees over without the DAC capabilities a…
QuentinBisson Sep 28, 2026
bb192af
fix(session): check a share's expiry against the clock that set it
QuentinBisson Sep 29, 2026
175c07a
chore(fork): upstream pin annotation main@e451630
QuentinBisson Sep 29, 2026
a77a33c
chore(substrate): pin the Substrate line's re-pin candidate 43ef683f …
QuentinBisson Oct 5, 2026
ae3efea
feat(substrate): the compiled ActorTemplate carries the revision's eg…
QuentinBisson Sep 29, 2026
5d3a144
fix(a2agateway): end a send whose runtime is lost, and delete a pause…
QuentinBisson Sep 29, 2026
661fe99
fix(harness): settle a cancel for a task the runtime holds nothing fo…
QuentinBisson Sep 29, 2026
b878562
fix(session): end a working turn whose runtime stopped saving events
QuentinBisson Sep 29, 2026
213f267
feat(session): suspend a runtime paused for input once the pause is o…
QuentinBisson Sep 29, 2026
adfa896
fix(session): leave an expired pause on a lost node alone, and delete…
QuentinBisson Sep 29, 2026
b16eaa4
fix(controller): start a crashed golden boot over instead of failing …
QuentinBisson Sep 29, 2026
fce4ccc
fix(migrations): refuse to start on a 1.x database instead of migrati…
QuentinBisson Sep 29, 2026
127c814
fix(helm): render the chart's Harness on api.kagent.dev/v1alpha3 with…
QuentinBisson Sep 29, 2026
a691240
fix(harness): refuse forwarder paths with dot segments or encoded sla…
QuentinBisson Oct 1, 2026
e0d2e00
fix(harness): check the raw forwarder path and forward only transport…
QuentinBisson Oct 1, 2026
0c71bc8
fix(harness): keep the compiled skills on Claude turns that need appr…
QuentinBisson Oct 1, 2026
cab4553
fix(a2agateway): run a turn a share of the session authorizes in its …
teemow Oct 1, 2026
ec3094e
fix(adk): defer MCP tool discovery that awaits the caller's credential
teemow Oct 1, 2026
ad4664f
feat(helm): harnesses renders further Harnesses beside the chart's own
QuentinBisson Sep 29, 2026
a46d6f8
feat(runtime): name the session on every model call
teemow Oct 2, 2026
f5425c0
fix(session): fail a session whose resume finds its snapshot lost
QuentinBisson Oct 5, 2026
3063b30
feat(harness): keep Claude's policy out of its reach
QuentinBisson Oct 5, 2026
cecc794
fix(harness): trust nothing Claude could write before a root start
QuentinBisson Oct 5, 2026
cbb2241
test(harness): build the driver tests off unix and pin the CI test ca…
QuentinBisson Oct 5, 2026
7557c78
ci: exec the root test binary straight from setpriv
QuentinBisson Oct 5, 2026
cf8b0a3
fix(harness): touch only the roots of Claude's trees on a root start
QuentinBisson Oct 5, 2026
90b0dd1
fix(adk): create /config for the Go ADK image's own user
QuentinBisson Oct 5, 2026
1da4afb
feat(api): Harness.spec.claude.limits — a budget and a turn cap on ev…
QuentinBisson Oct 5, 2026
b484d0c
feat(helm): harnesses[].limits renders Harness.spec.claude.limits
QuentinBisson Oct 5, 2026
29bccf2
fix(translator): the claude compiler accepts a ModelConfig with promp…
QuentinBisson Oct 5, 2026
4adf7e0
chore(fork): upstream pin annotation main@bf8afa5
QuentinBisson Oct 5, 2026
0f44bc3
fix(adk): name the person of the turn as the request span's end user …
fiunchinho Oct 5, 2026
d37bfc9
test(ui): budget the extension points journey now that its file holds…
QuentinBisson Oct 5, 2026
90d169b
fix(helm): keep the chart's kagent-api RemoteMCPServer out of tool di…
QuentinBisson Oct 5, 2026
87de232
test(e2e): prove the paused-runtime TTL, the lost runtime, the Claude…
QuentinBisson Oct 5, 2026
8d6a7fe
test(ui): measure the composer once the other conversation has loaded
QuentinBisson Oct 6, 2026
dff8df2
chore: align files according to platform standards
giantswarm-align-files[bot] Sep 30, 2026
2bb7714
ci(fork): count the candidates the re-pin left behind when numbering …
QuentinBisson Oct 5, 2026
49e0789
docs(fork): the ledger of the 2026-10-05 re-pin onto main@bf8afa56
QuentinBisson Oct 5, 2026
f7bf3da
chore(fork): run the line on Substrate 1.4.0, the re-pin onto kagent-…
QuentinBisson Oct 5, 2026
1b16660
fix(helm): keep the Agent and SandboxTemplate CRDs on uninstall like …
QuentinBisson Oct 6, 2026
9d8ab6c
docs(fork): record the 1.3.0 and 1.3.1 releases (#169)
QuentinBisson Oct 6, 2026
38f2d58
fix(translator): the claude compiler caps Claude Code's output at the…
QuentinBisson Oct 6, 2026
87b22df
fix(session): settle a failed quiesce from the Actor's state
teemow Oct 6, 2026
7d4fb02
docs(fork): ledger row for release 1.2.6
teemow Oct 6, 2026
b1c8f61
fix(session): take over a quiescence claim whose holder stopped (#177)
teemow Oct 6, 2026
db51592
fix(session): delete expired shares on the expiration sweep
teemow Oct 7, 2026
a1e193c
docs(fork): carry the expired-share sweep
teemow Oct 7, 2026
86e44e6
docs(fork): the expired-share sweep is queue row 122
teemow Oct 7, 2026
90279cb
docs(fork): release-1.2 stable is hand-cut while the orb guard fails
teemow Oct 7, 2026
f623209
fix(session): resume a superseded revision's session on the current one
teemow Oct 7, 2026
2bdb774
docs(fork): carry the superseded-revision resume on the session workflow
teemow Oct 7, 2026
5ba65a0
fix(session): keep the repoint within the lint rules
teemow Oct 7, 2026
e12b034
test(grpcserver): wire a session workflow where a gateway drives turns
teemow Oct 7, 2026
48caa33
fix(a2a): wait for an in-flight actor operation instead of failing
teemow Oct 7, 2026
3932828
docs(fork): carry the wait for an in-flight actor operation
teemow Oct 7, 2026
013362b
docs(fork): rows name environment roles, not installations
teemow Oct 7, 2026
09ec3db
fix(session): delete the sessions of a deleted Agent
teemow Oct 7, 2026
12fd5a8
docs(fork): ledger rows for releases 1.2.8 to 1.2.10
teemow Oct 7, 2026
7071312
fix(ui): start nginx before the controller Service resolves
teemow Oct 7, 2026
4f0cc25
docs(fork): ledger row for the UI's nginx resolver
teemow Oct 7, 2026
be9bce0
feat(cli): send a caller token as the bearer of every controller call
teemow Oct 7, 2026
7b8b3e0
fix(session): end a turn whose runtime is lost after it took the input
teemow Oct 7, 2026
574612f
ci(fork): follow every controller pod's log through the e2e run
teemow Oct 7, 2026
087b33c
docs(fork): ledger rows for the lost turn and the controller logs
teemow Oct 7, 2026
db88c29
chore(substrate): run the line on 1.5.0-rc.6, the fencing token's line
teemow Oct 7, 2026
b473abb
fix(session): fence a frozen quiescence holder's late Pause or Suspend
teemow Oct 7, 2026
826c63a
docs(fork): the fencing row is queued upstream with the takeover row
teemow Oct 7, 2026
39ee224
test(grpcserver): wait for the server span and metric in telemetry test
teemow Oct 8, 2026
ada981c
docs(fork): carry the telemetry test's wait for the server span
teemow Oct 8, 2026
736a142
docs(fork): the lost-turn row is queue row 134
teemow Oct 8, 2026
e8a6bf6
fix(substrate): send unfenced calls to a Substrate without the token
teemow Oct 8, 2026
a4529a9
docs(fork): ledger row for the unfenced fallback, #216's row corrected
teemow Oct 8, 2026
5f66481
chore: align files according to platform standards (#219)
giantswarm-align-files[bot] Oct 8, 2026
2df6988
fix(controller): write the Harness Ready condition from its golden boots
teemow Oct 8, 2026
dcc8457
docs(fork): FORK.md row for the Harness Ready condition
teemow Oct 8, 2026
9b8a4a7
fix(controller): keep a Harness Ready until a golden boot fails
teemow Oct 8, 2026
437289c
docs(fork): the Harness Ready row reads True until a boot fails
teemow Oct 8, 2026
c8445be
docs(fork): the Harness Ready row is queue row 136
teemow Oct 8, 2026
6a08500
fix(session): retry a failed quiesce once the Actor runs again (#234)
teemow Oct 8, 2026
1083ec2
ci(telemetry): fetch the contract's upstream sources once at their pi…
teemow Oct 8, 2026
2a4b6a3
chore(substrate): run the line on 1.5.0, the fencing token's release …
QuentinBisson Oct 8, 2026
c615a33
test(sandbox): bound TestServe's process wait by the guest, not the r…
teemow Oct 8, 2026
02ef87d
fix(controller): patch the Harness and ModelConfig status without a r…
QuentinBisson Oct 8, 2026
0ff4075
test(core): skip envtest tests without KUBEBUILDER_ASSETS
teemow Oct 8, 2026
8f2a928
fix(harness): one owner for an MCP server's Authorization under calle…
QuentinBisson Oct 8, 2026
549dc32
fix(skills): git sends the Authorization the egress gateway replaces …
teemow Oct 8, 2026
57a0030
test(e2e): prove the egress credential contract through the gateway f…
QuentinBisson Oct 8, 2026
fb448c8
feat(harness): caller routes on the Claude harness forwarder, git thr…
QuentinBisson Oct 2, 2026
12c2336
fix(harness): forward the credential a caller route admitted, pin git…
QuentinBisson Oct 2, 2026
9e17f20
fix(harness): end the forwarded requests of a turn when its credentia…
QuentinBisson Oct 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
478 changes: 478 additions & 0 deletions .circleci/config.yml

Large diffs are not rendered by default.

16 changes: 0 additions & 16 deletions .github/actions/build-release-artifacts/action.yaml

This file was deleted.

22 changes: 0 additions & 22 deletions .github/actions/publish-helm/action.yaml

This file was deleted.

36 changes: 0 additions & 36 deletions .github/actions/publish-image/action.yaml

This file was deleted.

179 changes: 137 additions & 42 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
name: CI Build

# Fork (giantswarm/kagent-upstream): the consumed branch and the sync
# candidates run this suite on every push and pull request, on GitHub-hosted
# runners (the org has no Blacksmith runners), and report one `ci-ok` status
# for the ruleset. No paths-ignore: a docs-only pull request must still report
# the required checks to be mergeable. See FORK.md.
on:
push:
branches: [main, "release/**"]
paths:
- "**"
- "!**/*.md"
- "docs/env.md"
branches: [main, "release/**", giantswarm, "sync/**"]
pull_request:
branches: [main, "release/**"]
paths:
- "**"
- "!**/*.md"
- "docs/env.md"
branches: [main, "release/**", giantswarm]
merge_group:
workflow_dispatch:
inputs:
Expand Down Expand Up @@ -53,18 +50,31 @@ jobs:
strategy:
fail-fast: false
matrix:
sandbox_class: [gvisor, microvm]
# The Giant Swarm line of Substrate publishes the gVisor worker only
# (its FORK.md, "Publishing"); the platform runs no micro-VM pool.
sandbox_class: [gvisor]
env:
VERSION: v0.0.1-test
SUBSTRATE_VERSION: 0.3.0-alpha3
KIND_SANDBOX_CLASS: ${{ matrix.sandbox_class }}
# Keep the four-vCPU runner bounded; manual runs can compare higher concurrency.
E2E_PARALLEL: ${{ inputs.e2e_parallel || '4' }}
runs-on: blacksmith-4vcpu-ubuntu-2404
# The upstream release whose kubectl-ate performs the CA/JWT bootstrap
# below; the Giant Swarm line of Substrate publishes no CLI. Same pin as
# the Makefile's SUBSTRATE_VERSION is built from.
KUBECTL_ATE_VERSION: 0.0.29
runs-on: ubuntu-latest
timeout-minutes: 40
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Resolve the Substrate pin
# One source of truth: the Makefile's SUBSTRATE_VERSION / SUBSTRATE_REPO
# (the Giant Swarm line of Substrate, gsoci.azurecr.io/giantswarm/substrate) drive
# the charts' dependencies and the Substrate this cluster runs.
run: |
make -s substrate-pin | tee -a "$GITHUB_ENV"
registry=$(make -s substrate-pin | sed -n 's|^SUBSTRATE_REPO=oci://||p')
echo "SUBSTRATE_IMAGE_REGISTRY=${registry%/helm}" | tee -a "$GITHUB_ENV"
- name: Initialize Environment
uses: ./.github/actions/initialize-environment
- name: Set up Go
Expand All @@ -88,12 +98,13 @@ jobs:
# See https://github.com/openai/codex/issues/14919
run: |
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 || true
- name: Setup Blacksmith Builder
uses: useblacksmith/setup-docker-builder@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
with:
cache-key: kagent-e2e
platforms: linux/amd64
nofallback: true
name: ${{ env.BUILDX_BUILDER_NAME }}
version: ${{ env.BUILDX_VERSION }}
driver-opts: network=host
use: "true"

- name: Set up Helm
uses: azure/setup-helm@v5.0.1
Expand All @@ -112,14 +123,24 @@ jobs:

- 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"
curl -fsSL -o kubectl-ate "https://github.com/kagent-dev/substrate/releases/download/v${KUBECTL_ATE_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 \
# The egress gateway dials upstream HTTPS itself and trusts this CA
# there; the egress credential tests sign their HTTPS upstreams with it.
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -days 1 -subj "/CN=kagent e2e egress upstream" \
-addext "basicConstraints=critical,CA:TRUE" -addext "keyUsage=critical,keyCertSign" \
-keyout "$RUNNER_TEMP/egress-ca.key" -out "$RUNNER_TEMP/egress-ca.crt"
helm upgrade --install substrate-crds "${SUBSTRATE_REPO}/substrate-crds" --version "${SUBSTRATE_VERSION}" --namespace ate-system --create-namespace
# Golden boots fetch git skill and plugin sources in atespace
# ate-golden, so it resolves kagent Secrets as the session atespace does.
helm upgrade --install substrate "${SUBSTRATE_REPO}/substrate" --version "${SUBSTRATE_VERSION}" --namespace ate-system \
--set-string 'atelet.extraArgs[0]=--localhost-registry-replacement=kind-registry:5000' \
--set-string 'ateApi.extraArgs[0]=--template-resync-interval=250ms' \
--set 'credentialProvider.namespacePolicies[0].atespace=kagent' \
--set 'credentialProvider.namespacePolicies[0].allowedNamespaces[0]=kagent'
--set 'credentialProvider.namespacePolicies[0].allowedNamespaces[0]=kagent' \
--set 'credentialProvider.namespacePolicies[1].atespace=ate-golden' \
--set 'credentialProvider.namespacePolicies[1].allowedNamespaces[0]=kagent' \
--set-file "atenetEgress.upstreamTrust.caBundle=$RUNNER_TEMP/egress-ca.crt"
./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
Expand All @@ -128,7 +149,7 @@ jobs:
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
helm upgrade substrate "${SUBSTRATE_REPO}/substrate" --version "${SUBSTRATE_VERSION}" --namespace ate-system --reuse-values --wait --timeout 5m

- name: Cache Cloud Hypervisor assets
if: matrix.sandbox_class == 'microvm'
Expand Down Expand Up @@ -157,7 +178,7 @@ jobs:
--set substrateWorkerPool.create=true
--set substrateWorkerPool.replicas=4
--set-string substrateWorkerPool.sandboxClass=${{ matrix.sandbox_class }}
--set-string substrateWorkerPool.workerImage=ghcr.io/kagent-dev/substrate/ateom-${{ matrix.sandbox_class }}:v${{ env.SUBSTRATE_VERSION }}
--set-string substrateWorkerPool.workerImage=${{ env.SUBSTRATE_IMAGE_REGISTRY }}/ateom-${{ matrix.sandbox_class }}:${{ env.SUBSTRATE_VERSION }}
--set otel.traces.enabled=true
--set-string otel.exporter.otlp.endpoint=http://e2e-otlp.kagent.svc.cluster.local:14317
run: |
Expand Down Expand Up @@ -213,6 +234,7 @@ jobs:
export KAGENT_E2E_CLI="$PWD/core/bin/kagent-local"
export KAGENT_E2E_API_URL="$KAGENT_API_URL"
export KAGENT_E2E_LOCAL_HOST=172.17.0.1
export KAGENT_E2E_EGRESS_CA_FILE="$RUNNER_TEMP/egress-ca.crt" KAGENT_E2E_EGRESS_CA_KEY_FILE="$RUNNER_TEMP/egress-ca.key"
envsubst < core/test/e2e/manifests/tracing.yaml.tmpl | kubectl apply -f -
# TestMain keeps the receiver alive for every runtime's response flush.
export KAGENT_E2E_OTLP_LISTEN_ADDRESS=:14317
Expand All @@ -222,15 +244,27 @@ jobs:
worker_logs_pid=$!
kubectl logs -n ate-system -l app --all-containers --prefix --timestamps --tail=-1 --follow --max-log-requests=20 > "$RUNNER_TEMP/e2e-logs/substrate.log" 2>&1 &
substrate_logs_pid=$!
trap 'kill "$worker_logs_pid" "$substrate_logs_pid" 2>/dev/null || true; wait "$worker_logs_pid" "$substrate_logs_pid" 2>/dev/null || true' EXIT
# Tests roll the controller (withControllerEnv, the sandbox restart), and a
# log read at the end holds only the final pod: every controller pod is
# followed from the moment it runs, into a file of its own.
controller_log_pids="$RUNNER_TEMP/controller-log-pids"
: > "$controller_log_pids"
(
followed=" "
while true; do
for pod in $(kubectl get pods -n kagent -l app.kubernetes.io/component=controller -o jsonpath='{.items[?(@.status.phase=="Running")].metadata.name}'); do
case "$followed" in *" $pod "*) continue ;; esac
followed="$followed$pod "
kubectl logs -n kagent "$pod" --all-containers --prefix --timestamps --tail=-1 --follow > "$RUNNER_TEMP/e2e-logs/controller-$pod.log" 2>&1 &
echo $! >> "$controller_log_pids"
done
sleep 5
done
) &
controller_logs_pid=$!
trap 'kill "$worker_logs_pid" "$substrate_logs_pid" "$controller_logs_pid" $(cat "$controller_log_pids") 2>/dev/null || true; wait "$worker_logs_pid" "$substrate_logs_pid" "$controller_logs_pid" $(cat "$controller_log_pids") 2>/dev/null || true' EXIT
go test -v github.com/kagent-dev/kagent/go/core/test/e2e -shuffle=on -parallel "$E2E_PARALLEL" -count=1 -timeout=30m 2>&1 | tee "$RUNNER_TEMP/e2e-logs/tests.log"

- name: Collect E2E controller logs
if: always()
run: |
mkdir -p "$RUNNER_TEMP/e2e-logs"
kubectl logs -n kagent deployment/kagent-controller --timestamps > "$RUNNER_TEMP/e2e-logs/controller.log" 2>&1 || true

- name: Upload E2E logs
if: always()
uses: actions/upload-artifact@v7
Expand Down Expand Up @@ -288,6 +322,11 @@ jobs:
with:
go-version-file: go/go.mod
cache: false
- name: Cache the contract's upstream sources at their pins
uses: actions/cache@v6
with:
path: telemetry/deps
key: telemetry-deps-${{ hashFiles('telemetry/versions.env') }}
- name: Check the registry and generated conventions
run: make semconv-verify

Expand All @@ -296,7 +335,7 @@ jobs:
- setup
env:
VERSION: v0.0.1-test
runs-on: blacksmith-4vcpu-ubuntu-2404
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -344,7 +383,7 @@ jobs:
- setup
env:
VERSION: v0.0.1-test
runs-on: blacksmith-4vcpu-ubuntu-2404
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -412,6 +451,17 @@ jobs:
export KUBEBUILDER_ASSETS="$(make -s envtest-path)"
go test -race -skip 'TestE2E.*' -v ./...

# Fork: the claude harness splits Claude Code off only when it runs as root,
# so its root-only tests run again as root, with no capability beyond the
# CHOWN, SETUID and SETGID the claude translator asks Substrate for.
- name: Run the claude harness tests as root
working-directory: go
run: |
go test -c -o "$RUNNER_TEMP/claude-adapter.test" ./harness/claude/internal/adapter/
caps="--bounding-set=-all,+chown,+setuid,+setgid --inh-caps=-all --ambient-caps=-all"
sudo setpriv $caps -- grep -E '^Cap(Prm|Eff)' /proc/self/status
sudo setpriv $caps -- "$RUNNER_TEMP/claude-adapter.test" -test.count=1 -test.v

helm-unit-tests:
env:
VERSION: v0.0.1-test
Expand Down Expand Up @@ -439,7 +489,7 @@ jobs:
helm unittest helm/tools/grafana-mcp

ui-tests:
runs-on: blacksmith-4vcpu-ubuntu-2404
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
Expand Down Expand Up @@ -491,22 +541,38 @@ jobs:
working-directory: ./ui
run: yarn test:pw

# What a failed attempt leaves behind: its screenshot and video, and the trace of
# its retry. The log names the step that timed out; only the trace shows what was
# on the page under the pointer while it did, and the runner discards it otherwise.
# Kept whether the job failed or a retry passed: a flaky test leaves the job green
# and is the case that most needs its trace. A run whose every attempt passed
# writes nothing here (Playwright's `.last-run.json` is hidden, and hidden files
# are not uploaded), so it keeps no artifact.
- name: Keep the browser suite's evidence of a failed attempt
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ui-test-results
path: ui/test-results
if-no-files-found: ignore
retention-days: 7

# This job builds the Docker images for the controller, UI, ADKs, and CLI on arm64.
build:
env:
VERSION: v0.0.1-test
strategy:
matrix:
# Fork: the images the platform publishes (FORK.md) — the Python ADK,
# the Codex harness and the CLI image are not offered.
image:
- controller
- ui
- kagent-adk
- cli
- golang-adk
- claude-harness
- codex-harness
- sandbox-guest
runs-on: blacksmith-2vcpu-ubuntu-2404
runs-on: ubuntu-latest
services:
registry:
image: registry:2
Expand All @@ -519,12 +585,13 @@ jobs:
uses: docker/setup-qemu-action@v4
with:
platforms: linux/amd64,linux/arm64
- name: Setup Blacksmith Builder
uses: useblacksmith/setup-docker-builder@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
with:
cache-key: kagent-build-${{ matrix.image }}
platforms: linux/amd64,linux/arm64
nofallback: true
name: ${{ env.BUILDX_BUILDER_NAME }}
version: ${{ env.BUILDX_VERSION }}
driver-opts: network=host
use: "true"
- name: Run make build
env:
DOCKER_BUILD_ARGS: >-
Expand Down Expand Up @@ -649,3 +716,31 @@ jobs:
exit 1
fi
echo "✓ Controller manifests are up to date"

# Fork: the one status the ruleset requires. Every job above must succeed; a
# leg a job skips internally (the upgrade tests on a non-release base) still
# ends in success, a skipped or failed job does not.
ci-ok:
if: always()
needs:
- setup
- test-e2e
- proto-check
- upgrade-tests
- rolling-upgrade-tests
- go-unit-tests
- helm-unit-tests
- ui-tests
- build
- go-lint
- python-test
- python-lint
- manifests-check
runs-on: ubuntu-latest
steps:
- name: Every job succeeded
env:
RESULTS: ${{ toJSON(needs) }}
run: |
jq -r 'to_entries[] | "\(.key): \(.value.result)"' <<< "$RESULTS"
jq -e 'all(.[]; .result == "success")' <<< "$RESULTS" > /dev/null
Loading
Loading