Skip to content
Open
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 go/core/pkg/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ func (cfg *Config) SetFlags(commandLine *flag.FlagSet) {
commandLine.StringVar(&agent_translator.PythonADKFullImageDigest, "app-full-image-digest", agent_translator.PythonADKFullImageDigest, "Manifest digest (sha256:...) for the full Python agent runtime image used by sandbox agents. Defaults to the digest baked in at build time; override when a mirrored registry re-assigns digests.")
commandLine.StringVar(&agent_translator.GoADKImageDigest, "golang-adk-image-digest", agent_translator.GoADKImageDigest, "Manifest digest (sha256:...) for the Go agent runtime image used by sandbox agents. Defaults to the digest baked in at build time; override when a mirrored registry re-assigns digests.")
commandLine.StringVar(&agent_translator.GoADKFullImageDigest, "golang-adk-full-image-digest", agent_translator.GoADKFullImageDigest, "Manifest digest (sha256:...) for the full Go agent runtime image used by sandbox agents. Defaults to the digest baked in at build time; override when a mirrored registry re-assigns digests.")
commandLine.StringVar(&substrate.AcpSandboxOpenClawImageDigest, "acp-sandbox-openclaw-image-digest", substrate.AcpSandboxOpenClawImageDigest, "Manifest digest (sha256:...) for the acp-sandbox OpenClaw Substrate workload image. Defaults to the digest baked in at build time; override when a mirrored registry re-assigns digests.")
commandLine.StringVar(&substrate.AcpSandboxHermesImageDigest, "acp-sandbox-hermes-image-digest", substrate.AcpSandboxHermesImageDigest, "Manifest digest (sha256:...) for the acp-sandbox Hermes Substrate workload image. Defaults to the digest baked in at build time; override when a mirrored registry re-assigns digests.")
commandLine.StringVar(&agent_translator.DefaultSkillsInitImageConfig.Registry, "skills-init-image-registry", agent_translator.DefaultSkillsInitImageConfig.Registry, "The registry to use for the skills init image.")
commandLine.StringVar(&agent_translator.DefaultSkillsInitImageConfig.Tag, "skills-init-image-tag", agent_translator.DefaultSkillsInitImageConfig.Tag, "The tag to use for the skills init image.")
commandLine.StringVar(&agent_translator.DefaultSkillsInitImageConfig.PullPolicy, "skills-init-image-pull-policy", agent_translator.DefaultSkillsInitImageConfig.PullPolicy, "The pull policy to use for the skills init image.")
Expand Down
22 changes: 13 additions & 9 deletions go/core/pkg/sandboxbackend/substrate/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ const (

// AcpSandboxOpenClawImageDigest and AcpSandboxHermesImageDigest are the
// link-time-injected image digests (sha256:...) for the acp-sandbox workload
// images, set via -X ...substrate.AcpSandbox*ImageDigest=... They are empty in
// source and in unit tests, in which case resolution returns an error rather
// than an unpinned ref.
// images, set via -X ...substrate.AcpSandbox*ImageDigest=... They can be
// overridden at runtime via --acp-sandbox-openclaw-image-digest /
// --acp-sandbox-hermes-image-digest (env ACP_SANDBOX_OPENCLAW_IMAGE_DIGEST /
// ACP_SANDBOX_HERMES_IMAGE_DIGEST) for private/mirrored registries that
// re-assign manifest digests. They are empty in source and in unit tests, in
// which case resolution returns an error rather than an unpinned ref.
var (
AcpSandboxOpenClawImageDigest string
AcpSandboxHermesImageDigest string
Expand Down Expand Up @@ -56,16 +59,17 @@ func acpSandboxHermesImage(cfg acpSandboxImageConfig) (string, error) {

// resolve composes the digest-pinned ref registry/repo/name@sha256:... for an
// acp-sandbox target. Substrate admission requires a digest, so a missing
// link-time digest is a hard error: the controller must be rebuilt after
// pushing the acp-sandbox images, or the harness/cluster must specify an
// explicit digest-pinned workload image. A missing registry or repository is
// likewise an error, since both are required to form a resolvable ref.
// digest is a hard error: the controller must be rebuilt after pushing the
// acp-sandbox images, the digest must be overridden via --<name>-image-digest,
// or the harness/cluster must specify an explicit digest-pinned workload
// image. A missing registry or repository is likewise an error, since both
// are required to form a resolvable ref.
func (cfg acpSandboxImageConfig) resolve(name, digest string) (string, error) {
digest = strings.TrimSpace(digest)
if digest == "" {
return "", fmt.Errorf(
"acp-sandbox %s image digest is not set at link time; rebuild the controller after pushing the acp-sandbox images (or set a digest-pinned Substrate.WorkloadImage)",
name,
"acp-sandbox %s image digest is not set; rebuild the controller after pushing the acp-sandbox images, or override it via --%s-image-digest (or set a digest-pinned Substrate.WorkloadImage)",
name, name,
)
}
if !strings.HasPrefix(digest, "sha256:") {
Expand Down
6 changes: 5 additions & 1 deletion go/core/pkg/sandboxbackend/substrate/constants_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,13 @@ func TestAcpSandboxImageResolve(t *testing.T) {

t.Run("errors when digest missing", func(t *testing.T) {
cfg := acpSandboxImageConfig{Registry: "ghcr.io", Repository: "kagent-dev/kagent/app"}
if _, err := cfg.resolve("acp-sandbox-openclaw", " "); err == nil {
_, err := cfg.resolve("acp-sandbox-openclaw", " ")
if err == nil {
t.Fatal("expected error for missing digest")
}
if !strings.Contains(err.Error(), "--acp-sandbox-openclaw-image-digest") {
t.Fatalf("error should point at the override flag, got: %v", err)
}
})

t.Run("errors when registry missing", func(t *testing.T) {
Expand Down
20 changes: 20 additions & 0 deletions helm/kagent/templates/controller-configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ data:
IMAGE_REGISTRY: {{ .Values.controller.agentImage.registry | default .Values.registry | quote }}
IMAGE_REPOSITORY: {{ .Values.controller.agentImage.repository | quote }}
IMAGE_TAG: {{ coalesce .Values.controller.agentImage.tag .Values.tag .Chart.Version | quote }}
{{- with .Values.controller.agentImage.digest }}
APP_IMAGE_DIGEST: {{ . | quote }}
{{- end }}
{{- with .Values.controller.agentImage.fullDigest }}
APP_FULL_IMAGE_DIGEST: {{ . | quote }}
{{- end }}
SKILLS_INIT_IMAGE_PULL_POLICY: {{ .Values.controller.skillsInitImage.pullPolicy | default .Values.imagePullPolicy | quote }}
SKILLS_INIT_IMAGE_REGISTRY: {{ .Values.controller.skillsInitImage.registry | default .Values.registry | quote }}
SKILLS_INIT_IMAGE_REPOSITORY: {{ .Values.controller.skillsInitImage.repository | quote }}
Expand All @@ -27,6 +33,20 @@ data:
GO_IMAGE_REGISTRY: {{ .Values.controller.goAgentImage.registry | default .Values.registry | quote }}
GO_IMAGE_REPOSITORY: {{ .Values.controller.goAgentImage.repository | quote }}
GO_IMAGE_TAG: {{ coalesce .Values.controller.goAgentImage.tag .Values.tag .Chart.Version | quote }}
{{- with .Values.controller.goAgentImage.digest }}
GOLANG_ADK_IMAGE_DIGEST: {{ . | quote }}
{{- end }}
{{- with .Values.controller.goAgentImage.fullDigest }}
GOLANG_ADK_FULL_IMAGE_DIGEST: {{ . | quote }}
{{- end }}
{{- with .Values.controller.acpSandboxImages }}
{{- with .openclawDigest }}
ACP_SANDBOX_OPENCLAW_IMAGE_DIGEST: {{ . | quote }}
{{- end }}
{{- with .hermesDigest }}
ACP_SANDBOX_HERMES_IMAGE_DIGEST: {{ . | quote }}
{{- end }}
{{- end }}
LEADER_ELECT: {{ include "kagent.leaderElectionEnabled" . | quote }}
# OpenTelemetry Configuration
OTEL_TRACING_ENABLED: {{ .Values.otel.tracing.enabled | quote }}
Expand Down
72 changes: 72 additions & 0 deletions helm/kagent/tests/image-digest-overrides_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
suite: test runtime image digest overrides in the controller ConfigMap
templates:
- controller-configmap.yaml
tests:
- it: should not emit digest overrides by default
asserts:
- notExists:
path: data.APP_IMAGE_DIGEST
- notExists:
path: data.APP_FULL_IMAGE_DIGEST
- notExists:
path: data.GOLANG_ADK_IMAGE_DIGEST
- notExists:
path: data.GOLANG_ADK_FULL_IMAGE_DIGEST
- notExists:
path: data.ACP_SANDBOX_OPENCLAW_IMAGE_DIGEST
- notExists:
path: data.ACP_SANDBOX_HERMES_IMAGE_DIGEST

- it: should emit Python runtime digest overrides when set
set:
controller:
agentImage:
digest: sha256:1111111111111111111111111111111111111111111111111111111111111111
fullDigest: sha256:2222222222222222222222222222222222222222222222222222222222222222
asserts:
- equal:
path: data.APP_IMAGE_DIGEST
value: sha256:1111111111111111111111111111111111111111111111111111111111111111
- equal:
path: data.APP_FULL_IMAGE_DIGEST
value: sha256:2222222222222222222222222222222222222222222222222222222222222222

- it: should emit Go runtime digest overrides when set
set:
controller:
goAgentImage:
digest: sha256:3333333333333333333333333333333333333333333333333333333333333333
fullDigest: sha256:4444444444444444444444444444444444444444444444444444444444444444
asserts:
- equal:
path: data.GOLANG_ADK_IMAGE_DIGEST
value: sha256:3333333333333333333333333333333333333333333333333333333333333333
- equal:
path: data.GOLANG_ADK_FULL_IMAGE_DIGEST
value: sha256:4444444444444444444444444444444444444444444444444444444444444444

- it: should emit acp-sandbox digest overrides when set
set:
controller:
acpSandboxImages:
openclawDigest: sha256:5555555555555555555555555555555555555555555555555555555555555555
hermesDigest: sha256:6666666666666666666666666666666666666666666666666666666666666666
asserts:
- equal:
path: data.ACP_SANDBOX_OPENCLAW_IMAGE_DIGEST
value: sha256:5555555555555555555555555555555555555555555555555555555555555555
- equal:
path: data.ACP_SANDBOX_HERMES_IMAGE_DIGEST
value: sha256:6666666666666666666666666666666666666666666666666666666666666666

- it: should allow setting only one acp-sandbox digest
set:
controller:
acpSandboxImages:
openclawDigest: sha256:7777777777777777777777777777777777777777777777777777777777777777
asserts:
- equal:
path: data.ACP_SANDBOX_OPENCLAW_IMAGE_DIGEST
value: sha256:7777777777777777777777777777777777777777777777777777777777777777
- notExists:
path: data.ACP_SANDBOX_HERMES_IMAGE_DIGEST
29 changes: 29 additions & 0 deletions helm/kagent/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,15 @@ controller:
pullPolicy: ""
# -- Image pull secret name set on agent pods created by the controller
pullSecret: ""
# -- Manifest digest (sha256:...) override for the Python agent runtime
# image used by sandbox agents (regular agents reference the image by tag).
# Defaults to the digest baked into the controller binary at build time;
# set this when serving the images from a private/mirrored registry that
# re-assigns manifest digests.
digest: ""
# -- Manifest digest (sha256:...) override for the full-variant Python
# agent runtime image used by sandbox agents. See `digest` above.
fullDigest: ""
# -- The image used by the skills-init container to clone skills from Git and pull OCI skill images.
skillsInitImage:
registry: ""
Expand All @@ -222,6 +231,26 @@ controller:
repository: kagent-dev/kagent/golang-adk
tag: "" # Will default to global, then Chart version
pullPolicy: ""
# -- Manifest digest (sha256:...) override for the Go agent runtime image
# used by sandbox agents (regular agents reference the image by tag).
# Defaults to the digest baked into the controller binary at build time;
# set this when serving the images from a private/mirrored registry that
# re-assigns manifest digests.
digest: ""
# -- Manifest digest (sha256:...) override for the full-variant Go agent
# runtime image used by sandbox agents. See `digest` above.
fullDigest: ""
# -- Digest overrides for the Substrate acp-sandbox workload images. Their
# registry/repository derive from agentImage (registry + repository parent
# path), and Substrate admission requires digest-pinned refs, so the digests
# default to the ones baked into the controller binary at build time. Set
# these when serving the images from a private/mirrored registry that
# re-assigns manifest digests.
acpSandboxImages:
# -- Manifest digest (sha256:...) override for the acp-sandbox-openclaw image.
openclawDigest: ""
# -- Manifest digest (sha256:...) override for the acp-sandbox-hermes image.
hermesDigest: ""
# -- @deprecated Removed in 0.10.0. The A2A SDK now handles SSE buffering and timeouts
# internally. These values have no effect and will be removed in a future release.
streaming: null
Expand Down
Loading