Skip to content

ci: add ct install gate, retire CircleCI test job - #49

Closed
QuentinBisson wants to merge 32 commits into
mainfrom
feat/ct-install-gate
Closed

QuentinBisson wants to merge 32 commits into
mainfrom
feat/ct-install-gate

Conversation

@QuentinBisson

@QuentinBisson QuentinBisson commented Jun 9, 2026 •

Copy link
Copy Markdown
Contributor

What

Adds a real install-test gate so dependency bumps like #45 (agentgateway v1→v2) can't
merge without green cluster-level CI.

Changes

New: .github/workflows/chart-test.yaml

  • Runs on every PR/push to main; job name chart-test is required in branch protection.
  • make helm-test — 9 helm-unittest tests covering every validateIngress guard branch (no cluster needed, fastest fail).
  • kind cluster, then sequential prereqs: Gateway API v1 CRDs, agentic-platform-crds, CNPG operator, Dex (in-cluster OIDC), Envoy Gateway CRDs, Cilium CRDs, Kyverno CRDs, Prometheus Operator CRDs.
  • ct lint --all then ct install --charts helm/agentic-platform against all ci/*.yaml fixtures.

Retired: CircleCI test-ingress-modes job
Guard coverage moves into helm-unittest in the new workflow; the CircleCI job and its workflows.test entry are removed. Tag-triggered package-and-push-chart release flow is unchanged.

make helm-test
New target; runs helm unittest helm/agentic-platform. Requires the helm-unittest plugin.

make verify-modes removed
Ingress-mode guard assertions now live in helm/agentic-platform/tests/validate_ingress_test.yaml and run via make helm-test.

Fixture cleanup

  • ci/lint-only/ removed entirely: ct does not recurse into subdirectories, so the files there were invisible to both ct lint and ct install — the directory name was a lie.
  • Previous fixtures consolidated into three: test-muster-direct-values.yaml, test-full-stack-values.yaml (agentgateway-muster + kagent + CNPG + oauth2-proxy), test-netpol-cilium-values.yaml.
  • test-private-registry-values.yaml deleted: template rendering is covered by lint; images at localhost:5000 are never present in kind.

Prereqs added to the workflow

  • Dex (in-memory, HTTP, static client oauth2-proxy) so oauth2-proxy can complete OIDC discovery on startup without crashlooping.
  • CNPG operator so the CloudNativePG Cluster CR in test-full-stack-values.yaml installs.
  • Envoy Gateway, Cilium, Kyverno, and Prometheus Operator CRDs (controllers not required; only the CRD surface is exercised).

helm/agentic-platform/tests/validate_ingress_test.yaml
9 helm-unittest tests: 7 negative guard assertions (errorMessage) + 2 positive render checks covering all validateIngress branches.

kagent.kyvernoPolicy.enabled defaults to false
Kyverno is not a universal platform component; opt-in explicitly. CI fixtures that enable kagent set kyvernoPolicy.enabled: true since Kyverno CRDs are installed as a workflow prereq.

Branch protection
chart-test added as a required status check on main.

Adds a GitHub Actions chart-test job that:
- runs make verify (ingress-mode render guards, replaces the CircleCI
  test-ingress-modes job)
- runs ct lint across both charts
- runs ct install against helm/agentic-platform using the ci/*.yaml
  fixtures, against a kind cluster pre-seeded with Gateway API CRDs
  and agentic-platform-crds

ci/*.yaml fixtures updated to explicitly disable valkey and muster oauth
server (both default to enabled) so they install in kind without
external storage or auth prerequisites. Fixtures that require CNPG,
oauth2-proxy secrets, or a private registry moved to ci/lint-only/ so
they continue to be linted but are excluded from the install job.

Adds test-kagent-basic-values.yaml: kagent controller with bundled
postgres, no oauth2-proxy, exercises the kagent CRD surface in kind.

Branch protection updated: chart-test added as a required status check
so dependency bumps (including majors like the v1→v2 agentgateway bump)
can no longer merge without install-test signal.
- Add Dex (in-cluster HTTP OIDC) as a prereq so test-kagent-routing
  installs cleanly: oauth2-proxy does OIDC discovery on startup and
  crashloops without a reachable issuer. Config in ci/dex-values.yaml
  (in-memory storage, static client matching the kagent-oauth2-proxy
  secret).
- Add CNPG operator as a prereq so test-postgres-values installs the
  CloudNativePG Cluster CR without a missing-CRD error.
- Move test-kagent-routing + test-postgres from ci/lint-only/ back to
  ci/; update OIDC_ISSUER_URL to the in-cluster Dex address.
- Delete test-private-registry-values.yaml: template rendering is
  already covered by lint; images at localhost:5000 are never present
  in kind and the fixture cannot install.
- Remove the ci/lint-only/ directory entirely — ct does not recurse
  into subdirectories so the files were invisible to both lint and
  install.
- Add helm/agentic-platform/tests/validate_ingress_test.yaml: 9 unit
  tests (helm-unittest) covering every validateIngress guard — 7
  negative cases with errorMessage assertions + 2 positive renders.
- Add make helm-test target (helm-unittest plugin); wire it into the
  chart-test workflow alongside the helm-unittest plugin install step.
Comment thread .circleci/config.yml Outdated
…age block

The chart was bumped to v2.2.1 in PR #45 but the subchart image tag stayed
at v1.2.1. The v1.2.1 controller binary ignores KGW_XDS_SERVICE_NAME and
hardcodes XDS_ADDRESS from the Gateway name, causing the data plane to
connect to the wrong service when fullnameOverride renames the controller
Service (agentgateway vs agentgateway-controller). The v2.2.1 binary reads
KGW_XDS_SERVICE_NAME and passes the correct address to data plane pods.

The proxy.image block is removed: the v2 chart does not have a proxy key;
the data plane image is managed internally by the controller binary.
…uisites

ClusterPolicy (kyverno.io/v1) and ServiceMonitor (monitoring.coreos.com/v1)
are rendered when kagent is enabled. The kind cluster used by ct install has
neither CRD set installed, so those fixtures fail with "no matches for kind".

Install the CRDs (no controllers) before ct lint so all fixtures pass.

Add kagent.kyvernoPolicy.enabled (default true) so the ClusterPolicy can be
disabled on clusters without Kyverno.
ct.yaml timeout: 600 is parsed as a bare integer and not forwarded to
helm install --timeout, so Helm uses its default 5m and the kagent
fixture (agentgateway + bundled postgres + oauth2-proxy) times out.
helm-extra-args passes the flag verbatim and resolves the timeout.

oauth2-proxy v7.6.0 uses /ready as its readiness probe (> 7.4.0
branch in the kagent chart's deployment template), which blocks until
OIDC provider initialization completes. Dex startup timing in kind
makes this an unreliable Helm --wait gate; disabling the probe in the
CI fixture lets the install complete as soon as the container starts.
kubectl wait --for=condition=Established errors immediately with
'accessor error: <nil>' when status.conditions has not been
populated yet by the CRD controller. Adding a 2s sleep after
kubectl apply --server-side gives the controller time to set the
field before the wait runs.
…i probe

Two changes that address the test-kagent-routing-values fixture timing out at
600s despite all workload pods becoming Ready by ~32s:

1. Annotate AgentgatewayBackend as a post-install/post-upgrade hook.
   Helm v3.13+ waits for any CRD resource whose schema defines
   status.conditions to reach Ready=True. AgentgatewayBackend defines
   status.conditions and the agentgateway controller sets an initial
   non-True condition while the data-plane confirms backend reachability.
   Moving it to a hook removes it from the --wait scope; it is still
   created (post-install/post-upgrade) and cleaned up before re-creation
   on upgrades (before-hook-creation policy).

2. Override kagent-ui startupProbe in the CI fixture with failureThreshold:30
   at periodSeconds:5 (150s window). The chart default is failureThreshold:3
   at periodSeconds:1 (4s), which is too tight for a single-node kind cluster
   under load from concurrent pod scheduling.

Also add a watchdog loop inside the ct install step that dumps pod states and
AgentgatewayBackend conditions every 30s. Even if the install succeeds, the
snapshots confirm what was blocking in earlier runs; if it fails again the
output survives in the step log.
extraEnv names (OIDC_ISSUER_URL etc.) are not read by oauth2-proxy.
Without a valid provider config it defaults to Google, does OIDC discovery
against accounts.google.com, fails with no internet in kind, and exits.

Replace extraEnv with config.configFile pointing at the in-cluster Dex
prereq (http://dex.dex.svc.cluster.local:5556). The static client already
matches (id: oauth2-proxy, matching secret and redirect URI).
Two bugs found via local kind cluster testing:

1. cookieSecret was 44 bytes (a base64 string whose decoded form is 31 bytes,
   neither of which is 16/24/32). The chart stores it via b64enc in the K8s
   Secret; the pod receives it as-is. Fixed to a plain 32-byte string.

2. configFile override was wrong — the kagent chart wires OIDC config via
   extraArgs using $(VAR_NAME) K8s substitution, not via the cfg file. The
   configFile approach left OIDC_ISSUER_URL and OIDC_REDIRECT_URL empty env
   vars, so oauth2-proxy started with --oidc-issuer-url='' and failed.
   Replaced with extraEnv overrides for all three vars (OIDC_ISSUER_URL,
   OIDC_REDIRECT_URL, UPSTREAM_URL). Helm replaces lists, not merges them,
   so UPSTREAM_URL must be included explicitly.

Verified locally: helm install --wait completes in ~90s on kind.
Remove 8 overlapping fixtures; the 3 that remain give distinct coverage:

- ci-values.yaml: muster-direct baseline (minimal pod set)
- test-full-stack-values.yaml: agentgateway-muster + kagent (oauth2-proxy,
  CNPG postgres, controllerRoute/uiRoute) + mcps + kubernetes NetworkPolicy
  + restricted agentgateway security contexts
- test-netpol-cilium-values.yaml: cilium NetworkPolicy flavor + kagent

Also fixes a latent bug in test-postgres: the CNPG app secret is named
kagent-pg-app (from the default postgres.clusterName = kagent-pg), not
agentic-platform-pg-app as the old fixture had. Never caught because ct
install was not running before this PR.

Verified locally: helm install --wait passes for test-full-stack in ~3m44s.
The extensionImage.reference approach injects an init container via CNPG
that must pull an OCI artifact from ghcr.io at install time. This hits
pull-rate limits in CI runners and is not supported with the ImageVolume
feature on older kind nodes. Postgres comes up clean without it.
@QuentinBisson
QuentinBisson marked this pull request as ready for review June 9, 2026 14:50
@QuentinBisson
QuentinBisson requested a review from a team as a code owner June 9, 2026 14:50
@QuentinBisson QuentinBisson self-assigned this Jun 9, 2026
@QuentinBisson
QuentinBisson enabled auto-merge (squash) June 9, 2026 14:50

@fiunchinho fiunchinho left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard to review this big PR. It looks good overall, and I like that it's not part of the circleci config, so that it can get generated now.

Comment on lines +8 to +16
# Rendered as a post-install/post-upgrade hook so that Helm's --wait loop does
# not block on status.conditions for this CRD (Helm v3.13+ waits for all CRD
# resources with a status.conditions field to reach Ready=True; the agentgateway
# controller sets an initial non-True condition until the data-plane confirms the
# backend is reachable, which can outlast the install timeout).
#
# hook-delete-policy is hook-failed only: Helm updates the resource in place on
# upgrade rather than delete-then-recreate, so there is no window where the
# backend registration is absent while agentgateway is routing live traffic.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this resource is not part of the helm release? what happens on later upgrades, does it get upgraded or ignored?

helm install cnpg cloudnative-pg \
--repo https://cloudnative-pg.github.io/charts \
--namespace cnpg-system --create-namespace --wait \
--version 0.28.2 --timeout 120s

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many different versions hardcoded in this file that can go out of date soon. I don't know of a better way of doing it though :/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well we can have renovate update it. But i'll discuss potential next steps with @piontec

auto-merge was automatically disabled June 18, 2026 08:56

Pull request was closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants