Skip to content

fix(controller): reference agent images by tag for private registries#2076

Closed
igabi wants to merge 1 commit into
kagent-dev:mainfrom
igabi:fix/2055-agent-image-digest-private-registry
Closed

fix(controller): reference agent images by tag for private registries#2076
igabi wants to merge 1 commit into
kagent-dev:mainfrom
igabi:fix/2055-agent-image-digest-private-registry

Conversation

@igabi

@igabi igabi commented Jun 23, 2026

Copy link
Copy Markdown

What

Declarative agent pods fail with ImagePullBackOff / manifest unknown when the controller is configured to use a private registry that does not preserve the upstream image manifest digest.

Since v0.9.7, declarative agent images are pinned by their link-time digest (registry/repository@sha256:...), injected via controller-digest-ldflags.sh. When --image-registry / --image-repository point to a private registry, the controller rewrites only the registry and repository segments but keeps the hardcoded upstream digest. Many mirrors (e.g. az acr import targets, pull-through proxies that re-push) assign a different manifest digest, so the emitted reference does not resolve. --image-tag is silently ignored for declarative agents, so there is no way to fall back to a tag.

This is the behaviour reported in #2055.

Fix

Add a --pin-runtime-image-digest flag (env PIN_RUNTIME_IMAGE_DIGEST), defaulting to true so current digest-pinning behaviour is unchanged.

When set to false, the Python and Go runtime image resolvers fall back to a tag reference (registry/repository:tag) through the existing ImageConfig.PinnedImage() helper — restoring the pre-0.9.7 behaviour for operators mirroring images into a registry that does not preserve digests.

Both runtime resolvers now share a small resolveRuntimeImage helper, and the "digest not set at link time" error now points operators at the new flag.

The Helm chart exposes this as controller.pinRuntimeImageDigest and plumbs it to the controller ConfigMap (picked up by the existing env → flag loading).

Testing

  • Go unit tests (go test ./core/internal/controller/translator/agent/...): added TestRuntime_PythonRuntime_TagReferenceWhenDigestPinningDisabled and TestRuntime_GoRuntime_TagReferenceWhenDigestPinningDisabled, asserting the rendered deployment references the image by tag (/app:<tag>, /golang-adk:<tag>) and contains no @sha256: when pinning is disabled. Existing digest-pinning tests continue to pass.
  • Helm unit test: added tests/controller-configmap_test.yaml asserting PIN_RUNTIME_IMAGE_DIGEST is "true" by default and "false" when controller.pinRuntimeImageDigest=false.
  • go vet and gofmt clean on the changed packages.

Usage

# values.yaml — mirror that does not preserve upstream digests
controller:
  agentImage:
    registry: my.private.registry/mirror
    repository: kagent-dev/kagent/app
  pinRuntimeImageDigest: false   # emit registry/repository:tag instead of @sha256

Fixes #2055

🤖 Generated with Claude Code

Declarative agent images are pinned by their link-time digest
(registry/repository@sha256:...) injected via controller-digest-ldflags.sh.
When --image-registry / --image-repository point to a private registry, only
the registry and repository are rewritten while the upstream digest is kept,
so the controller emits a reference that is not resolvable in registries that
do not preserve the upstream manifest digest. The agent pods then fail with
ImagePullBackOff / manifest unknown, and --image-tag is silently ignored for
declarative agents.

Add a --pin-runtime-image-digest flag (env PIN_RUNTIME_IMAGE_DIGEST), default
true to preserve current behaviour. When set to false, runtime image
resolution falls back to a tag reference (registry/repository:tag) via the
existing ImageConfig.PinnedImage(), restoring the pre-0.9.7 behaviour for
operators mirroring images into a private registry.

The Helm chart exposes this as controller.pinRuntimeImageDigest and plumbs it
to the controller ConfigMap.

Fixes kagent-dev#2055

Signed-off-by: Gabriel Ichim <gaby.10b@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes declarative agent ImagePullBackOff / manifest unknown failures when using private registries that don’t preserve upstream image digests, by allowing the controller to emit tag-based runtime image references instead of always using link-time digests.

Changes:

  • Added a --pin-runtime-image-digest / PIN_RUNTIME_IMAGE_DIGEST switch (default true) to control digest vs tag references for declarative runtime images.
  • Refactored Go/Python runtime image resolution to share a resolveRuntimeImage helper and improved the “digest not set” error guidance.
  • Exposed controller.pinRuntimeImageDigest in the Helm chart and added Helm + Go unit tests covering tag fallback behavior.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
