Skip to content

WIP: Split multi-arch source pipeline into arch-independent scr + arch-specific src#4995

Open
joepvd wants to merge 1 commit intoopenshift:mainfrom
joepvd:multi-arch-scr-from-scratch
Open

WIP: Split multi-arch source pipeline into arch-independent scr + arch-specific src#4995
joepvd wants to merge 1 commit intoopenshift:mainfrom
joepvd:multi-arch-scr-from-scratch

Conversation

@joepvd
Copy link
Contributor

@joepvd joepvd commented Mar 7, 2026

Summary

  • Introduces an architecture-independent scr image (FROM scratch) that clones source once, eliminating redundant git clones in multi-arch builds
  • Adds srcAssemblyStep that layers the cloned source from scr onto each arch-specific build root to produce per-architecture src images
  • Downstream pipeline steps (bin, test-bin, tests, images) continue to depend on src unchanged

Motivation

In multi-arch CI builds, source code is architecture-independent but was being cloned separately for each architecture (src-amd64, src-arm64). This is wasteful — the git clone is identical regardless of CPU architecture.

Design

The single sourceStep (producing src) is split into two steps:

  1. scr — Built once on a single architecture using a multi-stage Dockerfile. First stage clones source using the build root + clonerefs, second stage (FROM scratch) contains only /go/src. Does not implement MultiArchStep.

  2. srcsrcAssemblyStep combines the arch-specific root with source from scr via COPY --from=scr. Implements MultiArchStep, producing src-amd64, src-arm64 etc. with manifest lists as before.

Test plan

  • Unit tests updated and passing for pkg/api, pkg/steps, pkg/defaults, pkg/validation
  • Verify in a real multi-arch CI run that scr is built once and src-{arch} variants are assembled correctly
  • Verify cross-architecture COPY --from=scr works (amd64-built scr used on arm64 build node)

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Support for scratch-source pipeline images and a new source-assembly step for SCR-based workflows.
    • Architecture-independent source image builds via multi-stage (root → scratch) Docker flows.
  • Tests

    • Updated test fixtures and cases to use scratch-source targets and validate the new assembly step and multi-stage builds.

@openshift-ci-robot
Copy link
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

coderabbitai bot commented Mar 7, 2026

Walkthrough

Adds SCR (scratch-source) support: new SrcAssemblyStepConfiguration and srcAssemblyStep that produce architecture-specific source images, refactors source step emission to return multiple steps, converts source builds to a scratch-based multi-stage Dockerfile, and updates defaults, validation, tests, and handleBuild call sites.

Changes

Cohort / File(s) Summary
API Types
pkg/api/types.go
Added PipelineImageStreamTagReferenceScratchSource constant, SrcAssemblyStepConfiguration struct and TargetName(); added SrcAssemblyStepConfiguration *SrcAssemblyStepConfiguration field to StepConfiguration; updated source step docs.
Defaults & Test Expectations
pkg/defaults/defaults.go, pkg/defaults/defaults_test.go
Refactored sourceStepForRefsourceStepsForRef to emit multiple steps; consume SrcAssemblyStepConfiguration when generating steps; updated tests to expect additional SCR assembly steps and changed many To targets to scratch-source.
Source Step Implementation
pkg/steps/source.go, pkg/steps/source_test.go
Replaced single-stage sourceDockerfile with scratchSourceDockerfile; replaced createBuild with createScratchSourceBuild; added cloneRefs(); removed per-step architecture fields and multi-arch methods; tests renamed/adjusted for scratch-source.
Src Assembly Step
pkg/steps/src_assembly.go
New SrcAssemblyStep constructor and srcAssemblyStep implementation producing per-arch source images by combining scratch-source with arch-specific root images; includes srcAssemblyDockerfile and build orchestration.
HandleBuild Call Sites
pkg/steps/bundle_source.go, pkg/steps/project_image.go
Updated calls to handleBuild to remove the trailing predicate argument (call signature simplified).
Validation
pkg/validation/graph.go
Included ScratchSource in runtime-validated pipeline images and added handling for SrcAssemblyStepConfiguration when collecting validated targets.
Test Fixtures
pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_*.yaml
Renamed targets from srcscratch-source, updated pipeline image refs to pipeline:scratch-source, and converted Dockerfiles to two-stage flows (FROM root AS cloner + FROM scratch copying sources).

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Controller as Pipeline Controller
participant Builder as BuildClient
participant Pod as PodClient
participant ImageRegistry as ImageStream/Registry
Controller->>Builder: createScratchSourceBuild(spec referencing pipeline:scratch-source)
Builder->>ImageRegistry: resolve pipeline:scratch-source -> root digest
Builder->>Pod: start root/cloner build pod (cloner stage)
Pod-->>Builder: cloner build completes (produces cloner artifacts)
Controller->>Builder: SrcAssemblyStep requests per-arch builds
Builder->>ImageRegistry: pull architecture-specific root image digests
Builder->>Pod: start per-arch Dockerfile builds combining scratch-source + arch root
Pod-->>Builder: per-arch builds complete -> push arch-specific src images
Builder-->>Controller: report build results/creates target images

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ❓ Inconclusive The PR does not appear to contain Ginkgo BDD-style tests. Investigation shows standard Go testing framework usage with test data/fixtures. Ginkgo-specific quality checks cannot be properly applied. Verify whether this codebase uses Ginkgo testing framework. If not using Ginkgo, adjust checks to standard Go testing requirements instead.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: splitting the multi-arch source pipeline into an architecture-independent scratch-source image (scr) and architecture-specific src images, which aligns with the PR's core objective and substantial code changes across multiple files.
Stable And Deterministic Test Names ✅ Passed The PR uses standard Go testing framework (testing.T), not Ginkgo, making this check inapplicable.

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

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

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

❤️ Share

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

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Mar 7, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: joepvd
Once this PR has been reviewed and has the lgtm label, please assign smg247 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found 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

@joepvd joepvd force-pushed the multi-arch-scr-from-scratch branch from faa5edd to 3dfa5f4 Compare March 7, 2026 13:28
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.

🧹 Nitpick comments (2)
pkg/steps/src_assembly.go (1)

58-72: Consider simplifying the refs filtering logic.

The refs filtering logic correctly handles both primary refs and extra refs, filtering by config.Ref when specified. However, the pattern of building orgRepo and comparing it could be extracted to a helper for consistency with similar logic elsewhere.

♻️ Optional: Extract orgRepo matching to a helper
+func matchesRef(r prowv1.Refs, configRef string) bool {
+	if configRef == "" {
+		return true
+	}
+	return fmt.Sprintf("%s.%s", r.Org, r.Repo) == configRef
+}
+
 func (s *srcAssemblyStep) run(ctx context.Context) error {
 	var refs []prowv1.Refs
 	if s.jobSpec.Refs != nil {
-		r := *s.jobSpec.Refs
-		orgRepo := fmt.Sprintf("%s.%s", r.Org, r.Repo)
-		if s.config.Ref == "" || orgRepo == s.config.Ref {
+		if matchesRef(*s.jobSpec.Refs, s.config.Ref) {
 			refs = append(refs, r)
 		}
 	}
 	for _, r := range s.jobSpec.ExtraRefs {
-		orgRepo := fmt.Sprintf("%s.%s", r.Org, r.Repo)
-		if s.config.Ref == "" || orgRepo == s.config.Ref {
+		if matchesRef(r, s.config.Ref) {
 			refs = append(refs, r)
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/steps/src_assembly.go` around lines 58 - 72, The refs filtering in
srcAssemblyStep.run repeats building orgRepo and comparing to s.config.Ref for
both s.jobSpec.Refs and each entry in s.jobSpec.ExtraRefs; extract that logic
into a small helper function (e.g., func matchesRef(r prowv1.Refs, ref string)
bool) that constructs fmt.Sprintf("%s.%s", r.Org, r.Repo) and returns true when
ref=="" or orgRepo==ref, then call this helper when deciding to append for the
pointer case (jobSpec.Refs) and the loop over jobSpec.ExtraRefs to remove
duplication and keep behavior identical.
pkg/steps/source.go (1)

168-177: Consider removing unused metricsAgent field.

The metricsAgent field is passed to the struct via the SourceStep factory function (line 885, 895) but is not used anywhere in sourceStep's methods. The metrics are now handled internally by handleBuild via client.MetricsAgent().

This appears to be dead code after the refactor. Consider removing both the field and the corresponding parameter from the SourceStep factory function.

♻️ Proposed cleanup
 type sourceStep struct {
 	config          api.SourceStepConfiguration
 	resources       api.ResourceConfiguration
 	client          BuildClient
 	podClient       kubernetes.PodClient
 	jobSpec         *api.JobSpec
 	cloneAuthConfig *CloneAuthConfig
 	pullSecret      *corev1.Secret
-	metricsAgent    *metrics.MetricsAgent
 }

And update the factory function:

 func SourceStep(
 	config api.SourceStepConfiguration,
 	resources api.ResourceConfiguration,
 	buildClient BuildClient,
 	podClient kubernetes.PodClient,
 	jobSpec *api.JobSpec,
 	cloneAuthConfig *CloneAuthConfig,
 	pullSecret *corev1.Secret,
-	metricsAgent *metrics.MetricsAgent,
 ) api.Step {
 	return &sourceStep{
 		config:          config,
 		resources:       resources,
 		client:          buildClient,
 		podClient:       podClient,
 		jobSpec:         jobSpec,
 		cloneAuthConfig: cloneAuthConfig,
 		pullSecret:      pullSecret,
-		metricsAgent:    metricsAgent,
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/steps/source.go` around lines 168 - 177, The sourceStep struct contains
an unused field metricsAgent and the SourceStep factory function still
accepts/passes that parameter; remove the metricsAgent field from the sourceStep
struct and remove the corresponding parameter from the SourceStep factory
function signature and its internal assignment/argument passing (search for
sourceStep{... metricsAgent: ...} and the factory function that constructs
sourceStep) and update all call sites to stop providing that argument so the
code compiles; ensure no remaining references to metricsAgent exist in methods
on sourceStep and remove any related imports if they become unused.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@pkg/steps/source.go`:
- Around line 168-177: The sourceStep struct contains an unused field
metricsAgent and the SourceStep factory function still accepts/passes that
parameter; remove the metricsAgent field from the sourceStep struct and remove
the corresponding parameter from the SourceStep factory function signature and
its internal assignment/argument passing (search for sourceStep{...
metricsAgent: ...} and the factory function that constructs sourceStep) and
update all call sites to stop providing that argument so the code compiles;
ensure no remaining references to metricsAgent exist in methods on sourceStep
and remove any related imports if they become unused.

In `@pkg/steps/src_assembly.go`:
- Around line 58-72: The refs filtering in srcAssemblyStep.run repeats building
orgRepo and comparing to s.config.Ref for both s.jobSpec.Refs and each entry in
s.jobSpec.ExtraRefs; extract that logic into a small helper function (e.g., func
matchesRef(r prowv1.Refs, ref string) bool) that constructs fmt.Sprintf("%s.%s",
r.Org, r.Repo) and returns true when ref=="" or orgRepo==ref, then call this
helper when deciding to append for the pointer case (jobSpec.Refs) and the loop
over jobSpec.ExtraRefs to remove duplication and keep behavior identical.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro

Run ID: d5aa17fc-6323-4d92-92fd-2fd7f7de33ee

📥 Commits

Reviewing files that changed from the base of the PR and between 49a6a77 and 3dfa5f4.

⛔ Files ignored due to path filters (1)
  • pkg/api/zz_generated.deepcopy.go is excluded by !**/zz_generated*
📒 Files selected for processing (15)
  • pkg/api/types.go
  • pkg/defaults/defaults.go
  • pkg/defaults/defaults_test.go
  • pkg/steps/source.go
  • pkg/steps/source_test.go
  • pkg/steps/src_assembly.go
  • pkg/steps/testdata/zz_fixture_TestCreateScrBuild_basic_options_for_a_presubmit.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScrBuild_title_in_pull_gets_squashed.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScrBuild_with_OAuth_token.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScrBuild_with_a_path_alias.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScrBuild_with_a_pull_secret.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScrBuild_with_extra_refs.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScrBuild_with_extra_refs_setting_workdir_and_path_alias.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScrBuild_with_ssh_key.yaml
  • pkg/validation/graph.go

@joepvd joepvd force-pushed the multi-arch-scr-from-scratch branch from 3dfa5f4 to b97b312 Compare March 7, 2026 14:48
@joepvd joepvd changed the title Split multi-arch source pipeline into arch-independent scr + arch-specific src WIP: Split multi-arch source pipeline into arch-independent scr + arch-specific src Mar 7, 2026
@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Mar 7, 2026
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/defaults/defaults_test.go`:
- Around line 2315-2327: The comparator used in defaults_test.go (the anonymous
sort function that computes refA/refB from a.SourceStepConfiguration /
a.SrcAssemblyStepConfiguration and similarly for b) is not a strict total order
because different step variants can share the same Ref; update the comparator so
if refA == refB it returns a deterministic secondary ordering based on step kind
(e.g., derive kindA/kindB from which configuration is non-nil or an existing
Kind field and compare those strings/values), ensuring the comparator always
returns true or false strictly for any pair so cmpopts.SortSlices remains
deterministic.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro

Run ID: 2a643e86-aad0-44f8-b3a5-12419d9bde2d

📥 Commits

Reviewing files that changed from the base of the PR and between 3dfa5f4 and b97b312.

⛔ Files ignored due to path filters (2)
  • pkg/api/zz_generated.deepcopy.go is excluded by !**/zz_generated*
  • pkg/webreg/zz_generated.ci_operator_reference.go is excluded by !**/zz_generated*
📒 Files selected for processing (17)
  • pkg/api/types.go
  • pkg/defaults/defaults.go
  • pkg/defaults/defaults_test.go
  • pkg/steps/bundle_source.go
  • pkg/steps/project_image.go
  • pkg/steps/source.go
  • pkg/steps/source_test.go
  • pkg/steps/src_assembly.go
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_basic_options_for_a_presubmit.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_title_in_pull_gets_squashed.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_with_OAuth_token.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_with_a_path_alias.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_with_a_pull_secret.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_with_extra_refs.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_with_extra_refs_setting_workdir_and_path_alias.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_with_ssh_key.yaml
  • pkg/validation/graph.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/steps/source_test.go

Comment on lines +2315 to +2327
refA := ""
if a.SourceStepConfiguration != nil {
refA = a.SourceStepConfiguration.Ref
} else if a.SrcAssemblyStepConfiguration != nil {
refA = a.SrcAssemblyStepConfiguration.Ref
}
refB := ""
if b.SourceStepConfiguration != nil {
refB = b.SourceStepConfiguration.Ref
} else if b.SrcAssemblyStepConfiguration != nil {
refB = b.SrcAssemblyStepConfiguration.Ref
}
return refA < refB
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

Use a strict sort key here.

Both step variants for the same repo now share the same Ref, so this comparator returns false in both directions for those pairs. cmpopts.SortSlices expects a strict ordering; add a secondary key for the step kind so the helper stays deterministic.

Suggested fix
 			less := func(a, b api.StepConfiguration) bool {
-				refA := ""
+				refA, kindA := "", ""
 				if a.SourceStepConfiguration != nil {
 					refA = a.SourceStepConfiguration.Ref
+					kindA = "source"
 				} else if a.SrcAssemblyStepConfiguration != nil {
 					refA = a.SrcAssemblyStepConfiguration.Ref
+					kindA = "src-assembly"
 				}
-				refB := ""
+				refB, kindB := "", ""
 				if b.SourceStepConfiguration != nil {
 					refB = b.SourceStepConfiguration.Ref
+					kindB = "source"
 				} else if b.SrcAssemblyStepConfiguration != nil {
 					refB = b.SrcAssemblyStepConfiguration.Ref
+					kindB = "src-assembly"
 				}
-				return refA < refB
+				if refA != refB {
+					return refA < refB
+				}
+				return kindA < kindB
 			}
📝 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
refA := ""
if a.SourceStepConfiguration != nil {
refA = a.SourceStepConfiguration.Ref
} else if a.SrcAssemblyStepConfiguration != nil {
refA = a.SrcAssemblyStepConfiguration.Ref
}
refB := ""
if b.SourceStepConfiguration != nil {
refB = b.SourceStepConfiguration.Ref
} else if b.SrcAssemblyStepConfiguration != nil {
refB = b.SrcAssemblyStepConfiguration.Ref
}
return refA < refB
less := func(a, b api.StepConfiguration) bool {
refA, kindA := "", ""
if a.SourceStepConfiguration != nil {
refA = a.SourceStepConfiguration.Ref
kindA = "source"
} else if a.SrcAssemblyStepConfiguration != nil {
refA = a.SrcAssemblyStepConfiguration.Ref
kindA = "src-assembly"
}
refB, kindB := "", ""
if b.SourceStepConfiguration != nil {
refB = b.SourceStepConfiguration.Ref
kindB = "source"
} else if b.SrcAssemblyStepConfiguration != nil {
refB = b.SrcAssemblyStepConfiguration.Ref
kindB = "src-assembly"
}
if refA != refB {
return refA < refB
}
return kindA < kindB
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/defaults/defaults_test.go` around lines 2315 - 2327, The comparator used
in defaults_test.go (the anonymous sort function that computes refA/refB from
a.SourceStepConfiguration / a.SrcAssemblyStepConfiguration and similarly for b)
is not a strict total order because different step variants can share the same
Ref; update the comparator so if refA == refB it returns a deterministic
secondary ordering based on step kind (e.g., derive kindA/kindB from which
configuration is non-nil or an existing Kind field and compare those
strings/values), ensuring the comparator always returns true or false strictly
for any pair so cmpopts.SortSlices remains deterministic.

… + arch-specific src

Fixes the race condition (OCPBUGS-65845) where multiple ci-operator
instances building different architectures concurrently would conflict
on the shared pipeline ImageStream, causing "builds are using older
src image" errors.

The source pipeline is now two steps:
- scratch-source: arch-independent FROM-scratch image with cloned repo
- src assembly: per-architecture step copying scratch-source onto root

This eliminates the critical section where the race occurred and removes
the 5-minute sleep workaround along with the hardcoded multiArchRepos list.

Made-with: Cursor
@joepvd joepvd force-pushed the multi-arch-scr-from-scratch branch from b97b312 to af9afbf Compare March 7, 2026 17:13
@joepvd
Copy link
Contributor Author

joepvd commented Mar 7, 2026

/test images

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.

♻️ Duplicate comments (2)
pkg/defaults/defaults_test.go (1)

2314-2327: ⚠️ Potential issue | 🟡 Minor

Use a strict secondary key in this comparator.

SourceStepConfiguration and SrcAssemblyStepConfiguration can now share the same Ref, so this less function returns false in both directions for those pairs. cmpopts.SortSlices expects a strict ordering, and this can make the diff unstable.

♻️ Suggested fix
 			less := func(a, b api.StepConfiguration) bool {
-				refA := ""
+				refA, kindA := "", ""
 				if a.SourceStepConfiguration != nil {
 					refA = a.SourceStepConfiguration.Ref
+					kindA = "source"
 				} else if a.SrcAssemblyStepConfiguration != nil {
 					refA = a.SrcAssemblyStepConfiguration.Ref
+					kindA = "src-assembly"
 				}
-				refB := ""
+				refB, kindB := "", ""
 				if b.SourceStepConfiguration != nil {
 					refB = b.SourceStepConfiguration.Ref
+					kindB = "source"
 				} else if b.SrcAssemblyStepConfiguration != nil {
 					refB = b.SrcAssemblyStepConfiguration.Ref
+					kindB = "src-assembly"
 				}
-				return refA < refB
+				if refA != refB {
+					return refA < refB
+				}
+				return kindA < kindB
 			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/defaults/defaults_test.go` around lines 2314 - 2327, The comparator
function less (comparing api.StepConfiguration) isn't strict when
SourceStepConfiguration.Ref equals SrcAssemblyStepConfiguration.Ref; update less
to add a deterministic secondary key so it establishes a strict total order:
first compute refA/refB as now, then if refA != refB return refA < refB;
otherwise break ties by comparing a deterministic discriminator such as whether
SourceStepConfiguration is non-nil vs SrcAssemblyStepConfiguration (e.g., treat
SourceStepConfiguration < SrcAssemblyStepConfiguration), or compare another
stable field (like a Name/Path/ID) from the non-nil config, ensuring the
comparator always returns either true or false for any pair so
cmpopts.SortSlices gets a strict ordering.
pkg/defaults/defaults.go (1)

1123-1148: ⚠️ Potential issue | 🟠 Major

Keep LOCAL_IMAGE_SRC short-circuiting both source stages.

Line 1123 now emits scratch-source and src as separate steps. Because fromConfig() later applies checkForFullyQualifiedStep() per step, setting only LOCAL_IMAGE_SRC skips the assembly step but still runs the clone step. That changes the existing override contract and can still fail on clone auth/root import even when the final src image is already supplied externally. Please suppress the paired SourceStepConfiguration in that case and add a regression test for it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/defaults/defaults.go` around lines 1123 - 1148, The sourceStepsForRef
function currently emits two steps (SourceStepConfiguration and
SrcAssemblyStepConfiguration) which allows LOCAL_IMAGE_SRC to skip only the
assembly step; update sourceStepsForRef so that when the LOCAL_IMAGE_SRC
override is present it short-circuits both steps by omitting the
SourceStepConfiguration entirely (i.e., only emit the
SrcAssemblyStepConfiguration or suppress both as appropriate) so
checkForFullyQualifiedStep cannot accidentally run the clone stage; change
behavior around constructing orgRepo/root/scratchSource/source inside
sourceStepsForRef and ensure the logic checks for the LOCAL_IMAGE_SRC env var
before returning the slice, and add a regression test that sets LOCAL_IMAGE_SRC
and asserts the clone (SourceStepConfiguration) is not present.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@pkg/defaults/defaults_test.go`:
- Around line 2314-2327: The comparator function less (comparing
api.StepConfiguration) isn't strict when SourceStepConfiguration.Ref equals
SrcAssemblyStepConfiguration.Ref; update less to add a deterministic secondary
key so it establishes a strict total order: first compute refA/refB as now, then
if refA != refB return refA < refB; otherwise break ties by comparing a
deterministic discriminator such as whether SourceStepConfiguration is non-nil
vs SrcAssemblyStepConfiguration (e.g., treat SourceStepConfiguration <
SrcAssemblyStepConfiguration), or compare another stable field (like a
Name/Path/ID) from the non-nil config, ensuring the comparator always returns
either true or false for any pair so cmpopts.SortSlices gets a strict ordering.

In `@pkg/defaults/defaults.go`:
- Around line 1123-1148: The sourceStepsForRef function currently emits two
steps (SourceStepConfiguration and SrcAssemblyStepConfiguration) which allows
LOCAL_IMAGE_SRC to skip only the assembly step; update sourceStepsForRef so that
when the LOCAL_IMAGE_SRC override is present it short-circuits both steps by
omitting the SourceStepConfiguration entirely (i.e., only emit the
SrcAssemblyStepConfiguration or suppress both as appropriate) so
checkForFullyQualifiedStep cannot accidentally run the clone stage; change
behavior around constructing orgRepo/root/scratchSource/source inside
sourceStepsForRef and ensure the logic checks for the LOCAL_IMAGE_SRC env var
before returning the slice, and add a regression test that sets LOCAL_IMAGE_SRC
and asserts the clone (SourceStepConfiguration) is not present.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro

Run ID: d0a17647-2903-4836-b87c-65b2644203b1

📥 Commits

Reviewing files that changed from the base of the PR and between b97b312 and af9afbf.

⛔ Files ignored due to path filters (2)
  • pkg/api/zz_generated.deepcopy.go is excluded by !**/zz_generated*
  • pkg/webreg/zz_generated.ci_operator_reference.go is excluded by !**/zz_generated*
📒 Files selected for processing (17)
  • pkg/api/types.go
  • pkg/defaults/defaults.go
  • pkg/defaults/defaults_test.go
  • pkg/steps/bundle_source.go
  • pkg/steps/project_image.go
  • pkg/steps/source.go
  • pkg/steps/source_test.go
  • pkg/steps/src_assembly.go
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_basic_options_for_a_presubmit.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_title_in_pull_gets_squashed.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_with_OAuth_token.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_with_a_path_alias.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_with_a_pull_secret.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_with_extra_refs.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_with_extra_refs_setting_workdir_and_path_alias.yaml
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_with_ssh_key.yaml
  • pkg/validation/graph.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/steps/source_test.go
  • pkg/steps/testdata/zz_fixture_TestCreateScratchSourceBuild_with_extra_refs_setting_workdir_and_path_alias.yaml
  • pkg/validation/graph.go

@joepvd
Copy link
Contributor Author

joepvd commented Mar 8, 2026

/test images

@joepvd
Copy link
Contributor Author

joepvd commented Mar 9, 2026

/test e2e
/test e2e-oo

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Mar 9, 2026

@joepvd: 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 af9afbf link false /test breaking-changes
ci/prow/e2e-oo af9afbf link false /test e2e-oo

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

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants