Skip to content

Conversation

@Prucek
Copy link
Member

@Prucek Prucek commented Nov 24, 2025

Added pkg/dockerfile/inputs.go - Core detection logic:

  • Automatically detects registry.ci.openshift.org and quay-proxy.ci.openshift.org references in Dockerfiles
  • Parses references into org/repo/tag components
  • Generates base_images and inputs.as[] configuration on-the-fly
  • Using registry-replacer's detection logic

Integrated into pkg/defaults/defaults.go:

  • New detectDockerfileInputs() function reads Dockerfiles from source checkout
  • Calls DetectInputsFromDockerfile() during build graph construction
  • Creates input steps that tag detected base images into the pipeline ImageStream
  • Respects manual configuration (manual inputs.as[] takes precedence)

Real example config using a mocked prowjob: https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_cluster-api-operator/63/prucek-test-dockerfile-inputs/2009259226555224064

@openshift-ci-robot
Copy link
Contributor

Pipeline controller notification
This repository 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

@coderabbitai
Copy link

coderabbitai bot commented Nov 24, 2025

Walkthrough

Adds Dockerfile-based detection of base images into the build configuration pipeline, parsing Dockerfiles (literals or files), mapping detected registry references to ImageStreamTagReference inputs, integrating generated tagging steps, and adding unit and e2e tests exercising detection and parsing behaviors.

Changes

Cohort / File(s) Summary
Defaults integration
pkg/defaults/defaults.go
Adds Dockerfile input detection and processing functions (detectDockerfileInputs, readDockerfileForImage, processDetectedBaseImages, isBaseImagePresent) and integrates detection into runtimeStepConfigsForBuild; updates imports.
Dockerfile parsing logic
pkg/dockerfile/inputs.go
New package logic DetectInputsFromDockerfile and helpers to extract registry references (including quay-proxy and CI registry formats), parse org/repo/tag, deduplicate entries, respect manual replacements, and return api.ImageStreamTagReference mappings.
Unit tests
pkg/defaults/defaults_test.go, pkg/dockerfile/inputs_test.go
Adds tests covering reading Dockerfiles (paths and literals), processing detected base images (multiple, none, pre-existing/manual inputs), and parsing registry pull strings and detection behavior (dedupe, quay-proxy handling).
End-to-end test & fixtures
test/e2e/dockerfile-inputs/e2e_test.go, test/e2e/dockerfile-inputs/testdata/config.yaml
Adds an e2e test TestDockerfileInputs and test config YAML exercising various Dockerfile scenarios: auto-detection, manual inputs, cross-stage copies, quay-proxy refs, and reuse of base images.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

✨ Finishing touches
  • 📝 Generate docstrings

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 Nov 24, 2025
Copy link

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
pkg/defaults/defaults_test.go (1)

2445-2457: Prefer standard library strings.Contains.

These helper functions reimplement functionality available in the standard library. Using strings.Contains directly would simplify the code and improve maintainability.

Apply this diff:

-func containsString(s, substr string) bool {
-	return len(s) >= len(substr) && (s == substr || len(substr) == 0 ||
-		(len(s) > 0 && len(substr) > 0 && contains(s, substr)))
-}
-
-func contains(s, substr string) bool {
-	for i := 0; i <= len(s)-len(substr); i++ {
-		if s[i:i+len(substr)] == substr {
-			return true
-		}
-	}
-	return false
-}

Then update line 2237 to use strings.Contains directly:

+import "strings"
+
 				if tc.expectedErrContain != "" && err != nil {
-					if !containsString(err.Error(), tc.expectedErrContain) {
+					if !strings.Contains(err.Error(), tc.expectedErrContain) {
 						t.Errorf("expected error to contain %q, got: %v", tc.expectedErrContain, err)
 					}
 				}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 7c717b8 and fdaf457.

📒 Files selected for processing (12)
  • pkg/defaults/defaults.go (2 hunks)
  • pkg/defaults/defaults_test.go (3 hunks)
  • pkg/dockerfile/inputs.go (1 hunks)
  • pkg/dockerfile/inputs_test.go (1 hunks)
  • test/e2e/dockerfile-inputs/config.yaml (1 hunks)
  • test/e2e/dockerfile-inputs/e2e_test.go (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.copy-from (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.manual (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.multiple (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.no-refs (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.quay-proxy (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.single (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • test/e2e/dockerfile-inputs/config.yaml
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.quay-proxy
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.manual
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.multiple
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.copy-from
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.no-refs
  • pkg/dockerfile/inputs_test.go
  • pkg/dockerfile/inputs.go
  • pkg/defaults/defaults_test.go
  • pkg/defaults/defaults.go
  • test/e2e/dockerfile-inputs/e2e_test.go
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.single
🧬 Code graph analysis (4)
pkg/dockerfile/inputs_test.go (2)
pkg/api/types.go (2)
  • ImageBuildInputs (2748-2758)
  • ImageStreamTagReference (494-501)
pkg/dockerfile/inputs.go (1)
  • DetectInputsFromDockerfile (33-90)
pkg/dockerfile/inputs.go (1)
pkg/api/types.go (2)
  • ImageBuildInputs (2748-2758)
  • ImageStreamTagReference (494-501)
pkg/defaults/defaults.go (3)
pkg/api/types.go (9)
  • ReleaseBuildConfiguration (37-135)
  • StepConfiguration (618-632)
  • ProjectDirectoryImageBuildStepConfiguration (2661-2684)
  • ImageBuildInputs (2748-2758)
  • ImageStreamTagReference (494-501)
  • InputImageTagStepConfiguration (638-641)
  • InputImage (680-687)
  • PipelineImageStreamTagReference (2493-2493)
  • ImageStreamSource (699-702)
pkg/dockerfile/inputs.go (1)
  • DetectInputsFromDockerfile (33-90)
cmd/repo-init/api.go (1)
  • BaseImages (69-69)
test/e2e/dockerfile-inputs/e2e_test.go (1)
pkg/testhelper/accessory.go (1)
  • T (51-57)
🔇 Additional comments (15)
test/e2e/dockerfile-inputs/testdata/Dockerfile.no-refs (1)

1-2: LGTM!

Appropriate test fixture for verifying the "no registry references" detection path.

test/e2e/dockerfile-inputs/testdata/Dockerfile.manual (1)

1-2: LGTM!

Appropriate fixture for testing manual inputs precedence over auto-detection.

test/e2e/dockerfile-inputs/testdata/Dockerfile.quay-proxy (1)

1-2: LGTM!

Appropriate test fixture for verifying quay-proxy reference detection and parsing.

test/e2e/dockerfile-inputs/testdata/Dockerfile.single (1)

1-2: LGTM!

Appropriate fixture for the basic single-reference auto-detection scenario.

test/e2e/dockerfile-inputs/testdata/Dockerfile.multiple (1)

1-6: LGTM!

Appropriate multi-stage fixture for testing detection of multiple base image references.

test/e2e/dockerfile-inputs/testdata/Dockerfile.copy-from (1)

1-6: LGTM!

Appropriate fixture for testing COPY --from directive handling in multi-stage builds.

pkg/defaults/defaults_test.go (2)

7-7: LGTM!

The new imports are appropriately used in the test functions.

Also applies to: 20-20


2138-2443: Comprehensive test coverage.

The test functions provide thorough coverage of Dockerfile reading and base image detection scenarios, including edge cases for custom paths, literals, manual inputs, and multi-stage builds.

test/e2e/dockerfile-inputs/config.yaml (1)

1-30: LGTM!

Well-structured e2e test configuration that covers the key scenarios: single/multiple auto-detection, quay-proxy references, manual inputs precedence, COPY --from handling, and no-registry-references cases.

pkg/defaults/defaults.go (1)

1029-1137: LGTM: Clean integration of Dockerfile input detection.

The implementation follows good practices:

  • Soft-fail approach (logs and continues) for individual image failures is appropriate, as one malformed Dockerfile shouldn't block the entire build
  • Functions are well-factored and focused on single responsibilities
  • Error handling is consistent with the rest of the codebase
  • Mutations to config.BaseImages and image.Inputs follow existing patterns in this file
test/e2e/dockerfile-inputs/e2e_test.go (1)

12-90: LGTM: Comprehensive e2e test coverage.

The test cases cover the key scenarios:

  • Auto-detection of single and multiple registry references
  • Quay-proxy reference handling
  • Manual input override behavior
  • COPY --from references
  • No registry references case

Test structure is clean and maintainable.

pkg/dockerfile/inputs_test.go (1)

11-293: LGTM: Thorough unit test coverage.

The test suite covers:

  • Edge cases (empty dockerfile, duplicates, mixed registry/non-registry refs)
  • Multiple registry formats (registry.ci, registry.svc.ci, quay-proxy)
  • Error conditions (malformed references)
  • Manual input override behavior

Good use of table-driven tests and clear assertions.

pkg/dockerfile/inputs.go (3)

18-19: Regex pattern is permissive but acceptable.

The pattern \S+ matches any non-whitespace characters after the registry domain, which is quite permissive. However, this is acceptable because:

  1. orgRepoTagFromPullString() validates the format downstream (Lines 138-162)
  2. Invalid formats are caught and returned as errors
  3. The simple approach aligns with the stated goal of parity with registry-replacer

33-90: LGTM: Well-structured detection logic.

The function correctly:

  • Returns early for empty input or when manual inputs are defined
  • Deduplicates registry references
  • Handles parsing errors appropriately
  • Logs useful diagnostic information at appropriate levels

The approach of honoring manual inputs.as[] configuration while auto-detecting when not present is the right design choice.


181-220: Incorrect review comment. The function extractReplacementCandidatesFromDockerfile at pkg/dockerfile/inputs.go:183 IS actively called in the codebase at cmd/registry-replacer/main.go:305. It is not dead code or unused. The function serves its intended purpose within the codebase.

Likely an incorrect or invalid review comment.

@Prucek
Copy link
Member Author

Prucek commented Nov 25, 2025

/test e2e


// readDockerfileForImage reads the Dockerfile content for a given image configuration
// Returns content, a description of the source, and any error
func readDockerfileForImage(image *api.ProjectDirectoryImageBuildStepConfiguration, readFile readFile) ([]byte, string, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The nesting levels of this body can be decreased by doing so:

func readDockerfileForImage(image *api.ProjectDirectoryImageBuildStepConfiguration, readFile readFile) ([]byte, string, error) {
  if image.DockerfileLiteral != nil {
    return []byte(*image.DockerfileLiteral), "dockerfile_literal"
  }
  // Everything else here, no `else`
}

@droslean
Copy link
Member

/test images

@Prucek
Copy link
Member Author

Prucek commented Nov 27, 2025

/test e2e

Copy link

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
pkg/dockerfile/inputs.go (1)

93-101: Clarify or remove currently-unused per-reference manual override helper

hasManualInputs short-circuits auto-detection when any inputs.as entry is present, which matches the intended “manual config wins” semantics. Given that, the per-reference helper hasManualReplacementFor is currently unreachable in production: with the existing call pattern it can only run in cases where there are no manual inputs.as entries.

That’s not harmful but slightly confusing for future readers. Two options:

  • If you plan to support a “mixed” mode (some refs auto-detected, some overridden manually), add a comment on DetectInputsFromDockerfile explaining the intended future use of hasManualReplacementFor, or adjust the short-circuit logic accordingly.
  • If not, consider dropping hasManualReplacementFor for now and reintroducing it when such a mode is actually needed.

This keeps the detection path easier to reason about and avoids dead-code-like helpers.

Also applies to: 129-137

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between fdaf457 and f2792f4.

📒 Files selected for processing (12)
  • pkg/defaults/defaults.go (2 hunks)
  • pkg/defaults/defaults_test.go (3 hunks)
  • pkg/dockerfile/inputs.go (1 hunks)
  • pkg/dockerfile/inputs_test.go (1 hunks)
  • test/e2e/dockerfile-inputs/config.yaml (1 hunks)
  • test/e2e/dockerfile-inputs/e2e_test.go (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.copy-from (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.manual (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.multiple (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.no-refs (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.quay-proxy (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.single (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.quay-proxy
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.manual
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.single
  • pkg/defaults/defaults_test.go
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.copy-from
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.multiple
  • test/e2e/dockerfile-inputs/config.yaml
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • test/e2e/dockerfile-inputs/testdata/Dockerfile.no-refs
  • test/e2e/dockerfile-inputs/e2e_test.go
  • pkg/defaults/defaults.go
  • pkg/dockerfile/inputs.go
  • pkg/dockerfile/inputs_test.go
🧬 Code graph analysis (2)
test/e2e/dockerfile-inputs/e2e_test.go (1)
pkg/testhelper/accessory.go (1)
  • T (51-57)
pkg/dockerfile/inputs.go (1)
pkg/api/types.go (2)
  • ImageBuildInputs (2748-2758)
  • ImageStreamTagReference (494-501)
🔇 Additional comments (3)
test/e2e/dockerfile-inputs/testdata/Dockerfile.no-refs (1)

1-2: No-registry fixture correctly exercises negative path

This Dockerfile intentionally contains no registry.ci.openshift.org/quay-proxy refs and is appropriate for the "no auto-detect" scenario.

test/e2e/dockerfile-inputs/e2e_test.go (1)

1-90: E2E coverage for Dockerfile inputs is comprehensive and wired correctly

The table-driven TestDockerfileInputs exercises all key scenarios (single/multiple/quay-proxy/manual/COPY-from/no-refs) via the standard e2e framework, passing pull secrets and JOB_SPEC appropriately. Assertions on success and log output look sound.

pkg/dockerfile/inputs_test.go (1)

1-293: Unit tests thoroughly exercise detection and parsing helpers

TestDetectInputsFromDockerfile, TestOrgRepoTagFromPullString, and TestExtractReplacementCandidatesFromDockerfile collectively cover the important happy-path and edge cases (multiple registries, quay-proxy, legacy registry.svc, manual inputs, mixed/duplicate refs, and COPY/AS stages). This gives good confidence in the new parsing logic.

Comment on lines +1029 to +1047
// Detect Dockerfile inputs for project images and add InputImageTagStepConfiguration entries
dockerfileInputSteps, err := detectDockerfileInputs(config, readFile)
if err != nil {
return nil, fmt.Errorf("failed to detect Dockerfile inputs: %w", err)
}
buildSteps = append(buildSteps, dockerfileInputSteps...)

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Make Dockerfile-input detection best-effort instead of failing the build graph

Right now any error from detectDockerfileInputs (e.g., an unexpected registry reference that DetectInputsFromDockerfile cannot parse) will cause runtimeStepConfigsForBuild to return an error and abort graph construction. That’s a behavior change compared to today, where unusual but syntactically valid Dockerfiles still run, just without auto-detected inputs.

Given this feature is an additive convenience, it’s safer to degrade gracefully on detection errors and continue without auto-generated InputImageTagStepConfigurations. Otherwise, a single odd-looking reference to registry.ci.openshift.org/quay-proxy.ci.openshift.org can break the entire job.

Consider handling errors like this instead:

-	// Detect Dockerfile inputs for project images and add InputImageTagStepConfiguration entries
-	dockerfileInputSteps, err := detectDockerfileInputs(config, readFile)
-	if err != nil {
-		return nil, fmt.Errorf("failed to detect Dockerfile inputs: %w", err)
-	}
-	buildSteps = append(buildSteps, dockerfileInputSteps...)
+	// Detect Dockerfile inputs for project images and add InputImageTagStepConfiguration entries.
+	// This is best-effort and should not break existing configurations.
+	dockerfileInputSteps, err := detectDockerfileInputs(config, readFile)
+	if err != nil {
+		logrus.WithError(err).Warn("Dockerfile inputs detection failed; continuing without auto-detected base images")
+	} else {
+		buildSteps = append(buildSteps, dockerfileInputSteps...)
+	}

This keeps the new functionality while avoiding regressions for configs with unusual but valid image references.

Also applies to: 1042-1131

🤖 Prompt for AI Agents
In pkg/defaults/defaults.go around lines 1029 to 1035 (and similarly for
1042–1131), the call to detectDockerfileInputs currently returns an error that
aborts graph construction; make detection best‑effort by catching and logging
the error instead of returning it. Change the code to call
detectDockerfileInputs, and if it returns an error, write a warning-level log or
comment (including the error message) and continue without appending
dockerfileInputSteps; only return on fatal/unexpected errors, not on
parse/registry detection failures. Ensure the same non-fatal behavior is applied
to the other block(s) noted (1042–1131).

Comment on lines +34 to +37
func DetectInputsFromDockerfile(
dockerfile []byte,
existingInputs map[string]api.ImageBuildInputs,
) (map[string]api.ImageStreamTagReference, error) {
if len(dockerfile) == 0 {
return nil, nil
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid failing on unparseable registry refs; treat them as best-effort skips

DetectInputsFromDockerfile currently returns an error if orgRepoTagFromPullString cannot parse a matched registry reference (e.g., if the path doesn’t look like exactly /<org>/<repo>:<tag>). Combined with the caller in runtimeStepConfigsForBuild, this means:

  • Any Dockerfile line that happens to match registryRegex but uses a slightly different yet syntactically valid shape (extra path segment, missing explicit tag, future quay-proxy variant, etc.) can cause the entire job to fail, even though auto-detection is an additive feature.
  • The repo already has explicit unit tests for error cases in orgRepoTagFromPullString; those shouldn’t necessarily translate into hard failures for ci-operator.

To keep the feature robust while still surfacing problems, I’d recommend treating parse failures as “skip this ref with a warning” instead of aborting:

	for _, ref := range registryRefs {
-		// Skip if there's already a manual input for this reference
+		// Skip if there's already a manual input for this reference
 		if hasManualReplacementFor(existingInputs, ref) {
 			logrus.WithField("reference", ref).Debug("Skipping auto-detection: manual replacement exists")
 			continue
 		}

-		// Parse the registry reference into org/repo/tag
-		orgRepoTag, err := orgRepoTagFromPullString(ref)
-		if err != nil {
-			return nil, fmt.Errorf("failed to parse registry reference %s: %w", ref, err)
-		}
+		// Parse the registry reference into org/repo/tag. If the shape is unexpected,
+		// log and skip instead of failing the whole job.
+		orgRepoTag, err := orgRepoTagFromPullString(ref)
+		if err != nil {
+			logrus.WithError(err).Warnf("Dockerfile-inputs: skipping unrecognized registry reference %q", ref)
+			continue
+		}

With this change (and making the caller in runtimeStepConfigsForBuild best-effort as suggested earlier), detection cannot regress existing jobs simply because of a new or slightly different registry path pattern, while still emitting useful diagnostics when something looks off.

Also applies to: 56-67, 139-163

🤖 Prompt for AI Agents
In pkg/dockerfile/inputs.go around lines 34-40 (and similarly at 56-67 and
139-163), the function currently treats failures from orgRepoTagFromPullString
as fatal errors; change that behavior to be best-effort: when
orgRepoTagFromPullString returns an error, emit a warning (or debug log)
describing the unparseable ref and continue without adding that ref to the
result map instead of returning the error, so DetectInputsFromDockerfile skips
problematic registry refs but keeps processing the rest of the Dockerfile.

@Prucek
Copy link
Member Author

Prucek commented Nov 27, 2025

/test images

@Prucek
Copy link
Member Author

Prucek commented Nov 28, 2025

/test e2e

Copy link

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between eede1fe and b1d622c.

📒 Files selected for processing (8)
  • test/e2e/dockerfile-inputs/config.yaml (1 hunks)
  • test/e2e/dockerfile-inputs/e2e_test.go (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.copy-from (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.manual (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.multiple (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.no-refs (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.quay-proxy (1 hunks)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.single (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.manual
🚧 Files skipped from review as they are similar to previous changes (5)
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.quay-proxy
  • test/e2e/dockerfile-inputs/config.yaml
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.single
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.multiple
  • test/e2e/dockerfile-inputs/testdata/Dockerfile.copy-from
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • test/e2e/dockerfile-inputs/testdata/Dockerfile.no-refs
  • test/e2e/dockerfile-inputs/e2e_test.go
🧬 Code graph analysis (1)
test/e2e/dockerfile-inputs/e2e_test.go (1)
pkg/testhelper/accessory.go (1)
  • T (51-57)
🔇 Additional comments (3)
test/e2e/dockerfile-inputs/testdata/Dockerfile.no-refs (1)

1-2: LGTM!

Valid test fixture for the no-registry-references case. The Dockerfile correctly uses a public base image and explicitly documents the test intent.

test/e2e/dockerfile-inputs/e2e_test.go (2)

1-13: LGTM!

Standard e2e test structure with appropriate build tags and minimal imports. The defaultJobSpec is lengthy but acceptable as test fixture data.


15-73: LGTM!

Comprehensive test coverage with clear table-driven structure. The test cases appropriately cover various scenarios including single/multiple references, quay-proxy, manual overrides, COPY --from, and the no-references case.

@Prucek
Copy link
Member Author

Prucek commented Dec 2, 2025

/test e2e

@Prucek Prucek force-pushed the dockerfile-inputs branch from b1d622c to 4c6b6d5 Compare January 6, 2026 14:52
Copy link

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

Actionable comments posted: 3

🤖 Fix all issues with AI Agents
In @pkg/defaults/defaults.go:
- Around line 1039-1044: The call to detectDockerfileInputs currently propagates
errors and aborts graph construction; change it to treat errors as non-fatal:
call detectDockerfileInputs(config, readFile), and if it returns an error log a
warning (using the package's logger) that includes the error message and
context, do not return the error, and only append returned dockerfileInputSteps
to buildSteps when non-nil/non-empty so auto-detection stays additive rather
than failing the build graph.

In @pkg/dockerfile/inputs.go:
- Around line 58-61: The code currently treats a failure from
orgRepoTagFromPullString(ref) as fatal; change this to a best-effort approach by
catching the error, emitting a warning (using the existing logger in scope) that
includes ref and the error, and skipping/continuing past this ref instead of
returning the error so processing can continue for other entries; make this
change around the orgRepoTagFromPullString call and ensure any downstream code
that expects orgRepoTag is not executed when parsing fails.
🧹 Nitpick comments (1)
pkg/dockerfile/inputs.go (1)

96-99: Inconsistent case handling for Dockerfile instructions

Dockerfile instructions are case-insensitive. The check includes lowercase copy but not lowercase from, which could miss valid references.

🔎 Proposed fix
 	for _, line := range bytes.Split(dockerfile, []byte("\n")) {
-		if !bytes.Contains(line, []byte("FROM")) && !bytes.Contains(line, []byte("COPY")) && !bytes.Contains(line, []byte("copy")) {
+		upperLine := bytes.ToUpper(line)
+		if !bytes.Contains(upperLine, []byte("FROM")) && !bytes.Contains(upperLine, []byte("COPY")) {
 			continue
 		}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between b1d622c and 4c6b6d5.

📒 Files selected for processing (6)
  • pkg/defaults/defaults.go
  • pkg/defaults/defaults_test.go
  • pkg/dockerfile/inputs.go
  • pkg/dockerfile/inputs_test.go
  • test/e2e/dockerfile-inputs/config.yaml
  • test/e2e/dockerfile-inputs/e2e_test.go
✅ Files skipped from review due to trivial changes (1)
  • pkg/dockerfile/inputs_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/defaults/defaults_test.go
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • test/e2e/dockerfile-inputs/e2e_test.go
  • test/e2e/dockerfile-inputs/config.yaml
  • pkg/defaults/defaults.go
  • pkg/dockerfile/inputs.go
🧬 Code graph analysis (3)
test/e2e/dockerfile-inputs/e2e_test.go (1)
pkg/testhelper/accessory.go (1)
  • T (51-57)
pkg/defaults/defaults.go (2)
pkg/api/types.go (7)
  • StepConfiguration (623-637)
  • ProjectDirectoryImageBuildStepConfiguration (2699-2722)
  • ImageBuildInputs (2786-2796)
  • ImageStreamTagReference (499-506)
  • InputImageTagStepConfiguration (643-646)
  • InputImage (685-692)
  • ReleaseTagConfiguration (516-532)
pkg/dockerfile/inputs.go (1)
  • DetectInputsFromDockerfile (34-79)
pkg/dockerfile/inputs.go (1)
pkg/api/types.go (2)
  • ImageBuildInputs (2786-2796)
  • ImageStreamTagReference (499-506)
🔇 Additional comments (4)
pkg/defaults/defaults.go (1)

1098-1141: LGTM!

The function correctly detects base images, updates the configuration, and generates appropriate InputImageTagStepConfiguration steps. The mutation of config.BaseImages and image.Inputs is intentional for proper pipeline integration.

test/e2e/dockerfile-inputs/config.yaml (1)

1-67: LGTM!

The test configuration provides good coverage of Dockerfile input detection scenarios: single/multiple registry references, quay-proxy format, manual inputs override, COPY --from handling, and no-registry-refs case.

test/e2e/dockerfile-inputs/e2e_test.go (1)

12-100: LGTM!

The table-driven test structure provides comprehensive coverage of the Dockerfile input detection feature. Test cases align well with the scenarios defined in config.yaml.

pkg/dockerfile/inputs.go (1)

169-208: These functions are actively used in the codebase. extractReplacementCandidatesFromDockerfile is called in pkg/dockerfile/inputs_test.go:270 and cmd/registry-replacer/main.go:305, while nodeHasFromRef is used in cmd/registry-replacer/main.go:565 and within the extraction function itself at line 196.

Likely an incorrect or invalid review comment.

Comment on lines +1039 to +1046
// Detect Dockerfile inputs for project images and add InputImageTagStepConfiguration entries
dockerfileInputSteps, err := detectDockerfileInputs(config, readFile)
if err != nil {
return nil, fmt.Errorf("failed to detect Dockerfile inputs: %w", err)
}
buildSteps = append(buildSteps, dockerfileInputSteps...)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Detection errors should not fail the build graph

Per earlier feedback, detectDockerfileInputs errors should be logged as warnings, not propagated as fatal errors. This keeps the auto-detection feature additive without breaking existing configurations.

🔎 Proposed fix
 	// Detect Dockerfile inputs for project images and add InputImageTagStepConfiguration entries
 	dockerfileInputSteps, err := detectDockerfileInputs(config, readFile)
 	if err != nil {
-		return nil, fmt.Errorf("failed to detect Dockerfile inputs: %w", err)
+		logrus.WithError(err).Warn("Dockerfile inputs detection failed; continuing without auto-detected base images")
+	} else {
+		buildSteps = append(buildSteps, dockerfileInputSteps...)
 	}
-	buildSteps = append(buildSteps, dockerfileInputSteps...)
📝 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.

Suggested change
// Detect Dockerfile inputs for project images and add InputImageTagStepConfiguration entries
dockerfileInputSteps, err := detectDockerfileInputs(config, readFile)
if err != nil {
return nil, fmt.Errorf("failed to detect Dockerfile inputs: %w", err)
}
buildSteps = append(buildSteps, dockerfileInputSteps...)
// Detect Dockerfile inputs for project images and add InputImageTagStepConfiguration entries
dockerfileInputSteps, err := detectDockerfileInputs(config, readFile)
if err != nil {
logrus.WithError(err).Warn("Dockerfile inputs detection failed; continuing without auto-detected base images")
} else {
buildSteps = append(buildSteps, dockerfileInputSteps...)
}
🤖 Prompt for AI Agents
In @pkg/defaults/defaults.go around lines 1039 - 1044, The call to
detectDockerfileInputs currently propagates errors and aborts graph
construction; change it to treat errors as non-fatal: call
detectDockerfileInputs(config, readFile), and if it returns an error log a
warning (using the package's logger) that includes the error message and
context, do not return the error, and only append returned dockerfileInputSteps
to buildSteps when non-nil/non-empty so auto-detection stays additive rather
than failing the build graph.

Comment on lines +58 to +54
orgRepoTag, err := orgRepoTagFromPullString(ref)
if err != nil {
return nil, fmt.Errorf("failed to parse registry reference %s: %w", ref, err)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Parse errors should be best-effort, not fatal

This hard failure on parse errors can break jobs when encountering unexpected but valid registry reference formats. Per earlier review feedback, consider logging a warning and skipping instead of returning an error.

🔎 Proposed fix
 		orgRepoTag, err := orgRepoTagFromPullString(ref)
 		if err != nil {
-			return nil, fmt.Errorf("failed to parse registry reference %s: %w", ref, err)
+			logrus.WithError(err).Warnf("Dockerfile-inputs: skipping unrecognized registry reference %q", ref)
+			continue
 		}
📝 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.

Suggested change
orgRepoTag, err := orgRepoTagFromPullString(ref)
if err != nil {
return nil, fmt.Errorf("failed to parse registry reference %s: %w", ref, err)
}
orgRepoTag, err := orgRepoTagFromPullString(ref)
if err != nil {
logrus.WithError(err).Warnf("Dockerfile-inputs: skipping unrecognized registry reference %q", ref)
continue
}
🤖 Prompt for AI Agents
In @pkg/dockerfile/inputs.go around lines 58 - 61, The code currently treats a
failure from orgRepoTagFromPullString(ref) as fatal; change this to a
best-effort approach by catching the error, emitting a warning (using the
existing logger in scope) that includes ref and the error, and
skipping/continuing past this ref instead of returning the error so processing
can continue for other entries; make this change around the
orgRepoTagFromPullString call and ensure any downstream code that expects
orgRepoTag is not executed when parsing fails.

Comment on lines +93 to +49
if testCase.success != (err == nil) {
t.Fatalf("%s: didn't expect an error from ci-operator: %v; output:\n%v", testCase.name, err, string(output))
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify error messages for both failure modes

The error message is misleading when testCase.success is false but the command succeeds. Per earlier feedback, split into distinct messages for unexpected success vs. unexpected failure.

🔎 Proposed fix
-		if testCase.success != (err == nil) {
-			t.Fatalf("%s: didn't expect an error from ci-operator: %v; output:\n%v", testCase.name, err, string(output))
-		}
+		if testCase.success && err != nil {
+			t.Fatalf("%s: expected success but got error: %v; output:\n%v", testCase.name, err, string(output))
+		} else if !testCase.success && err == nil {
+			t.Fatalf("%s: expected failure but command succeeded; output:\n%v", testCase.name, string(output))
+		}
📝 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.

Suggested change
if testCase.success != (err == nil) {
t.Fatalf("%s: didn't expect an error from ci-operator: %v; output:\n%v", testCase.name, err, string(output))
}
if testCase.success && err != nil {
t.Fatalf("%s: expected success but got error: %v; output:\n%v", testCase.name, err, string(output))
} else if !testCase.success && err == nil {
t.Fatalf("%s: expected failure but command succeeded; output:\n%v", testCase.name, string(output))
}

@Prucek
Copy link
Member Author

Prucek commented Jan 6, 2026

/test e2e

@Prucek Prucek force-pushed the dockerfile-inputs branch from 4c6b6d5 to 275363c Compare January 7, 2026 14:19
@Prucek
Copy link
Member Author

Prucek commented Jan 7, 2026

/test e2e

@Prucek Prucek force-pushed the dockerfile-inputs branch from 275363c to 966e16b Compare January 7, 2026 14:24
Copy link

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @pkg/dockerfile/inputs_test.go:
- Around line 185-190: Update the test case name string "wrong reguistry format"
to the correct spelling "wrong registry format" in the table-driven test entry
(the struct literal with fields name, pullString, expected, expectError) so the
test description is accurate; search for the entry containing pullString
"registry.ci.openshift.org/ocp:latest" or the name value to locate and fix it.
🧹 Nitpick comments (2)
pkg/dockerfile/inputs.go (1)

75-78: Dockerfile instructions are case-insensitive; consider normalizing

The check filters lines containing FROM, COPY, or copy, but Dockerfile instructions are case-insensitive. A line like from registry.ci... or From registry.ci... would be skipped.

♻️ Suggested fix
 	for _, line := range bytes.Split(dockerfile, []byte("\n")) {
-		if !bytes.Contains(line, []byte("FROM")) && !bytes.Contains(line, []byte("COPY")) && !bytes.Contains(line, []byte("copy")) {
+		upperLine := bytes.ToUpper(line)
+		if !bytes.Contains(upperLine, []byte("FROM")) && !bytes.Contains(upperLine, []byte("COPY")) {
 			continue
 		}
pkg/defaults/defaults.go (1)

1065-1068: Inconsistent error handling: consider making processing failures best-effort too

Read failures at lines 1056-1059 are gracefully skipped with a debug log, but processing failures here are fatal. For consistency with the best-effort approach, consider logging a warning and continuing instead.

♻️ Suggested fix
 		imageSteps, err := processDetectedBaseImages(config, image, dockerfileContent, dockerfilePath)
 		if err != nil {
-			return nil, err
+			logrus.WithError(err).WithField("image", image.To).Warn("Failed to process detected base images, skipping")
+			continue
 		}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 4c6b6d5 and 966e16b.

📒 Files selected for processing (6)
  • pkg/defaults/defaults.go
  • pkg/defaults/defaults_test.go
  • pkg/dockerfile/inputs.go
  • pkg/dockerfile/inputs_test.go
  • test/e2e/dockerfile-inputs/config.yaml
  • test/e2e/dockerfile-inputs/e2e_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/defaults/defaults_test.go
  • test/e2e/dockerfile-inputs/config.yaml
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • test/e2e/dockerfile-inputs/e2e_test.go
  • pkg/dockerfile/inputs.go
  • pkg/defaults/defaults.go
  • pkg/dockerfile/inputs_test.go
🧬 Code graph analysis (3)
test/e2e/dockerfile-inputs/e2e_test.go (1)
pkg/testhelper/accessory.go (1)
  • T (51-57)
pkg/dockerfile/inputs.go (1)
pkg/api/types.go (2)
  • ImageBuildInputs (2786-2796)
  • ImageStreamTagReference (499-506)
pkg/defaults/defaults.go (2)
pkg/api/types.go (8)
  • StepConfiguration (623-637)
  • ImageBuildInputs (2786-2796)
  • ImageStreamTagReference (499-506)
  • InputImageTagStepConfiguration (643-646)
  • InputImage (685-692)
  • PipelineImageStreamTagReference (2531-2531)
  • ImageStreamSource (704-707)
  • ImageStreamSourceBase (698-698)
pkg/dockerfile/inputs.go (1)
  • DetectInputsFromDockerfile (34-68)
🔇 Additional comments (7)
pkg/dockerfile/inputs.go (2)

108-129: LGTM!

The parsing logic correctly handles both standard registry references and the special quay-proxy format with underscore-encoded tags.


148-187: The function is actively used in production code at cmd/registry-replacer/main.go:305, so no action is needed here.

Likely an incorrect or invalid review comment.

pkg/defaults/defaults.go (2)

1075-1096: LGTM!

The function structure is clean with an early return for the literal case, and the path construction logic correctly handles the various configuration options.


1119-1147: LGTM!

The logic correctly handles duplicate detection via isBaseImagePresent, adds new base images to the configuration, and creates appropriate InputImageTagStepConfiguration entries. The informative logging will help users understand what's being auto-detected.

test/e2e/dockerfile-inputs/e2e_test.go (1)

21-34: LGTM!

Good coverage of the expected detection scenarios including single/multiple references, quay-proxy format, manual input skipping, and existing base image matching.

pkg/dockerfile/inputs_test.go (2)

11-167: LGTM!

Comprehensive test coverage including empty dockerfile, single/multiple registry references, quay-proxy variants, manual replacement skipping, non-registry references, mixed scenarios, and duplicate handling.


226-293: LGTM!

Good test coverage for the replacement candidates extraction, including multi-stage builds and COPY --from scenarios.

@Prucek Prucek force-pushed the dockerfile-inputs branch from 966e16b to 041eb39 Compare January 8, 2026 12:51
@Prucek
Copy link
Member Author

Prucek commented Jan 8, 2026

/test e2e

Copy link

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @pkg/defaults/defaults.go:
- Around line 1128-1134: When isBaseImagePresent returns a presentAlias but the
matched presentBaseImage has an empty As, avoid inserting an empty string into
image.Inputs[presentAlias].As; update the block that assigns
image.Inputs[presentAlias] so it checks presentBaseImage.As and if empty uses
presentAlias (or otherwise omits the As slice), e.g. compute a non-empty asValue
= presentBaseImage.As != "" ? presentBaseImage.As : presentAlias and set
ImageBuildInputs.As to []string{asValue}; alternatively add a validation step in
config loading to ensure BaseImages always have As populated.

In @pkg/dockerfile/inputs_test.go:
- Around line 185-190: Update the test case name string to correct the typo:
change the "name" field value in the failing test case from "wrong reguistry
format" to "wrong registry format" in the test table entry (the struct literal
with pullString "registry.ci.openshift.org/ocp:latest" and expectError true) so
the test description is spelled correctly.
🧹 Nitpick comments (1)
pkg/defaults/defaults.go (1)

1084-1092: Consider consistent path formatting.

The path construction prepends ./ when there's no ContextDir (line 1091), but doesn't for paths with ContextDir (line 1089). This inconsistency is minor but could cause confusion in log messages.

♻️ Suggested fix for consistency
 	if image.ContextDir != "" {
 		dockerfilePath = fmt.Sprintf("%s/%s", image.ContextDir, dockerfilePath)
-	} else {
-		dockerfilePath = fmt.Sprintf("./%s", dockerfilePath)
 	}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 966e16b and 041eb39.

📒 Files selected for processing (7)
  • pkg/defaults/defaults.go
  • pkg/defaults/defaults_test.go
  • pkg/dockerfile/inputs.go
  • pkg/dockerfile/inputs_test.go
  • test/e2e/dockerfile-inputs/e2e_test.go
  • test/e2e/dockerfile-inputs/testdata/config.yaml
  • test/e2e/dockerfile-inputs/testdata/real.yaml
🚧 Files skipped from review as they are similar to previous changes (3)
  • test/e2e/dockerfile-inputs/e2e_test.go
  • pkg/dockerfile/inputs.go
  • pkg/defaults/defaults_test.go
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • test/e2e/dockerfile-inputs/testdata/config.yaml
  • pkg/defaults/defaults.go
  • test/e2e/dockerfile-inputs/testdata/real.yaml
  • pkg/dockerfile/inputs_test.go
🧬 Code graph analysis (2)
pkg/defaults/defaults.go (2)
pkg/api/types.go (7)
  • StepConfiguration (623-637)
  • ImageBuildInputs (2792-2802)
  • ImageStreamTagReference (499-506)
  • InputImageTagStepConfiguration (643-646)
  • InputImage (685-692)
  • ImageStreamSource (704-707)
  • ImageStreamSourceBase (698-698)
pkg/dockerfile/inputs.go (1)
  • DetectInputsFromDockerfile (34-68)
pkg/dockerfile/inputs_test.go (2)
pkg/api/types.go (2)
  • ImageBuildInputs (2792-2802)
  • ImageStreamTagReference (499-506)
pkg/dockerfile/inputs.go (1)
  • DetectInputsFromDockerfile (34-68)
🔇 Additional comments (7)
pkg/defaults/defaults.go (3)

1041-1047: LGTM on integration point.

The integration of Dockerfile input detection is cleanly placed after source steps and before returning build steps. Error handling properly wraps and propagates failures.


1051-1075: LGTM on detection orchestration.

The function appropriately handles read failures gracefully by logging at debug level and continuing. This ensures the auto-detection feature doesn't break builds when Dockerfiles are unavailable or malformed.


1156-1163: LGTM on base image presence check.

The comparison correctly uses the image identity fields (Namespace, Name, Tag) while excluding As which is just an alias.

pkg/dockerfile/inputs_test.go (2)

11-167: Solid test coverage for DetectInputsFromDockerfile.

The test cases comprehensively cover the main scenarios including empty input, single/multiple references, different registry formats (registry.ci.openshift.org, quay-proxy, registry.svc.ci.openshift.org), manual replacement skipping, and deduplication.


226-293: LGTM on extraction tests.

Good coverage of FROM instruction parsing including multi-stage builds and COPY --from scenarios. The set membership verification approach is appropriate for unordered results.

test/e2e/dockerfile-inputs/testdata/real.yaml (1)

1-30: LGTM on realistic test configuration.

This configuration provides a real-world example that exercises the build pipeline with from_repository: true, external base images, and container-based tests. Good addition for e2e validation.

test/e2e/dockerfile-inputs/testdata/config.yaml (1)

1-71: Excellent test configuration coverage.

This config comprehensively tests the Dockerfile input detection feature including:

  • Single and multiple registry references
  • quay-proxy format handling
  • Manual input precedence (manual-inputs case)
  • COPY --from scenarios
  • Non-registry references (should be ignored)
  • Existing base image detection

The detect-existing-base-image case (lines 59-62) correctly tests against the os base image defined in lines 2-5, ensuring the duplicate detection logic works.

@Prucek Prucek force-pushed the dockerfile-inputs branch from 041eb39 to 36e9780 Compare January 8, 2026 13:27
@Prucek Prucek force-pushed the dockerfile-inputs branch from 36e9780 to 9589379 Compare January 8, 2026 14:01
Copy link

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @pkg/defaults/defaults.go:
- Around line 1128-1134: When a matching existing base image is detected via
isBaseImagePresent, the code currently sets image.Inputs[presentAlias].As to
presentBaseImage.As (which is often empty) causing wrong replacements; change
the assignment so the As value uses the detected registry reference baseImage.As
instead of presentBaseImage.As (i.e., set image.Inputs[presentAlias] =
api.ImageBuildInputs{ As: []string{baseImage.As} }) and keep the rest of the
logic (log and continue) unchanged.

In @pkg/dockerfile/inputs.go:
- Around line 148-198: The functions extractReplacementCandidatesFromDockerfile
and nodeHasFromRef are dead code; either remove both functions or keep them with
a clear TODO explaining future intent and why they’re retained (e.g., "TODO:
reserved for future Dockerfile image-ref extraction used by X feature — keep
until feature Y is implemented"), and ensure any references/commented usage are
noted; if you remove them, also remove related imports (bytes, imagebuilder,
parser, sets, strings, fmt) that become unused and update any tests or
documentation that referenced them.
- Line 76: The filter currently checks for uppercase "FROM" but handles
"COPY"/"copy" case-insensitively; update the condition that filters lines (the
if using bytes.Contains(line, []byte("FROM")) ...) to perform a case-insensitive
match for instructions—e.g., compute lower := bytes.ToLower(line) and use
bytes.Contains(lower, []byte("from")) and bytes.Contains(lower, []byte("copy"))
(or use bytes.EqualFold variants) so both "FROM" and "from" are detected
consistently with "COPY"/"copy".
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 36e9780 and 9589379.

📒 Files selected for processing (7)
  • pkg/defaults/defaults.go
  • pkg/defaults/defaults_test.go
  • pkg/dockerfile/inputs.go
  • pkg/dockerfile/inputs_test.go
  • test/e2e/dockerfile-inputs/e2e_test.go
  • test/e2e/dockerfile-inputs/testdata/config.yaml
  • test/e2e/dockerfile-inputs/testdata/real.yaml
🚧 Files skipped from review as they are similar to previous changes (3)
  • test/e2e/dockerfile-inputs/testdata/real.yaml
  • pkg/defaults/defaults_test.go
  • test/e2e/dockerfile-inputs/testdata/config.yaml
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • test/e2e/dockerfile-inputs/e2e_test.go
  • pkg/defaults/defaults.go
  • pkg/dockerfile/inputs.go
  • pkg/dockerfile/inputs_test.go
🧬 Code graph analysis (2)
test/e2e/dockerfile-inputs/e2e_test.go (1)
pkg/testhelper/accessory.go (1)
  • T (51-57)
pkg/dockerfile/inputs.go (2)
pkg/api/types.go (2)
  • ImageBuildInputs (2792-2802)
  • ImageStreamTagReference (499-506)
pkg/util/util.go (1)
  • Contains (61-68)

Comment on lines 148 to 198
// extractReplacementCandidatesFromDockerfile extracts all image references from a Dockerfile
// This is used to understand which images are actually referenced in the Dockerfile
func extractReplacementCandidatesFromDockerfile(dockerfile []byte) (sets.Set[string], error) {
replacementCandidates := sets.Set[string]{}
node, err := imagebuilder.ParseDockerfile(bytes.NewBuffer(dockerfile))
if err != nil {
return nil, fmt.Errorf("failed to parse Dockerfile: %w", err)
}

// copied from https://github.com/openshift/builder/blob/1205194b1d67f2b68c163add5ae17e4b81962ec3/pkg/build/builder/common.go#L472-L497
// only difference: We collect the replacement source values rather than doing the replacements
names := make(map[string]string)
stages, err := imagebuilder.NewStages(node, imagebuilder.NewBuilder(make(map[string]string)))
if err != nil {
return nil, fmt.Errorf("failed to construct imagebuilder stages: %w", err)
}
for _, stage := range stages {
for _, child := range stage.Node.Children {
switch {
case child.Value == "from" && child.Next != nil:
image := child.Next
replacementCandidates.Insert(image.Value)
names[stage.Name] = image.Value
if alias := image.Next; alias != nil && alias.Value == "AS" && alias.Next != nil {
replacementCandidates.Insert(alias.Next.Value)
}
case child.Value == "copy":
if ref, ok := nodeHasFromRef(child); ok {
if len(ref) > 0 {
if _, ok := names[ref]; !ok {
replacementCandidates.Insert(ref)
}
}
}
}
}
}

return replacementCandidates, nil
}

// nodeHasFromRef checks if a COPY instruction has a --from flag
func nodeHasFromRef(node *parser.Node) (string, bool) {
for _, arg := range node.Flags {
if after, ok := strings.CutPrefix(arg, "--from="); ok {
from := after
return from, true
}
}
return "", false
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove unused functions or document future intent.

The functions extractReplacementCandidatesFromDockerfile and nodeHasFromRef are not called anywhere in the codebase. If these are intended for future use, add a TODO comment explaining the purpose. Otherwise, remove them to reduce code clutter.

🤖 Prompt for AI Agents
In @pkg/dockerfile/inputs.go around lines 148 - 198, The functions
extractReplacementCandidatesFromDockerfile and nodeHasFromRef are dead code;
either remove both functions or keep them with a clear TODO explaining future
intent and why they’re retained (e.g., "TODO: reserved for future Dockerfile
image-ref extraction used by X feature — keep until feature Y is implemented"),
and ensure any references/commented usage are noted; if you remove them, also
remove related imports (bytes, imagebuilder, parser, sets, strings, fmt) that
become unused and update any tests or documentation that referenced them.

@Prucek
Copy link
Member Author

Prucek commented Jan 8, 2026

/test e2e

@Prucek
Copy link
Member Author

Prucek commented Jan 9, 2026

/test e2e

Copy link

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

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In @pkg/defaults/defaults.go:
- Around line 1041-1075: detectDockerfileInputs currently always inspects
Dockerfiles even when an image has manually specified inputs; add a guard at the
start of the image loop to skip detection when len(image.Inputs) > 0 by logging
that detection is skipped for image.To and continuing the loop so
processDetectedBaseImages is not called for that image. Ensure the log uses
logrus.Infof with a clear message mentioning image.To and that detection was
skipped for manual inputs.
🧹 Nitpick comments (2)
pkg/dockerfile/inputs_test.go (1)

11-167: Unit coverage looks strong; consider adding a “matched by regex but unparsable” Dockerfile case to assert error propagation.

pkg/dockerfile/inputs.go (1)

102-126: Consider supporting digest-form (@sha256:...) or explicitly documenting it’s unsupported to avoid surprising failures.

If registryRegex (or future changes) can match digest pullspecs, orgRepoTagFromPullString will currently reject them.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9589379 and de386a0.

📒 Files selected for processing (6)
  • pkg/defaults/defaults.go
  • pkg/defaults/defaults_test.go
  • pkg/dockerfile/inputs.go
  • pkg/dockerfile/inputs_test.go
  • test/e2e/dockerfile-inputs/e2e_test.go
  • test/e2e/dockerfile-inputs/testdata/config.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/defaults/defaults_test.go
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • pkg/dockerfile/inputs_test.go
  • pkg/defaults/defaults.go
  • test/e2e/dockerfile-inputs/e2e_test.go
  • test/e2e/dockerfile-inputs/testdata/config.yaml
  • pkg/dockerfile/inputs.go
🧬 Code graph analysis (4)
pkg/dockerfile/inputs_test.go (2)
pkg/api/types.go (2)
  • ImageBuildInputs (2792-2802)
  • ImageStreamTagReference (499-506)
pkg/dockerfile/inputs.go (1)
  • DetectInputsFromDockerfile (31-65)
pkg/defaults/defaults.go (3)
pkg/api/types.go (8)
  • StepConfiguration (623-637)
  • ProjectDirectoryImageBuildStepConfiguration (2705-2728)
  • ImageBuildInputs (2792-2802)
  • ImageStreamTagReference (499-506)
  • InputImageTagStepConfiguration (643-646)
  • InputImage (685-692)
  • PipelineImageStreamTagReference (2537-2537)
  • ImageStreamSource (704-707)
pkg/dockerfile/inputs.go (1)
  • DetectInputsFromDockerfile (31-65)
cmd/repo-init/api.go (1)
  • BaseImages (69-69)
test/e2e/dockerfile-inputs/e2e_test.go (1)
pkg/testhelper/accessory.go (1)
  • T (51-57)
pkg/dockerfile/inputs.go (1)
pkg/api/types.go (2)
  • ImageBuildInputs (2792-2802)
  • ImageStreamTagReference (499-506)
🔇 Additional comments (3)
test/e2e/dockerfile-inputs/testdata/config.yaml (1)

1-70: Good e2e coverage matrix for auto-detection + manual override + reuse scenarios.

pkg/dockerfile/inputs_test.go (1)

169-224: Parsing tests for org/repo/tag (incl. quay-proxy encoding) look correct and readable.

test/e2e/dockerfile-inputs/e2e_test.go (1)

12-55: E2E assertion relies on exact log strings; please ensure production emits “manual inputs defined” at the same verbosity.

This test will be flaky if log wording/level diverges.

Comment on lines +1041 to +1075
// Detect Dockerfile inputs for project images and add InputImageTagStepConfiguration entries
dockerfileInputSteps, err := detectDockerfileInputs(config, readFile)
if err != nil {
return nil, fmt.Errorf("failed to detect Dockerfile inputs: %w", err)
}
buildSteps = append(buildSteps, dockerfileInputSteps...)

return buildSteps, nil
}

// detectDockerfileInputs reads Dockerfiles for project images and detects registry.ci.openshift.org
// references that should be added as base images
func detectDockerfileInputs(config *api.ReleaseBuildConfiguration, readFile readFile) ([]api.StepConfiguration, error) {
var steps []api.StepConfiguration

for i := range config.Images {
image := &config.Images[i]
dockerfileContent, dockerfilePath, err := readDockerfileForImage(image, readFile)
if err != nil {
logrus.WithError(err).WithField("image", image.To).Debug("Failed to read Dockerfile for input detection, skipping")
continue
}
if dockerfileContent == nil {
continue
}
logrus.Infof("Detecting base images for \"%s\" from Dockerfile at \"%s\"", image.To, dockerfilePath)
imageSteps, err := processDetectedBaseImages(config, image, dockerfileContent, dockerfilePath)
if err != nil {
return nil, err
}
steps = append(steps, imageSteps...)
}

return steps, nil
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the full context around the flagged lines
cd /repo 2>/dev/null || cd . 
cat -n pkg/defaults/defaults.go | sed -n '1020,1100p'

Repository: openshift/ci-tools

Length of output: 3291


🏁 Script executed:

# Search for the e2e test that validates this behavior
find . -type f -name "*.go" -path "*/e2e/*" | head -20

Repository: openshift/ci-tools

Length of output: 737


🏁 Script executed:

# Look for test files related to Dockerfile input detection
fd "test" -e go | grep -i dockerfile | head -20

Repository: openshift/ci-tools

Length of output: 130


🏁 Script executed:

# Search for references to image inputs and Dockerfile detection
rg "detectDockerfileInputs" -A 5 -B 5 --type go

Repository: openshift/ci-tools

Length of output: 1498


🏁 Script executed:

# Examine the e2e test for dockerfile-inputs
cat -n test/e2e/dockerfile-inputs/e2e_test.go

Repository: openshift/ci-tools

Length of output: 3761


🏁 Script executed:

# Look at the unit tests for inputs
cat -n pkg/dockerfile/inputs_test.go

Repository: openshift/ci-tools

Length of output: 7687


🏁 Script executed:

# Search for input.As references in the codebase
rg "\.As" -B 3 -A 3 --type go | grep -i input | head -50

Repository: openshift/ci-tools

Length of output: 3393


🏁 Script executed:

# Search for image.Inputs references
rg "image\.Inputs" --type go | head -20

Repository: openshift/ci-tools

Length of output: 1612


🏁 Script executed:

# Look at the api.ProjectDirectoryImageBuildStepConfiguration struct
rg "type ProjectDirectoryImageBuildStepConfiguration" -A 30 --type go

Repository: openshift/ci-tools

Length of output: 1916


🏁 Script executed:

# Find and read the e2e test config
find test/e2e/dockerfile-inputs -name "*.yaml" -o -name "config*"

Repository: openshift/ci-tools

Length of output: 109


🏁 Script executed:

# Read the test config
cat -n test/e2e/dockerfile-inputs/testdata/config.yaml

Repository: openshift/ci-tools

Length of output: 2526


🏁 Script executed:

# Find processDetectedBaseImages function
rg "func processDetectedBaseImages" -A 40 --type go

Repository: openshift/ci-tools

Length of output: 2501


🏁 Script executed:

# Search for "Skipping Dockerfile inputs detection" message
rg "Skipping Dockerfile inputs detection" --type go -B 5 -A 5

Repository: openshift/ci-tools

Length of output: 2071


🏁 Script executed:

# Search for the exact message expected by e2e test
rg "Skipping Dockerfile inputs detection: manual inputs defined" --type go

Repository: openshift/ci-tools

Length of output: 167


🏁 Script executed:

# Let's check if there's any logic to skip entire image detection based on manual inputs
rg "manual.*input" --type go -i | grep -i skip

Repository: openshift/ci-tools

Length of output: 241


🏁 Script executed:

# Look for where manual inputs are checked at the image level (not individual references)
rg "len.*Inputs.*>.*0" --type go -B 3 -A 3 | head -40

Repository: openshift/ci-tools

Length of output: 427


🏁 Script executed:

# Check the detectDockerfileInputs function more carefully - does it have any early return logic?
cat -n pkg/defaults/defaults.go | sed -n '1053,1075p'

Repository: openshift/ci-tools

Length of output: 1030


🏁 Script executed:

# Search for any condition checking if an image has inputs before processing
rg "if.*image\.Inputs" --type go -B 2 -A 2 | head -50

Repository: openshift/ci-tools

Length of output: 1295


🏁 Script executed:

# Look at the unit test case "skip when manual inputs exist"
rg -A 30 "skip when manual inputs exist" pkg/defaults/defaults_test.go

Repository: openshift/ci-tools

Length of output: 1102


🏁 Script executed:

# Get full context of defaults_test.go around this test case
grep -n "skip when manual inputs exist" pkg/defaults/defaults_test.go

Repository: openshift/ci-tools

Length of output: 110


🏁 Script executed:

# Read the test to understand expected behavior
cat -n pkg/defaults/defaults_test.go | sed -n '1,50p'

Repository: openshift/ci-tools

Length of output: 1884


🏁 Script executed:

# Find the test case in defaults_test.go
rg "\"skip when manual inputs exist\"" -A 50 --type go

Repository: openshift/ci-tools

Length of output: 3155


🏁 Script executed:

# Let's search more broadly for "manual inputs defined"
rg "manual inputs defined" --type go

Repository: openshift/ci-tools

Length of output: 167


🏁 Script executed:

# Let's look at which function the unit test is testing
grep -B 20 "skip when manual inputs exist" pkg/defaults/defaults_test.go | head -30

Repository: openshift/ci-tools

Length of output: 646


🏁 Script executed:

# Find the test function name
cat -n pkg/defaults/defaults_test.go | sed -n '2430,2480p'

Repository: openshift/ci-tools

Length of output: 2037


🏁 Script executed:

# Check if there's another version of detectDockerfileInputs or processDetectedBaseImages
rg "detectDockerfileInputs|processDetectedBaseImages" --type go -l

Repository: openshift/ci-tools

Length of output: 116


🏁 Script executed:

# Find the test function that uses these test cases
cat -n pkg/defaults/defaults_test.go | sed -n '2400,2430p'

Repository: openshift/ci-tools

Length of output: 1283


🏁 Script executed:

# Look for the function that processes these test cases
rg "for.*testCases|for.*tc.*:=" pkg/defaults/defaults_test.go -B 5 -A 2 | head -50

Repository: openshift/ci-tools

Length of output: 1377


🏁 Script executed:

# Get the full test function name and see what it's testing
cat -n pkg/defaults/defaults_test.go | sed -n '2390,2410p'

Repository: openshift/ci-tools

Length of output: 911


🏁 Script executed:

# Search for where the test cases are defined and what function they test
rg "testCases\s*:=\s*\[\]struct" -B 50 pkg/defaults/defaults_test.go | tail -60

Repository: openshift/ci-tools

Length of output: 1512


🏁 Script executed:

# Look at processDetectedBaseImages more completely
cat -n pkg/defaults/defaults.go | sed -n '1102,1170p'

Repository: openshift/ci-tools

Length of output: 3192


🏁 Script executed:

# Check if there's a guard at the beginning of processDetectedBaseImages
rg "func processDetectedBaseImages" -A 60 pkg/defaults/defaults.go

Repository: openshift/ci-tools

Length of output: 2316


🏁 Script executed:

# Search for the "manual inputs defined" log message - it should be somewhere
rg "manual.*inputs.*defined" --type go -B 3 -A 3

Repository: openshift/ci-tools

Length of output: 934


🏁 Script executed:

# Let me check if there's a different version or if the code was recently changed
git log --oneline pkg/defaults/defaults.go | head -10

Repository: openshift/ci-tools

Length of output: 103


🏁 Script executed:

# Check the git log more carefully - when was the unit test added?
git log --oneline -p pkg/defaults/defaults_test.go | grep -B 5 -A 5 "skip when manual inputs exist" | head -30

Repository: openshift/ci-tools

Length of output: 461


🏁 Script executed:

# Search for where "Skipping Dockerfile inputs detection: manual inputs defined" should be logged
rg "Skipping.*Dockerfile" --type go

Repository: openshift/ci-tools

Length of output: 303


🏁 Script executed:

# Let's verify what the code currently does - does it skip the entire image or just individual references?
rg "if len.*image\.Inputs" --type go -B 3 -A 3

Repository: openshift/ci-tools

Length of output: 427


🏁 Script executed:

# Check if detectDockerfileInputs has been recently modified
git log --oneline -p pkg/defaults/defaults.go | grep -A 30 "func detectDockerfileInputs" | head -50

Repository: openshift/ci-tools

Length of output: 1290


🏁 Script executed:

# Let me check what the exact error message is when running tests
# Search for the test execution to see if it's skipped or something else
rg "manual.*inputs.*exist" pkg/defaults/defaults_test.go -B 5 -A 10

Repository: openshift/ci-tools

Length of output: 556


🏁 Script executed:

# Let me check if there's a recent change to add this guard
git log -p pkg/defaults/defaults.go | grep -B 20 -A 20 "len.*Inputs.*> 0" | head -60

Repository: openshift/ci-tools

Length of output: 44


🏁 Script executed:

# Check the git history for the e2e test to see when it was added
git log --oneline test/e2e/dockerfile-inputs/e2e_test.go

Repository: openshift/ci-tools

Length of output: 103


🏁 Script executed:

# Look at the specific commit for the e2e test
git show de386a04a:test/e2e/dockerfile-inputs/e2e_test.go | grep -A 10 -B 10 "manual inputs defined"

Repository: openshift/ci-tools

Length of output: 1402


🏁 Script executed:

# Check if detectDockerfileInputs should have a guard but doesn't
git log -p --all pkg/defaults/defaults.go | grep -B 5 -A 15 "len(image.Inputs) > 0" | head -80

Repository: openshift/ci-tools

Length of output: 44


Add guard to skip image detection when manual inputs are already defined. The code currently does not skip Dockerfile input detection for images that have manual inputs configured, but both the unit test and e2e test expect this behavior. When an image has Inputs defined (i.e., len(image.Inputs) > 0), the entire detection should be skipped to respect the manual configuration. Add a check in detectDockerfileInputs before calling processDetectedBaseImages:

if len(image.Inputs) > 0 {
    logrus.Infof("Skipping Dockerfile inputs detection: manual inputs defined for \"%s\"", image.To)
    continue
}

This prevents auto-detection from overriding explicitly configured manual inputs.

🤖 Prompt for AI Agents
In @pkg/defaults/defaults.go around lines 1041 - 1075, detectDockerfileInputs
currently always inspects Dockerfiles even when an image has manually specified
inputs; add a guard at the start of the image loop to skip detection when
len(image.Inputs) > 0 by logging that detection is skipped for image.To and
continuing the loop so processDetectedBaseImages is not called for that image.
Ensure the log uses logrus.Infof with a clear message mentioning image.To and
that detection was skipped for manual inputs.

Comment on lines +1077 to +1100
// readDockerfileForImage reads the Dockerfile content for a given image configuration
// Returns content, a description of the source, and any error
func readDockerfileForImage(image *api.ProjectDirectoryImageBuildStepConfiguration, readFile readFile) ([]byte, string, error) {

if image.DockerfileLiteral != nil {
return []byte(*image.DockerfileLiteral), "dockerfile_literal", nil
}
dockerfilePath := "Dockerfile"
if image.DockerfilePath != "" {
dockerfilePath = image.DockerfilePath
}
if image.ContextDir != "" {
dockerfilePath = fmt.Sprintf("%s/%s", image.ContextDir, dockerfilePath)
} else {
dockerfilePath = fmt.Sprintf("./%s", dockerfilePath)
}

dockerfileContent, err := readFile(dockerfilePath)
if err != nil {
return nil, dockerfilePath, fmt.Errorf("failed to read Dockerfile at %s: %w", dockerfilePath, err)
}

return dockerfileContent, dockerfilePath, nil
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Harden Dockerfile path handling (use filepath.Join + prevent .. escape).

This reads from a source checkout in PR contexts; config-controlled DockerfilePath/ContextDir should not be able to traverse outside the repo workdir.

Proposed fix (join + clean)
-	dockerfilePath := "Dockerfile"
+	dockerfilePath := "Dockerfile"
 	if image.DockerfilePath != "" {
 		dockerfilePath = image.DockerfilePath
 	}
-	if image.ContextDir != "" {
-		dockerfilePath = fmt.Sprintf("%s/%s", image.ContextDir, dockerfilePath)
-	} else {
-		dockerfilePath = fmt.Sprintf("./%s", dockerfilePath)
-	}
+	if image.ContextDir != "" {
+		dockerfilePath = filepath.Join(image.ContextDir, dockerfilePath)
+	}
+	dockerfilePath = filepath.Clean(dockerfilePath)
+	if strings.HasPrefix(dockerfilePath, ".."+string(filepath.Separator)) || dockerfilePath == ".." {
+		return nil, dockerfilePath, fmt.Errorf("invalid Dockerfile path (escapes context): %s", dockerfilePath)
+	}
📝 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.

Suggested change
// readDockerfileForImage reads the Dockerfile content for a given image configuration
// Returns content, a description of the source, and any error
func readDockerfileForImage(image *api.ProjectDirectoryImageBuildStepConfiguration, readFile readFile) ([]byte, string, error) {
if image.DockerfileLiteral != nil {
return []byte(*image.DockerfileLiteral), "dockerfile_literal", nil
}
dockerfilePath := "Dockerfile"
if image.DockerfilePath != "" {
dockerfilePath = image.DockerfilePath
}
if image.ContextDir != "" {
dockerfilePath = fmt.Sprintf("%s/%s", image.ContextDir, dockerfilePath)
} else {
dockerfilePath = fmt.Sprintf("./%s", dockerfilePath)
}
dockerfileContent, err := readFile(dockerfilePath)
if err != nil {
return nil, dockerfilePath, fmt.Errorf("failed to read Dockerfile at %s: %w", dockerfilePath, err)
}
return dockerfileContent, dockerfilePath, nil
}
// readDockerfileForImage reads the Dockerfile content for a given image configuration
// Returns content, a description of the source, and any error
func readDockerfileForImage(image *api.ProjectDirectoryImageBuildStepConfiguration, readFile readFile) ([]byte, string, error) {
if image.DockerfileLiteral != nil {
return []byte(*image.DockerfileLiteral), "dockerfile_literal", nil
}
dockerfilePath := "Dockerfile"
if image.DockerfilePath != "" {
dockerfilePath = image.DockerfilePath
}
if image.ContextDir != "" {
dockerfilePath = filepath.Join(image.ContextDir, dockerfilePath)
}
dockerfilePath = filepath.Clean(dockerfilePath)
if strings.HasPrefix(dockerfilePath, ".."+string(filepath.Separator)) || dockerfilePath == ".." {
return nil, dockerfilePath, fmt.Errorf("invalid Dockerfile path (escapes context): %s", dockerfilePath)
}
dockerfileContent, err := readFile(dockerfilePath)
if err != nil {
return nil, dockerfilePath, fmt.Errorf("failed to read Dockerfile at %s: %w", dockerfilePath, err)
}
return dockerfileContent, dockerfilePath, nil
}

Comment on lines 1123 to 1134
for alias, baseImage := range detectedBaseImages {
if config.BaseImages == nil {
config.BaseImages = make(map[string]api.ImageStreamTagReference)
}

if presentAlias, presentBaseImage := isBaseImagePresent(config, baseImage); presentAlias != "" {
image.Inputs[presentAlias] = api.ImageBuildInputs{
As: []string{presentBaseImage.As},
}
logrus.Infof("Detected base image for \"%s\" from \"%s\" matches existing base image \"%s\"", image.To, dockerfilePath, presentAlias)
continue
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Bug: existing base image reuse sets Inputs.As to an empty string (likely), so Dockerfile replacement won’t happen.

When presentBaseImage.As is empty (typical for configured base_images), image.Inputs[presentAlias].As becomes [""] instead of the Dockerfile pullspec.

Proposed fix
 		if presentAlias, presentBaseImage := isBaseImagePresent(config, baseImage); presentAlias != "" {
 			image.Inputs[presentAlias] = api.ImageBuildInputs{
-				As: []string{presentBaseImage.As},
+				// Replace the Dockerfile pullspec with the existing base image alias.
+				As: []string{baseImage.As},
 			}
 			logrus.Infof("Detected base image for \"%s\" from \"%s\" matches existing base image \"%s\"", image.To, dockerfilePath, presentAlias)
 			continue
 		}

@Prucek Prucek force-pushed the dockerfile-inputs branch from de386a0 to cdbefa6 Compare January 9, 2026 09:54
Copy link

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
pkg/defaults/defaults_test.go (1)

2597-2609: Use standard library strings.Contains instead of custom helpers.

The containsString and contains helper functions reimplement functionality already available in the standard library's strings.Contains.

♻️ Simplify using standard library

Remove the custom helper functions and use strings.Contains directly:

-func containsString(s, substr string) bool {
-	return len(s) >= len(substr) && (s == substr || len(substr) == 0 ||
-		(len(s) > 0 && len(substr) > 0 && contains(s, substr)))
-}
-
-func contains(s, substr string) bool {
-	for i := 0; i <= len(s)-len(substr); i++ {
-		if s[i:i+len(substr)] == substr {
-			return true
-		}
-	}
-	return false
-}

At line 2356, update the call:

-				if !containsString(err.Error(), tc.expectedErrContain) {
+				if !strings.Contains(err.Error(), tc.expectedErrContain) {

Ensure strings is already imported (it is, from the existing import block).

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between de386a0 and cdbefa6.

📒 Files selected for processing (6)
  • pkg/defaults/defaults.go
  • pkg/defaults/defaults_test.go
  • pkg/dockerfile/inputs.go
  • pkg/dockerfile/inputs_test.go
  • test/e2e/dockerfile-inputs/e2e_test.go
  • test/e2e/dockerfile-inputs/testdata/config.yaml
🚧 Files skipped from review as they are similar to previous changes (4)
  • pkg/dockerfile/inputs_test.go
  • test/e2e/dockerfile-inputs/e2e_test.go
  • pkg/defaults/defaults.go
  • test/e2e/dockerfile-inputs/testdata/config.yaml
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • pkg/dockerfile/inputs.go
  • pkg/defaults/defaults_test.go
🧬 Code graph analysis (1)
pkg/defaults/defaults_test.go (1)
pkg/api/types.go (6)
  • ProjectDirectoryImageBuildStepConfiguration (2705-2728)
  • ProjectDirectoryImageBuildInputs (2746-2770)
  • ImageStreamTagReference (499-506)
  • ImageBuildInputs (2792-2802)
  • InputConfiguration (272-309)
  • InputImageTagStepConfiguration (643-646)
🔇 Additional comments (1)
pkg/dockerfile/inputs.go (1)

119-121: The hardcoded check at line 119 correctly handles the known quay-proxy pattern. The code is not fragile: it specifically targets the /openshift/ci path which encodes org/repo/tag in the tag field (org_repo_tag format), while other quay-proxy patterns (e.g., /openshift/release) correctly fall through to standard parsing. Test coverage confirms both cases work as intended.

@jmguzik
Copy link
Contributor

jmguzik commented Jan 9, 2026

/lgtm

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Jan 9, 2026
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 9, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: jmguzik, Prucek

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-robot
Copy link
Contributor

/retest-required

Remaining retests: 0 against base HEAD 36264d7 and 2 for PR HEAD cdbefa6 in total

@openshift-ci-robot
Copy link
Contributor

Scheduling required tests:
/test e2e

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test integration-optional-test

var steps []api.StepConfiguration

for i := range config.Images {
image := &config.Images[i]
Copy link
Member

Choose a reason for hiding this comment

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

I don't see why you need to do that here. Just do for _, image := range config.Images and use the image var.

logrus.WithError(err).WithField("image", image.To).Debug("Failed to read Dockerfile for input detection, skipping")
continue
}
if dockerfileContent == nil {
Copy link
Member

Choose a reason for hiding this comment

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

I am not sure how this will ever happen.

// readDockerfileForImage reads the Dockerfile content for a given image configuration
// Returns content, a description of the source, and any error
func readDockerfileForImage(image *api.ProjectDirectoryImageBuildStepConfiguration, readFile readFile) ([]byte, string, error) {

Copy link
Member

Choose a reason for hiding this comment

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

nit: lets remove that line.

if image.DockerfilePath != "" {
dockerfilePath = image.DockerfilePath
}
if image.ContextDir != "" {
Copy link
Member

Choose a reason for hiding this comment

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

This block can be simplified as:

dockerfilePath = fmt.Sprintf("./%s", dockerfilePath)
if image.ContextDir != "" {
    dockerfilePath = fmt.Sprintf("%s/%s", image.ContextDir, dockerfilePath)
}

}

// processDetectedBaseImages detects base images from a Dockerfile and updates the configuration
func processDetectedBaseImages(
Copy link
Member

Choose a reason for hiding this comment

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

Let's put all args in one line.

}
orgRepoTag, err := orgRepoTagFromPullString(ref)
if err != nil {
return nil, fmt.Errorf("failed to parse registry reference %s: %w", ref, err)
Copy link
Member

Choose a reason for hiding this comment

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

Do we want to continue parsing the rest?

}

// extractRegistryReferences finds all registry.ci.openshift.org and quay-proxy.ci.openshift.org references in the Dockerfile
func extractRegistryReferences(dockerfile []byte) []string {
Copy link
Member

Choose a reason for hiding this comment

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

Are there any official libraries that we can use instead? I guess you need to do this because of multi stages, which you could just grep the FROM only.


for _, line := range bytes.Split(dockerfile, []byte("\n")) {
upper := bytes.ToUpper(line)
if !bytes.Contains(upper, []byte("FROM")) && !bytes.Contains(upper, []byte("COPY")) {
Copy link
Member

Choose a reason for hiding this comment

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

why COPY?

func orgRepoTagFromPullString(pullString string) (orgRepoTag, error) {
res := orgRepoTag{}

slashSplit := strings.Split(pullString, "/")
Copy link
Member

Choose a reason for hiding this comment

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

I think we already have this logic somewhere in ci-tools.


// orgRepoTagFromQuayProxyTag parses a quay-proxy tag like "ocp_builder_rhel-9-golang-1.21-openshift-4.16"
// which encodes org_repo_tag format, into its component parts
func orgRepoTagFromQuayProxyTag(quayTag string) (orgRepoTag, error) {
Copy link
Member

Choose a reason for hiding this comment

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

This logic should already exists somewhere in ci-tools as well.

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 9, 2026

@Prucek: 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/breaking-changes cdbefa6 link false /test breaking-changes
ci/prow/integration-optional-test cdbefa6 link true /test integration-optional-test
ci/prow/e2e cdbefa6 link true /test e2e

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.

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.

5 participants