Skip to content

Return image ID from PullImage instead of repo digest#9728

Merged
openshift-merge-bot[bot] merged 1 commit into
cri-o:mainfrom
saschagrunert:fix-pullimage-return-imageid
Feb 27, 2026
Merged

Return image ID from PullImage instead of repo digest#9728
openshift-merge-bot[bot] merged 1 commit into
cri-o:mainfrom
saschagrunert:fix-pullimage-return-imageid

Conversation

@saschagrunert

@saschagrunert saschagrunert commented Jan 27, 2026

Copy link
Copy Markdown
Member

What type of PR is this?

/kind bug

What this PR does / why we need it:

This PR changes PullImage to return the storage image ID instead of the repo digest, fixing a compatibility issue with Kubernetes credential verification which expects PullImage and GetImageRef to return compatible values for pull record lookups.

The ref-to-ID resolution happens in the server layer (server/image_pull.go) via a new resolveImageRefToID method, keeping the storage layer's PullImage contract unchanged. For OCI artifacts (not stored in container storage), it falls back to the artifact store.

Which issue(s) this PR fixes:

None

Special notes for your reviewer:

None

Does this PR introduce a user-facing change?

PullImage now returns the image ID directly, ensuring compatibility with Kubernetes credential verification for image pulls.

@openshift-ci openshift-ci Bot added the release-note-none Denotes a PR that doesn't merit a release note. label Jan 27, 2026
@openshift-ci openshift-ci Bot requested review from QiWang19 and littlejawa January 27, 2026 14:23
@openshift-ci openshift-ci Bot added kind/bug Categorizes issue or PR as related to a bug. dco-signoff: yes Indicates the PR's author has DCO signed all their commits. labels Jan 27, 2026
@openshift-ci

openshift-ci Bot commented Jan 27, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: saschagrunert

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jan 27, 2026
@coderabbitai

coderabbitai Bot commented Jan 27, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Pull operations now return and propagate a storage-provided image ID (*storage.StorageImageID) instead of a canonical registry reference; OCI artifacts produce a nil imageID and the server falls back to ArtifactStore.Status for a CRI image ID. Tests, mocks, runtime, and in-process/out-of-process pull flows updated accordingly.

Changes

Cohort / File(s) Summary
Server: pull handling
server/image_pull.go
Top-level pull now returns *storage.StorageImageID; constructs out-of-process ImageRef from it. If nil (OCI artifact), query ArtifactStore.Status for CRI image ID. Error paths return nil, err.
Server: synchronization
server/server.go
pullOperation now stores imageID *storage.StorageImageID (nil denotes OCI artifact); comments and access patterns updated.
Server tests
server/image_pull_test.go
Unit tests updated to expect *StorageImageID from mocked pulls, assert response ImageRef equals storage ID hex, and mock failures return nil, err.
Integration tests (bats & policy)
test/image.bats, test/policy.bats
Added bats test asserting pull returns image ID; policy tests switched to parse IMAGE_ID from crictl output and use it in container config.
Internal storage: pull flow
internal/storage/image.go, internal/storage/image_test.go
ImageServer.PullImage and internal pull helpers now return (*StorageImageID, error); pull output items include ImageID string alongside canonical result; in-process/out-of-process plumbing updated; OCI artifacts may yield empty/nil ImageID.
Runtime: CRI integration
internal/storage/runtime.go, internal/storage/runtime_test.go
CreatePodSandbox and tests now use returned imageID (error if nil for pause images); NewStoreReference uses imageID.IDStringForOutOfProcessConsumptionOnly().
Mocks & helpers
test/mocks/criostorage/criostorage.go, internal/storage/mock_helpers_test.go
Mock PullImage signature and gomock recorder updated to return (*storage.StorageImageID, error); removed a nolint directive in test helper.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant CRI_Server
  participant Storage as Storage_ImageService
  participant Artifact as Artifact_Store

  Client->>CRI_Server: PullImage(request)
  CRI_Server->>Storage: PullImage(imageName)
  Storage-->>CRI_Server: (imageID) or (nil) or error
  alt imageID returned
    CRI_Server-->>Client: PullImageResponse(ImageRef=imageID)
  else imageID nil (OCI artifact)
    CRI_Server->>Artifact: Status(imageName)
    alt Artifact returns CRI image ID
      Artifact-->>CRI_Server: CRIImage().GetId()
      CRI_Server-->>Client: PullImageResponse(ImageRef=artifact CRI ID)
    else
      CRI_Server-->>Client: PullImageResponse(ImageRef=canonicalRef)
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

lgtm

Suggested reviewers

  • mrunalp
  • littlejawa

Poem

🐇 I hopped through layers, found a hex so neat,
Carried StorageID home on tiny feet,
When artifacts hid, I asked the store,
Dug out a CRI id to show at the door,
Little whiskers twitched — the pull was complete.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately reflects the core change: modifying PullImage to return image ID instead of repo digest, which is the primary objective of the changeset.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@saschagrunert saschagrunert changed the title Return image ID from PullImage instead of repo digest WIP: Return image ID from PullImage instead of repo digest Jan 27, 2026
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jan 27, 2026
@saschagrunert saschagrunert force-pushed the fix-pullimage-return-imageid branch 2 times, most recently from f501204 to 27c5fd4 Compare January 27, 2026 14:43

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/image_pull_test.go (1)

32-53: Use the storage ID formatter to avoid prefix mismatches.

Line 53 hard-codes a bare hex value even though Line 32 parses a prefixed digest. To keep the test aligned with the intended “sha256:” format and with production formatting, compare against the StorageImageID formatter instead of a literal.

✅ Suggested fix
- Expect(response.ImageRef).To(Equal("1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"))
+ Expect(response.ImageRef).To(Equal(imageID.IDStringForOutOfProcessConsumptionOnly()))
🤖 Fix all issues with AI agents
In `@test/image.bats`:
- Around line 479-495: The test currently strips the "sha256:" prefix by
extracting only the final word into pulled_id and validating only 64 hex chars;
change the extraction and validation to capture and verify the full prefixed
digest (e.g., capture "sha256:<64-hex>" from pulled_ref into pulled_id using a
regex and assert it matches ^sha256:[a-f0-9]{64}$), and ensure imageid (from
crictl images --quiet "$IMAGE") is not altered so the subsequent equality check
[ "$pulled_id" = "$imageid" ] compares the full prefixed digest strings.

Comment thread test/image.bats
@saschagrunert saschagrunert force-pushed the fix-pullimage-return-imageid branch 3 times, most recently from 7b52ca7 to a134fb3 Compare January 27, 2026 15:00
@openshift-ci openshift-ci Bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. and removed release-note-none Denotes a PR that doesn't merit a release note. labels Jan 27, 2026
@saschagrunert saschagrunert force-pushed the fix-pullimage-return-imageid branch from a134fb3 to a5e24a7 Compare January 27, 2026 15:13
@saschagrunert saschagrunert changed the title WIP: Return image ID from PullImage instead of repo digest Return image ID from PullImage instead of repo digest Jan 27, 2026
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jan 27, 2026
@saschagrunert

Copy link
Copy Markdown
Member Author

@cri-o/cri-o-maintainers PTAL

@codecov

codecov Bot commented Jan 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 65.21739% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.52%. Comparing base (7421a8e) to head (aed9671).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9728      +/-   ##
==========================================
+ Coverage   67.45%   67.52%   +0.07%     
==========================================
  Files         210      210              
  Lines       29123    29141      +18     
==========================================
+ Hits        19644    19678      +34     
+ Misses       7790     7778      -12     
+ Partials     1689     1685       -4     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@saschagrunert

Copy link
Copy Markdown
Member Author

/retest

@saschagrunert

Copy link
Copy Markdown
Member Author

/hold

Integration tests are not happy.

@openshift-ci openshift-ci Bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jan 27, 2026
@bitoku

bitoku commented Jan 27, 2026

Copy link
Copy Markdown
Contributor

iiuc ID field is not well-defined. I'd want to define the format first though I'm not opposed to the change.

@saschagrunert

Copy link
Copy Markdown
Member Author

iiuc ID field is not well-defined. I'd want to define the format first though I'm not opposed to the change.

We can also follow-up on CRI docs for that, yep.