helm/kagent/values.yaml Adds chart value controller.pinRuntimeImageDigest (default true) with operator-facing docs.
helm/kagent/tests/controller-configmap_test.yaml Adds Helm unit tests asserting the default and overridden PIN_RUNTIME_IMAGE_DIGEST ConfigMap value.
helm/kagent/templates/controller-configmap.yaml Plumbs controller.pinRuntimeImageDigest into the controller ConfigMap as PIN_RUNTIME_IMAGE_DIGEST.
go/core/pkg/app/app.go Introduces the --pin-runtime-image-digest flag wired to the translator package global.
go/core/internal/controller/translator/agent/runtime_test.go Adds unit tests validating that disabling pinning produces tag-based image references (no @sha256:).
go/core/internal/controller/translator/agent/deployments.go Implements shared resolveRuntimeImage and updates runtime image resolution to honor the new flag.
go/core/internal/controller/translator/agent/adk_api_translator.go Adds the PinRuntimeImageDigest default and documentation for the new behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@EItanya EItanya left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I actually think that a different fix is in order here. We switched to digests because substrate does not allow tags, but that surfaced an implementation detail of that system into the broader kagent. Rather I think we should switch back to tags for standard deployments, and then allow overriding of digests for substrate. What do you think?

@mesutoezdil

Copy link
Copy Markdown
Contributor

runtime_test.go -- pinruntimeImagedigest=false is tested for the golang-adk path but not for the golang-adk-full path (skills-enabled agents). is this intentional?

@github-actions

Copy link
Copy Markdown

This pull request has been marked as stale because of no activity in the last 15 days. It will be closed in the next 5 days unless it is tagged "no stalebot" or other activity occurs.

@github-actions github-actions Bot added the stale This issue or PR has become stale label Jul 11, 2026
@Jan-M

Jan-M commented Jul 13, 2026

Copy link
Copy Markdown

Would be great to get this resolved. We struggle with it as well.

@ppeau

ppeau commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Hi,

We are also blocked by this issue.

This bug potentially affects any organization using private registries with mirroring (ACR import, Harbor, Nexus, Artifactory, etc.). The digest pinning breaks declarative agents as soon as the mirror re-assigns a different digest.

If needed, I'm happy to pick this up and finish it.

It would be great to get this fixed soon.

@github-actions github-actions Bot removed the stale This issue or PR has become stale label Jul 14, 2026
@iplay88keys

Copy link
Copy Markdown
Contributor

I have a fix for this here.

EItanya pushed a commit that referenced this pull request Jul 15, 2026
…2242)

# Description

Declarative agent images are now referenced by tag
(`registry/repository:tag`), honoring `--image-tag` / Helm `IMAGE_TAG`.
Digest-pinned references (`registry/repository@sha256:...`) are only
used for sandbox agents, where Substrate ActorTemplate validation
rejects tag refs.

- Regular agents: `resolvePythonRuntimeImage` / `resolveGoRuntimeImage`
emit `registry/repo:tag`; full variants (skills / SRT) use the
`<tag>-full` convention the Makefile publishes (`APP_FULL_IMAGE_TAG`,
`GOLANG_ADK_FULL_IMAGE_TAG`).
- Sandbox agents (`SandboxAgent`, workload mode `sandbox`): unchanged
digest pinning from the link-time digests.
- New controller flags to override the link-time digests for sandbox
agents when a mirror re-assigns digests: `--app-image-digest`,
`--app-full-image-digest`, `--golang-adk-image-digest`,
`--golang-adk-full-image-digest` (env: `APP_IMAGE_DIGEST`, etc.).
Defaults are the digests baked in at build time.
- No Helm changes: `IMAGE_TAG` was already plumbed through the
controller ConfigMap; the digest overrides are settable via controller
env.

Supersedes #2076, following the approach requested in its review: tags
for standard deployments, digests kept only where Substrate requires
them, rather than an opt-out flag.

Fixes #2055

# Test plan

- `go test ./core/internal/controller/translator/agent/...` —
regular-agent tests now assert tag refs (and no `@sha256:`),
sandbox-agent test asserts digest refs, new unit tests cover tag
resolution including the `-full` suffix and the missing-digest error.
- Golden files regenerated (`UPDATE_GOLDEN=true`): all 35 regular-agent
outputs change `app@sha256:...` → `app:dev`.

Signed-off-by: Jeremy Alvis <jeremy.alvis@solo.io>
@iplay88keys

iplay88keys commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Closed as my PR has been merged. I will be backporting it to 0.9.x as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Pinned Agent images | Ignoring --image-registry / --image-repository in private-registry deployments

7 participants