Repository navigation
Conversation
Add an optional `authorizationFrom` Secret key reference to AgentTemplate `skills[].source.git`. The compiler binds the key to the repository hostname as a Substrate egress gateway credential and the runtime sends a placeholder `Authorization` header for the gateway to replace, so the token never enters the Actor, its configuration, or a snapshot. A gateway credential only applies once an Actor has egress, which Substrate activates after readiness and never grants the golden Actor (kagent-dev#2604). Runtimes therefore fetch standalone skills before the first task of a session Actor instead of at startup: the Go ADK, Claude and Codex runtimes call Materialization.EnsureSkills per task, and a fetch failure fails that task with a `skills_unavailable` message instead of crashing the golden Actor. Plugins keep their startup fetch and reject `authorizationFrom`. Refs kagent-dev#2604, kagent-dev#2815 Signed-off-by: acherifi <ali.cherifi@homagames.com>
|
We hit the same failure on a Substrate line with replace-only A few notes:
I'll close #2899 in favour of this one. The full-header Secret is the better shape. |
|
Tested this PR on a three-node K3s cluster with kagent v1.0.0-alpha9 ( Before (stock alpha9 harnesses). An AgentTemplate that selected skills through With this PR. The same templates use standalone
Not covered: We now run these patched harness images in our development environment until a release includes this fix. Thanks for working on it! |
|
Follow-up to my earlier comment, after pood1e's run and the conflict with #3144. The credential half is proven on a Substrate line where golden actors already have egress: a private GitHub skill fetched with the placeholder through the real gateway (200 on On the deferred fetch: it is the right workaround for #2604 on Substrate today, but skills are immutable and the end state is one fetch per revision with the content in the golden snapshot, which is what agent-substrate/substrate#2159 ( The branch needs a rebase: #3144 removed |
| } | ||
| // The runtime sends a placeholder Authorization header that the | ||
| // gateway replaces with the Secret value. | ||
| if err := bind(git.URL, "authorization", "", agent.Template.Namespace, git.AuthorizationFrom.Name, git.AuthorizationFrom.Key); err != nil { |
There was a problem hiding this comment.
no ResolvedRefs failure when this secret or key is missing
There was a problem hiding this comment.
Addressed in dafd341. The compiler now resolves the same-namespace Secret through KRT before emitting credentials. Missing Secrets and missing or empty keys produce ResolvedRefs=False with ReferenceResolutionFailed. Secret changes trigger recompilation for root and Shared child templates. The new controller test covers missing Secret → missing key → missing origin grant → success → grant removal without editing the Agent. Compiler and controller tests pass with -race.
| if agent.Template != nil { | ||
| for _, skill := range agent.Template.Spec.Skills { | ||
| git := skill.Source.Git | ||
| if git == nil || git.AuthorizationFrom == nil { |
There was a problem hiding this comment.
what stops pointing url at an attacker host with any secret?
There was a problem hiding this comment.
Addressed in dafd341. A Secret owner must grant one exact HTTPS origin through kagent.dev/git-credential-origin. Template authors cannot change that grant through an AgentTemplate. The compiler checks scheme, DNS name, and port before emitting a binding; missing grants, different hosts/ports, wildcards, and malformed origins fail compilation. Git also scopes its placeholder to http.<repository URL>.extraHeader and rejects authenticated redirects. Tests cover attacker hosts, invalid grants, and redirects. The gateway authority remains origin-wide, so the docs require read-only repository-scoped tokens and separate Secret-write permissions. Grant removal prevents new compilations; it does not revoke existing pinned Actors.
Signed-off-by: acherifi <ali.cherifi@homagames.com>
|
Updated in dafd341 and merged current main ( @QuentinBisson: Git now uses per-command @moezdil: both review comments have code changes and regression coverage. Missing Secrets/keys fail Verification:
The PR body now reflects this behavior. This update did not run a private Git fetch through a live Substrate gateway, so I have left the PR as draft. No cluster resources were changed. |
Signed-off-by: acherifi <ali.cherifi@homagames.com>
|
Merged current main (
Verification passed: affected Go packages with |
Signed-off-by: acherifi <ali.cherifi@homagames.com>
|
Updated the branch from main (
Verification passed: affected Go packages with |
) kagent-dev#3340 files the Harness conditions (Ready from the WorkerPool, Booted from the golden boots); the status merge patch files on its own later. The git fetch retry rows wait for kagent-dev#3099, which rewrites CloneGitCommit, and carry the notes for the re-cut; the durable copy is superseded by kagent-dev#3099's task-time skill install. The SKILL.md frontmatter row points at google/adk-go#1957 and kagent-dev#1958. Signed-off-by: QuentinBisson <quentin@giantswarm.io>
Problem
Standalone skills need private HTTPS Git access without exposing credentials to the runtime (#2815). Startup networking is unavailable on some Substrate deployments (#2604). A credential field alone does not solve that constraint.
Changes
Credential references and authority
skills[].source.git.authorizationFromreferences a Secret key in the AgentTemplate namespace. The key contains the fullAuthorizationheader value.kagent.dev/git-credential-origin, for examplehttps://github.com. The compiler compares scheme, DNS name, and port. Wildcards, IP addresses, URL credentials, query strings, and fragments are rejected.ResolvedRefs=False. Secret changes trigger recompilation for root and Shared child templates.gateway_authorization: true, not the Secret value or its reference. The typed Go ADK protobuf contract preserves this flag.Example Secret metadata:
The Secret's
authorizationkey holds the full header value. The template usesauthorizationFrom: {name: skills-auth, key: authorization}.Git transport
Authorization: kagent-credential-injectedthrough per-commandhttp.<repository URL>.extraHeaderconfiguration..git/config.Startup and task-time loading
skills_unavailable: …. Successful installations remain reusable while their files exist.CloneGitandrunGithelpers remain removed. CRDs and protobuf outputs are regenerated.Security and limits
The gateway binding covers an origin, not a repository path. Tools can use its authority by sending an
Authorizationheader to that origin. Use read-only, repository-scoped tokens and separate Secret-write permissions from template-write permissions.The annotation is a compilation-time grant. Removing it blocks new successful compilations; it does not revoke existing pinned Actors. Immediate revocation requires the platform's credential and egress controls.
Do not grant the shared
ate-goldenidentity unrestricted namespace Secret access. Startup fetching succeeds only when networking, egress policy, and credential-provider grants permit it. This PR does not change those platform grants.Credentials never enter the runtime. Private skill files can enter golden or session snapshots when fetching succeeds. Snapshot access controls must protect that content.
authorizationFromremains unsupported on plugins. SSH authentication and token exchange are unsupported. Python ADK does not yet consume theagent_pluginsruntime contract.Related work
Verification
-race: skillsinit, agentplugins, translator, controller, v1alpha3 CRD validation, Go ADK config/agent/A2A, and Claude/Codex harnesses.make -C go lintwith zero issues.make controller-manifests proto-generate.Regression coverage includes origin grants, missing Secret keys, root/shared-child Secret reconciliation, redirect rejection, startup recovery, and runtime failure handling.
A standalone smoke exercised the actual materializer with real Git and
git http-backend. A local proxy simulated replace-only credential injection. It verified unavailable startup, task recovery, pinned content, executable skill files, durable reuse, successful startup, unauthorized fetch rejection, and redirect blocking.A live private-repository fetch through Substrate was not run for this update. The local proxy smoke does not replace that verification. The PR remains draft.