@saschagrunert saschagrunert force-pushed the fix-pullimage-return-imageid branch from ca614a9 to da079e0 Compare February 18, 2026 08:06
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 18, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
internal/storage/image.go (1)

831-837: Minor: unnecessary else after return in PullImage.

Both branches return, so the else is redundant. This is a pre-existing pattern, but a trivial cleanup opportunity.

Optional simplification
 func (svc *imageService) PullImage(ctx context.Context, imageName RegistryImageReference, options *ImageCopyOptions) (*StorageImageID, error) {
 	if options.CgroupPull.UseNewCgroup {
 		return svc.pullImageParent(ctx, imageName, options.CgroupPull.ParentCgroup, options)
-	} else {
-		return pullImageImplementation(ctx, svc.lookup, svc.store, svc.storageTransport, imageName, options)
 	}
+	return pullImageImplementation(ctx, svc.lookup, svc.store, svc.storageTransport, imageName, options)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/storage/image.go` around lines 831 - 837, In PullImage (method
imageService.PullImage) remove the unnecessary else: since the if branch returns
svc.pullImageParent(...), follow it with a bare return of
pullImageImplementation(ctx, svc.lookup, svc.store, svc.storageTransport,
imageName, options) without wrapping it in an else block; update the function
body to return directly when the if is false, keeping svc.pullImageParent and
pullImageImplementation calls unchanged.
server/image_pull.go (1)

126-146: Clean branching on imageID nilness for regular images vs. OCI artifacts.

The nil check on pullOp.imageID before calling IDStringForOutOfProcessConsumptionOnly() correctly prevents a panic on the value-type method. The OCI artifact fallback via ArtifactStore().Status() is a sensible alternative path.

One consideration: if ArtifactStore().Status() also fails, the error message at line 141 ("get image status after pull") could be confusing since the pull itself succeeded (with a nil imageID). Consider adding context that this is an OCI artifact lookup.

Suggested clarification in error message
-		return nil, fmt.Errorf("get image status after pull: %w", err)
+		return nil, fmt.Errorf("get OCI artifact status after pull: %w", err)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/image_pull.go` around lines 126 - 146, The error returned from
ArtifactStore().Status(...) after a nil pullOp.imageID can be misleading because
the pull succeeded but the OCI artifact lookup failed; update the error returned
from the Status call to include context that this was an OCI artifact lookup
(include the image variable and mention "OCI artifact lookup" in the message) so
callers see "OCI artifact lookup for <image> failed: %w" (or similar) instead of
"get image status after pull"; adjust the fmt.Errorf invocation in the branch
that calls ArtifactStore().Status to provide that clarified message and include
the original error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@internal/storage/image.go`:
- Around line 831-837: In PullImage (method imageService.PullImage) remove the
unnecessary else: since the if branch returns svc.pullImageParent(...), follow
it with a bare return of pullImageImplementation(ctx, svc.lookup, svc.store,
svc.storageTransport, imageName, options) without wrapping it in an else block;
update the function body to return directly when the if is false, keeping
svc.pullImageParent and pullImageImplementation calls unchanged.

In `@server/image_pull.go`:
- Around line 126-146: The error returned from ArtifactStore().Status(...) after
a nil pullOp.imageID can be misleading because the pull succeeded but the OCI
artifact lookup failed; update the error returned from the Status call to
include context that this was an OCI artifact lookup (include the image variable
and mention "OCI artifact lookup" in the message) so callers see "OCI artifact
lookup for <image> failed: %w" (or similar) instead of "get image status after
pull"; adjust the fmt.Errorf invocation in the branch that calls
ArtifactStore().Status to provide that clarified message and include the
original error.

@saschagrunert

Copy link
Copy Markdown
Member Author

/retest

@saschagrunert

Copy link
Copy Markdown
Member Author

/override ci/prow/e2e-gcp-ovn
/override ci/prow/e2e-aws-ovn

@openshift-ci

openshift-ci Bot commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

@saschagrunert: Overrode contexts on behalf of saschagrunert: ci/prow/e2e-aws-ovn, ci/prow/e2e-gcp-ovn

Details

In response to this:

/override ci/prow/e2e-gcp-ovn
/override ci/prow/e2e-aws-ovn

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 20, 2026
@saschagrunert saschagrunert force-pushed the fix-pullimage-return-imageid branch from da079e0 to b661a05 Compare February 23, 2026 08:05
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 23, 2026
@saschagrunert saschagrunert force-pushed the fix-pullimage-return-imageid branch from b661a05 to 692a101 Compare February 23, 2026 08:06
@saschagrunert

Copy link
Copy Markdown
Member Author

/test ci-fedora-integration

Comment thread internal/storage/image.go Outdated
type pullImageOutputItem struct {
Progress *types.ProgressProperties `json:",omitempty"`
Result string `json:",omitempty"` // If not "", in the format of RegistryImageReference.StringForOutOfProcessConsumptionOnly(), and always contains a digest.
ImageID string `json:",omitempty"` // If not "", the storage image ID in the format of StorageImageID.IDStringForOutOfProcessConsumptionOnly()

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.

nit:

Suggested change
ImageID string `json:",omitempty"` // If not "", the storage image ID in the format of StorageImageID.IDStringForOutOfProcessConsumptionOnly()
// ImageID is in the format of StorageImageID.IDStringForOutOfProcessConsumptionOnly(), or "" if it's OCI artifacts
ImageID string `json:",omitempty"`

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed

Comment thread internal/storage/image.go Outdated
@saschagrunert saschagrunert force-pushed the fix-pullimage-return-imageid branch from 692a101 to 3533b03 Compare February 26, 2026 09:42
Comment thread internal/storage/image.go Outdated
// OCI artifacts are not stored in container storage and therefore have
// no storage image ID. Returning nil signals callers to fall back to
// the artifact store for status lookups (see PullImage in server/image_pull.go).
return nil, nil

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.

Probably we shouldn't have implemented artifact pull in this storage, but returning nil here doesn't sound right to me.
If we think the OCI artifacts are managed by this package, artifacts should have storageID, and otherwise we should move pull implementation to elsewhere.

For now, I think keeping it return reference, and return ID in image_pull is better. Sorry for backing down my initial comment.

@saschagrunert saschagrunert Feb 26, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I've updated the PR to keep pullImageImplementation returning RegistryImageReference (unchanged storage layer) and moved the ref to ID resolution to server/image_pull.go via a new resolveImageRefToID method. It tries ImageStatusByName first, then falls back to the artifact store for OCI artifacts. No more nil return path.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I really have no idea why doing that outside of pullImageImplementation should be easier (what if an object with the same name@digest exists in both??) but it’s not my codebase to maintain.

Resolve the pulled image reference to a storage image ID in the server
layer (server/image_pull.go) rather than changing the storage layer's
PullImage return type. This keeps the storage layer's contract unchanged
while the server resolves references to IDs via ImageStatusByName, with
a fallback to the artifact store for OCI artifacts.

Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
@saschagrunert saschagrunert force-pushed the fix-pullimage-return-imageid branch from 3533b03 to aed9671 Compare February 26, 2026 11:50
@bitoku

bitoku commented Feb 26, 2026

Copy link
Copy Markdown
Contributor

lgtm, though I want to make sure there's enough time for others to review it.

@bitoku

bitoku commented Feb 27, 2026

Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Feb 27, 2026
@openshift-merge-bot openshift-merge-bot Bot merged commit 34f5b85 into cri-o:main Feb 27, 2026
81 of 84 checks passed
@saschagrunert saschagrunert deleted the fix-pullimage-return-imageid branch February 27, 2026 10:34
@haircommander

Copy link
Copy Markdown
Member

/cherry-pick release-1.35

@openshift-cherrypick-robot

Copy link
Copy Markdown

@haircommander: #9728 failed to apply on top of branch "release-1.35":

Applying: Return image ID from PullImage instead of repo digest
Using index info to reconstruct a base tree...
M	server/server.go
M	test/image.bats
Falling back to patching base and 3-way merge...
Auto-merging test/image.bats
CONFLICT (content): Merge conflict in test/image.bats
Auto-merging server/server.go
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Patch failed at 0001 Return image ID from PullImage instead of repo digest

Details

In response to this:

/cherry-pick release-1.35

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

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

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. dco-signoff: yes Indicates the PR's author has DCO signed all their commits. kind/bug Categorizes issue or PR as related to a bug. lgtm Indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants