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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **`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.

- **An Overview board, the entry point of the platform's Grafana folder** (giantswarm/giantswarm#36711). `dashboards` in both charts renders one ConfigMap per JSON under the connectivity chart's `dashboards/` directory, discovered by observability-operator through `app.giantswarm.io/kind: dashboard` and placed by the organization and folder annotations (both values carry a space, so neither can be a label). It ships `overview.json`, uid `agent-platform-overview`, in `Shared Org / Agent Platform`: what the platform is and which board covers what; component health; what it is doing; and the Postgres and Valkey rows, which have no board of their own. Every health panel reads the **same series as the alert that pages for it** — `gotk_resource_info`, `kube_deployment_status_replicas_available`, `muster_mcpserver_state`, `kube_cnpg_cluster_info`, `kube_pod_container_status_restarts_total`, `muster_session_store_backend`, `redis_memory_used_bytes` — so a panel and a page cannot disagree. Today the six alerts of `agent-platform.rules.yml` hand on-call a runbook and no graph. The ConfigMaps render under the resolved `global.observability.metrics.serviceMonitor.enabled`: the operator that picks them up is part of the observability platform the monitors write to. A component's own board still comes from its own chart. The Postgres and the Valkey row, and the six agentgateway panels of the "what it is doing" row, are gated on the series they read: each one repeats over a hidden `label_values(<metric>, __name__)` variable, which yields one value while the metric exists and none while it does not, so an installation that runs neither CloudNativePG nor Valkey nor the agentgateway data plane opens the board without a row of "No data". A component that is on but not yet scraped is hidden the same way, which a Helm conditional on `components.<name>.enabled` could not do.

### 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.
Expand Down
17 changes: 15 additions & 2 deletions Makefile.custom.mk
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ GOLDEN_REF ?= origin/main
# is on by default with no backend (giantswarm/agent-platform#329), an intended difference
# held equal on both sides — a chart that predates the default accepts the key. Empty this
# once GOLDEN_REF carries the line.
# The platform's own board ConfigMaps are dropped from a golden render by name,
# never by a value: GOLDEN_REF's schema has no `dashboards` key, so --set on it
# fails the render outright and every document then reads as added
# (giantswarm/giantswarm#36711). One name per board; the list goes with the line.
DASHBOARDS_GOLDEN_DROP := agent-platform-connectivity-dashboard-overview
# Drop those documents from a rendered manifest in place, by metadata.name, and
# keep the leading document separator whatever was dropped — a stripped first
# document would otherwise read as a one-line diff of its own.
define drop_dashboards
@python3 -c 'import re,sys; ex=set(sys.argv[2].split()); docs=open(sys.argv[1]).read().split("\n---\n"); keep=[d for d in docs if not (re.search(r"^ name: (\S+)", d, re.M) and re.search(r"^ name: (\S+)", d, re.M).group(1) in ex)]; out="\n---\n".join(keep).lstrip("-\n"); open(sys.argv[1],"w").write("---\n"+out.rstrip("\n")+"\n")' $(1) "$(DASHBOARDS_GOLDEN_DROP)"
endef
WIRING_PG_GOLDEN_HOLD := --set components.model-manager.enabled=false
# Objects the 4.0 line changes on purpose, dropped from BOTH renders before the
# golden diff (by metadata.name): the v1alpha2 agent Deployments' seccomp
Expand All @@ -99,7 +110,7 @@ WIRING_PG_GOLDEN_HOLD := --set components.model-manager.enabled=false
# on (templates/kagent/harness.yaml — a new object with no 3.x counterpart; its
# shape is asserted by verify-kagent-harness / verify-kagent-crds). Empty this
# list once GOLDEN_REF carries the line.
GOLDEN_EXCLUDE := kagent-declarative-seccomp agent-platform-connectivity-kagent-controller-ingress kagent
GOLDEN_EXCLUDE := kagent-declarative-seccomp agent-platform-connectivity-kagent-controller-ingress kagent $(DASHBOARDS_GOLDEN_DROP)
# Any reference is enough: the assertions read the rendered exception, not the image.
PGVECTOR_IMG := gsoci.azurecr.io/giantswarm/pgvector:0.8.2-18-bookworm

Expand Down Expand Up @@ -228,7 +239,7 @@ verify-modes: ## Assert ingress.mode fail-guards fire (connectivity chart owns t
$(GOLDEN_RETIRED) $$out/golden; \
helm template t $(CONNECTIVITY_DIR) $(KYVERNO_GOLDEN) >$$out/head 2>&1 \
|| { echo "FAIL: the working-tree render failed"; cat $$out/head; exit 1; }; \
for f in golden head; do python3 -c 'import re,sys; ex=set(sys.argv[2].split()); docs=open(sys.argv[1]).read().split("\n---\n"); keep=[d for d in docs if not (re.search(r"^ name: (\S+)", d, re.M) and re.search(r"^ name: (\S+)", d, re.M).group(1) in ex)]; out="\n---\n".join(keep).rstrip("\n"); open(sys.argv[1],"w").write(out+"\n")' $$out/$$f "$(GOLDEN_EXCLUDE)"; done; \
for f in golden head; do python3 -c 'import re,sys; ex=set(sys.argv[2].split()); docs=open(sys.argv[1]).read().split("\n---\n"); keep=[d for d in docs if not (re.search(r"^ name: (\S+)", d, re.M) and re.search(r"^ name: (\S+)", d, re.M).group(1) in ex)]; out="\n---\n".join(keep).lstrip("-\n"); open(sys.argv[1],"w").write("---\n"+out.rstrip("\n")+"\n")' $$out/$$f "$(GOLDEN_EXCLUDE)"; done; \
if diff -u $$out/golden $$out/head; then echo "ok: default render unchanged (excluding $(GOLDEN_EXCLUDE))"; \
else echo "FAIL: the default render drifted from $(GOLDEN_REF)"; exit 1; fi; \
fi
Expand Down Expand Up @@ -2439,6 +2450,8 @@ verify-wiring: ## Assert the standalone's ported wiring: toggles off = no object
for flavor in cilium kubernetes; do \
helm template t $(CONNECTIVITY_DIR) $(WIRING_PG) $(WIRING_PG_GOLDEN_HOLD) --set networkPolicy.flavor=$$flavor 2>/dev/null >/tmp/vw-pg-new-$$flavor.out; \
helm template t /tmp/vw-pg-ref/$(CONNECTIVITY_DIR) $(WIRING_PG) $(WIRING_PG_GOLDEN_HOLD) --set networkPolicy.flavor=$$flavor 2>/dev/null >/tmp/vw-pg-old-$$flavor.out; \
python3 -c 'import re,sys; ex=set(sys.argv[2].split()); docs=open(sys.argv[1]).read().split("\n---\n"); keep=[d for d in docs if not (re.search(r"^ name: (\S+)", d, re.M) and re.search(r"^ name: (\S+)", d, re.M).group(1) in ex)]; out="\n---\n".join(keep).lstrip("-\n"); open(sys.argv[1],"w").write("---\n"+out.rstrip("\n")+"\n")' /tmp/vw-pg-new-$$flavor.out "$(DASHBOARDS_GOLDEN_DROP)"; \
python3 -c 'import re,sys; ex=set(sys.argv[2].split()); docs=open(sys.argv[1]).read().split("\n---\n"); keep=[d for d in docs if not (re.search(r"^ name: (\S+)", d, re.M) and re.search(r"^ name: (\S+)", d, re.M).group(1) in ex)]; out="\n---\n".join(keep).lstrip("-\n"); open(sys.argv[1],"w").write("---\n"+out.rstrip("\n")+"\n")' /tmp/vw-pg-old-$$flavor.out "$(DASHBOARDS_GOLDEN_DROP)"; \
diff -u /tmp/vw-pg-old-$$flavor.out /tmp/vw-pg-new-$$flavor.out || { echo "FAIL: the $$flavor render changed with postgres.imagePullSecrets and .affinity unset"; git worktree remove --force /tmp/vw-pg-ref; exit 1; }; \
done; \
git worktree remove --force /tmp/vw-pg-ref; \
Expand Down
4 changes: 4 additions & 0 deletions helm/agent-platform-connectivity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,10 @@ The kagent block is open in the schema, so the template refuses a key under `kag
| hooks.opensslImage.repository | string | `"giantswarm/alpine-openssl"` | |
| hooks.opensslImage.tag | string | `"3.5.8"` | |
| extraObjects | list | `[]` | |
| dashboards.enabled | bool | `true` | |
| dashboards.namespace | string | `""` | |
| dashboards.organization | string | `"Shared Org"` | |
| dashboards.folder | string | `"Agent Platform"` | |
| dicebear | object | `{}` | |
| muster.enabled | bool | `true` | |
| muster.image.registry | string | `"gsoci.azurecr.io"` | |
Expand Down
Loading
Loading