Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

\1- **The three upstream lines at their decoupled releases: kagent `1.0.0`, Substrate `1.0.0`, agentgateway `2.0.0` under its nested names** (giantswarm/agent-platform#608; epic giantswarm/giantswarm#37705). The lines release stable semver of their own, decoupled from the upstream versions their `FORK.md`s record, and publish nothing more under the former `vX.Y.Z-gs.N` scheme. `components.kagent*.versionRange` and `components.substrate*.versionRange` are `>=1.0.0 <1.1.0`; both charts name the agentgateway line's `2.0.0` in full — `agentgateway.controller.image` `giantswarm/agentgateway-upstream/controller:2.0.0`, `agentgateway.proxy.image` `giantswarm/agentgateway-upstream/agentgateway:2.0.0`, `substrate.images.agentgateway` the same data plane for Substrate's egress gateway — so the packaging chart's defaults cannot move the images (a value wins over a chart default, and a default that moved alone to the nested names rendered a tag that existed only there); `components.agentgateway.versionRange` is `>=2.2.2 <3.0.0`, the packaging release that renders a bare tag as written. The range shape follows the scheme — a patch of a line never changes a runtime contract, a re-pin onto another upstream release is at least a minor — so `agent-platform.substrate.validateRange` admits an exact version or `>=X.Y.Z <X.(Y+1).0` and refuses a `-0` bound (Flux's Masterminds semver skips prereleases while no bound of a range carries one and evaluates them all once one does, so `<1.1.0-0` would have put every installation on the line's newest dev build) and the former `>=X.Y.Z-gs.N <X.Y.(Z+1)-0`, `agent-platform.substrate.workerPoolSpreadFloor` is `1.0.0`, `examples/customer-bom.yaml` pins `1.0.0` and `2.2.2`, and the verify scripts' fixtures move to the stable shapes. UPGRADE.md names the operator's part.\n\n- **The kagent line's and the Substrate line's charts come from gsoci; the lines move to `v0.11.0-gs.22` and `v0.0.30-gs.5`** (giantswarm/agent-platform#580; epic giantswarm/giantswarm#37853). The two lines publish natively to the org's registry from CircleCI — the multi-arch images and the charts, signed with the Giant Swarm identity, releases and dev builds alike — so `components.kagent.repository` and `components.kagent-crds.repository` are `oci://gsoci.azurecr.io/giantswarm/kagent/helm`, `components.substrate.repository` and `components.substrate-crds.repository` are `oci://gsoci.azurecr.io/giantswarm/substrate/helm`. The Substrate floor moves to `0.0.30-gs.5` — the line's first release published there, the patches of gs.4 — in `components.substrate*.versionRange` (`>=0.0.30-gs.5 <0.0.31-0`), the BOM pin and, derived from it, the kagent WorkerPool's worker image, so the atelet and the worker are one native, signed release and nothing of the line depends on a copy. The kagent floor moves to `0.11.0-gs.22` the same way (`components.kagent*.versionRange` `>=0.11.0-gs.22 <0.11.1-0`, the BOM pin): the chart paths on gsoci begin with each line's first native release — the older releases exist there as retagger's image copies only, no charts — and the kagent chart's stamped digests of its Go ADK and Claude harness images resolve on gsoci from that release on. With the charts the last ghcr.io reference of the two lines goes: a default installation pulls everything of kagent and Substrate from gsoci, and the dev channel (a `components.<name>.semverFilter` on the lines' `-dev.giantswarm.` builds) needs no registry override any more — `kagent.registry` and `substrate.image.registry` stay on their defaults (README "Dev channel"). `make verify-images` tolerates the two lines by name no longer; the upstream CloudNativePG chart is the one pending entry left, behind a Giant Swarm wrapper release on the same operator line. `verify-components` and `verify-kagent-wiring` assert the new sources; `verify-target` holds them on both sides of the golden comparison until `origin/main` carries them. UPGRADE.md.
### Added

- **The three upstream lines at their decoupled releases: kagent `1.0.0`, Substrate `1.0.0`, agentgateway `2.0.0` under its nested names** (giantswarm/agent-platform#608; epic giantswarm/giantswarm#37705). The lines release stable semver of their own, decoupled from the upstream versions their `FORK.md`s record, and publish nothing more under the former `vX.Y.Z-gs.N` scheme. `components.kagent*.versionRange` and `components.substrate*.versionRange` are `>=1.0.0 <1.1.0`; both charts name the agentgateway line's `2.0.0` in full — `agentgateway.controller.image` `giantswarm/agentgateway-upstream/controller:2.0.0`, `agentgateway.proxy.image` `giantswarm/agentgateway-upstream/agentgateway:2.0.0`, `substrate.images.agentgateway` the same data plane for Substrate's egress gateway — so the packaging chart's defaults cannot move the images (a value wins over a chart default, and a default that moved alone to the nested names rendered a tag that existed only there); `components.agentgateway.versionRange` is `>=2.2.2 <3.0.0`, the packaging release that renders a bare tag as written. The range shape follows the scheme — a patch of a line never changes a runtime contract, a re-pin onto another upstream release is at least a minor — so `agent-platform.substrate.validateRange` admits an exact version or `>=X.Y.Z <X.(Y+1).0` and refuses a `-0` bound (Flux's Masterminds semver skips prereleases while no bound of a range carries one and evaluates them all once one does, so `<1.1.0-0` would have put every installation on the line's newest dev build) and the former `>=X.Y.Z-gs.N <X.Y.(Z+1)-0`, `agent-platform.substrate.workerPoolSpreadFloor` is `1.0.0`, `examples/customer-bom.yaml` pins `1.0.0` and `2.2.2`, and the verify scripts' fixtures move to the stable shapes. UPGRADE.md names the operator's part.\n\n- **The kagent line's and the Substrate line's charts come from gsoci; the lines move to `v0.11.0-gs.22` and `v0.0.30-gs.5`** (giantswarm/agent-platform#580; epic giantswarm/giantswarm#37853). The two lines publish natively to the org's registry from CircleCI — the multi-arch images and the charts, signed with the Giant Swarm identity, releases and dev builds alike — so `components.kagent.repository` and `components.kagent-crds.repository` are `oci://gsoci.azurecr.io/giantswarm/kagent/helm`, `components.substrate.repository` and `components.substrate-crds.repository` are `oci://gsoci.azurecr.io/giantswarm/substrate/helm`. The Substrate floor moves to `0.0.30-gs.5` — the line's first release published there, the patches of gs.4 — in `components.substrate*.versionRange` (`>=0.0.30-gs.5 <0.0.31-0`), the BOM pin and, derived from it, the kagent WorkerPool's worker image, so the atelet and the worker are one native, signed release and nothing of the line depends on a copy. The kagent floor moves to `0.11.0-gs.22` the same way (`components.kagent*.versionRange` `>=0.11.0-gs.22 <0.11.1-0`, the BOM pin): the chart paths on gsoci begin with each line's first native release — the older releases exist there as retagger's image copies only, no charts — and the kagent chart's stamped digests of its Go ADK and Claude harness images resolve on gsoci from that release on. With the charts the last ghcr.io reference of the two lines goes: a default installation pulls everything of kagent and Substrate from gsoci, and the dev channel (a `components.<name>.semverFilter` on the lines' `-dev.giantswarm.` builds) needs no registry override any more — `kagent.registry` and `substrate.image.registry` stay on their defaults (README "Dev channel"). `make verify-images` tolerates the two lines by name no longer; the upstream CloudNativePG chart is the one pending entry left, behind a Giant Swarm wrapper release on the same operator line. `verify-components` and `verify-kagent-wiring` assert the new sources; `verify-target` holds them on both sides of the golden comparison until `origin/main` carries them. UPGRADE.md.

- **`qwen3-8-27b-l40s` serves NVIDIA's own Qwen3.8-27B-NVFP4 checkpoint from its signed model image** (giantswarm/agent-platform#591): `nvidia/Qwen3.8-27B-NVFP4` (20.4 GiB — NVFP4 on the MLPs and the language-model head, FP8 on the attention layers) replaces the Inferact repack's `hf://` source; the preset gains the model-image environment (HOME, HF_HOME and VLLM_CACHE_ROOT under /tmp) and declares 21 + 20 GiB. Parsers, the thinking-off default and the 64k context are unchanged; `qwen3-8-27b`, the Blackwell recipe, still serves the Inferact repack.
- **`modelServing.imageVerification` is on by default: a model pod's images are verified at admission against the Giant Swarm signing identity** (giantswarm/agent-platform#575; epic giantswarm/giantswarm#37853). 4.41.0 gave the block its defaults — `images: [gsoci.azurecr.io/giantswarm/*]`, one keyless attestor for the identity the architect orb's cosign keyless signing gives every image a Giant Swarm CircleCI project builds or re-signs (issuer `https://oidc.circleci.com`, subject the pipeline definition that ran), `type: SigstoreBundle` — and left the switch off until every image a model pod runs was signed. Every one is now, verified with `cosign verify` against that identity: the curated model image the shipped `oci://` preset names, `gsoci.azurecr.io/giantswarm/models/qwen3-8-flash-next-nvfp4:7c4f1bc1a2d6`, which giantswarm/models builds, signs and publishes (giantswarm/agent-platform#554); the llm-d runtime and sidecars of the well-known `LLMInferenceServiceConfig`s at the `llm-d-fast/` prefix (`llm-d-cuda:v0.8.0`, `llm-d-router-disagg-sidecar:v0.9.0`, the endpoint picker, tokenizer and latency-predictor images; giantswarm/llm-d signs every mirror and repack); the KServe `storage-initializer:v0.20.0` and `agent:v0.20.0` retagger copies (giantswarm/retagger#1230); the pre-pull DaemonSet's `pause:3.10.1`; and the `vllm-b12x:20260913` mirror an installation serves the flash-next preset with. Both charts' defaults carry `enabled: true`, so a serving shape under Kyverno renders `<release>-model-serving-image-verification` without being asked: one `verifyImages` rule per pod shape over the model pods of the serving namespace at CREATE and UPDATE, every verified image pinned to its digest, a signature required, Enforce. A container image matching no pattern is left alone, so an installation serving from a registry of its own is untouched until it names its pattern and its signer; an installation whose model pods run an image under the platform's namespace that none of these signed adds its signer or turns the switch off before it upgrades (UPGRADE.md). `make verify-model-serving-policies` asserts the default render carries the policy with its defaults and that the switch off or no Kyverno renders none; `make verify-target` holds the switch on both sides of the golden comparison until `origin/main` carries it. Proof: `kyverno apply` of the rendered default policy over a pod of the llm-d workload shape naming every image above admits it with every image rewritten to its digest, and denies a pod naming an unsigned image under the pattern with `sigstore bundle verification failed`; the same two cases on a lab's Kyverno.

### Changed

- **Every agent platform dashboard lands in one folder customers can reach: `Shared Org / Agent Platform`** (giantswarm/giantswarm#36711). The muster board (`Muster / MCP Gateway`) was loaded into the staff-only `Giant Swarm` organization, in a folder named after the component, so the people who run agents on the platform could not see it: `muster.observability.grafanaDashboard.folder` is `Agent Platform` and `.giantswarm.organization` is `Shared Org`. `Shared Org` is the organization every logged-in customer reaches as a Viewer and it carries the observability data of Giant Swarm managed components, which is where these boards belong; the `Giant Swarm` organization is staff-only. The boards that follow — the agentgateway gateway board, the platform's own overview — land in the same folder.

### Removed

- **The Qwen3 small presets `qwen3-4b-instruct`, `qwen3-8b-fp8` and `qwen3-14b`** (giantswarm/agent-platform#591). They pinned 2025 checkpoints whose successors are smaller or stronger under the same licence and are replaced by the 24 GB line-up above (`qwen3-5-4b` for the 4B, `qwen3-5-9b-fp8` or `gemma-4-12b` for the 8B, `gpt-oss-20b` or `gemma-4-12b` for the 14B — which, at 28 GiB of BF16 weights, never fit a 24 GB card and was tuned for a 128 GB node). The upgrade removes their ConfigMaps; a model already served from one keeps serving (the `LLMInferenceService` is model-manager's object), and an installation that wants one back carries its file under `modelServing.presets` (UPGRADE.md).
Expand Down
2 changes: 2 additions & 0 deletions helm/agent-platform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,9 @@ The map is merged into each component's own `nodeSelector` (`muster.nodeSelector
| muster.muster.observability.metrics.prometheus.prometheusRule.enabled | string | `"auto"` | |
| muster.muster.observability.metrics.prometheus.prometheusRule.labels."observability.giantswarm.io/tenant" | string | `"giantswarm"` | |
| muster.muster.observability.grafanaDashboard.enabled | string | `"auto"` | |
| muster.muster.observability.grafanaDashboard.folder | string | `"Agent Platform"` | |
| muster.muster.observability.grafanaDashboard.giantswarm.enabled | bool | `true` | |
| muster.muster.observability.grafanaDashboard.giantswarm.organization | string | `"Shared Org"` | |
| valkey.ciliumNetworkPolicy.enabled | string | `"auto"` | |
| valkey.vpa.enabled | bool | `false` | |
| valkey.podDisruptionBudget.enabled | bool | `true` | |
Expand Down
8 changes: 8 additions & 0 deletions helm/agent-platform/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1860,8 +1860,16 @@ muster: # @schema skipProperties: true; additionalProperties: true
# this key must not be set for an older muster.
grafanaDashboard:
enabled: auto # auto | true | false
# One folder for every agent platform board, so an operator opens one
# place. The chart's own default is a folder named after the component.
folder: "Agent Platform"
giantswarm:
enabled: true
# Shared Org is the organization customers reach; the Giant Swarm
# organization is staff-only, and the people who run agents on this
# platform are the ones who need its boards. The chart's own default
# is the staff organization.
organization: "Shared Org"

# Bundled giantswarm/valkey-app for muster's OAuth session storage.
# Wrapper chart exposes three top-level blocks consumed here:
Expand Down
12 changes: 10 additions & 2 deletions tests/verify-target.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@
# GOLDEN_REF names the flattened controller repository and the v1.5.1-gs.4 data
# plane. Held equal on BOTH sides of the meta and the connectivity renders;
# dropped once GOLDEN_REF carries #608.
# giantswarm/giantswarm#36711: the muster board moves to the platform's own
# Grafana folder and to the organization customers reach, and GOLDEN_REF carries
# the muster chart's own defaults for both. Held equal on BOTH sides of the meta
# renders; dropped once GOLDEN_REF carries them.
MUSTER_DASHBOARD_HOLD = [
"--set", "muster.muster.observability.grafanaDashboard.folder=muster",
"--set", "muster.muster.observability.grafanaDashboard.giantswarm.organization=Giant Swarm",
]
AGENTGATEWAY_IMAGES_HOLD = [
"--set", "agentgateway.controller.image.repository=giantswarm/agentgateway-upstream/controller",
"--set", "agentgateway.controller.image.tag=2.0.0",
Expand Down Expand Up @@ -306,8 +314,8 @@ def check_golden(meta: str, connectivity: str) -> None:
# carries the switch.
hold_iv = ["--set", "modelServing.imageVerification.enabled=false"]
shapes = [
("meta default", meta, [*hold_608, *METRIC_LABELS_HOLD, *hold_iv]),
("meta ci + engine off", meta, ["-f", f"{meta}/ci/ci-values.yaml", *ENGINE_OFF, *hold_608, *METRIC_LABELS_HOLD, *hold_iv]),
("meta default", meta, [*hold_608, *METRIC_LABELS_HOLD, *hold_iv, *MUSTER_DASHBOARD_HOLD]),
("meta ci + engine off", meta, ["-f", f"{meta}/ci/ci-values.yaml", *ENGINE_OFF, *hold_608, *METRIC_LABELS_HOLD, *hold_iv, *MUSTER_DASHBOARD_HOLD]),
("connectivity default", connectivity, [*VM, *METRIC_LABELS_HOLD, *hold_iv, *AGENTGATEWAY_IMAGES_HOLD]),
("connectivity full", connectivity, [*CONN_FULL, *METRIC_LABELS_HOLD, *hold_iv, *AGENTGATEWAY_IMAGES_HOLD]),
("connectivity backstage", connectivity, [*CONN_BACKSTAGE, *METRIC_LABELS_HOLD, *hold_iv, *AGENTGATEWAY_IMAGES_HOLD]),
Expand Down
Loading