Skip to content

fix: quay promotion digest resolve for ocp/4.x#5216

Merged
openshift-merge-bot[bot] merged 1 commit into
openshift:mainfrom
deepsm007:fix/promotion-quay-digest-resolve
May 29, 2026
Merged

fix: quay promotion digest resolve for ocp/4.x#5216
openshift-merge-bot[bot] merged 1 commit into
openshift:mainfrom
deepsm007:fix/promotion-quay-digest-resolve

Conversation

@deepsm007
Copy link
Copy Markdown
Contributor

@deepsm007 deepsm007 commented May 29, 2026

Consolidated ocp/4.11–4.22 promotion targets now resolve quay-proxy digests post-mirror via oc image info + oc tag. Mirror retries fail the pod after 5 attempts; official digest-tag runs outside set +e.

Summary

This PR fixes image promotion for OpenShift's consolidated OCP/4.x release streams in the CI operator. Previously, promotion of container images to Quay had issues with properly resolving digest references after mirroring images between registries.

What Changed

Core Issue: The promotion logic for quay-proxy didn't correctly handle digest resolution when pushing images to consolidated ocp/4.x streams (e.g., ocp/4.13, ocp/4.21). After mirroring an image to quay-proxy, the system couldn't reliably determine the resulting image digest to tag it into release streams.

Solution:

  • Dynamic digest resolution: After mirroring images to quay-proxy, the system now runs oc image info to dynamically fetch the actual image digest, then uses oc tag to apply the correct tags. This replaces the previous approach of using fixed/hardcoded digests.
  • Improved retry logic: Mirror operations now have explicit retry handling that fails the pod after 5 attempts (instead of proceeding with stale data). Each retry includes randomized backoff (0-120 second sleep) to avoid thundering-herd effects.
  • Consolidated stream support: The quay-proxy tag parser now handles both the newer namespaced format (namespace/stream-quay:tag) and the consolidated format (ocp/4.x:tag).
  • Separate handling for official vs. non-official targets: Official digest-tag runs now execute outside set +e error suppression (ensuring proper failure detection), while template/non-digest tags use best-effort tagging with error suppression.

Practical Impact

For CI operators: Image promotions to consolidated OCP release streams should now complete more reliably, with proper error handling when mirrors fail and accurate digest tracking after cross-registry operations. Failed mirroring will now properly fail the promotion pod instead of continuing with stale state.

For test fixtures: The shell scripts that execute within promotion pods now contain more structured retry logic with clearer exit/failure semantics, making promotion jobs easier to debug when issues occur.

Files Modified

  • pkg/steps/release/promote.go - Added mirror retry helpers, split quay-step flow for official vs. non-official targets, dynamic digest resolution
  • pkg/steps/release/promote_test.go - New test for mirror retry logic, expanded quay-proxy tag mapping tests
  • Multiple test fixtures - Updated shell scripts to use structured retry loops with oc image info for dynamic digest resolution

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

📝 Walkthrough

Walkthrough

This PR refactors release image promotions for Quay by introducing explicit mirror retry helpers with randomized backoff, updating tag derivation to support consolidated OCP streams, and reorganizing promotion pod command construction to separate mirroring from resolve-and-tag operations. All test fixtures are updated to reflect the new retry-loop structure and dynamic digest resolution.

Changes

Quay image promotion retry and mirror refactor

Layer / File(s) Summary
Quay proxy tag derivation contract
pkg/steps/release/promote.go
quayProxyTagFromISKey updated to recognize both -quay-suffixed and consolidated ocp/4.x streams, deriving quay-proxy floating tags accordingly.
Mirror retry shell helper
pkg/steps/release/promote.go
Introduces getMirrorRetryShell function generating retry loops with randomized exponential backoff for image mirroring, alongside separate retry constants for mirror vs. digest-resolution operations.
Promotion pod command restructuring
pkg/steps/release/promote.go
getPromotionPod refactored to append mirror commands conditionally via getMirrorRetryShell, handle quay official targets in a dedicated resolve-and-tag loop, and apply best-effort batch tagging with per-tag retries for non-official templates.
Mirror retry shell validation
pkg/steps/release/promote_test.go
New TestGetMirrorRetryShell validates generated shell includes retry-loop structure, attempt logging, oc image mirror invocation, and final failure behavior; extended TestQuayProxyTagFromISKey covers consolidated OCP streams.
Basic and Quay promotion fixtures
pkg/steps/release/testdata/zz_fixture_*.yaml
All promotion fixtures updated to use structured multi-line retry-loop scripts with explicit control flow and randomized backoff; Quay fixtures now include dynamic digest resolution via oc image info for per-tag retries instead of fixed digests.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • openshift/ci-tools#5211: Modifies getPromotionPod inputs and image selection logic affecting promotion pod construction in this PR.

Suggested labels

lgtm

🚥 Pre-merge checks | ✅ 16 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (16 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: fixing quay promotion digest resolution for ocp/4.x streams.
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.
Go Error Handling ✅ Passed All error handling complies: 0 ignored errors, 7 error returns wrapped with fmt.Errorf %w, 0 panic calls, string indexing properly bounds-checked.
Test Coverage For New Features ✅ Passed Two new Go functions have unit tests; quayProxyTagFromISKey has expanded coverage; getPromotionPod tested via fixtures validating generated retry shell commands.
Stable And Deterministic Test Names ✅ Passed Tests use standard Go testing package with static, deterministic test names. No Ginkgo framework detected. All test function names and table case names are static strings with no dynamic content.
Test Structure And Quality ✅ Passed This PR's tests are standard Go unit tests, not Ginkgo. Custom check is inapplicable; tests demonstrate quality: single responsibilities, meaningful assertions, consistent patterns.
Microshift Test Compatibility ✅ Passed No Ginkgo e2e tests are added in this PR. Changes are limited to Go unit tests in pkg/steps/release/promote_test.go and YAML fixtures, which are not subject to this MicroShift compatibility check.
Single Node Openshift (Sno) Test Compatibility ✅ Passed This PR contains no Ginkgo e2e tests; only unit tests for CI tooling in the promote package. The SNO compatibility check is not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed PR modifies only internal CI promotion code and golden test fixtures. No deployment manifests, operator code, or controllers with topology-aware scheduling constraints are added/modified.
Ote Binary Stdout Contract ✅ Passed PR modifies library code and tests; no process-level stdout writes (main, init, TestMain, BeforeSuite) detected. Functions use fmt.Sprintf for string building, not stdout writes.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No Ginkgo e2e tests added. Changes include unit tests using standard Go testing package for helper functions, not Ginkgo e2e test definitions.
No-Weak-Crypto ✅ Passed No weak crypto (MD5, SHA1, DES, RC4, 3DES, Blowfish, ECB), custom implementations, or unsafe comparisons found in the PR changes.
Container-Privileges ✅ Passed No privileged container configurations found in promote.go, promote_test.go, or YAML fixtures (no privileged mode, hostPID/Network/IPC, SYS_ADMIN, allowPrivilegeEscalation, or root execution).
No-Sensitive-Data-In-Logs ✅ Passed No sensitive data logging found. Echo statements only log attempt numbers, tag names, and backoff durations. Registry config paths are not echoed or logged directly.
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

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

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 29, 2026
@deepsm007
Copy link
Copy Markdown
Contributor Author

/test e2e

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
pkg/steps/release/promote_test.go (2)

1113-1127: ⚡ Quick win

Tighten the helper-specific assertions here.

This test would still pass if the retry helper dropped the randomized backoff or the rendered mirror flags. Please assert the helper-specific contract too, e.g. $(($RANDOM % 120)), sleep $backoff, --registry-config=..., and --max-per-registry=10.

As per coding guidelines, "New or modified functionality should include test coverage. New Go functions and methods should have corresponding unit tests. Bug fixes should include a regression test that fails without the fix. Pure functions should always be tested. Prefer table-driven tests."

🤖 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 `@pkg/steps/release/promote_test.go` around lines 1113 - 1127, The test
TestGetMirrorRetryShell currently checks generic substrings; tighten it to
assert the helper-specific contract by verifying the randomized backoff
expression and usage, the sleep call, and required flags: ensure
getMirrorRetryShell(regcfg, []string{"src=dst"}, 2) output contains the
substring '$(($RANDOM % 120))', the variable usage 'sleep $backoff', the
registry flag '--registry-config=' followed by the provided regcfg value, and
the flag '--max-per-registry=10'; update TestGetMirrorRetryShell to include
these contains checks so the test fails if backoff, sleep, or mirror flags are
omitted or altered.

1189-1203: ⚡ Quick win

Add boundary cases for the consolidated stream window.

The new contract is specifically ocp/4.11 through ocp/4.22, but the added cases only hit interior values plus 4.23. Please add explicit 4.11, 4.22, and ideally 4.10 coverage so an off-by-one in api.ConsolidatedQuayPromotionVersion cannot slip through.

As per coding guidelines, "New or modified functionality should include test coverage. New Go functions and methods should have corresponding unit tests. Bug fixes should include a regression test that fails without the fix. Pure functions should always be tested. Prefer table-driven tests."

🤖 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 `@pkg/steps/release/promote_test.go` around lines 1189 - 1203, The table-driven
test for consolidated streams is missing boundary cases around
api.ConsolidatedQuayPromotionVersion; add explicit test rows for "ocp/4.10:..."
(expect wantOK false), "ocp/4.11:..." (expect wantOK true), and "ocp/4.22:..."
(expect wantOK true) to the test cases alongside the existing interior and 4.23
checks so off-by-one errors in ConsolidatedQuayPromotionVersion are caught;
reference the existing test case entries (e.g., the rows using isTagKey like
"ocp/4.13:secondary-scheduler-operator") and mirror their wantTag/wantOK
expectations for the new rows.
🤖 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.

Nitpick comments:
In `@pkg/steps/release/promote_test.go`:
- Around line 1113-1127: The test TestGetMirrorRetryShell currently checks
generic substrings; tighten it to assert the helper-specific contract by
verifying the randomized backoff expression and usage, the sleep call, and
required flags: ensure getMirrorRetryShell(regcfg, []string{"src=dst"}, 2)
output contains the substring '$(($RANDOM % 120))', the variable usage 'sleep
$backoff', the registry flag '--registry-config=' followed by the provided
regcfg value, and the flag '--max-per-registry=10'; update
TestGetMirrorRetryShell to include these contains checks so the test fails if
backoff, sleep, or mirror flags are omitted or altered.
- Around line 1189-1203: The table-driven test for consolidated streams is
missing boundary cases around api.ConsolidatedQuayPromotionVersion; add explicit
test rows for "ocp/4.10:..." (expect wantOK false), "ocp/4.11:..." (expect
wantOK true), and "ocp/4.22:..." (expect wantOK true) to the test cases
alongside the existing interior and 4.23 checks so off-by-one errors in
ConsolidatedQuayPromotionVersion are caught; reference the existing test case
entries (e.g., the rows using isTagKey like
"ocp/4.13:secondary-scheduler-operator") and mirror their wantTag/wantOK
expectations for the new rows.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 9fe3bad2-e0e6-41c4-8b2e-4d0e81a18e9e

📥 Commits

Reviewing files that changed from the base of the PR and between 7b6e7b8 and 953ae88.

📒 Files selected for processing (9)
  • pkg/steps/release/promote.go
  • pkg/steps/release/promote_test.go
  • pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_basic_case.yaml
  • pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_basic_case__arm64_only.yaml
  • pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_basic_case__multi_architecture.yaml
  • pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay.yaml
  • pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_4.12.yaml
  • pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_multiple_tags.yaml
  • pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_non_release_namespace.yaml

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

Tests from second stage were triggered manually. Pipeline can be controlled only manually, until HEAD changes. Use command to trigger second stage.

@danilo-gemoli
Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label May 29, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 29, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: danilo-gemoli, deepsm007

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 [danilo-gemoli,deepsm007]

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

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 29, 2026

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

@openshift-merge-bot openshift-merge-bot Bot merged commit e89b8e9 into openshift:main May 29, 2026
17 checks passed
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. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants