Skip to content

OADP-7384: Copy imagestream images from the stream's own repository#444

Merged
openshift-merge-bot[bot] merged 1 commit into
openshift:oadp-devfrom
kaovilai:oadp-7384-imagestream-manifest-unknown
Jul 22, 2026
Merged

OADP-7384: Copy imagestream images from the stream's own repository#444
openshift-merge-bot[bot] merged 1 commit into
openshift:oadp-devfrom
kaovilai:oadp-7384-imagestream-manifest-unknown

Conversation

@kaovilai

@kaovilai kaovilai commented Jul 17, 2026

Copy link
Copy Markdown
Member

Note

Responses generated with Claude

What this PR does

CopyLocalImageStreamImages built the copy source path verbatim from the status item's DockerImageReference. When an image was promoted across namespaces (e.g. oc tag namespace-dev/imagefoo:v1 namespace-int/imagefoo:v1 --reference-policy local), that reference can point at the source namespace's repository. The internal registry scopes manifest reads to repositories whose imagestream still references the digest, so once the source tag is deleted or pruned, backups fail with:

initializing source docker://image-registry.openshift-image-registry.svc:5000/namespace-dev/imagefoo@sha256:...:
reading manifest sha256:... in image-registry.openshift-image-registry.svc:5000/namespace-dev/imagefoo: manifest unknown

