From f247528bfe7e965cea7cebe2818a65615c4c9684 Mon Sep 17 00:00:00 2001 From: Peter Jausovec Date: Wed, 3 Jun 2026 15:27:11 -0700 Subject: [PATCH 1/5] switch from tags to digest for images Signed-off-by: Peter Jausovec --- Makefile | 26 +++-- go/README.md | 14 +++ .../translator/agent/adk_api_translator.go | 29 +++++ .../translator/agent/deployments.go | 49 +++++++-- .../agent/digest_testmain_external_test.go | 15 +++ .../translator/agent/imageconfig_test.go | 100 ++++++++++++++++++ .../translator/agent/runtime_test.go | 45 ++++++-- .../outputs/agent_with_a2a_config.json | 2 +- .../outputs/agent_with_allowed_headers.json | 2 +- .../testdata/outputs/agent_with_code.json | 2 +- .../outputs/agent_with_context_config.json | 2 +- .../agent_with_cross_namespace_tools.json | 2 +- .../outputs/agent_with_custom_sa.json | 2 +- .../outputs/agent_with_default_sa.json | 2 +- .../agent_with_embedding_provider.json | 2 +- .../outputs/agent_with_extra_containers.json | 2 +- .../outputs/agent_with_git_skills.json | 2 +- .../outputs/agent_with_http_toolserver.json | 2 +- .../outputs/agent_with_mcp_service.json | 2 +- .../testdata/outputs/agent_with_memory.json | 2 +- .../outputs/agent_with_nested_agent.json | 2 +- .../outputs/agent_with_passthrough.json | 2 +- .../outputs/agent_with_prompt_template.json | 2 +- .../testdata/outputs/agent_with_proxy.json | 2 +- .../agent_with_proxy_external_remotemcp.json | 2 +- .../outputs/agent_with_proxy_mcpserver.json | 2 +- ...t_with_proxy_mcpserver_custom_timeout.json | 2 +- .../outputs/agent_with_proxy_service.json | 2 +- .../outputs/agent_with_require_approval.json | 2 +- .../agent_with_scheduling_attributes.json | 2 +- .../outputs/agent_with_security_context.json | 2 +- .../testdata/outputs/agent_with_skills.json | 2 +- .../outputs/agent_with_streaming.json | 2 +- ...nt_with_system_message_from_configmap.json | 2 +- ...agent_with_system_message_from_secret.json | 2 +- .../testdata/outputs/anthropic_agent.json | 2 +- .../agent/testdata/outputs/basic_agent.json | 2 +- .../agent/testdata/outputs/bedrock_agent.json | 2 +- .../agent/testdata/outputs/ollama_agent.json | 2 +- .../testdata/outputs/tls-with-custom-ca.json | 2 +- .../outputs/tls-with-disabled-verify.json | 2 +- .../outputs/tls-with-system-cas-disabled.json | 2 +- scripts/controller-digest-ldflags.sh | 41 +++++++ 43 files changed, 331 insertions(+), 58 deletions(-) create mode 100644 go/core/internal/controller/translator/agent/digest_testmain_external_test.go create mode 100644 go/core/internal/controller/translator/agent/imageconfig_test.go create mode 100755 scripts/controller-digest-ldflags.sh diff --git a/Makefile b/Makefile index abea744aba..84acf54b12 100644 --- a/Makefile +++ b/Makefile @@ -78,9 +78,9 @@ TOOLS_GO_VERSION ?= $(shell $(AWK) '/^go / { print $$2 }' go/go.mod) export GOTOOLCHAIN=go$(TOOLS_GO_VERSION) # Version information for the build -LDFLAGS := "-X github.com/$(DOCKER_REPO)/go/core/internal/version.Version=$(VERSION) \ - -X github.com/$(DOCKER_REPO)/go/core/internal/version.GitCommit=$(GIT_COMMIT) \ - -X github.com/$(DOCKER_REPO)/go/core/internal/version.BuildDate=$(BUILD_DATE)" +LDFLAGS := -X github.com/$(DOCKER_REPO)/go/core/internal/version.Version=$(VERSION) \ + -X github.com/$(DOCKER_REPO)/go/core/internal/version.GitCommit=$(GIT_COMMIT) \ + -X github.com/$(DOCKER_REPO)/go/core/internal/version.BuildDate=$(BUILD_DATE) #tools versions TOOLS_UV_VERSION ?= 0.10.4 @@ -89,7 +89,7 @@ TOOLS_PYTHON_VERSION ?= 3.13 # build args TOOLS_IMAGE_BUILD_ARGS = --build-arg VERSION=$(VERSION) -TOOLS_IMAGE_BUILD_ARGS += --build-arg LDFLAGS=$(LDFLAGS) +TOOLS_IMAGE_BUILD_ARGS += --build-arg LDFLAGS="$(LDFLAGS)" TOOLS_IMAGE_BUILD_ARGS += --build-arg DOCKER_REPO=$(DOCKER_REPO) TOOLS_IMAGE_BUILD_ARGS += --build-arg DOCKER_REGISTRY=$(DOCKER_REGISTRY) TOOLS_IMAGE_BUILD_ARGS += --build-arg BASE_IMAGE_REGISTRY=$(BASE_IMAGE_REGISTRY) @@ -197,7 +197,7 @@ build-all: buildx-create .PHONY: build build: ## Build and push all component images -build: buildx-create build-controller build-ui build-app build-golang-adk build-golang-adk-full build-skills-init +build: buildx-create build-ui build-skills-init build-golang-adk build-golang-adk-full build-app build-controller @echo "Build completed successfully." @echo "Controller Image: $(CONTROLLER_IMG)" @echo "UI Image: $(UI_IMG)" @@ -241,9 +241,19 @@ controller-manifests: ## Regenerate CRD manifests and copy them into the Helm ch cp go/api/config/crd/bases/* helm/kagent-crds/templates/ .PHONY: build-controller -build-controller: ## Build and push the controller image -build-controller: buildx-create controller-manifests - $(DOCKER_BUILDER) $(DOCKER_BUILD_ARGS) $(TOOLS_IMAGE_BUILD_ARGS) --build-arg BUILD_PACKAGE=core/cmd/controller/main.go -t $(CONTROLLER_IMG) -f go/Dockerfile ./go +build-controller: ## Build and push the controller image (embeds agent runtime digests via scripts/controller-digest-ldflags.sh) +build-controller: buildx-create controller-manifests build-app build-golang-adk build-golang-adk-full + @set -e; \ + DIGEST_LDFLAGS=$$(CONTAINER_RUNTIME=$(CONTAINER_RUNTIME) \ + TRANSLATOR_PKG=github.com/$(DOCKER_REPO)/go/core/internal/controller/translator/agent \ + APP_IMG=$(APP_IMG) \ + GOLANG_ADK_IMG=$(GOLANG_ADK_IMG) \ + GOLANG_ADK_FULL_IMG=$(GOLANG_ADK_FULL_IMG) \ + ./scripts/controller-digest-ldflags.sh); \ + $(DOCKER_BUILDER) $(DOCKER_BUILD_ARGS) $(TOOLS_IMAGE_BUILD_ARGS) \ + --build-arg LDFLAGS="$(LDFLAGS)$$DIGEST_LDFLAGS" \ + --build-arg BUILD_PACKAGE=core/cmd/controller/main.go \ + -t $(CONTROLLER_IMG) -f go/Dockerfile ./go $(DOCKER_PUSH) $(CONTROLLER_IMG) .PHONY: build-ui diff --git a/go/README.md b/go/README.md index 04e51f5fc8..f77cd9679d 100644 --- a/go/README.md +++ b/go/README.md @@ -110,6 +110,20 @@ docker build --build-arg BUILD_PACKAGE=adk/cmd/main.go -t golang-adk . In practice, use the root Makefile targets (`make build-controller`, `make build-golang-adk`). +### Agent runtime image digests + +The controller embeds OCI manifest digests for agent workload images at **link time** so declarative agents are deployed with `@sha256:...` refs instead of tags. Substrate ActorTemplates require digest-pinned images. + +| Image | Makefile target | Injected into | +|---|---|---| +| `app` (Python runtime) | `build-app` | `DefaultAppImageDigest` | +| `golang-adk` | `build-golang-adk` | `DefaultGoImageDigest` | +| `golang-adk-full` | `build-golang-adk-full` | `DefaultGoFullImageDigest` | + +`make build-controller` builds those three images first, runs [`scripts/controller-digest-ldflags.sh`](../scripts/controller-digest-ldflags.sh) to inspect their digests from the registry, and passes the result via `LDFLAGS` (same mechanism as version/git metadata). + +`kagent-adk` is not included — it is only a build-time base for `app`, not a deployed agent runtime. + ## Quick Testing with Oneshot The `adk/examples/oneshot` tool lets you test agent configs locally: diff --git a/go/core/internal/controller/translator/agent/adk_api_translator.go b/go/core/internal/controller/translator/agent/adk_api_translator.go index d8e62b722d..04fb66da40 100644 --- a/go/core/internal/controller/translator/agent/adk_api_translator.go +++ b/go/core/internal/controller/translator/agent/adk_api_translator.go @@ -77,6 +77,7 @@ func NewValidationError(format string, args ...any) error { type ImageConfig struct { Registry string `json:"registry,omitempty"` Tag string `json:"tag,omitempty"` + Digest string `json:"digest,omitempty"` // OCI manifest digest (sha256:...), set at link time PullPolicy string `json:"pullPolicy,omitempty"` PullSecret string `json:"pullSecret,omitempty"` Repository string `json:"repository,omitempty"` @@ -87,6 +88,25 @@ func (c ImageConfig) Image() string { return fmt.Sprintf("%s/%s:%s", c.Registry, c.Repository, c.Tag) } +// PinnedImage returns registry/repository@sha256:... when Digest is set, otherwise Image(). +func (c ImageConfig) PinnedImage() string { + if digest := normalizeImageDigest(c.Digest); digest != "" { + return fmt.Sprintf("%s/%s@%s", c.Registry, c.Repository, digest) + } + return c.Image() +} + +func normalizeImageDigest(digest string) string { + digest = strings.TrimSpace(digest) + if digest == "" { + return "" + } + if strings.HasPrefix(digest, "sha256:") { + return digest + } + return "sha256:" + strings.TrimPrefix(digest, "sha256:") +} + var DefaultImageConfig = ImageConfig{ Registry: "cr.kagent.dev", Tag: version.Get().Version, @@ -95,6 +115,15 @@ var DefaultImageConfig = ImageConfig{ Repository: "kagent-dev/kagent/app", } +// DefaultAppImageDigest is set at controller link time from the pushed app (Python runtime) manifest digest. +// Use a package-level string (not DefaultImageConfig.Digest) so -ldflags -X can inject it at link time. +var DefaultAppImageDigest string + +// DefaultGoImageDigest and DefaultGoFullImageDigest are set at controller link time +// from the pushed golang-adk / golang-adk-full manifest digests. +var DefaultGoImageDigest string +var DefaultGoFullImageDigest string + // DefaultSkillsInitImageConfig is the image config for the skills-init container // that clones skill repositories from Git and pulls OCI skill images. var DefaultSkillsInitImageConfig = ImageConfig{ diff --git a/go/core/internal/controller/translator/agent/deployments.go b/go/core/internal/controller/translator/agent/deployments.go index cb0608af12..d2e2f243e8 100644 --- a/go/core/internal/controller/translator/agent/deployments.go +++ b/go/core/internal/controller/translator/agent/deployments.go @@ -122,6 +122,33 @@ func validateExtraContainers(containers []corev1.Container) error { return nil } +func resolvePythonRuntimeImage(registry string) (string, error) { + repo := DefaultImageConfig.Repository + if d := normalizeImageDigest(DefaultAppImageDigest); d != "" { + return fmt.Sprintf("%s/%s@%s", registry, repo, d), nil + } + return "", fmt.Errorf( + "app image digest is not set at link time; rebuild the controller after pushing agent runtime images", + ) +} + +func resolveGoRuntimeImage(registry string, full bool) (string, error) { + repo := getRuntimeImageRepository(v1alpha2.DeclarativeRuntime_Go) + digest := DefaultGoImageDigest + imageLabel := "golang-adk" + if full { + digest = DefaultGoFullImageDigest + imageLabel = "golang-adk-full" + } + if d := normalizeImageDigest(digest); d != "" { + return fmt.Sprintf("%s/%s@%s", registry, repo, d), nil + } + return "", fmt.Errorf( + "%s image digest is not set at link time; rebuild the controller after pushing agent runtime images", + imageLabel, + ) +} + func resolveInlineDeployment(agent v1alpha2.AgentObject, mdd *modelDeploymentData) (*resolvedDeployment, error) { specRef := agent.GetAgentSpec() // Defaults @@ -156,15 +183,23 @@ func resolveInlineDeployment(agent v1alpha2.AgentObject, mdd *modelDeploymentDat registry = spec.ImageRegistry } - repository := getRuntimeImageRepository(runtime) - - tag := DefaultImageConfig.Tag - if runtime == v1alpha2.DeclarativeRuntime_Go && needsSRTSettings(agent, specRef.Sandbox) { - tag += "-full" + var image string + full := runtime == v1alpha2.DeclarativeRuntime_Go && needsSRTSettings(agent, specRef.Sandbox) + switch runtime { + case v1alpha2.DeclarativeRuntime_Go: + var err error + image, err = resolveGoRuntimeImage(registry, full) + if err != nil { + return nil, err + } + default: + var err error + image, err = resolvePythonRuntimeImage(registry) + if err != nil { + return nil, err + } } - image := fmt.Sprintf("%s/%s:%s", registry, repository, tag) - imagePullPolicy := corev1.PullPolicy(DefaultImageConfig.PullPolicy) if spec.ImagePullPolicy != "" { imagePullPolicy = corev1.PullPolicy(spec.ImagePullPolicy) diff --git a/go/core/internal/controller/translator/agent/digest_testmain_external_test.go b/go/core/internal/controller/translator/agent/digest_testmain_external_test.go new file mode 100644 index 0000000000..a7a23d5661 --- /dev/null +++ b/go/core/internal/controller/translator/agent/digest_testmain_external_test.go @@ -0,0 +1,15 @@ +package agent_test + +import ( + "os" + "testing" + + translator "github.com/kagent-dev/kagent/go/core/internal/controller/translator/agent" +) + +func TestMain(m *testing.M) { + translator.DefaultAppImageDigest = "sha256:test-app" + translator.DefaultGoImageDigest = "sha256:test-go-base" + translator.DefaultGoFullImageDigest = "sha256:test-go-full" + os.Exit(m.Run()) +} diff --git a/go/core/internal/controller/translator/agent/imageconfig_test.go b/go/core/internal/controller/translator/agent/imageconfig_test.go new file mode 100644 index 0000000000..e888e4e6b5 --- /dev/null +++ b/go/core/internal/controller/translator/agent/imageconfig_test.go @@ -0,0 +1,100 @@ +package agent + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestImageConfigPinnedImage(t *testing.T) { + cfg := ImageConfig{ + Registry: "localhost:5001", + Repository: "kagent-dev/kagent/app", + Tag: "v1.0.0", + Digest: "sha256:abc123", + } + require.Equal(t, "localhost:5001/kagent-dev/kagent/app@sha256:abc123", cfg.PinnedImage()) + require.Equal(t, "localhost:5001/kagent-dev/kagent/app:v1.0.0", cfg.Image()) +} + +func TestImageConfigPinnedImageWithoutDigest(t *testing.T) { + cfg := ImageConfig{ + Registry: "cr.kagent.dev", + Repository: "kagent-dev/kagent/app", + Tag: "v1.0.0", + } + require.Equal(t, cfg.Image(), cfg.PinnedImage()) +} + +func TestResolveGoRuntimeImageWithDigest(t *testing.T) { + originalBase := DefaultGoImageDigest + originalFull := DefaultGoFullImageDigest + t.Cleanup(func() { + DefaultGoImageDigest = originalBase + DefaultGoFullImageDigest = originalFull + }) + DefaultGoImageDigest = "sha256:go-base" + DefaultGoFullImageDigest = "sha256:go-full" + + got, err := resolveGoRuntimeImage("localhost:5001", false) + require.NoError(t, err) + require.Equal(t, "localhost:5001/kagent-dev/kagent/golang-adk@sha256:go-base", got) + + got, err = resolveGoRuntimeImage("localhost:5001", true) + require.NoError(t, err) + require.Equal(t, "localhost:5001/kagent-dev/kagent/golang-adk@sha256:go-full", got) +} + +func TestResolveGoRuntimeImageWithoutDigest(t *testing.T) { + originalBase := DefaultGoImageDigest + originalFull := DefaultGoFullImageDigest + t.Cleanup(func() { + DefaultGoImageDigest = originalBase + DefaultGoFullImageDigest = originalFull + }) + DefaultGoImageDigest = "" + DefaultGoFullImageDigest = "" + + _, err := resolveGoRuntimeImage("localhost:5001", false) + require.Error(t, err) + require.Contains(t, err.Error(), "golang-adk") + + _, err = resolveGoRuntimeImage("localhost:5001", true) + require.Error(t, err) + require.Contains(t, err.Error(), "golang-adk-full") +} + +func TestResolvePythonRuntimeImageWithDigest(t *testing.T) { + original := DefaultAppImageDigest + t.Cleanup(func() { + DefaultAppImageDigest = original + }) + DefaultAppImageDigest = "sha256:app-digest" + + got, err := resolvePythonRuntimeImage("cr.kagent.dev") + require.NoError(t, err) + require.Equal(t, "cr.kagent.dev/kagent-dev/kagent/app@sha256:app-digest", got) +} + +func TestDefaultAppImageDigestSupportsLinkerFlag(t *testing.T) { + // DefaultAppImageDigest must be a package-level string var (not a struct field) so + // scripts/controller-digest-ldflags.sh can inject it via -ldflags -X at controller build time. + original := DefaultAppImageDigest + t.Cleanup(func() { + DefaultAppImageDigest = original + }) + DefaultAppImageDigest = "sha256:link-time-check" + require.Equal(t, "sha256:link-time-check", DefaultAppImageDigest) +} + +func TestResolvePythonRuntimeImageWithoutDigest(t *testing.T) { + original := DefaultAppImageDigest + t.Cleanup(func() { + DefaultAppImageDigest = original + }) + DefaultAppImageDigest = "" + + _, err := resolvePythonRuntimeImage("cr.kagent.dev") + require.Error(t, err) + require.Contains(t, err.Error(), "app") +} diff --git a/go/core/internal/controller/translator/agent/runtime_test.go b/go/core/internal/controller/translator/agent/runtime_test.go index 9bf8425a76..48c034d976 100644 --- a/go/core/internal/controller/translator/agent/runtime_test.go +++ b/go/core/internal/controller/translator/agent/runtime_test.go @@ -16,7 +16,29 @@ import ( translator "github.com/kagent-dev/kagent/go/core/internal/controller/translator/agent" ) +func withGoRuntimeDigests(t *testing.T) { + t.Helper() + originalBase := translator.DefaultGoImageDigest + originalFull := translator.DefaultGoFullImageDigest + translator.DefaultGoImageDigest = "sha256:test-go-base" + translator.DefaultGoFullImageDigest = "sha256:test-go-full" + t.Cleanup(func() { + translator.DefaultGoImageDigest = originalBase + translator.DefaultGoFullImageDigest = originalFull + }) +} + +func withPythonRuntimeDigest(t *testing.T) { + t.Helper() + original := translator.DefaultAppImageDigest + translator.DefaultAppImageDigest = "sha256:test-app" + t.Cleanup(func() { + translator.DefaultAppImageDigest = original + }) +} + func TestRuntime_GoRuntime(t *testing.T) { + withGoRuntimeDigests(t) ctx := context.Background() // Create agent with Go runtime @@ -83,7 +105,7 @@ func TestRuntime_GoRuntime(t *testing.T) { require.Len(t, deployment.Spec.Template.Spec.Containers, 1) container := deployment.Spec.Template.Spec.Containers[0] assert.Contains(t, container.Image, "golang-adk", "Image should use golang-adk repository") - assert.NotContains(t, container.Image, "-full", "Go runtime without sandboxed execution should use the distroless tag") + assert.Contains(t, container.Image, "@sha256:test-go-base", "Go runtime should use digest-pinned golang-adk image") // Verify Go runtime readiness probe timings (fast startup) require.NotNil(t, container.ReadinessProbe) @@ -93,6 +115,7 @@ func TestRuntime_GoRuntime(t *testing.T) { } func TestRuntime_GoRuntimeWithSkillsUsesFullImageTag(t *testing.T) { + withGoRuntimeDigests(t) ctx := context.Background() agent := &v1alpha2.Agent{ @@ -155,10 +178,11 @@ func TestRuntime_GoRuntimeWithSkillsUsesFullImageTag(t *testing.T) { require.Len(t, deployment.Spec.Template.Spec.Containers, 1) container := deployment.Spec.Template.Spec.Containers[0] assert.Contains(t, container.Image, "golang-adk", "Image should use golang-adk repository") - assert.Contains(t, container.Image, "-full", "Go runtime with skills should use the full image tag") + assert.Contains(t, container.Image, "@sha256:test-go-full", "Go runtime with skills should use digest-pinned golang-adk-full image") } func TestRuntime_PythonRuntime(t *testing.T) { + withPythonRuntimeDigest(t) ctx := context.Background() // Create agent with Python runtime (explicit) @@ -221,10 +245,11 @@ func TestRuntime_PythonRuntime(t *testing.T) { } require.NotNil(t, deployment, "Deployment should be in manifest") - // Verify container image uses app (Python ADK) + // Verify container image uses digest-pinned app (Python ADK) require.Len(t, deployment.Spec.Template.Spec.Containers, 1) container := deployment.Spec.Template.Spec.Containers[0] - assert.Contains(t, container.Image, "/app:", "Image should use app repository") + assert.Contains(t, container.Image, "/app@", "Image should use app repository") + assert.Contains(t, container.Image, "@sha256:test-app", "Python runtime should use digest-pinned app image") // Verify Python runtime readiness probe timings (slower startup) require.NotNil(t, container.ReadinessProbe) @@ -234,6 +259,7 @@ func TestRuntime_PythonRuntime(t *testing.T) { } func TestRuntime_DefaultToPython(t *testing.T) { + withPythonRuntimeDigest(t) ctx := context.Background() // Create agent without runtime field (should default to Python) @@ -296,10 +322,11 @@ func TestRuntime_DefaultToPython(t *testing.T) { } require.NotNil(t, deployment, "Deployment should be in manifest") - // Verify container image uses app (Python ADK) by default + // Verify container image uses digest-pinned app (Python ADK) by default require.Len(t, deployment.Spec.Template.Spec.Containers, 1) container := deployment.Spec.Template.Spec.Containers[0] - assert.Contains(t, container.Image, "/app:", "Image should default to app repository") + assert.Contains(t, container.Image, "/app@", "Image should default to app repository") + assert.Contains(t, container.Image, "@sha256:test-app", "Default Python runtime should use digest-pinned app image") // Verify Python runtime readiness probe timings require.NotNil(t, container.ReadinessProbe) @@ -309,6 +336,7 @@ func TestRuntime_DefaultToPython(t *testing.T) { } func TestRuntime_CustomRepositoryPath(t *testing.T) { + withGoRuntimeDigests(t) ctx := context.Background() // Save original DefaultImageConfig.Repository and restore after test @@ -384,10 +412,11 @@ func TestRuntime_CustomRepositoryPath(t *testing.T) { require.Len(t, deployment.Spec.Template.Spec.Containers, 1) container := deployment.Spec.Template.Spec.Containers[0] assert.Contains(t, container.Image, "my-registry.com/custom/golang-adk", "Image should use custom repository with golang-adk") - assert.NotContains(t, container.Image, "-full", "Go runtime without sandboxed execution should keep the base tag") + assert.Contains(t, container.Image, "@sha256:test-go-base", "Go runtime should use digest-pinned golang-adk image") } func TestRuntime_CustomRepositoryPath_WithSkillsUsesFullTag(t *testing.T) { + withGoRuntimeDigests(t) ctx := context.Background() originalRepo := translator.DefaultImageConfig.Repository @@ -456,5 +485,5 @@ func TestRuntime_CustomRepositoryPath_WithSkillsUsesFullTag(t *testing.T) { require.Len(t, deployment.Spec.Template.Spec.Containers, 1) container := deployment.Spec.Template.Spec.Containers[0] assert.Contains(t, container.Image, "my-registry.com/custom/golang-adk", "Image should use custom repository with golang-adk") - assert.Contains(t, container.Image, "-full", "Go runtime with skills should use the full tag") + assert.Contains(t, container.Image, "@sha256:test-go-full", "Go runtime with skills should use digest-pinned golang-adk-full image") } diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_a2a_config.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_a2a_config.json index 3a467bf506..61d26d46f6 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_a2a_config.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_a2a_config.json @@ -178,7 +178,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_allowed_headers.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_allowed_headers.json index 6c94d2f86d..296a2856eb 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_allowed_headers.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_allowed_headers.json @@ -188,7 +188,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_code.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_code.json index 597478474b..401e05a987 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_code.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_code.json @@ -185,7 +185,7 @@ "value": "/config/srt-settings.json" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_context_config.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_context_config.json index 1ac7356e6d..17b9792480 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_context_config.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_context_config.json @@ -199,7 +199,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_cross_namespace_tools.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_cross_namespace_tools.json index edaedd9719..db64c813a2 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_cross_namespace_tools.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_cross_namespace_tools.json @@ -194,7 +194,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_custom_sa.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_custom_sa.json index d2ecefd3a6..e3897e2ebb 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_custom_sa.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_custom_sa.json @@ -147,7 +147,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_default_sa.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_default_sa.json index 19548c5d01..3bce12748c 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_default_sa.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_default_sa.json @@ -147,7 +147,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_embedding_provider.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_embedding_provider.json index f2a9de95bf..3e27842ad4 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_embedding_provider.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_embedding_provider.json @@ -194,7 +194,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_extra_containers.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_extra_containers.json index 6f9d1fa0bf..8887980ad7 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_extra_containers.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_extra_containers.json @@ -172,7 +172,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_git_skills.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_git_skills.json index 29d7fc178b..73ea78d645 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_git_skills.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_git_skills.json @@ -207,7 +207,7 @@ "value": "/config/srt-settings.json" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_http_toolserver.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_http_toolserver.json index 838ef2dbc2..c96b85aba8 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_http_toolserver.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_http_toolserver.json @@ -187,7 +187,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_mcp_service.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_mcp_service.json index 852ebeeafd..b44ad40915 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_mcp_service.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_mcp_service.json @@ -183,7 +183,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_memory.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_memory.json index c8b70f08b4..c6693a3716 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_memory.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_memory.json @@ -183,7 +183,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_nested_agent.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_nested_agent.json index caba32bec9..505896bbe5 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_nested_agent.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_nested_agent.json @@ -181,7 +181,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_passthrough.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_passthrough.json index 0a9a7fcda8..6f88bfd766 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_passthrough.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_passthrough.json @@ -165,7 +165,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_prompt_template.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_prompt_template.json index e13ba958fe..719bf32c9f 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_prompt_template.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_prompt_template.json @@ -185,7 +185,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy.json index 901ce90339..47fd01f9e8 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy.json @@ -194,7 +194,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_external_remotemcp.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_external_remotemcp.json index 53cf7f4bc7..1593aa7e2f 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_external_remotemcp.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_external_remotemcp.json @@ -183,7 +183,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_mcpserver.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_mcpserver.json index e80a0bf78e..c3cef54b8b 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_mcpserver.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_mcpserver.json @@ -186,7 +186,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_mcpserver_custom_timeout.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_mcpserver_custom_timeout.json index 150bc253d0..11d04b8a7b 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_mcpserver_custom_timeout.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_mcpserver_custom_timeout.json @@ -186,7 +186,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_service.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_service.json index 0010bc16d9..3902f11a85 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_service.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_proxy_service.json @@ -185,7 +185,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_require_approval.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_require_approval.json index e48937b0f2..76cfc92367 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_require_approval.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_require_approval.json @@ -189,7 +189,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_scheduling_attributes.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_scheduling_attributes.json index c1f32a0921..f34a25b563 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_scheduling_attributes.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_scheduling_attributes.json @@ -198,7 +198,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_security_context.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_security_context.json index b1372c0b3b..832439f719 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_security_context.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_security_context.json @@ -179,7 +179,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_skills.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_skills.json index 93458886a6..b925634f41 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_skills.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_skills.json @@ -207,7 +207,7 @@ "value": "/config/srt-settings.json" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_streaming.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_streaming.json index e0d08cd124..9d4ab244ac 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_streaming.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_streaming.json @@ -179,7 +179,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_system_message_from_configmap.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_system_message_from_configmap.json index de6ed10545..23ff61eef8 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_system_message_from_configmap.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_system_message_from_configmap.json @@ -172,7 +172,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_system_message_from_secret.json b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_system_message_from_secret.json index a03bbbea85..b1f6764b84 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_system_message_from_secret.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/agent_with_system_message_from_secret.json @@ -172,7 +172,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/anthropic_agent.json b/go/core/internal/controller/translator/agent/testdata/outputs/anthropic_agent.json index b17be6ab43..a7ac988f81 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/anthropic_agent.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/anthropic_agent.json @@ -171,7 +171,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/basic_agent.json b/go/core/internal/controller/translator/agent/testdata/outputs/basic_agent.json index 81915807b9..79d857f722 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/basic_agent.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/basic_agent.json @@ -179,7 +179,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/bedrock_agent.json b/go/core/internal/controller/translator/agent/testdata/outputs/bedrock_agent.json index c610f58ca2..9b830c4b89 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/bedrock_agent.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/bedrock_agent.json @@ -185,7 +185,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/ollama_agent.json b/go/core/internal/controller/translator/agent/testdata/outputs/ollama_agent.json index 02a0ddae91..b01ca641d6 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/ollama_agent.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/ollama_agent.json @@ -174,7 +174,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/tls-with-custom-ca.json b/go/core/internal/controller/translator/agent/testdata/outputs/tls-with-custom-ca.json index 62e996c083..7658ba290e 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/tls-with-custom-ca.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/tls-with-custom-ca.json @@ -177,7 +177,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/tls-with-disabled-verify.json b/go/core/internal/controller/translator/agent/testdata/outputs/tls-with-disabled-verify.json index 5da58bfdcd..011da7ddca 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/tls-with-disabled-verify.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/tls-with-disabled-verify.json @@ -176,7 +176,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/go/core/internal/controller/translator/agent/testdata/outputs/tls-with-system-cas-disabled.json b/go/core/internal/controller/translator/agent/testdata/outputs/tls-with-system-cas-disabled.json index 620c29c9f5..1154deaa4d 100644 --- a/go/core/internal/controller/translator/agent/testdata/outputs/tls-with-system-cas-disabled.json +++ b/go/core/internal/controller/translator/agent/testdata/outputs/tls-with-system-cas-disabled.json @@ -177,7 +177,7 @@ "value": "http://kagent-controller.kagent:8083" } ], - "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app", "imagePullPolicy": "IfNotPresent", "name": "kagent", "ports": [ diff --git a/scripts/controller-digest-ldflags.sh b/scripts/controller-digest-ldflags.sh new file mode 100755 index 0000000000..b6f336997b --- /dev/null +++ b/scripts/controller-digest-ldflags.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Emit -X ldflags for agent runtime image digests baked into the controller binary. +# +# Required environment variables: +# TRANSLATOR_PKG Go import path for the translator agent package +# APP_IMG Python agent runtime image ref (repo:tag) +# GOLANG_ADK_IMG Go agent runtime image ref (repo:tag) +# GOLANG_ADK_FULL_IMG Go agent full runtime image ref (repo:tag) +# +# Optional: +# CONTAINER_RUNTIME docker (default) + +set -o errexit +set -o pipefail + +CONTAINER_RUNTIME="${CONTAINER_RUNTIME:-docker}" + +: "${TRANSLATOR_PKG:?TRANSLATOR_PKG is required}" +: "${APP_IMG:?APP_IMG is required}" +: "${GOLANG_ADK_IMG:?GOLANG_ADK_IMG is required}" +: "${GOLANG_ADK_FULL_IMG:?GOLANG_ADK_FULL_IMG is required}" + +image_digest() { + "${CONTAINER_RUNTIME}" buildx imagetools inspect "$1" --format '{{.Manifest.Digest}}' 2>/dev/null || true +} + +append_digest_ldflag() { + local go_var=$1 + local image_ref=$2 + local digest + digest="$(image_digest "${image_ref}")" + if [[ -z "${digest}" ]]; then + echo "error: could not resolve OCI digest for ${image_ref} (is it pushed to the registry?)" >&2 + exit 1 + fi + printf ' -X %s.%s=%s' "${TRANSLATOR_PKG}" "${go_var}" "${digest}" +} + +append_digest_ldflag "DefaultAppImageDigest" "${APP_IMG}" +append_digest_ldflag "DefaultGoImageDigest" "${GOLANG_ADK_IMG}" +append_digest_ldflag "DefaultGoFullImageDigest" "${GOLANG_ADK_FULL_IMG}" From b247f105bd00df509a612ec6f34090fd6ddacf5e Mon Sep 17 00:00:00 2001 From: Eitan Yarmush Date: Thu, 4 Jun 2026 14:02:12 +0000 Subject: [PATCH 2/5] Simplify runtime image digest wiring Signed-off-by: Eitan Yarmush --- Makefile | 2 - go/README.md | 6 +- .../translator/agent/adk_api_translator.go | 22 ++----- .../translator/agent/deployments.go | 6 +- .../agent/digest_testmain_external_test.go | 6 +- .../translator/agent/imageconfig_test.go | 65 ++++++++----------- .../translator/agent/runtime_test.go | 18 ++--- scripts/controller-digest-ldflags.sh | 9 ++- 8 files changed, 54 insertions(+), 80 deletions(-) diff --git a/Makefile b/Makefile index 84acf54b12..b91d7c377d 100644 --- a/Makefile +++ b/Makefile @@ -245,7 +245,6 @@ build-controller: ## Build and push the controller image (embeds agent runtime d build-controller: buildx-create controller-manifests build-app build-golang-adk build-golang-adk-full @set -e; \ DIGEST_LDFLAGS=$$(CONTAINER_RUNTIME=$(CONTAINER_RUNTIME) \ - TRANSLATOR_PKG=github.com/$(DOCKER_REPO)/go/core/internal/controller/translator/agent \ APP_IMG=$(APP_IMG) \ GOLANG_ADK_IMG=$(GOLANG_ADK_IMG) \ GOLANG_ADK_FULL_IMG=$(GOLANG_ADK_FULL_IMG) \ @@ -566,4 +565,3 @@ prune-images: ## Remove old kagent images and dangling images from the local dae grep -v ":$(VERSION) " | grep kagent | grep -v '' | awk '{print $$2}' | xargs -r $(CONTAINER_RUNTIME) rmi || : $(CONTAINER_RUNTIME) images --filter dangling=true -q | xargs -r $(CONTAINER_RUNTIME) rmi || : - diff --git a/go/README.md b/go/README.md index f77cd9679d..4b032b5466 100644 --- a/go/README.md +++ b/go/README.md @@ -116,9 +116,9 @@ The controller embeds OCI manifest digests for agent workload images at **link t | Image | Makefile target | Injected into | |---|---|---| -| `app` (Python runtime) | `build-app` | `DefaultAppImageDigest` | -| `golang-adk` | `build-golang-adk` | `DefaultGoImageDigest` | -| `golang-adk-full` | `build-golang-adk-full` | `DefaultGoFullImageDigest` | +| `app` (Python runtime) | `build-app` | `PythonADKImageDigest` | +| `golang-adk` | `build-golang-adk` | `GoADKImageDigest` | +| `golang-adk-full` | `build-golang-adk-full` | `GoADKFullImageDigest` | `make build-controller` builds those three images first, runs [`scripts/controller-digest-ldflags.sh`](../scripts/controller-digest-ldflags.sh) to inspect their digests from the registry, and passes the result via `LDFLAGS` (same mechanism as version/git metadata). diff --git a/go/core/internal/controller/translator/agent/adk_api_translator.go b/go/core/internal/controller/translator/agent/adk_api_translator.go index 04fb66da40..6522362528 100644 --- a/go/core/internal/controller/translator/agent/adk_api_translator.go +++ b/go/core/internal/controller/translator/agent/adk_api_translator.go @@ -77,7 +77,6 @@ func NewValidationError(format string, args ...any) error { type ImageConfig struct { Registry string `json:"registry,omitempty"` Tag string `json:"tag,omitempty"` - Digest string `json:"digest,omitempty"` // OCI manifest digest (sha256:...), set at link time PullPolicy string `json:"pullPolicy,omitempty"` PullSecret string `json:"pullSecret,omitempty"` Repository string `json:"repository,omitempty"` @@ -88,14 +87,6 @@ func (c ImageConfig) Image() string { return fmt.Sprintf("%s/%s:%s", c.Registry, c.Repository, c.Tag) } -// PinnedImage returns registry/repository@sha256:... when Digest is set, otherwise Image(). -func (c ImageConfig) PinnedImage() string { - if digest := normalizeImageDigest(c.Digest); digest != "" { - return fmt.Sprintf("%s/%s@%s", c.Registry, c.Repository, digest) - } - return c.Image() -} - func normalizeImageDigest(digest string) string { digest = strings.TrimSpace(digest) if digest == "" { @@ -115,14 +106,11 @@ var DefaultImageConfig = ImageConfig{ Repository: "kagent-dev/kagent/app", } -// DefaultAppImageDigest is set at controller link time from the pushed app (Python runtime) manifest digest. -// Use a package-level string (not DefaultImageConfig.Digest) so -ldflags -X can inject it at link time. -var DefaultAppImageDigest string - -// DefaultGoImageDigest and DefaultGoFullImageDigest are set at controller link time -// from the pushed golang-adk / golang-adk-full manifest digests. -var DefaultGoImageDigest string -var DefaultGoFullImageDigest string +// PythonADKImageDigest, GoADKImageDigest, and GoADKFullImageDigest are set at +// controller link time from the pushed runtime image manifest digests. +var PythonADKImageDigest string +var GoADKImageDigest string +var GoADKFullImageDigest string // DefaultSkillsInitImageConfig is the image config for the skills-init container // that clones skill repositories from Git and pulls OCI skill images. diff --git a/go/core/internal/controller/translator/agent/deployments.go b/go/core/internal/controller/translator/agent/deployments.go index d2e2f243e8..b8eeaf716c 100644 --- a/go/core/internal/controller/translator/agent/deployments.go +++ b/go/core/internal/controller/translator/agent/deployments.go @@ -124,7 +124,7 @@ func validateExtraContainers(containers []corev1.Container) error { func resolvePythonRuntimeImage(registry string) (string, error) { repo := DefaultImageConfig.Repository - if d := normalizeImageDigest(DefaultAppImageDigest); d != "" { + if d := normalizeImageDigest(PythonADKImageDigest); d != "" { return fmt.Sprintf("%s/%s@%s", registry, repo, d), nil } return "", fmt.Errorf( @@ -134,10 +134,10 @@ func resolvePythonRuntimeImage(registry string) (string, error) { func resolveGoRuntimeImage(registry string, full bool) (string, error) { repo := getRuntimeImageRepository(v1alpha2.DeclarativeRuntime_Go) - digest := DefaultGoImageDigest + digest := GoADKImageDigest imageLabel := "golang-adk" if full { - digest = DefaultGoFullImageDigest + digest = GoADKFullImageDigest imageLabel = "golang-adk-full" } if d := normalizeImageDigest(digest); d != "" { diff --git a/go/core/internal/controller/translator/agent/digest_testmain_external_test.go b/go/core/internal/controller/translator/agent/digest_testmain_external_test.go index a7a23d5661..db798c77cf 100644 --- a/go/core/internal/controller/translator/agent/digest_testmain_external_test.go +++ b/go/core/internal/controller/translator/agent/digest_testmain_external_test.go @@ -8,8 +8,8 @@ import ( ) func TestMain(m *testing.M) { - translator.DefaultAppImageDigest = "sha256:test-app" - translator.DefaultGoImageDigest = "sha256:test-go-base" - translator.DefaultGoFullImageDigest = "sha256:test-go-full" + translator.PythonADKImageDigest = "sha256:test-app" + translator.GoADKImageDigest = "sha256:test-go-base" + translator.GoADKFullImageDigest = "sha256:test-go-full" os.Exit(m.Run()) } diff --git a/go/core/internal/controller/translator/agent/imageconfig_test.go b/go/core/internal/controller/translator/agent/imageconfig_test.go index e888e4e6b5..949f16d094 100644 --- a/go/core/internal/controller/translator/agent/imageconfig_test.go +++ b/go/core/internal/controller/translator/agent/imageconfig_test.go @@ -6,35 +6,24 @@ import ( "github.com/stretchr/testify/require" ) -func TestImageConfigPinnedImage(t *testing.T) { - cfg := ImageConfig{ - Registry: "localhost:5001", - Repository: "kagent-dev/kagent/app", - Tag: "v1.0.0", - Digest: "sha256:abc123", - } - require.Equal(t, "localhost:5001/kagent-dev/kagent/app@sha256:abc123", cfg.PinnedImage()) - require.Equal(t, "localhost:5001/kagent-dev/kagent/app:v1.0.0", cfg.Image()) -} - -func TestImageConfigPinnedImageWithoutDigest(t *testing.T) { +func TestImageConfigImage(t *testing.T) { cfg := ImageConfig{ Registry: "cr.kagent.dev", Repository: "kagent-dev/kagent/app", Tag: "v1.0.0", } - require.Equal(t, cfg.Image(), cfg.PinnedImage()) + require.Equal(t, "cr.kagent.dev/kagent-dev/kagent/app:v1.0.0", cfg.Image()) } func TestResolveGoRuntimeImageWithDigest(t *testing.T) { - originalBase := DefaultGoImageDigest - originalFull := DefaultGoFullImageDigest + originalBase := GoADKImageDigest + originalFull := GoADKFullImageDigest t.Cleanup(func() { - DefaultGoImageDigest = originalBase - DefaultGoFullImageDigest = originalFull + GoADKImageDigest = originalBase + GoADKFullImageDigest = originalFull }) - DefaultGoImageDigest = "sha256:go-base" - DefaultGoFullImageDigest = "sha256:go-full" + GoADKImageDigest = "sha256:go-base" + GoADKFullImageDigest = "sha256:go-full" got, err := resolveGoRuntimeImage("localhost:5001", false) require.NoError(t, err) @@ -46,14 +35,14 @@ func TestResolveGoRuntimeImageWithDigest(t *testing.T) { } func TestResolveGoRuntimeImageWithoutDigest(t *testing.T) { - originalBase := DefaultGoImageDigest - originalFull := DefaultGoFullImageDigest + originalBase := GoADKImageDigest + originalFull := GoADKFullImageDigest t.Cleanup(func() { - DefaultGoImageDigest = originalBase - DefaultGoFullImageDigest = originalFull + GoADKImageDigest = originalBase + GoADKFullImageDigest = originalFull }) - DefaultGoImageDigest = "" - DefaultGoFullImageDigest = "" + GoADKImageDigest = "" + GoADKFullImageDigest = "" _, err := resolveGoRuntimeImage("localhost:5001", false) require.Error(t, err) @@ -65,34 +54,34 @@ func TestResolveGoRuntimeImageWithoutDigest(t *testing.T) { } func TestResolvePythonRuntimeImageWithDigest(t *testing.T) { - original := DefaultAppImageDigest + original := PythonADKImageDigest t.Cleanup(func() { - DefaultAppImageDigest = original + PythonADKImageDigest = original }) - DefaultAppImageDigest = "sha256:app-digest" + PythonADKImageDigest = "sha256:app-digest" got, err := resolvePythonRuntimeImage("cr.kagent.dev") require.NoError(t, err) require.Equal(t, "cr.kagent.dev/kagent-dev/kagent/app@sha256:app-digest", got) } -func TestDefaultAppImageDigestSupportsLinkerFlag(t *testing.T) { - // DefaultAppImageDigest must be a package-level string var (not a struct field) so - // scripts/controller-digest-ldflags.sh can inject it via -ldflags -X at controller build time. - original := DefaultAppImageDigest +func TestPythonADKImageDigestSupportsLinkerFlag(t *testing.T) { + // PythonADKImageDigest must be a package-level string var so + // scripts/controller-digest-ldflags.sh can inject it via -ldflags -X. + original := PythonADKImageDigest t.Cleanup(func() { - DefaultAppImageDigest = original + PythonADKImageDigest = original }) - DefaultAppImageDigest = "sha256:link-time-check" - require.Equal(t, "sha256:link-time-check", DefaultAppImageDigest) + PythonADKImageDigest = "sha256:link-time-check" + require.Equal(t, "sha256:link-time-check", PythonADKImageDigest) } func TestResolvePythonRuntimeImageWithoutDigest(t *testing.T) { - original := DefaultAppImageDigest + original := PythonADKImageDigest t.Cleanup(func() { - DefaultAppImageDigest = original + PythonADKImageDigest = original }) - DefaultAppImageDigest = "" + PythonADKImageDigest = "" _, err := resolvePythonRuntimeImage("cr.kagent.dev") require.Error(t, err) diff --git a/go/core/internal/controller/translator/agent/runtime_test.go b/go/core/internal/controller/translator/agent/runtime_test.go index 48c034d976..f196415ed8 100644 --- a/go/core/internal/controller/translator/agent/runtime_test.go +++ b/go/core/internal/controller/translator/agent/runtime_test.go @@ -18,22 +18,22 @@ import ( func withGoRuntimeDigests(t *testing.T) { t.Helper() - originalBase := translator.DefaultGoImageDigest - originalFull := translator.DefaultGoFullImageDigest - translator.DefaultGoImageDigest = "sha256:test-go-base" - translator.DefaultGoFullImageDigest = "sha256:test-go-full" + originalBase := translator.GoADKImageDigest + originalFull := translator.GoADKFullImageDigest + translator.GoADKImageDigest = "sha256:test-go-base" + translator.GoADKFullImageDigest = "sha256:test-go-full" t.Cleanup(func() { - translator.DefaultGoImageDigest = originalBase - translator.DefaultGoFullImageDigest = originalFull + translator.GoADKImageDigest = originalBase + translator.GoADKFullImageDigest = originalFull }) } func withPythonRuntimeDigest(t *testing.T) { t.Helper() - original := translator.DefaultAppImageDigest - translator.DefaultAppImageDigest = "sha256:test-app" + original := translator.PythonADKImageDigest + translator.PythonADKImageDigest = "sha256:test-app" t.Cleanup(func() { - translator.DefaultAppImageDigest = original + translator.PythonADKImageDigest = original }) } diff --git a/scripts/controller-digest-ldflags.sh b/scripts/controller-digest-ldflags.sh index b6f336997b..9cc58f3396 100755 --- a/scripts/controller-digest-ldflags.sh +++ b/scripts/controller-digest-ldflags.sh @@ -2,7 +2,6 @@ # Emit -X ldflags for agent runtime image digests baked into the controller binary. # # Required environment variables: -# TRANSLATOR_PKG Go import path for the translator agent package # APP_IMG Python agent runtime image ref (repo:tag) # GOLANG_ADK_IMG Go agent runtime image ref (repo:tag) # GOLANG_ADK_FULL_IMG Go agent full runtime image ref (repo:tag) @@ -14,8 +13,8 @@ set -o errexit set -o pipefail CONTAINER_RUNTIME="${CONTAINER_RUNTIME:-docker}" +TRANSLATOR_PKG="github.com/kagent-dev/kagent/go/core/internal/controller/translator/agent" -: "${TRANSLATOR_PKG:?TRANSLATOR_PKG is required}" : "${APP_IMG:?APP_IMG is required}" : "${GOLANG_ADK_IMG:?GOLANG_ADK_IMG is required}" : "${GOLANG_ADK_FULL_IMG:?GOLANG_ADK_FULL_IMG is required}" @@ -36,6 +35,6 @@ append_digest_ldflag() { printf ' -X %s.%s=%s' "${TRANSLATOR_PKG}" "${go_var}" "${digest}" } -append_digest_ldflag "DefaultAppImageDigest" "${APP_IMG}" -append_digest_ldflag "DefaultGoImageDigest" "${GOLANG_ADK_IMG}" -append_digest_ldflag "DefaultGoFullImageDigest" "${GOLANG_ADK_FULL_IMG}" +append_digest_ldflag "PythonADKImageDigest" "${APP_IMG}" +append_digest_ldflag "GoADKImageDigest" "${GOLANG_ADK_IMG}" +append_digest_ldflag "GoADKFullImageDigest" "${GOLANG_ADK_FULL_IMG}" From 57d62fb8d244fc67d9a5b8d9b899ecf7bb998de6 Mon Sep 17 00:00:00 2001 From: Eitan Yarmush Date: Thu, 4 Jun 2026 14:19:19 +0000 Subject: [PATCH 3/5] Fix runtime image digest extraction Signed-off-by: Eitan Yarmush --- scripts/controller-digest-ldflags.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/controller-digest-ldflags.sh b/scripts/controller-digest-ldflags.sh index 9cc58f3396..efe3533170 100755 --- a/scripts/controller-digest-ldflags.sh +++ b/scripts/controller-digest-ldflags.sh @@ -20,7 +20,7 @@ TRANSLATOR_PKG="github.com/kagent-dev/kagent/go/core/internal/controller/transla : "${GOLANG_ADK_FULL_IMG:?GOLANG_ADK_FULL_IMG is required}" image_digest() { - "${CONTAINER_RUNTIME}" buildx imagetools inspect "$1" --format '{{.Manifest.Digest}}' 2>/dev/null || true + "${CONTAINER_RUNTIME}" buildx imagetools inspect "$1" 2>/dev/null | awk '/^Digest:[[:space:]]+sha256:/ { print $2; exit }' } append_digest_ldflag() { From 4e8f38dfa15959aac9cd44c09ebc26178c8e8584 Mon Sep 17 00:00:00 2001 From: Eitan Yarmush Date: Thu, 4 Jun 2026 14:36:52 +0000 Subject: [PATCH 4/5] Seed runtime image digests in agent handler tests Signed-off-by: Eitan Yarmush --- .../httpserver/handlers/agents_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/go/core/internal/httpserver/handlers/agents_test.go b/go/core/internal/httpserver/handlers/agents_test.go index efe2bf352c..c676d3a8f7 100644 --- a/go/core/internal/httpserver/handlers/agents_test.go +++ b/go/core/internal/httpserver/handlers/agents_test.go @@ -20,6 +20,7 @@ import ( "github.com/kagent-dev/kagent/go/api/database" api "github.com/kagent-dev/kagent/go/api/httpapi" "github.com/kagent-dev/kagent/go/api/v1alpha2" + agenttranslator "github.com/kagent-dev/kagent/go/core/internal/controller/translator/agent" "github.com/kagent-dev/kagent/go/core/internal/httpserver/auth" "github.com/kagent-dev/kagent/go/core/internal/httpserver/handlers" common "github.com/kagent-dev/kagent/go/core/internal/utils" @@ -81,6 +82,9 @@ func createTestSandboxAgentCRD(name string, modelConfig *v1alpha2.ModelConfig, c } func setupTestHandler(t *testing.T, objects ...client.Object) (*handlers.AgentsHandler, string) { + t.Helper() + withRuntimeImageDigests(t) + kubeClient := fake.NewClientBuilder(). WithScheme(setupScheme()). WithObjects(objects...). @@ -103,6 +107,21 @@ func setupTestHandler(t *testing.T, objects ...client.Object) (*handlers.AgentsH return handlers.NewAgentsHandler(base), userID } +func withRuntimeImageDigests(t *testing.T) { + t.Helper() + originalPython := agenttranslator.PythonADKImageDigest + originalGo := agenttranslator.GoADKImageDigest + originalGoFull := agenttranslator.GoADKFullImageDigest + agenttranslator.PythonADKImageDigest = "sha256:test-python-adk" + agenttranslator.GoADKImageDigest = "sha256:test-go-adk" + agenttranslator.GoADKFullImageDigest = "sha256:test-go-adk-full" + t.Cleanup(func() { + agenttranslator.PythonADKImageDigest = originalPython + agenttranslator.GoADKImageDigest = originalGo + agenttranslator.GoADKFullImageDigest = originalGoFull + }) +} + func createAgent(client database.Client, agent *v1alpha2.Agent) { dbAgent := &database.Agent{ Config: &adk.AgentConfig{}, From 9ffe268819331da8784c220a548eeb905be6d36a Mon Sep 17 00:00:00 2001 From: Eitan Yarmush Date: Tue, 9 Jun 2026 15:10:23 +0000 Subject: [PATCH 5/5] Fix controller digest lookup for CI builds Signed-off-by: Eitan Yarmush --- scripts/controller-digest-ldflags.sh | 62 +++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/scripts/controller-digest-ldflags.sh b/scripts/controller-digest-ldflags.sh index efe3533170..7f34640a78 100755 --- a/scripts/controller-digest-ldflags.sh +++ b/scripts/controller-digest-ldflags.sh @@ -14,13 +14,73 @@ set -o pipefail CONTAINER_RUNTIME="${CONTAINER_RUNTIME:-docker}" TRANSLATOR_PKG="github.com/kagent-dev/kagent/go/core/internal/controller/translator/agent" +MANIFEST_ACCEPT="application/vnd.oci.image.index.v1+json, application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.docker.distribution.manifest.v2+json" : "${APP_IMG:?APP_IMG is required}" : "${GOLANG_ADK_IMG:?GOLANG_ADK_IMG is required}" : "${GOLANG_ADK_FULL_IMG:?GOLANG_ADK_FULL_IMG is required}" +registry_manifest_digest() { + local image_ref=$1 + local registry remainder repository tag scheme headers + + if [[ "${image_ref}" == *@sha256:* ]]; then + printf '%s\n' "${image_ref##*@}" + return 0 + fi + + registry="${image_ref%%/*}" + remainder="${image_ref#*/}" + if [[ "${registry}" == "${image_ref}" || "${remainder}" != *:* ]]; then + return 1 + fi + + repository="${remainder%:*}" + tag="${remainder##*:}" + scheme="https" + if [[ "${registry}" == localhost:* || "${registry}" == 127.* || "${registry}" == "[::1]:"* ]]; then + scheme="http" + fi + + if ! command -v curl >/dev/null 2>&1; then + return 1 + fi + + if ! headers="$( + curl -fsSI \ + -H "Accept: ${MANIFEST_ACCEPT}" \ + "${scheme}://${registry}/v2/${repository}/manifests/${tag}" + )"; then + return 1 + fi + + printf '%s\n' "${headers}" | awk 'tolower($1) == "docker-content-digest:" { gsub("\r", "", $2); print $2; exit }' +} + image_digest() { - "${CONTAINER_RUNTIME}" buildx imagetools inspect "$1" 2>/dev/null | awk '/^Digest:[[:space:]]+sha256:/ { print $2; exit }' + local image_ref=$1 + local digest output status + + if digest="$(registry_manifest_digest "${image_ref}")" && [[ -n "${digest}" ]]; then + printf '%s\n' "${digest}" + return 0 + fi + + if output="$("${CONTAINER_RUNTIME}" buildx imagetools inspect "${image_ref}" 2>&1)"; then + digest="$(printf '%s\n' "${output}" | awk '/^Digest:[[:space:]]+sha256:/ { print $2; exit }')" + if [[ -n "${digest}" ]]; then + printf '%s\n' "${digest}" + return 0 + fi + echo "error: could not find OCI digest in imagetools output for ${image_ref}" >&2 + printf '%s\n' "${output}" >&2 + return 1 + fi + + status=$? + echo "error: failed to inspect OCI digest for ${image_ref}" >&2 + printf '%s\n' "${output}" >&2 + return "${status}" } append_digest_ldflag() {