Skip to content

feat: [POC] Substrate gates, platform.valuesFiles and the proofs on kagent main - #129

Draft
teemow wants to merge 11 commits into
mainfrom
poc/substrate-gates
Draft

teemow wants to merge 11 commits into
mainfrom
poc/substrate-gates

Conversation

@teemow

@teemow teemow commented Sep 9, 2026

Copy link
Copy Markdown
Member

POC — do not merge as is. This branch is what ran the kagent main (API v2, kagent.dev/v1alpha3) POC in an isolated agentlab. Parts of it are upstreamable on their own (the kind template gates as an opt-in knob, platform.valuesFiles); the proofs assert v1alpha3 objects the released platform does not serve yet. Plan: giantswarm/bumblebee-plans#51 (agent-v1alpha3-migration).

What changed

  • kind-config.yaml.tmpl: the apiserver feature gates Substrate needs (ClusterTrustBundle, ClusterTrustBundleProjection, PodCertificateRequest), runtimeConfig certificates.k8s.io/v1beta1, and containerdConfigPatches config_path = "/etc/containerd/certs.d" (kindest/node v1.36.1 ships without it, so a hosts.toml drop is ignored otherwise); TestKindConfigSubstrateGates decodes the render into kind's own types.
  • platform.valuesFiles: extra Helm values files merged over the rendered lab values with -f semantics — a lab can point a component at another chart source (components.<name>.repository/versionRange/insecure) or forward values the template does not know.
  • The Agent-CR heals (golang-adk image heal, iconUrl CRD patch) are skipped when agents.kagent.dev is not served.
  • The proofs speak kagent main: a shared turn helper drives gRPC-Web through the edge (CreateAgentInstance → A2A SendMessageDeleteAgentInstance, headers x-user-id, authorization, x-kagent-agent-instance-id; messages generated from the controller's descriptor set into internal/kagentpb, no replace); agents-test, toolsets-test and models-test assert AgentTemplates, toolset-carrier RemoteMCPServers and v1alpha3 ModelConfigs (ResolvedRefs too); platform-test expects the kagent scrape target only when a controller ServiceMonitor exists (kagent main serves no metrics listener); backstage-test gains the portal's Agent Platform pages (agents list per user, a session and a chat turn).
  • Kubernetes 1.36 grants clustertrustbundles discovery to every ServiceAccount, so the "agent-manager's SA holds no RBAC" check compares against a bindings-less SA.

Verified

go build/vet/test green, gofmt clean. On the isolated POC lab with kagent main as the meta chart's kagent component and the Dev Portal / agent-manager / model-manager POC images: platform-test 6/6, agents-test, toolsets-test (11 verdicts), models-test, backstage-test all rc 0.

Turn on ClusterTrustBundle, ClusterTrustBundleProjection and
PodCertificateRequest plus certificates.k8s.io/v1beta1 in the kind config:
Substrate's WorkerPools project pod identities and trust bundles into their
ateom workers and cannot start a pod without them. Point containerd's CRI
registry config_path at /etc/containerd/certs.d so a hosts.toml on the node
is honored (the node image leaves it empty). All three are fixed at
`kind create`, so they render always; a test decodes the render into kind's
own v1alpha4.Cluster and asserts them.
platform.valuesFiles merges extra Helm values files over the rendered lab
values (-f order, the overlays win), so a lab can point a component at
another chart source or forward values the template does not know.

The Agent-CR heals (the golang-adk image heal, the iconUrl CRD patch) are
skipped when kagent serves no agents.kagent.dev: kagent API v2 (Harness +
AgentTemplate, v1alpha3) has nothing for them to apply to.
…est on kagent main (kagent.dev/v1alpha3)

kagent API v2 has no Agent CR, no HelmRelease per agent and no REST: an agent is
an AgentTemplate in the kagent namespace admitted by a Harness, its toolset rides
on a per-agent RemoteMCPServer copy of muster (headersFrom X-Muster-Toolset) the
template binds, readiness is status.harnesses[].conditions, and a turn is an
AgentInstance plus one A2A SendMessage over gRPC.

- internal/lab/kagentapi.go: the turn the way the portal takes it — gRPC-Web
  through the agentgateway edge at <agentgateway>/kagent, x-user-id and the
  person's bearer, x-kagent-agent-instance-id; the instance is created for the
  person and deleted afterwards. Messages: internal/kagentpb (kagent.api.v1alpha1
  common + agent_instances, generated from the controller's descriptor set) and
  the A2A v1 package the controller is built with (a2a-go/v2 v2.5.0).
- internal/lab/agenttemplate.go: v1alpha3 reads through discovery — the template,
  its Harness conditions, the carrier's header (literal or Secret), the delete of
  template and carrier.
- agents-test: the AgentTemplate carries the agent-manager field manager and
  kagent.dev/harness=kagent, the carrier the toolset, Ready on the Harness before
  get_agent_status agrees, the delete removes template and carrier;
  created.agentTemplate replaces created.helmRelease.
- toolsets-test: the header on the carrier the template binds; an agent without
  a toolset binds muster directly; the runtime turns are kagent turns;
  --skip-portal for a portal that does not speak kagent main yet; the composer's
  manifest is the carrier plus the AgentTemplate.
- models-test: the turn on a throwaway AgentTemplate on the Go ADK Harness as
  the user; the ModelConfig reads stay version-agnostic.
- backstage-test: with agents on, the Agent Platform pages — the agents list for
  every user, a session and one message for the first — failing by name against
  a portal that still speaks kagent 0.10.
…onitor; a ModelConfig needs ResolvedRefs too

platform-test expected Prometheus to scrape kagent whenever agents run; kagent
main's controller serves no metrics listener, so a lab that renders no
ServiceMonitor for it has no target to expect. The expectation now follows a
kagent-controller ServiceMonitor in the kagent namespace (the connectivity
chart's or the kagent chart's own), with a note when there is none.

kagent main splits a ModelConfig's verdict into Accepted (the spec is coherent)
and ResolvedRefs (the Secret it names exists and holds the key): an Accepted
ModelConfig whose ResolvedRefs is False is not usable. waitModelConfigAccepted
refuses that with the condition's message; a status without the condition (the
0.x line) still passes.
…, so the sign-in and muster evidence is complete before a portal without them fails the proof
…ted v1alpha3 contract

create_agent reports created.agentTemplate and created.toolsetCarrier, both
asserted; delete_agent reports agentTemplateDeleted and toolsetCarrierDeleted;
update_agent.changed carries the field names without the agent. prefix;
get_info.apiVersions.agentTemplate must be the platform's kagent.dev/v1alpha3
(an agent-manager still composing v1alpha2 fails by name); get_agent's harness
and toolsetCarrier{name,exists,header} are asserted. Every declared toolset
rides on a carrier, preset:none included — the toolsets proof no longer
tolerates a template without a binding.
…lds beyond a ServiceAccount no binding names — a 1.36 cluster with the ClusterTrustBundle gate hands every principal the trust-bundle discovery
…ps for a template it did not label (the portal and legacy agents of the proof)
The kagent-main portal backend serves GET /kagent/agent-templates?namespace=
(not /kagent/agents) and answers the released plugin's {error, data} envelope
with one summary per AgentTemplate (ref, harnesses[], ready, resource). The
proof reads that shape.
@teemow teemow changed the title POC: Substrate gates, platform.valuesFiles and the proofs on kagent main feat: [POC] Substrate gates, platform.valuesFiles and the proofs on kagent main Sep 9, 2026
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.

1 participant