The digest is by definition a member of the imagestream being copied (it comes from that stream's status.tags), so the source path is now built from the stream's own namespace/name:

srcPath += fmt.Sprintf("%s/%s/%s@%s", srcPathRegistry, imageStream.Namespace, imageStream.Name, tag.Items[i].Image)
  • Same-namespace references (the common case) produce byte-identical paths — no behavior change.
  • Backup-write (<migrationRegistry>/<is-namespace>/<is-name>) and restore-read become symmetric; previously cross-namespace-tagged images were also unrestorable because restore read the source path derived from DockerImageReference while backup had written under the stream's own repository.

Tests

New unit tests for CopyLocalImageStreamImages (via a copyImageFn stub seam):

  • cross-namespace reference → source uses the stream's own repository (failed before the fix)
  • same-namespace reference → path unchanged (regression guard)
  • external (non-internal-registry) image → not copied
  • full tag history → every item copied from own repository under its own digest

Fixes #443

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved local ImageStream image copying for internal image references across namespaces by deriving copy sources from the ImageStream’s own repository and the tag’s digest.
    • Skips internal-registry ImageStream tags when the digest is missing, preventing malformed copy requests.
    • Skips tags not hosted in the configured internal registry.
  • Tests
    • Expanded unit tests to verify cross-namespace vs same-namespace path handling, external image skipping, digest-less tag behavior, and correct copying of full tag history.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 17, 2026
@openshift-ci-robot

openshift-ci-robot commented Jul 17, 2026

Copy link
Copy Markdown

@kaovilai: This pull request references OADP-7384 which is a valid jira issue.

Details

In response to this:

[!Note]
Responses generated with Claude

What this PR does

CopyLocalImageStreamImages built the copy source path verbatim from the status item's DockerImageReference. When an image was promoted across namespaces (e.g. oc tag namespace-dev/imagefoo:v1 namespace-int/imagefoo:v1 --reference-policy local), that reference can point at the source namespace's repository. The internal registry scopes manifest reads to repositories whose imagestream still references the digest, so once the source tag is deleted or pruned, backups fail with:

initializing source docker://image-registry.openshift-image-registry.svc:5000/namespace-dev/imagefoo@sha256:...:
reading manifest sha256:... in image-registry.openshift-image-registry.svc:5000/namespace-dev/imagefoo: manifest unknown

The digest is by definition a member of the imagestream being copied (it comes from that stream's status.tags), so the source path is now built from the stream's own namespace/name:

srcPath += fmt.Sprintf("%s/%s/%s@%s", srcPathRegistry, imageStream.Namespace, imageStream.Name, tag.Items[i].Image)
  • Same-namespace references (the common case) produce byte-identical paths — no behavior change.
  • Backup-write (<migrationRegistry>/<is-namespace>/<is-name>) and restore-read become symmetric; previously cross-namespace-tagged images were also unrestorable because restore read the source path derived from DockerImageReference while backup had written under the stream's own repository.

Tests

New unit tests for CopyLocalImageStreamImages (via a copyImageFn stub seam):

  • cross-namespace reference → source uses the stream's own repository (failed before the fix)
  • same-namespace reference → path unchanged (regression guard)
  • external (non-internal-registry) image → not copied
  • full tag history → every item copied from own repository under its own digest

Fixes #443

🤖 Generated with Claude Code

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 openshift-eng/jira-lifecycle-plugin repository.

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

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Walkthrough

CopyLocalImageStreamImages now derives source paths from the ImageStream repository and item digest, skips digest-less internal tags, and uses an injectable copy function. Tests cover namespace handling, external images, skipped tags, and tag history.

Changes

ImageStream image copying

Layer / File(s) Summary
Correct source paths and copy seam
velero-plugins/imagecopy/imagestream.go
Digest-less internal tags are skipped, source paths use the ImageStream repository and item digest, and copying calls copyImageFn.
Cover copy and skip behavior
velero-plugins/imagecopy/imagestream_test.go
Tests stub copy operations and verify namespace handling, external-image skipping, digest-less tags, destination paths, tag history, and call ordering.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: shubham-pampattiwar, eemcmullan


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error PR still logs the full dockerImageReference on the new skip path, which can include internal registry host/repo data. Change the skip log to a generic message or redact registry/namespace components; avoid logging full source/dest image paths at Info level.
✅ Passed checks (14 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: copying imagestream images from the stream's own repository.
Linked Issues check ✅ Passed The code matches #443 by sourcing copies from the ImageStream's own namespace/name and digest, and skipping digest-less tags.
Out of Scope Changes check ✅ Passed The PR stays focused on the imagestream copy fix and related unit-test seam, with no unrelated code changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Stable And Deterministic Test Names ✅ Passed New tests use static Go function names; no Ginkgo titles or dynamic values appear in the added test file.
Test Structure And Quality ✅ Passed New tests are plain unit tests, each targets one behavior, use t.Cleanup for stub restoration, and include explicit failure messages; no cluster waits/timeouts apply.
Microshift Test Compatibility ✅ Passed The PR adds only plain Go unit tests in imagestream_test.go; no Ginkgo/e2e tests, MicroShift guards, or unsupported OpenShift APIs/resources were introduced.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; imagestream_test.go is plain Go unit tests with testing.T and no SNO-sensitive multi-node assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed Only image-copy logic and unit tests changed; no deployment, affinity, nodeSelector, replica, or topology-aware scheduling code was added.
Ote Binary Stdout Contract ✅ Passed The diff only adds image-copy logic and unit tests; no main/init/TestMain/suite-level stdout writes or fmt.Print/klog stdout usage were introduced.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the new tests are unit tests with stubbed copy calls and no IPv4/external connectivity requirements.
No-Weak-Crypto ✅ Passed Touched files only adjust imagestream copy paths/tests; no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or secret comparisons are present.
Container-Privileges ✅ Passed Only Go logic/tests changed; no container/K8s manifests or privileged settings (privileged, hostPID/network/IPC, SYS_ADMIN, allowPrivilegeEscalation) were added.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@kaovilai

Copy link
Copy Markdown
Member Author

/cherry-pick oadp-1.6

@openshift-cherrypick-robot

Copy link
Copy Markdown
Contributor

@kaovilai: once the present PR merges, I will cherry-pick it on top of oadp-1.6 in a new PR and assign it to you.

Details

In response to this:

/cherry-pick oadp-1.6

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.

@kaovilai

Copy link
Copy Markdown
Member Author

/cherry-pick oadp-1.5

@openshift-cherrypick-robot

Copy link
Copy Markdown
Contributor

@kaovilai: once the present PR merges, I will cherry-pick it on top of oadp-1.5 in a new PR and assign it to you.

Details

In response to this:

/cherry-pick oadp-1.5

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.

@kaovilai

This comment was marked as resolved.

@kaovilai
kaovilai force-pushed the oadp-7384-imagestream-manifest-unknown branch from 6f6efd8 to 77d872a Compare July 22, 2026 13:17
CopyLocalImageStreamImages built the copy source path from the status
item's DockerImageReference. When an image was promoted across
namespaces (e.g. `oc tag namespace-dev/imagefoo:v1
namespace-int/imagefoo:v1`), that reference can point at the source
namespace's repository, which stops serving the digest once the source
tag is deleted or pruned ("manifest unknown", or a 500 when the source
imagestream/namespace is gone entirely), failing the whole imagestream
backup item.

The digest is by definition a member of the imagestream being copied,
so build the source path from the stream's own namespace/name instead.
Same-namespace references produce byte-identical paths, and backup
(write to migration registry) and restore (read back) become symmetric.

Tag events with no image digest (verbatim reference tags from
`oc tag --reference`) are skipped with a log line: there is nothing
content-addressed to copy, and the imagestreamtag restore path restores
reference tags as pointers without needing image data. Building the
own-repository path for them would produce a malformed "<repo>@"
reference. Surfaced by e2e work in openshift/oadp-operator#2313.

Fixes openshift#443

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
@kaovilai
kaovilai force-pushed the oadp-7384-imagestream-manifest-unknown branch from 77d872a to 7870046 Compare July 22, 2026 13:18

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@velero-plugins/imagecopy/imagestream.go`:
- Around line 91-98: Update the skip log in the tag-copy loop around
tag.Items[i].Image and dockerImageReference so it no longer includes the full
internal image reference. Use only the tag name or a generic sanitized
identifier while preserving the existing reference-tag skip reason.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 48fb23bf-4d7e-47b2-9ed6-2e7aecf66a61

📥 Commits

Reviewing files that changed from the base of the PR and between 77d872a and 7870046.

📒 Files selected for processing (2)
  • velero-plugins/imagecopy/imagestream.go
  • velero-plugins/imagecopy/imagestream_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • velero-plugins/imagecopy/imagestream_test.go

Comment on lines +91 to +98
// Verbatim reference tags (`oc tag --reference`) have no image digest in
// their tag event, so there is nothing content-addressed to copy; the
// imagestreamtag restore path restores such tags as pointers without
// needing the image data.
if len(tag.Items[i].Image) == 0 {
o.Log.Info(fmt.Sprintf("[imagecopy] skipping copy of %s (tag %s): tag event has no image digest (reference tag)", dockerImageReference, tag.Tag))
continue
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not log the full internal image reference.

dockerImageReference may expose an internal registry hostname and repository path in logs. Log only a generic skip reason or a sanitized identifier.

As per coding guidelines, Go files must not log passwords, tokens, PII, internal hostnames, or customer data.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@velero-plugins/imagecopy/imagestream.go` around lines 91 - 98, Update the
skip log in the tag-copy loop around tag.Items[i].Image and dockerImageReference
so it no longer includes the full internal image reference. Use only the tag
name or a generic sanitized identifier while preserving the existing
reference-tag skip reason.

Source: Coding guidelines

@openshift-ci

openshift-ci Bot commented Jul 22, 2026

Copy link
Copy Markdown

@kaovilai: all tests passed!

Full PR test history. Your PR dashboard.

Details

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. I understand the commands that are listed here.

@shubham-pampattiwar

Copy link
Copy Markdown
Member

/lgtm

@openshift-ci

openshift-ci Bot commented Jul 22, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: Joeavaikath, kaovilai, shubham-pampattiwar

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:
  • OWNERS [Joeavaikath,kaovilai,shubham-pampattiwar]

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 lgtm Indicates that a PR is ready to be merged. label Jul 22, 2026
@openshift-merge-bot
openshift-merge-bot Bot merged commit c7ad5d6 into openshift:oadp-dev Jul 22, 2026
7 checks passed
@openshift-cherrypick-robot

Copy link
Copy Markdown
Contributor

@kaovilai: new pull request created: #451

Details

In response to this:

/cherry-pick oadp-1.6

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-cherrypick-robot

Copy link
Copy Markdown
Contributor

@kaovilai: new pull request created: #452

Details

In response to this:

/cherry-pick oadp-1.5

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. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OADP-7384: ImageStream backup fails with manifest unknown when a status tag item references another namespace's repository and that reference is stale

5 participants