Skip to content

[release-4.22] OCPBUGS-98716: Include index image sub-digests in dry run mapping.txt#1474

Open
dorzel wants to merge 1 commit into
openshift:release-4.22from
dorzel:cherry-pick-OCPBUGS-66263-to-release-4.22
Open

[release-4.22] OCPBUGS-98716: Include index image sub-digests in dry run mapping.txt#1474
dorzel wants to merge 1 commit into
openshift:release-4.22from
dorzel:cherry-pick-OCPBUGS-66263-to-release-4.22

Conversation

@dorzel

@dorzel dorzel commented Jul 14, 2026

Copy link
Copy Markdown
Member

Description

Manual backport of #1355

Github / Jira issue: https://redhat.atlassian.net/browse/OCPBUGS-66263

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Code Improvements (Refactoring, Performance, CI upgrades, etc)
  • Internal repo assets (diagrams / docs on github repo)
  • This change requires a documentation update on openshift docs

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.

Expected Outcome

Please describe the outcome expected from the tests.

Summary by CodeRabbit

  • New Features
    • Added an option to inspect manifest lists during dry runs and include sub-manifest digest mappings in mapping.txt.
    • Added digest-aware destination handling for Docker image references.
  • Bug Fixes
    • Dry runs now continue successfully when registries are unreachable, while retaining available mappings and reporting warnings.
    • Improved handling of tag-and-digest image references in generated mirror configurations.
    • Catalog references are pinned more consistently before mirror execution.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci-robot openshift-ci-robot added jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Jul 14, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@dorzel: This pull request references Jira Issue OCPBUGS-66263, which is invalid:

  • expected the bug to be in one of the following states: NEW, ASSIGNED, POST, but it is MODIFIED instead

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Description

Manual backport of #1355

Github / Jira issue: https://redhat.atlassian.net/browse/OCPBUGS-66263

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Code Improvements (Refactoring, Performance, CI upgrades, etc)
  • Internal repo assets (diagrams / docs on github repo)
  • This change requires a documentation update on openshift docs

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.

Expected Outcome

Please describe the outcome expected from the tests.

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 needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 14, 2026
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Walkthrough

The PR adds manifest-list sub-digest support to dry-run mappings, moves operator catalog digest pinning earlier in M2D/M2M workflows, migrates blob and history tracking to typed sets, and includes tag-and-digest images in digest-only mirror generation.

Changes

oc-mirror functional changes

Layer / File(s) Summary
Blob and history set migration
go.mod, internal/pkg/archive/..., internal/pkg/history/..., internal/pkg/delete/delete_images_test.go
Blob gathering, archive diffing, and history operations now use sets.Set[string] instead of map[string]struct{}.
Manifest-list inspection and dry-run mappings
internal/pkg/manifest/..., internal/pkg/mirror/options.go, internal/pkg/cli/dryrun.go, internal/pkg/cli/executor.go, internal/pkg/cli/dryrun_test.go, internal/pkg/*/*collector_test.go
Manifest-list instance digests can be inspected during dry runs, emitted as digest-pinned mappings, and handled with bounded concurrency and warning-only inspection failures.
Early catalog digest pinning
internal/pkg/config/..., internal/pkg/cli/executor.go, internal/pkg/operator/...
Operator catalog references are pinned during workflow completion, while configuration writing consumes the already-pinned configuration.
Digest-only mirror selection
internal/pkg/clusterresources/...
Images referenced by both tag and digest are included in generated IDMS and ITMS resources.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Executor
  participant DryRun
  participant Manifest
  participant MappingFile
  Executor->>DryRun: enable manifest-list dry run
  DryRun->>Manifest: retrieve manifest-list digests
  Manifest-->>DryRun: return instance digests
  DryRun->>MappingFile: write base and digest-pinned mappings
Loading

Possibly related PRs

Suggested reviewers: r4f4, adolfo-ab, aguidirh

🚥 Pre-merge checks | ✅ 4 | ❌ 11

❌ Failed checks (1 warning, 10 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Stable And Deterministic Test Names ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Test Structure And Quality ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Microshift Test Compatibility ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Single Node Openshift (Sno) Test Compatibility ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Topology-Aware Scheduling Compatibility ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Ote Binary Stdout Contract ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Ipv6 And Disconnected Network Test Compatibility ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
No-Weak-Crypto ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Container-Privileges ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
No-Sensitive-Data-In-Logs ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding index image sub-digests to dry-run mapping.txt.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@dorzel
dorzel changed the base branch from main to release-4.22 July 14, 2026 19:02
@openshift-ci-robot

Copy link
Copy Markdown

@dorzel: This pull request references Jira Issue OCPBUGS-66263, which is invalid:

  • expected the bug to target either version "4.22." or "openshift-4.22.", but it targets "5.0" instead
  • expected the bug to be in one of the following states: NEW, ASSIGNED, POST, but it is MODIFIED instead
  • release note text must be set and not match the template OR release note type must be set to "Release Note Not Required". For more information you can reference the OpenShift Bug Process.
  • expected Jira Issue OCPBUGS-66263 to depend on a bug targeting a version in 5.0.0 and in one of the following states: MODIFIED, ON_QA, VERIFIED, but no dependents were found

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

Details

In response to this:

Description

Manual backport of #1355

Github / Jira issue: https://redhat.atlassian.net/browse/OCPBUGS-66263

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Code Improvements (Refactoring, Performance, CI upgrades, etc)
  • Internal repo assets (diagrams / docs on github repo)
  • This change requires a documentation update on openshift docs

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.

Expected Outcome

Please describe the outcome expected from the tests.

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 requested review from aguidirh and r4f4 July 14, 2026 19:03

@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: 7

🧹 Nitpick comments (2)
internal/pkg/history/history.go (1)

154-159: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Ensure deterministic history output.

Iterating over a set (map under the hood) produces an unpredictable order on every run. Consider sorting the blobs to make the written history file deterministic, which improves reproducibility and simplifies diffing if these files are archived.

♻️ Proposed fix
-	for blob := range historyBlobs {
+	for _, blob := range sets.List(historyBlobs) {
 		_, err := writer.WriteString(blob + "\n")
 		if err != nil {
 			return historyBlobs, fmt.Errorf("unable to write to history file: %w", err)
 		}
 	}
🤖 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 `@internal/pkg/history/history.go` around lines 154 - 159, Sort the history
blobs before the write loop so output from the history-writing flow is
deterministic. Update the iteration around historyBlobs to use the sorted order
while preserving the existing writer.WriteString error handling and return
behavior.
internal/pkg/archive/archive.go (1)

160-160: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid O(N²) allocations by inserting elements directly instead of using Union inside loops.

Using sets.Union inside a loop allocates a new set and copies all elements on every iteration, leading to quadratic time complexity and unnecessary memory churn. Iterate over the new elements and insert them into the accumulator set directly.

  • internal/pkg/archive/archive.go#L160-L160: Replace with a loop for blob := range addedBlobs { allAddedBlobs.Insert(blob) }.
  • internal/pkg/archive/image-blob-gatherer.go#L115-L115: Replace with a loop for blob := range singleArchBlobs { blobs.Insert(blob) }.
🤖 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 `@internal/pkg/archive/archive.go` at line 160, The archive blob accumulation
in internal/pkg/archive/archive.go lines 160-160 should iterate over addedBlobs
and insert each blob into allAddedBlobs directly instead of calling Union. Apply
the same change in internal/pkg/archive/image-blob-gatherer.go lines 115-115 by
iterating over singleArchBlobs and inserting each blob into blobs; preserve the
existing accumulator behavior without allocating a new set per iteration.
🤖 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 `@go.mod`:
- Line 10: Revert the manual version change for the indirect
github.com/go-jose/go-jose/v4 dependency in go.mod. Identify and upgrade the
direct dependency that introduces it, then run go mod tidy to resolve the
indirect version automatically.

In `@internal/pkg/cli/dryrun.go`:
- Around line 141-199: Bound both new registry-inspection paths with a finite
timeout, using the existing checkRegistryAccess timeout pattern. In
internal/pkg/cli/dryrun.go lines 141-199, update inspectManifestLists and its
GetManifestListDigests call after newSystemContextForSource to use a
timeout-derived context and cancel it; in internal/pkg/cli/executor.go lines
581-588, replace context.Background() before config.PinCatalogDigests with the
command context when available and derive a bounded timeout context.
- Around line 59-67: Update the availability log condition in the dry-run flow
to emit the “all images available” message only when no images are missing,
while preserving the existing message when all required images are cached. Use
the surrounding nbMissingImgs and nbAvailableImgs checks in the method as the
change point.
- Around line 107-139: Update writeSubDigestEntries to derive sourceBase by
parsing img.Source with the same image.ParseRef approach used by
subDigestDestination, ensuring both tags and existing digests are removed before
appending `@digest`. Preserve the current fallback behavior for parse failures and
keep subDigestDestination unchanged.

In `@internal/pkg/cli/executor.go`:
- Line 299: Update the help text for the IsDryRunManifestLists flag registration
to state that this option enables dry-run behavior automatically and must not be
used together with an explicit --dry-run flag; remove the self-contradictory
wording while preserving the existing flag semantics.
- Around line 1383-1384: Update the comment above
ExecutorSchema.createConfigsWithPinnedCatalogs to reference the actual
config.PinCatalogDigests call used at workflow start, replacing the nonexistent
pinOperatorCatalogs name while preserving the M2D/M2M context.

In `@internal/pkg/config/pin_catalogs.go`:
- Around line 135-156: Move the TargetTag preservation block in the catalog
pinning flow after catalogDigest is confirmed non-empty and the empty-digest
early return in the digest resolution logic. Keep the existing condition and log
message, ensuring op.TargetTag is not mutated when resolution fails or pinning
is skipped.

---

Nitpick comments:
In `@internal/pkg/archive/archive.go`:
- Line 160: The archive blob accumulation in internal/pkg/archive/archive.go
lines 160-160 should iterate over addedBlobs and insert each blob into
allAddedBlobs directly instead of calling Union. Apply the same change in
internal/pkg/archive/image-blob-gatherer.go lines 115-115 by iterating over
singleArchBlobs and inserting each blob into blobs; preserve the existing
accumulator behavior without allocating a new set per iteration.

In `@internal/pkg/history/history.go`:
- Around line 154-159: Sort the history blobs before the write loop so output
from the history-writing flow is deterministic. Update the iteration around
historyBlobs to use the sorted order while preserving the existing
writer.WriteString error handling and return behavior.
🪄 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: e93bc181-f07c-4efc-8ebf-76cb0137667b

📥 Commits

Reviewing files that changed from the base of the PR and between 2522a9e and 29f89b6.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (26)
  • go.mod
  • internal/pkg/additional/local_stored_collector_test.go
  • internal/pkg/archive/archive.go
  • internal/pkg/archive/archive_test.go
  • internal/pkg/archive/image-blob-gatherer.go
  • internal/pkg/archive/image-blob-gatherer_test.go
  • internal/pkg/archive/interface.go
  • internal/pkg/cli/dryrun.go
  • internal/pkg/cli/dryrun_test.go
  • internal/pkg/cli/executor.go
  • internal/pkg/clusterresources/clusterresources.go
  • internal/pkg/clusterresources/clusterresources_test.go
  • internal/pkg/config/pin_catalogs.go
  • internal/pkg/config/pin_catalogs_test.go
  • internal/pkg/delete/delete_images_test.go
  • internal/pkg/history/history.go
  • internal/pkg/history/history_test.go
  • internal/pkg/history/interface.go
  • internal/pkg/manifest/interface.go
  • internal/pkg/manifest/manifest.go
  • internal/pkg/mirror/options.go
  • internal/pkg/operator/filtered_collector.go
  • internal/pkg/operator/filtered_collector_test.go
  • internal/pkg/release/cincinnati_test.go
  • internal/pkg/release/local_stored_collector_test.go
  • internal/pkg/signature/cosign_tag_based_signatures_test.go

@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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 7

🧹 Nitpick comments (2)
internal/pkg/history/history.go (1)

154-159: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Ensure deterministic history output.

Iterating over a set (map under the hood) produces an unpredictable order on every run. Consider sorting the blobs to make the written history file deterministic, which improves reproducibility and simplifies diffing if these files are archived.

♻️ Proposed fix
-	for blob := range historyBlobs {
+	for _, blob := range sets.List(historyBlobs) {
 		_, err := writer.WriteString(blob + "\n")
 		if err != nil {
 			return historyBlobs, fmt.Errorf("unable to write to history file: %w", err)
 		}
 	}
🤖 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 `@internal/pkg/history/history.go` around lines 154 - 159, Sort the history
blobs before the write loop so output from the history-writing flow is
deterministic. Update the iteration around historyBlobs to use the sorted order
while preserving the existing writer.WriteString error handling and return
behavior.
internal/pkg/archive/archive.go (1)

160-160: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid O(N²) allocations by inserting elements directly instead of using Union inside loops.

Using sets.Union inside a loop allocates a new set and copies all elements on every iteration, leading to quadratic time complexity and unnecessary memory churn. Iterate over the new elements and insert them into the accumulator set directly.

  • internal/pkg/archive/archive.go#L160-L160: Replace with a loop for blob := range addedBlobs { allAddedBlobs.Insert(blob) }.
  • internal/pkg/archive/image-blob-gatherer.go#L115-L115: Replace with a loop for blob := range singleArchBlobs { blobs.Insert(blob) }.
🤖 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 `@internal/pkg/archive/archive.go` at line 160, The archive blob accumulation
in internal/pkg/archive/archive.go lines 160-160 should iterate over addedBlobs
and insert each blob into allAddedBlobs directly instead of calling Union. Apply
the same change in internal/pkg/archive/image-blob-gatherer.go lines 115-115 by
iterating over singleArchBlobs and inserting each blob into blobs; preserve the
existing accumulator behavior without allocating a new set per iteration.
🤖 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 `@go.mod`:
- Line 10: Revert the manual version change for the indirect
github.com/go-jose/go-jose/v4 dependency in go.mod. Identify and upgrade the
direct dependency that introduces it, then run go mod tidy to resolve the
indirect version automatically.

In `@internal/pkg/cli/dryrun.go`:
- Around line 141-199: Bound both new registry-inspection paths with a finite
timeout, using the existing checkRegistryAccess timeout pattern. In
internal/pkg/cli/dryrun.go lines 141-199, update inspectManifestLists and its
GetManifestListDigests call after newSystemContextForSource to use a
timeout-derived context and cancel it; in internal/pkg/cli/executor.go lines
581-588, replace context.Background() before config.PinCatalogDigests with the
command context when available and derive a bounded timeout context.
- Around line 59-67: Update the availability log condition in the dry-run flow
to emit the “all images available” message only when no images are missing,
while preserving the existing message when all required images are cached. Use
the surrounding nbMissingImgs and nbAvailableImgs checks in the method as the
change point.
- Around line 107-139: Update writeSubDigestEntries to derive sourceBase by
parsing img.Source with the same image.ParseRef approach used by
subDigestDestination, ensuring both tags and existing digests are removed before
appending `@digest`. Preserve the current fallback behavior for parse failures and
keep subDigestDestination unchanged.

In `@internal/pkg/cli/executor.go`:
- Line 299: Update the help text for the IsDryRunManifestLists flag registration
to state that this option enables dry-run behavior automatically and must not be
used together with an explicit --dry-run flag; remove the self-contradictory
wording while preserving the existing flag semantics.
- Around line 1383-1384: Update the comment above
ExecutorSchema.createConfigsWithPinnedCatalogs to reference the actual
config.PinCatalogDigests call used at workflow start, replacing the nonexistent
pinOperatorCatalogs name while preserving the M2D/M2M context.

In `@internal/pkg/config/pin_catalogs.go`:
- Around line 135-156: Move the TargetTag preservation block in the catalog
pinning flow after catalogDigest is confirmed non-empty and the empty-digest
early return in the digest resolution logic. Keep the existing condition and log
message, ensuring op.TargetTag is not mutated when resolution fails or pinning
is skipped.

---

Nitpick comments:
In `@internal/pkg/archive/archive.go`:
- Line 160: The archive blob accumulation in internal/pkg/archive/archive.go
lines 160-160 should iterate over addedBlobs and insert each blob into
allAddedBlobs directly instead of calling Union. Apply the same change in
internal/pkg/archive/image-blob-gatherer.go lines 115-115 by iterating over
singleArchBlobs and inserting each blob into blobs; preserve the existing
accumulator behavior without allocating a new set per iteration.

In `@internal/pkg/history/history.go`:
- Around line 154-159: Sort the history blobs before the write loop so output
from the history-writing flow is deterministic. Update the iteration around
historyBlobs to use the sorted order while preserving the existing
writer.WriteString error handling and return behavior.
🪄 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: e93bc181-f07c-4efc-8ebf-76cb0137667b

📥 Commits

Reviewing files that changed from the base of the PR and between 2522a9e and 29f89b6.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (26)
  • go.mod
  • internal/pkg/additional/local_stored_collector_test.go
  • internal/pkg/archive/archive.go
  • internal/pkg/archive/archive_test.go
  • internal/pkg/archive/image-blob-gatherer.go
  • internal/pkg/archive/image-blob-gatherer_test.go
  • internal/pkg/archive/interface.go
  • internal/pkg/cli/dryrun.go
  • internal/pkg/cli/dryrun_test.go
  • internal/pkg/cli/executor.go
  • internal/pkg/clusterresources/clusterresources.go
  • internal/pkg/clusterresources/clusterresources_test.go
  • internal/pkg/config/pin_catalogs.go
  • internal/pkg/config/pin_catalogs_test.go
  • internal/pkg/delete/delete_images_test.go
  • internal/pkg/history/history.go
  • internal/pkg/history/history_test.go
  • internal/pkg/history/interface.go
  • internal/pkg/manifest/interface.go
  • internal/pkg/manifest/manifest.go
  • internal/pkg/mirror/options.go
  • internal/pkg/operator/filtered_collector.go
  • internal/pkg/operator/filtered_collector_test.go
  • internal/pkg/release/cincinnati_test.go
  • internal/pkg/release/local_stored_collector_test.go
  • internal/pkg/signature/cosign_tag_based_signatures_test.go
🛑 Comments failed to post (7)
go.mod (1)

10-10: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Avoid manually updating indirect dependencies.

As per learnings, in go.mod files, do not manually upgrade entries marked as indirect dependencies. Instead, upgrade the direct dependencies that introduce those indirect requirements, then run go mod tidy so the indirect versions are updated automatically.

🤖 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 `@go.mod` at line 10, Revert the manual version change for the indirect
github.com/go-jose/go-jose/v4 dependency in go.mod. Identify and upgrade the
direct dependency that introduces it, then run go mod tidy to resolve the
indirect version automatically.

Source: Learnings

internal/pkg/cli/dryrun.go (3)

59-67: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

"All images available" message can be misleading in mixed missing/available runs.

This log fires whenever nbAvailableImgs > 0, even when nbMissingImgs > 0 in the same run, printing a contradictory "all %d images required for mirroring are available in local cache" right alongside the missing-images warning.

💬 Suggested fix
-	if nbAvailableImgs > 0 {
+	if nbAvailableImgs > 0 && nbMissingImgs == 0 {
 		o.Log.Info("all %d images required for mirroring are available in local cache. You may proceed with mirroring from disk to disconnected registry", nbAvailableImgs)
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	if nbMissingImgs > 0 {
		if err := o.writeMissingImagesFile(outDir, missingImgsBuff.Bytes(), nbMissingImgs, len(allImages)); err != nil {
			return err
		}
	}

	if nbAvailableImgs > 0 && nbMissingImgs == 0 {
		o.Log.Info("all %d images required for mirroring are available in local cache. You may proceed with mirroring from disk to disconnected registry", nbAvailableImgs)
	}
🤖 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 `@internal/pkg/cli/dryrun.go` around lines 59 - 67, Update the availability log
condition in the dry-run flow to emit the “all images available” message only
when no images are missing, while preserving the existing message when all
required images are cached. Use the surrounding nbMissingImgs and
nbAvailableImgs checks in the method as the change point.

107-139: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Files of interest:\n'
git ls-files 'internal/pkg/cli/dryrun.go' 'go.mod' | cat

printf '\nSearch for relevant symbols/usages:\n'
rg -n --no-heading 'writeSubDigestEntries|subDigestDestination|manifestListDigests|mapping\.txt|subDigestEntry|CopyImageSchema' internal/pkg -S

printf '\nOutline dryrun.go:\n'
ast-grep outline internal/pkg/cli/dryrun.go --view expanded || true

Repository: openshift/oc-mirror

Length of output: 1924


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Read relevant sections of internal/pkg/cli/dryrun.go:\n'
nl -ba internal/pkg/cli/dryrun.go | sed -n '1,220p'

printf '\nInspect go.mod for containers/image version:\n'
rg -n --no-heading 'containers/image|github.com/containers/image' go.mod -S || true

Repository: openshift/oc-mirror

Length of output: 1924


🌐 Web query:

containers/image ParseRef transport syntax tag and digest docker transport oci transport mapping.txt

💡 Result:

The containers/image library uses a unified syntax for identifying container images, generally defined as transport:details [1][2]. The transport prefix determines how the remaining details are parsed by the corresponding transport driver [3]. Docker Transport (docker://) The docker transport follows the format: docker://docker-reference, where docker-reference is defined as name[:tag | @digest] [2][4]. - Tag and Digest: The docker transport does not support specifying both a tag and a digest simultaneously [2][5]. - Unknown Digest: To push an image without a tag or digest, the reference can be suffixed with @@unknown-digest@@ (e.g., docker://my-image@@unknown-digest@@) [4][6]. OCI Transport (oci:path[:reference]) The OCI transport refers to an image in a directory structure compliant with the Open Container Image Layout Specification [7]. - Syntax: The syntax is oci:path[:{reference|@source-index}] [7]. - Path Handling: The path value terminates at the first colon (:) character; any subsequent colons are treated as part of the reference string [7]. - Reference: The reference part is used to match or set the org.opencontainers.image.ref.name annotation in the OCI index [7]. - Digest Support: Unlike the docker transport, the OCI transport does not natively support referencing an image by manifest digest using the @digest syntax [8]. - Indexing: For reading images, @source-index (a zero-based index) can be used to access untagged images [7]. If neither a reference nor a @source-index is specified, the path must contain exactly one image [7]. Summary of Transport Mappings - docker://: Maps to name[:tag | @digest] [2]. - oci:path: Maps to a directory at path, optionally with a tag reference or a numeric @source-index [7]. - General rule: The library functions such as ParseImageName split the input string at the first colon to determine the transport, then pass the remainder to the transport's specific ParseReference method [3][9].

Citations:


internal/pkg/cli/dryrun.go:107-139 — Strip any tag from img.Source before appending @digest. strings.Cut(img.Source, "@") only removes an existing digest, so tag-based sources become name:tag@digest, which containers/image rejects for docker references and doesn’t document for OCI references. Reuse the same ref parsing used in subDigestDestination to derive sourceBase.

🤖 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 `@internal/pkg/cli/dryrun.go` around lines 107 - 139, Update
writeSubDigestEntries to derive sourceBase by parsing img.Source with the same
image.ParseRef approach used by subDigestDestination, ensuring both tags and
existing digests are removed before appending `@digest`. Preserve the current
fallback behavior for parse failures and keep subDigestDestination unchanged.

141-199: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

New network calls in both files lack a bounded timeout. This PR introduces two new registry-inspection network paths — manifest-list digest inspection and early catalog digest pinning — neither of which applies a timeout, unlike the existing checkRegistryAccess pattern (context.WithTimeout(ctx, 2*time.Minute)) already used elsewhere in executor.go.

  • internal/pkg/cli/dryrun.go#L141-L199: wrap the per-image GetManifestListDigests call (via newSystemContextForSource) in a bounded context.WithTimeout so one slow/unresponsive registry can't hold a semaphore slot indefinitely.
  • internal/pkg/cli/executor.go#L581-L588: replace context.Background() with a context derived with a timeout (and, ideally, threaded from the command's context) before calling config.PinCatalogDigests.
📍 Affects 2 files
  • internal/pkg/cli/dryrun.go#L141-L199 (this comment)
  • internal/pkg/cli/executor.go#L581-L588
🤖 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 `@internal/pkg/cli/dryrun.go` around lines 141 - 199, Bound both new
registry-inspection paths with a finite timeout, using the existing
checkRegistryAccess timeout pattern. In internal/pkg/cli/dryrun.go lines
141-199, update inspectManifestLists and its GetManifestListDigests call after
newSystemContextForSource to use a timeout-derived context and cancel it; in
internal/pkg/cli/executor.go lines 581-588, replace context.Background() before
config.PinCatalogDigests with the command context when available and derive a
bounded timeout context.
internal/pkg/cli/executor.go (2)

299-299: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Confusing flag help text.

"implies --dry-run, cannot be combined with --dry-run" reads as self-contradictory. Consider clarifying that it already enables dry-run behavior and must not be passed alongside an explicit --dry-run.

📝 Suggested fix
-	cmd.Flags().BoolVar(&opts.IsDryRunManifestLists, "dry-run-manifest-lists", false, "Like --dry-run, but also includes manifest list sub-digests in mapping.txt (implies --dry-run, cannot be combined with --dry-run)")
+	cmd.Flags().BoolVar(&opts.IsDryRunManifestLists, "dry-run-manifest-lists", false, "Like --dry-run, but also includes manifest list sub-digests in mapping.txt. This flag already implies --dry-run; do not pass --dry-run explicitly alongside it")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	cmd.Flags().BoolVar(&opts.IsDryRunManifestLists, "dry-run-manifest-lists", false, "Like --dry-run, but also includes manifest list sub-digests in mapping.txt. This flag already implies --dry-run; do not pass --dry-run explicitly alongside it")
🤖 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 `@internal/pkg/cli/executor.go` at line 299, Update the help text for the
IsDryRunManifestLists flag registration to state that this option enables
dry-run behavior automatically and must not be used together with an explicit
--dry-run flag; remove the self-contradictory wording while preserving the
existing flag semantics.

1383-1384: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Comment references a function name that doesn't exist in this file.

The comment says catalogs are "already pinned by pinOperatorCatalogs()", but the function actually invoked (line 586) is config.PinCatalogDigests. This mismatch can mislead future readers trying to trace the pinning logic.

📝 Suggested fix
-// Catalogs are already pinned by pinOperatorCatalogs() at workflow start for M2D/M2M modes.
+// Catalogs are already pinned by config.PinCatalogDigests() at workflow start for M2D/M2M modes.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

// Catalogs are already pinned by config.PinCatalogDigests() at workflow start for M2D/M2M modes.
func (o *ExecutorSchema) createConfigsWithPinnedCatalogs() {
🤖 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 `@internal/pkg/cli/executor.go` around lines 1383 - 1384, Update the comment
above ExecutorSchema.createConfigsWithPinnedCatalogs to reference the actual
config.PinCatalogDigests call used at workflow start, replacing the nonexistent
pinOperatorCatalogs name while preserving the M2D/M2M context.
internal/pkg/config/pin_catalogs.go (1)

135-156: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

TargetTag is mutated before digest resolution succeeds, contradicting the "skip = no action" contract.

op.TargetTag is preserved at Lines 136-139 unconditionally, before the network resolution at Line 147 and the empty-digest skip at Lines 152-156. If resolution fails or returns an empty digest, op.Catalog stays unpinned but op.TargetTag has already been mutated as a side effect — inconsistent with the doc comment's "skipped (catalog won't be pinned)" / "no action needed" framing. Move the TargetTag preservation after the digest is confirmed non-empty.

🐛 Proposed fix to defer TargetTag mutation until pinning succeeds
-	// Preserve the original tag for the destination if user didn't provide targetTag
-	if op.TargetTag == "" && imgSpec.Tag != "" {
-		op.TargetTag = imgSpec.Tag
-		log.Debug("Preserving original tag %s as TargetTag for catalog %s", imgSpec.Tag, op.Catalog)
-	}
-
 	// Resolve tag to digest via network
 	srcCtx, err := opts.SrcImage.NewSystemContext()
 	if err != nil {
 		return fmt.Errorf("failed to create system context: %w", err)
 	}
 
 	catalogDigest, err := manifestAPI.ImageDigest(ctx, srcCtx, imgSpec.ReferenceWithTransport)
 	if err != nil {
 		return fmt.Errorf("failed to resolve digest for catalog %s: %w", op.Catalog, err)
 	}
 
 	// Skip pinning if digest is empty
 	if catalogDigest == "" {
 		log.Debug("Skipping catalog %s (empty digest)", op.Catalog)
 		return nil
 	}
+
+	// Preserve the original tag for the destination if user didn't provide targetTag
+	if op.TargetTag == "" && imgSpec.Tag != "" {
+		op.TargetTag = imgSpec.Tag
+		log.Debug("Preserving original tag %s as TargetTag for catalog %s", imgSpec.Tag, op.Catalog)
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	// Resolve tag to digest via network
	srcCtx, err := opts.SrcImage.NewSystemContext()
	if err != nil {
		return fmt.Errorf("failed to create system context: %w", err)
	}

	catalogDigest, err := manifestAPI.ImageDigest(ctx, srcCtx, imgSpec.ReferenceWithTransport)
	if err != nil {
		return fmt.Errorf("failed to resolve digest for catalog %s: %w", op.Catalog, err)
	}

	// Skip pinning if digest is empty
	if catalogDigest == "" {
		log.Debug("Skipping catalog %s (empty digest)", op.Catalog)
		return nil
	}

	// Preserve the original tag for the destination if user didn't provide targetTag
	if op.TargetTag == "" && imgSpec.Tag != "" {
		op.TargetTag = imgSpec.Tag
		log.Debug("Preserving original tag %s as TargetTag for catalog %s", imgSpec.Tag, op.Catalog)
	}
🤖 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 `@internal/pkg/config/pin_catalogs.go` around lines 135 - 156, Move the
TargetTag preservation block in the catalog pinning flow after catalogDigest is
confirmed non-empty and the empty-digest early return in the digest resolution
logic. Keep the existing condition and log message, ensuring op.TargetTag is not
mutated when resolution fails or pinning is skipped.

@openshift-ci

openshift-ci Bot commented Jul 14, 2026

Copy link
Copy Markdown

@dorzel: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/integration 29f89b6 link true /test integration
ci/prow/images 29f89b6 link true /test images
ci/prow/okd-scos-images 29f89b6 link true /test okd-scos-images
ci/prow/verify-deps 29f89b6 link true /test verify-deps
ci/prow/lint 29f89b6 link true /test lint
ci/prow/sanity 29f89b6 link true /test sanity
ci/prow/unit 29f89b6 link true /test unit

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.

@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 14, 2026
@aguidirh

Copy link
Copy Markdown
Contributor

/retest

@aguidirh

Copy link
Copy Markdown
Contributor

/jira cherrypick OCPBUGS-66263

@openshift-ci-robot

Copy link
Copy Markdown

@aguidirh: Jira Issue OCPBUGS-66263 has been cloned as Jira Issue OCPBUGS-98716. Will retitle bug to link to clone.
/retitle OCPBUGS-98716: [release-4.22] OCPBUGS-66263: Include index image sub-digests in dry run mapping.txt

Details

In response to this:

/jira cherrypick OCPBUGS-66263

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 changed the title [release-4.22] OCPBUGS-66263: Include index image sub-digests in dry run mapping.txt OCPBUGS-98716: [release-4.22] OCPBUGS-66263: Include index image sub-digests in dry run mapping.txt Jul 15, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@dorzel: This pull request references Jira Issue OCPBUGS-98716, which is invalid:

  • release note text must be set and not match the template OR release note type must be set to "Release Note Not Required". For more information you can reference the OpenShift Bug Process.
  • expected dependent Jira Issue OCPBUGS-66263 to target a version in 5.0.0, but it targets "5.0" instead

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Description

Manual backport of #1355

Github / Jira issue: https://redhat.atlassian.net/browse/OCPBUGS-66263

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Code Improvements (Refactoring, Performance, CI upgrades, etc)
  • Internal repo assets (diagrams / docs on github repo)
  • This change requires a documentation update on openshift docs

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.

Expected Outcome

Please describe the outcome expected from the tests.

Summary by CodeRabbit

  • New Features
  • Added an option to inspect manifest lists during dry runs and include sub-manifest digest mappings in mapping.txt.
  • Added digest-aware destination handling for Docker image references.
  • Bug Fixes
  • Dry runs now continue successfully when registries are unreachable, while retaining available mappings and reporting warnings.
  • Improved handling of tag-and-digest image references in generated mirror configurations.
  • Catalog references are pinned more consistently before mirror execution.

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.

@aguidirh aguidirh changed the title OCPBUGS-98716: [release-4.22] OCPBUGS-66263: Include index image sub-digests in dry run mapping.txt [release-4.22] OCPBUGS-98716: Include index image sub-digests in dry run mapping.txt Jul 15, 2026
@aguidirh

Copy link
Copy Markdown
Contributor

/jira refresh

@openshift-ci-robot

Copy link
Copy Markdown

@aguidirh: This pull request references Jira Issue OCPBUGS-98716, which is invalid:

  • release note text must be set and not match the template OR release note type must be set to "Release Note Not Required". For more information you can reference the OpenShift Bug Process.

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

/jira refresh

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.

@aguidirh

Copy link
Copy Markdown
Contributor

/jira cherrypick OCPBUGS-66263

@dorzel the command above is needed when we do manual backport, it will clone the bug in jira and generate a new one for the manual backport PR.

For this PR I already did it, only sharing information here.

@r4f4

r4f4 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

/label backport-risk-assessed

@openshift-ci openshift-ci Bot added the backport-risk-assessed Indicates a PR to a release branch has been evaluated and considered safe to accept. label Jul 15, 2026
@openshift-ci

openshift-ci Bot commented Jul 15, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: aguidirh, dorzel

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 Jul 15, 2026
@aguidirh

Copy link
Copy Markdown
Contributor

/test okd-scos-images

@aguidirh

Copy link
Copy Markdown
Contributor

/retest

1 similar comment
@dorzel

dorzel commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

/retest

@aguidirh

Copy link
Copy Markdown
Contributor

@dorzel probably the conflict is happening because we need to merge #1457 before this one.

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. backport-risk-assessed Indicates a PR to a release branch has been evaluated and considered safe to accept. jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants