Skip to content

fix: reconfigure local e2e suite for CRC OpenShift compatibility#243

Merged
bennyz merged 1 commit into
centos-automotive-suite:mainfrom
maboras-rh:localtest-infra
Apr 27, 2026
Merged

fix: reconfigure local e2e suite for CRC OpenShift compatibility#243
bennyz merged 1 commit into
centos-automotive-suite:mainfrom
maboras-rh:localtest-infra

Conversation

@maboras-rh

@maboras-rh maboras-rh commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Leverage CRC OpenShift cluster into local E2e Test execution, instead of using kind cluster.
while keeping E2E Tests workflow in Github Actions using kind cluster.

Related Issues

Relates to #176

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • CI/CD improvement
  • Refactoring

Testing

  • Unit tests pass (make test)
  • Linter passes (make lint)
  • Manifests are up to date (make manifests generate)
  • Tested on OpenShift cluster (if applicable)

Summary by CodeRabbit

  • Documentation

    • Standardized CRC registry-exposure instructions: unified CRC-user invocation on Linux/macOS and clarified when Linux may prompt for sudo.
  • Chores

    • Safer CRC scripts: central CRC API URL, prefer running as CRC user, use per-run temporary dirs with automatic cleanup, and consolidated cross-platform command snippets.
    • E2E workflow migrated from Kind/Docker to CRC/OpenShift with updated operator and registry setup.
  • Tests

    • Hardened E2E tests and utilities: improved OpenShift detection, namespace cleanup, build/image publish flow, auth handling, and readiness polling.

@coderabbitai

coderabbitai Bot commented Apr 20, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@maboras-rh has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 31 minutes and 28 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ecfbc267-d3c7-4fc3-89ca-f6b68497dffa

📥 Commits

Reviewing files that changed from the base of the PR and between bb0aadb and 69c29b7.

📒 Files selected for processing (7)
  • hack/crc/01-prep-host.sh
  • hack/crc/02-deploy-operator.sh
  • hack/crc/04-expose-default-registry.sh
  • hack/crc/README.md
  • hack/run-e2e-local.sh
  • test/e2e/e2e_test.go
  • test/utils/utils.go
📝 Walkthrough

Walkthrough

Switches local E2E tooling from Kind/Docker to CRC/OpenShift, updates CRC helper scripts to use CRC_API_URL and per-run cert staging, rewrites the e2e runner to bootstrap CRC and install Tekton via Operator Subscription, and adds OpenShift-aware test utilities and namespace cleanup logic.

Changes

Cohort / File(s) Summary
CRC Registry Setup
hack/crc/04-expose-default-registry.sh, hack/crc/README.md
Derive OS, CRC_API_URL, CRC_USER_HOME early; use mktemp per-run cert dir with EXIT trap and cleanup; README unified invocation and documents CRC-user execution and Linux sudo notes.
Local E2E Runner
hack/run-e2e-local.sh
Replaces Kind/docker lifecycle with CRC/OpenShift flow: source ~/.crc_env, run crc oc-env, verify CRC, oc login via CRC_API_URL, install Tekton via Subscription and wait for CSV Succeeded; add strict bash safety and re-exec-on-sudo; remove Kind-specific plumbing.
E2E Tests
test/e2e/e2e_test.go
Introduce shared constants, replace Kind-only logic with utils.* helpers, use CleanupNamespace, use PrepareOperatorImage, add OpenShift vs Kind branching for build/push flows, and improve polling/assertions for Build API/pod readiness.
Test Utilities
test/utils/utils.go
Run/RunSafe now preserve pre-set cmd.Env; add IsOpenShiftCluster, HasOpenShiftRouteCRD, GetBuildAPIURL, CleanupNamespace, PatchTektonTaskStep, NewCaibCommand, PrepareOperatorImage, LoadImageToClusterWithName and OpenShift push helpers.
CRC Auth Helpers
hack/crc/01-prep-host.sh, hack/crc/02-deploy-operator.sh
Introduce CRC_API_URL variable and use it for displayed oc login commands instead of a hardcoded API endpoint.
Docs / Minor
hack/crc/README.md
Consolidated platform instructions into unified macOS/Linux commands; clarified CRC-user execution and potential Linux sudo prompts for cert/install steps.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant Runner as hack/run-e2e-local.sh
    participant CRC as CRC daemon
    participant OC as oc CLI
    participant Registry as OpenShift Registry
    participant BuildAPI as Build API / CAIB

    Dev->>Runner: invoke local e2e runner
    Runner->>CRC: ensure crc running & source ~/.crc_env
    Runner->>OC: run `crc oc-env` and `oc login` (kubeadmin via CRC_API_URL)
    Runner->>OC: apply Tekton Subscription and wait for CSV Succeeded
    Runner->>OC: detect node ARCH via `oc get nodes`
    Runner->>Runner: PrepareOperatorImage() (build/tag/image)
    Runner->>Registry: LoadImageToClusterWithName -> resolve registry route and push
    Runner->>BuildAPI: run CAIB flows (health/auth checks) against Build API route
    BuildAPI->>OC: trigger/monitor in-cluster builds
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • bkhizgiy
  • bennyz

Poem

🐇 I swapped Kind nets for CRC air,
Per-run certs tucked with careful care,
No stale root crumbs left on the trail,
OC logs in and Tekton sets sail,
Hop, tag, push — the pipeline tells its tale.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 39.47% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main objective: reconfiguring the local E2E test suite for CRC OpenShift compatibility, which aligns with the core changes replacing Kind with CRC/OpenShift infrastructure.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

@maboras-rh maboras-rh changed the title Localtest infra fix: update local e2e test to run on crc openshift cluster Apr 20, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (6)
test/utils/utils.go (3)

135-135: Nit: extract "podman" / "docker" to constants (goconst).

Three "podman" occurrences flagged by goconst in the Lint Code check. Optional cleanup:

+const (
+	toolPodman = "podman"
+	toolDocker = "docker"
+)

and reuse in resolveContainerTool and the two tool == "podman" branches.

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

In `@test/utils/utils.go` at line 135, Extract the literal strings "podman" and
"docker" into package-level constants (e.g., const podman = "podman", docker =
"docker") and replace all direct string occurrences with those constants; update
resolveContainerTool and every branch using tool == "podman" (and any tool ==
"docker") to use the new constants so the three flagged occurrences are
consolidated and reused across the file.

202-219: splitImageName does not handle digest references.

foo/bar@sha256:abc... will produce tag = "abc..." and name = "foo/bar@sha256", and repo becomes "bar@sha256". Not an issue for current e2e paths (tag-based refs), but worth documenting or guarding if this helper is reused. Optional.

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

In `@test/utils/utils.go` around lines 202 - 219, splitImageName mis-parses digest
references (foo/bar@sha256:abc...) as tags; update the function so it first
checks for a digest marker by finding lastAt := strings.LastIndex(image, "@")
and if lastAt >= 0 treat tag = image[lastAt+1:] and name = image[:lastAt];
otherwise fall back to the existing lastColon/lastSlash logic (use lastColon
only when no '@' present and lastColon > lastSlash). Modify splitImageName to
prefer the '@' branch so repo extraction (using lastSlash) works correctly for
digest refs.

149-150: Avoid shelling out through bash -c for a single command.

oc create imagestream ... can be invoked directly without bash -c, avoiding any concern around shell-metacharacter interpolation in namespace/repo. While the inputs here are controlled, the direct form is simpler and safer:

♻️ Proposed refactor
-	_, _ = Run(exec.Command("bash", "-c",
-		"oc create imagestream "+repo+" -n "+namespace+" 2>/dev/null || true"))
+	_, _ = Run(exec.Command("oc", "create", "imagestream", repo, "-n", namespace))

Ignoring the error already yields the "|| true" semantics.

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

In `@test/utils/utils.go` around lines 149 - 150, Replace the shell invocation
that uses bash -c with a direct exec.Command call to avoid shell interpolation:
change the Run(exec.Command("bash", "-c", "oc create imagestream "+repo+" -n
"+namespace+" 2>/dev/null || true")) to call Run(exec.Command("oc", "create",
"imagestream", repo, "-n", namespace)) and simply ignore its returned error (or
explicitly discard stderr via the Cmd.Stderr set to ioutil.Discard) to preserve
the "|| true" semantics; update the call site in test/utils/utils.go where Run
and exec.Command are used.
test/e2e/e2e_test.go (2)

356-361: Optional: set MinVersion on TLS configs used against cluster routes.

gosec/ast-grep flags the two tls.Config{InsecureSkipVerify: true} usages (lines 358 and 768) for missing MinVersion. Since these target a cluster-local Route in tests, the practical risk is near zero, but adding MinVersion: tls.VersionTLS12 silences the lint noise and matches repository-wide crypto hygiene.

-TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+TLSClientConfig: &tls.Config{InsecureSkipVerify: true, MinVersion: tls.VersionTLS12},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/e2e_test.go` around lines 356 - 361, Update the test TLS configs to
include a minimum TLS version: in the http client creation that sets Transport:
&http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, add
MinVersion: tls.VersionTLS12 to the tls.Config literal (and do the same for the
other tls.Config usage flagged elsewhere in the test file). Locate the
tls.Config initializers (e.g., the one assigned inside the httpClient variable
and the second tls.Config occurrence) and set MinVersion to tls.VersionTLS12 to
satisfy the linter and maintain crypto hygiene.

77-112: Duplicated namespace cleanup/finalizer-stripping logic across suites.

The block at 77-112 (controller BeforeAll) and 586-616 (OIDC BeforeAll) implement essentially the same "delete ns, strip finalizers from blocking resources, wait-for-gone" sequence. Extracting into a helper like cleanupNamespace(namespace) in test/utils (or a local file-scoped helper) would remove ~50 lines of duplication and make future maintenance (e.g., adding new finalizer-prone resources) a single-line change.

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

In `@test/e2e/e2e_test.go` around lines 77 - 112, Extract the duplicated "delete
ns, strip finalizers, wait for gone" sequence into a single helper function
cleanupNamespace(namespace string) (e.g., in test/utils or a file-scoped helper)
that runs the same steps currently implemented around waitForNamespaceGone:
execute kubectl delete ns with --ignore-not-found and --timeout, iterate the
resource list
("operatorconfig","taskruns","pipelineruns","persistentvolumeclaims") to patch
metadata.finalizers to [], and perform the wait loop (repeating the strip logic
while checking kubectl get ns) until the namespace is gone; then replace the
duplicated blocks in both BeforeAlls with a single call to
cleanupNamespace(namespace) and keep using utils.Run and Eventually as needed.
hack/run-e2e-local.sh (1)

46-86: ensure_tekton CSV readiness label selector looks fragile.

The label operators.coreos.com/openshift-pipelines-operator-rh.openshift-operators= is an empty-value selector that depends on OLM having fully reconciled the subscription and labelled the CSV. On a fresh install, oc get csv ... -o jsonpath='{.items[0].status.phase}' may return empty for a long time before OLM creates the CSV, which is fine, but a transient kube-apiserver error in that loop swallows the error (|| true) and retries — also fine. Main risk: if the operator ever ships under a different CSV naming, the selector silently matches nothing forever until the 15-min cap. Consider falling back to oc get csv -n openshift-operators -l operators.coreos.com/openshift-pipelines-operator-rh.openshift-operators -o jsonpath='{.items[?(@.status.phase=="Succeeded")].metadata.name}' or polling by CSV name prefix. Optional hardening.

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

In `@hack/run-e2e-local.sh` around lines 46 - 86, The CSV readiness check in
ensure_tekton is brittle because it relies on an empty-value label selector;
update the polling to be resilient by first attempting to find any CSV with
status.phase == "Succeeded" using a jsonpath like
{.items[?(@.status.phase=="Succeeded")].metadata.name} and, if that returns
empty, fall back to polling CSVs by name prefix (e.g. names starting with
"openshift-pipelines-operator-rh") or by listing all CSVs in the
openshift-operators namespace and checking their .status.phase values; modify
the loop in ensure_tekton to use this two-step approach and fail only after the
timeout, ensuring oc errors are captured and handled (not silently swallowed) so
the function reliably detects readiness even if labels or CSV naming change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hack/run-e2e-local.sh`:
- Line 4: The NAMESPACE variable declared in run-e2e-local.sh is unused
(Shellcheck SC2034); either remove the unused
NAMESPACE="automotive-dev-operator-system" line or make the script actually use
it by replacing hard-coded namespace occurrences with the variable (e.g.,
reference NAMESPACE where other scripts currently pass -n
automotive-dev-operator-system) or export NAMESPACE so sub-scripts can consume
it; update any invocation patterns in run-e2e-local.sh that call sub-scripts to
pass or inherit this variable to eliminate the unused-variable warning.

In `@test/e2e/e2e_test.go`:
- Around line 489-499: The test stores the OpenShift token directly into the
global env var REGISTRY_PASSWORD via the block in test/e2e/e2e_test.go (using
utils.Run and os.Setenv), which risks leaking it in downstream tool output;
instead, avoid putting the token in the global process env — pass it only to the
specific commands that need it (set command.Env on exec.Command) or set
REGISTRY_PASSWORD locally and immediately unset it (defer os.Unsetenv) after the
registry auth step, and ensure any test logging/sanitizers (where utils.Run
wraps command output) scrub or mask occurrences of the token; update the
e2e_test.go block to use per-command env injection or temporary setting+clearing
and verify utils.Run does not print the token.

In `@test/utils/utils.go`:
- Around line 134-140: The login call is leaking credentials because Run(cmd)
logs cmd.Args and errors; replace the current login invocation in
pushImageToOpenShiftRegistry to avoid passing the token as a CLI arg: build the
exec.Command for the login tool with the password-stdin flag (remove "-p", use
"--password-stdin" or podman's equivalent), set cmd.Stdin to the token (e.g.,
strings.NewReader(token)), and run cmd.Run() directly instead of Run() so the
token never appears in args/logs; also ensure any returned error or log message
does not include cmd.Args or the raw token (return a sanitized error message if
the login fails). Ensure tlsVerifyArgs() and username are still passed as flags
but never include the token in any logged string.

---

Nitpick comments:
In `@hack/run-e2e-local.sh`:
- Around line 46-86: The CSV readiness check in ensure_tekton is brittle because
it relies on an empty-value label selector; update the polling to be resilient
by first attempting to find any CSV with status.phase == "Succeeded" using a
jsonpath like {.items[?(@.status.phase=="Succeeded")].metadata.name} and, if
that returns empty, fall back to polling CSVs by name prefix (e.g. names
starting with "openshift-pipelines-operator-rh") or by listing all CSVs in the
openshift-operators namespace and checking their .status.phase values; modify
the loop in ensure_tekton to use this two-step approach and fail only after the
timeout, ensuring oc errors are captured and handled (not silently swallowed) so
the function reliably detects readiness even if labels or CSV naming change.

In `@test/e2e/e2e_test.go`:
- Around line 356-361: Update the test TLS configs to include a minimum TLS
version: in the http client creation that sets Transport:
&http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, add
MinVersion: tls.VersionTLS12 to the tls.Config literal (and do the same for the
other tls.Config usage flagged elsewhere in the test file). Locate the
tls.Config initializers (e.g., the one assigned inside the httpClient variable
and the second tls.Config occurrence) and set MinVersion to tls.VersionTLS12 to
satisfy the linter and maintain crypto hygiene.
- Around line 77-112: Extract the duplicated "delete ns, strip finalizers, wait
for gone" sequence into a single helper function cleanupNamespace(namespace
string) (e.g., in test/utils or a file-scoped helper) that runs the same steps
currently implemented around waitForNamespaceGone: execute kubectl delete ns
with --ignore-not-found and --timeout, iterate the resource list
("operatorconfig","taskruns","pipelineruns","persistentvolumeclaims") to patch
metadata.finalizers to [], and perform the wait loop (repeating the strip logic
while checking kubectl get ns) until the namespace is gone; then replace the
duplicated blocks in both BeforeAlls with a single call to
cleanupNamespace(namespace) and keep using utils.Run and Eventually as needed.

In `@test/utils/utils.go`:
- Line 135: Extract the literal strings "podman" and "docker" into package-level
constants (e.g., const podman = "podman", docker = "docker") and replace all
direct string occurrences with those constants; update resolveContainerTool and
every branch using tool == "podman" (and any tool == "docker") to use the new
constants so the three flagged occurrences are consolidated and reused across
the file.
- Around line 202-219: splitImageName mis-parses digest references
(foo/bar@sha256:abc...) as tags; update the function so it first checks for a
digest marker by finding lastAt := strings.LastIndex(image, "@") and if lastAt
>= 0 treat tag = image[lastAt+1:] and name = image[:lastAt]; otherwise fall back
to the existing lastColon/lastSlash logic (use lastColon only when no '@'
present and lastColon > lastSlash). Modify splitImageName to prefer the '@'
branch so repo extraction (using lastSlash) works correctly for digest refs.
- Around line 149-150: Replace the shell invocation that uses bash -c with a
direct exec.Command call to avoid shell interpolation: change the
Run(exec.Command("bash", "-c", "oc create imagestream "+repo+" -n "+namespace+"
2>/dev/null || true")) to call Run(exec.Command("oc", "create", "imagestream",
repo, "-n", namespace)) and simply ignore its returned error (or explicitly
discard stderr via the Cmd.Stderr set to ioutil.Discard) to preserve the "||
true" semantics; update the call site in test/utils/utils.go where Run and
exec.Command are used.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 45bbfa6b-4b12-49cd-bc7c-a75783d9d6d1

📥 Commits

Reviewing files that changed from the base of the PR and between 8861439 and add0dc0.

📒 Files selected for processing (5)
  • hack/crc/04-expose-default-registry.sh
  • hack/crc/README.md
  • hack/run-e2e-local.sh
  • test/e2e/e2e_test.go
  • test/utils/utils.go

Comment thread hack/run-e2e-local.sh Outdated
Comment thread test/e2e/e2e_test.go
Comment thread test/utils/utils.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

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

Inline comments:
In `@hack/run-e2e-local.sh`:
- Around line 135-136: The shellcheck suppression currently disables SC1090 but
the reported warning for sourcing the dynamic file "$HOME/.crc_env" is SC1091;
update the directive on the sourcing line in hack/run-e2e-local.sh to suppress
the correct code (use disable=SC1091, or include both disable=SC1090,SC1091) so
the dynamic source line "source \"$HOME/.crc_env\"" no longer emits the
shellcheck warning.
- Around line 120-123: The sudo re-exec uses exec sudo -u "$SUDO_USER" -i bash
"$(realpath "$0")" "$@" which may drop the current working directory into the
target user's home and break later repo-relative paths like
hack/crc/04-expose-default-registry.sh and make test-e2e; update the re-exec so
it preserves the repository working directory (repo root) when switching
users—capture the current repo root (e.g., via pwd or realpath on the script or
repo root marker) and run the sudo -u "$SUDO_USER" invocation with a command
that first cds to that repo root before executing "$(realpath "$0")" with the
original "$@" so subsequent commands using repo-relative paths continue to work.

In `@test/utils/utils.go`:
- Around line 159-160: Replace the fragile shell-invocation that builds a "bash
-c" string with a direct exec.Command invocation and stop swallowing errors:
call Run(exec.Command("oc", "create", "imagestream", repo, "-n", namespace)) (or
capture the returned output/error from Run), remove the "2>/dev/null || true"
shell redirection, and handle or return any error so failures to create the
ImageStream are surfaced; update code that calls Run to check the error and fail
the test or log the detailed error if Run reports one.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dbddabdf-2b0c-4834-a02e-2fc956723fad

📥 Commits

Reviewing files that changed from the base of the PR and between add0dc0 and f29e9ad.

📒 Files selected for processing (3)
  • hack/run-e2e-local.sh
  • test/e2e/e2e_test.go
  • test/utils/utils.go

Comment thread hack/run-e2e-local.sh Outdated
Comment thread hack/run-e2e-local.sh Outdated
Comment thread test/utils/utils.go Outdated
@maboras-rh

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Apr 20, 2026

Copy link
Copy Markdown
✅ Actions performed

Full review triggered.

@maboras-rh maboras-rh changed the title fix: update local e2e test to run on crc openshift cluster fix: reconfigure local e2e suite for CRC OpenShift compatibility Apr 20, 2026
@maboras-rh maboras-rh requested review from bennyz and bkhizgiy April 20, 2026 16:42
@bennyz

bennyz commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

@ambient-code please review

@ambient-code ambient-code Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review — PR #243: Reconfigure local e2e suite for CRC OpenShift compatibility

Overall: Well-structured PR. The migration from Kind to CRC/OpenShift for local e2e is a significant improvement — it makes local testing match closer to the real deployment target. The helper extraction (CleanupNamespace, PrepareOperatorImage, LoadImageToClusterWithName) reduces duplication nicely, and the Run()/RunSafe() env-merge fix is a subtle but important correctness improvement.

Highlights

  • The OIDC test fix (switching from kubectl apply to kubectl patch --type=merge) is a great catch — the full apply would strip osBuilds, triggering an unwanted reconcile.
  • Using --password-stdin for registry login in pushImageToOpenShiftRegistry is the right pattern — avoids leaking tokens in process args.
  • The set_build_platform change to read arch from the cluster (kubectl get nodes) instead of uname -m is correct for CRC scenarios.
  • The Eventually-based polling for OIDC config instead of time.Sleep(10s) is more robust and faster when things work.

Issues

See inline comments for details. One critical item regarding the deleted pull-secret.txt.

Comment thread hack/crc/pull-secret.txt Outdated
Comment thread hack/run-e2e-local.sh Outdated
Comment thread test/utils/utils.go
Comment thread test/utils/utils.go Outdated
Comment thread test/e2e/e2e_test.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
test/utils/utils.go (1)

317-323: ⚠️ Potential issue | 🟡 Minor

Avoid GNU-only xargs -r in namespace cleanup.

On BSD/macOS hosts, xargs -r is invalid; since the error is ignored, finalizers may never be stripped and CleanupNamespace can time out. Prefer direct kubectl commands and skip empty names in Go.

Suggested cleanup refactor
 func stripNamespaceFinalizers(targetNamespace string) {
 	for _, resource := range namespaceFinalizerResources {
-		stripCmd := exec.Command("bash", "-c",
-			`kubectl get `+resource+` -n `+targetNamespace+
-				` -o name 2>/dev/null | xargs -r -I{} kubectl patch {} -n `+targetNamespace+
-				` --type=merge -p '{"metadata":{"finalizers":[]}}' 2>/dev/null || true`)
-		_, _ = Run(stripCmd)
+		namesOutput, err := Run(exec.Command("kubectl", "get", resource, "-n", targetNamespace, "-o", "name"))
+		if err != nil {
+			continue
+		}
+		for _, name := range GetNonEmptyLines(string(namesOutput)) {
+			_, _ = Run(exec.Command(
+				"kubectl", "patch", name,
+				"-n", targetNamespace,
+				"--type=merge",
+				"-p", `{"metadata":{"finalizers":[]}}`,
+			))
+		}
 	}
 }
#!/bin/bash
# Verify whether GNU-only xargs flags remain in Go test helpers.
rg -nP 'xargs\s+-r' --type=go -C2
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/utils/utils.go` around lines 317 - 323, stripNamespaceFinalizers
currently builds a shell pipeline using GNU-only `xargs -r`, which fails on
BSD/macOS and can leave finalizers unstripped; change it to call kubectl get -o
name from Go, capture and split the output, skip empty lines, and for each
resource name call kubectl patch via exec.Command to remove finalizers (using
the same merge patch payload), handling/ignoring errors as before; update
references in this function to use namespaceFinalizerResources and Run (or
inline exec handling) so the logic is platform-agnostic and does not rely on
shell-only xargs flags.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hack/run-e2e-local.sh`:
- Around line 34-44: ensure_crc_login currently treats any valid oc session as
CRC; update it to verify the server is the CRC API endpoint
(https://api.crc.testing:6443) before returning or explicitly set/override
KUBECONFIG to the CRC kubeconfig. Specifically, in ensure_crc_login use `oc
whoami --show-server` and check the output equals https://api.crc.testing:6443
(or fail/continue to login if not), or export KUBECONFIG to the CRC kubeconfig
path prior to calling oc; keep the existing get_kubeadmin_pass and oc login
logic but ensure the server check or KUBECONFIG override prevents operating
against a non-CRC cluster.
- Around line 24-27: The current extraction of pass using jq can cause the
script to exit under set -euo pipefail if crc returns non-JSON; change the
assignment to make jq failures non-fatal, e.g. replace the pass assignment with
a safe subshell that swallows jq errors: pass="$(echo "$json" | jq -r
'.adminCredentials.password // empty' 2>/dev/null || true)". This ensures the
variables json and pass (and the crc console invocation) remain reachable even
when jq fails, and keeps the unique identifiers (json, pass, crc console, jq)
for easy location.

In `@test/e2e/e2e_test.go`:
- Around line 618-623: The HTTP probe currently creates an http.Client with a
custom Transport but no timeout, so requests (the client.Get call to apiURL +
"/v1/auth/config") can hang indefinitely; set the client's Timeout field (e.g.,
Timeout: 10*time.Second or same duration used by other route probes) on the
client struct and ensure time is imported so the request will fail fast instead
of blocking forever.

---

Duplicate comments:
In `@test/utils/utils.go`:
- Around line 317-323: stripNamespaceFinalizers currently builds a shell
pipeline using GNU-only `xargs -r`, which fails on BSD/macOS and can leave
finalizers unstripped; change it to call kubectl get -o name from Go, capture
and split the output, skip empty lines, and for each resource name call kubectl
patch via exec.Command to remove finalizers (using the same merge patch
payload), handling/ignoring errors as before; update references in this function
to use namespaceFinalizerResources and Run (or inline exec handling) so the
logic is platform-agnostic and does not rely on shell-only xargs flags.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 754fa843-51c4-4bf3-a610-f3f10cfc042e

📥 Commits

Reviewing files that changed from the base of the PR and between f29e9ad and 7502fac.

📒 Files selected for processing (5)
  • hack/crc/04-expose-default-registry.sh
  • hack/crc/README.md
  • hack/run-e2e-local.sh
  • test/e2e/e2e_test.go
  • test/utils/utils.go
✅ Files skipped from review due to trivial changes (1)
  • hack/crc/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • hack/crc/04-expose-default-registry.sh

Comment thread hack/run-e2e-local.sh
Comment thread hack/run-e2e-local.sh Outdated
Comment thread test/e2e/e2e_test.go
@maboras-rh

Copy link
Copy Markdown
Contributor Author

@ambient-code please review

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

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

Inline comments:
In `@hack/run-e2e-local.sh`:
- Around line 49-63: The function ensure_tekton currently returns as soon as
CRDs exist but must also verify the operator/controllers are healthy; update
ensure_tekton so after the CRD loop it additionally polls the OpenShift
Pipelines operator CSV (ensure its phase is "Succeeded") and/or checks the
Tekton controller deployment(s) (e.g., tekton-pipelines-controller or
pipelines-controller) have the desired replicas ready, with a retry loop and
timeout; if these health checks fail, treat as not ready (set ready=false or
wait) so the e2e suite only proceeds when reconciliation is available.
- Around line 34-47: The current ensure_crc_login function only checks for any
authenticated user; change it to verify the identity is the kubeadmin account
and, if not, perform an explicit kubeadmin login using get_kubeadmin_pass.
Specifically, in ensure_crc_login call oc whoami --show-user and ensure it
returns "kubeadmin"; if it does not, obtain the password from get_kubeadmin_pass
and run oc login -u kubeadmin -p "$kube_pass" https://api.crc.testing:6443
--insecure-skip-tls-verify, then re-check identity and fail with a clear message
if login still does not yield kubeadmin; keep references to ensure_crc_login,
get_kubeadmin_pass, oc whoami --show-user, and oc login so the change is easy to
locate.

In `@test/utils/utils.go`:
- Around line 121-128: The closure waitForNamespaceGone currently treats any
kubectl error as success (returns nil), which masks auth/context/API issues;
change it to only return nil when the error/command output clearly indicates the
namespace is NotFound (e.g., contains "NotFound" or "Error from server
(NotFound)"), otherwise return the original error so callers know the check
failed; call stripNamespaceFinalizers(targetNamespace) only when the namespace
still exists (i.e., when kubectl succeeded), and preserve/return the original
err from Run(cmd) for non-NotFound failures so timeouts and retries work
correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9cd07e60-a6a8-4eb9-b19e-6adcf68262f2

📥 Commits

Reviewing files that changed from the base of the PR and between 7502fac and ea58884.

📒 Files selected for processing (3)
  • hack/run-e2e-local.sh
  • test/e2e/e2e_test.go
  • test/utils/utils.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/e2e/e2e_test.go

Comment thread hack/run-e2e-local.sh
Comment thread hack/run-e2e-local.sh Outdated
Comment thread test/utils/utils.go
Comment thread test/utils/utils.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 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 `@hack/run-e2e-local.sh`:
- Line 130: The current sudo re-exec line uses exec "$@" which attempts to run
"$SCRIPT_PATH" directly and fails if that file isn't executable; update the
command so the handed-off process invokes the script via bash instead of
executing it directly—for the existing line that references SUDO_USER,
REPO_ROOT, and SCRIPT_PATH, replace the final exec "$@" with exec bash "$@"
(i.e., run the script through bash after the cd/shift handoff) so non-executable
script files will still run under sudo.

In `@test/e2e/e2e_test.go`:
- Around line 382-388: caibEnv is created as an isolated slice, causing
subprocesses to lose inherited environment; change caibEnv to start from
os.Environ() and then append/merge the CAIB-specific entries ("CAIB_TOKEN=...",
"CAIB_SERVER=...", and conditional "CAIB_INSECURE=true") so the subprocess
inherits PATH, HOME, KUBECONFIG, proxy and cert settings while the CAIB
variables override any existing keys. Ensure the merge logic for caibEnv (used
when calling NewCaibCommand and assigning to cmd.Env) replaces existing CAIB_*
entries if present rather than duplicating them.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2efea175-b979-45e9-aaf3-245996ba940e

📥 Commits

Reviewing files that changed from the base of the PR and between ea58884 and 43c4133.

📒 Files selected for processing (6)
  • hack/crc/01-prep-host.sh
  • hack/crc/02-deploy-operator.sh
  • hack/crc/04-expose-default-registry.sh
  • hack/run-e2e-local.sh
  • test/e2e/e2e_test.go
  • test/utils/utils.go
✅ Files skipped from review due to trivial changes (3)
  • hack/crc/01-prep-host.sh
  • hack/crc/02-deploy-operator.sh
  • test/utils/utils.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • hack/crc/04-expose-default-registry.sh

Comment thread hack/run-e2e-local.sh Outdated
Comment thread test/e2e/e2e_test.go Outdated
Comment thread hack/crc/README.md Outdated
@maboras-rh maboras-rh force-pushed the localtest-infra branch 3 times, most recently from 5e21a11 to 1d5813d Compare April 23, 2026 13:57
@maboras-rh maboras-rh requested a review from bennyz April 23, 2026 13:58

@ambient-code ambient-code Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review -- PR #243: Reconfigure local e2e suite for CRC OpenShift compatibility

Overall: This is a well-executed migration. The previous review surfaced 14+ items and all have been addressed in subsequent commits. The code is substantially improved since the first review.

The CRC and Kind paths are cleanly separated -- CI continues to use Kind via the GitHub Actions workflow, while hack/run-e2e-local.sh now targets CRC exclusively. The test code uses IsOpenShiftCluster() to branch at the right points without coupling.

What looks good

  • CleanupNamespace with finalizer stripping: The robust namespace cleanup logic with --ignore-not-found (addressing bennyz's suggestion) is a real reliability improvement. Stuck finalizers are a common cause of flaky e2e teardown.
  • pushImageToOpenShiftRegistry using --password-stdin: Properly avoids leaking tokens in process args and GinkgoWriter logs. Good follow-through on the previous review.
  • caibEnv seeded from os.Environ(): The fix to inherit the parent environment (PATH, HOME, KUBECONFIG, etc.) prevents broken subprocess execution.
  • CSV readiness check in ensure_tekton: Checking the CSV phase rather than just CRD presence avoids races where CRDs exist but the controller is still rolling out.
  • setEnv helper: Clean deduplication logic that avoids polluting os.Environ() globally. The in-place filtering pattern (filtered := caibEnv[:0]) is correct here because the write index never exceeds the read index.
  • OIDC test fix: Using kubectl patch --type=merge instead of kubectl apply to avoid stripping osBuilds is a subtle but important correctness fix.

Issues

See inline comments. No critical items -- two minor issues and two nits.

Comment thread hack/run-e2e-local.sh Outdated
Comment thread test/e2e/e2e_test.go Outdated
Comment thread test/e2e/e2e_test.go
Comment thread test/e2e/e2e_test.go
@maboras-rh maboras-rh force-pushed the localtest-infra branch 2 times, most recently from b14635c to c948b17 Compare April 26, 2026 11:18
@maboras-rh

Copy link
Copy Markdown
Contributor Author

@bennyz @bkhizgiy - PTAL

Comment thread test/utils/utils.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/e2e/e2e_test.go (1)

252-257: ⚠️ Potential issue | 🔴 Critical

Remove or clarify the :5000 port suffix on external registry routes.

The external OpenShift registry route (default-route-openshift-image-registry.<apps-domain>) is served on standard HTTPS (443), not port 5000. Appending :5000 to registryHost at lines 255 and 471 makes clusterRegistryRoute and the caib --push target invalid. Either remove the port suffix to use standard HTTPS, or use the internal cluster address (image-registry.openshift-image-registry.svc:5000) if the caib service is deployed in-cluster.

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

In `@test/e2e/e2e_test.go` around lines 252 - 257, The test incorrectly appends
":5000" to the external registry host (registryHost) when setting
OperatorConfig.spec.osBuilds.clusterRegistryRoute and when forming the caib
--push target; update the test to either remove the ":5000" suffix for external
routes (use the HTTPS route as-is) or, if you intend to target the in-cluster
registry, replace registryHost with the internal service address
"image-registry.openshift-image-registry.svc:5000"; specifically modify the
fmt.Sprintf call that sets clusterRegistryRoute and the place where the caib
push target is constructed so they use the appropriate host form depending on
deployment (no port for external HTTPS route or the internal svc:5000 for
in-cluster).
🧹 Nitpick comments (5)
hack/run-e2e-local.sh (1)

159-159: 60s oc wait may be tight on slow CRC bring-ups.

If CRC has just been started or resumed, the single node can take more than a minute to report Ready (kubelet/CSR approvals, MCO catch-up). With set -euo pipefail this aborts the whole run. Consider bumping the timeout (e.g., --timeout=10m) — the wait short-circuits as soon as the node is Ready, so a generous upper bound is essentially free.

♻️ Suggested change
-oc wait --for=condition=Ready nodes --all --timeout=60s >/dev/null
+oc wait --for=condition=Ready nodes --all --timeout=10m >/dev/null
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hack/run-e2e-local.sh` at line 159, Increase the timeout on the oc wait call
to avoid aborting runs on slow CRC bring-ups: update the command using oc wait
--for=condition=Ready nodes --all --timeout=60s to a larger value (e.g.,
--timeout=10m) in hack/run-e2e-local.sh so the single-node readiness wait in
that script (the oc wait invocation) has a generous upper bound but still
short-circuits as soon as the node becomes Ready.
hack/crc/04-expose-default-registry.sh (1)

90-96: Consider mktemp -d instead of a deterministic per-UID directory.

The new path ${TMPDIR:-/tmp}/registry-certs-$(id -u) is predictable, and the stale-dir guard escalates with sudo rm -rf whenever the directory exists and isn’t writable by the current user. On a shared host, another local user could pre-create that path (or a symlinked variant) before the script runs and trick the privileged removal into operating on a path they control. Using mktemp -d -t registry-certs.XXXXXX (and trapping cleanup on EXIT) sidesteps both the staleness problem and the privileged removal entirely.

♻️ Suggested refactor
-CERT_DIR="${TMPDIR:-/tmp}/registry-certs-$(id -u)"
-# Clean up a stale dir left by a previous root run if we can't write to it.
-if [[ -d "$CERT_DIR" ]] && [[ ! -w "$CERT_DIR" ]]; then
-    warn "Stale $CERT_DIR not writable (owned by another user). Removing via sudo..."
-    sudo rm -rf "$CERT_DIR"
-fi
-mkdir -p "$CERT_DIR"
+CERT_DIR="$(mktemp -d -t registry-certs.XXXXXX)"
+trap 'rm -rf "$CERT_DIR"' EXIT
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hack/crc/04-expose-default-registry.sh` around lines 90 - 96, Replace the
predictable CERT_DIR assignment and sudo-based stale-dir removal with a secure
temporary directory created via mktemp -d (e.g., use mktemp -d -t
registry-certs.XXXXXX) instead of "${TMPDIR:-/tmp}/registry-certs-$(id -u)";
remove the sudo rm -rf path and the writable check, and install a trap on EXIT
to clean up the mktemp-created directory; update uses of CERT_DIR (the mkdir -p
and any subsequent usage) to rely on the mktemp result and ensure the warn/error
messages still reference CERT_DIR where applicable.
test/utils/utils.go (1)

63-66: Behavior shift in env handling — confirm callers seed os.Environ() themselves.

The new logic only copies os.Environ() when cmd.Env is empty; otherwise the caller-supplied slice is used verbatim (plus GO111MODULE=on). This is fine for the current call sites (caibEnv is seeded from os.Environ() in test/e2e/e2e_test.go line 377, and NewCaibCommand just passes it through), but any future caller that pre-populates cmd.Env with only a couple of vars will silently lose PATH, HOME, KUBECONFIG, etc. Worth a short comment on Run/RunSafe documenting that pre-set cmd.Env fully replaces the process environment.

📝 Suggested doc tweak
 // Run executes the provided command within this context.
 // Not goroutine-safe due to os.Chdir; use RunSafe for concurrent execution.
+// If cmd.Env is non-empty, it fully replaces the process environment (callers
+// must include any required vars such as PATH/HOME/KUBECONFIG themselves).
 func Run(cmd *exec.Cmd) ([]byte, error) {

Also applies to: 83-86

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

In `@test/utils/utils.go` around lines 63 - 66, Update the documentation in Run
and RunSafe to state that if cmd.Env is non-empty it is used verbatim (only
"GO111MODULE=on" is appended) and therefore does not inherit the process
environment (os.Environ()); callers must seed PATH, HOME, KUBECONFIG, etc.
themselves if they pre-populate cmd.Env (refer to cmd.Env, Run, RunSafe and the
GO111MODULE=on append logic).
test/e2e/e2e_test.go (2)

459-471: Magic strings — extract myorg / automotive-os-test1 to constants.

"myorg" and "automotive-os-test1" appear in both this push reference and the OpenShift oc create imagestream call (line 283). If they ever drift, the imagestream pre-creation and the push target will silently mismatch. Lifting them into the existing const (...) block at the top of the file (next to statusRunning) keeps them in sync.

const (
    artifactImageName = "automotive-os-test1"
    kindPushNamespace = "myorg"
    // ...
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/e2e_test.go` around lines 459 - 471, Extract the hardcoded values
"myorg" and "automotive-os-test1" into constants (e.g., kindPushNamespace and
artifactImageName) in the existing top-level const block next to statusRunning,
then replace the literal usages: set pushNamespace's default to
kindPushNamespace and use artifactImageName in the registry push fmt.Sprintf and
in the OpenShift imagestream creation call so both places reference the same
constants (look for pushNamespace, registryHost and containerBuildName to locate
the push code and the imagestream creation near the earlier oc create call).

282-284: Inconsistent error handling on ImageStream pre-creation.

utils.pushImageToOpenShiftRegistry (utils.go lines 270-274) treats anything other than AlreadyExists as a hard failure, while this call site silently discards every error from oc create imagestream. If the create fails for a reason other than the resource already existing (RBAC, API outage, etc.), the build will only fail much later inside the Tekton push step and the root cause won't be obvious in the test log. Worth aligning with the helper:

♻️ Suggested alignment
-					By("pre-creating artifact ImageStream on OpenShift")
-					cmd = exec.Command("oc", "create", "imagestream", "automotive-os-test1", "-n", namespace)
-					_, _ = utils.Run(cmd)
+					By("pre-creating artifact ImageStream on OpenShift")
+					createIS := exec.Command("oc", "create", "imagestream", "automotive-os-test1", "-n", namespace)
+					if out, err := utils.Run(createIS); err != nil &&
+						!strings.Contains(string(out), "AlreadyExists") {
+						Fail(fmt.Sprintf("create ImageStream automotive-os-test1: %v: %s", err, out))
+					}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/e2e_test.go` around lines 282 - 284, The pre-creation of the
ImageStream in the test currently ignores all errors from exec.Command("oc",
"create", "imagestream", ...), causing unrelated failures later; change the call
site in the test (the block creating the imagestream) to check the command
result and handle errors the same way as utils.pushImageToOpenShiftRegistry:
capture stderr/stdout from utils.Run, detect the "AlreadyExists" condition and
ignore only that case, but fail the test (using the test harness'
failure/assertion mechanism) for any other error (RBAC, API outage, etc.) so
root causes show up immediately in the test logs. Ensure you reference the same
helper behavior as utils.pushImageToOpenShiftRegistry when implementing the
check.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@test/e2e/e2e_test.go`:
- Around line 252-257: The test incorrectly appends ":5000" to the external
registry host (registryHost) when setting
OperatorConfig.spec.osBuilds.clusterRegistryRoute and when forming the caib
--push target; update the test to either remove the ":5000" suffix for external
routes (use the HTTPS route as-is) or, if you intend to target the in-cluster
registry, replace registryHost with the internal service address
"image-registry.openshift-image-registry.svc:5000"; specifically modify the
fmt.Sprintf call that sets clusterRegistryRoute and the place where the caib
push target is constructed so they use the appropriate host form depending on
deployment (no port for external HTTPS route or the internal svc:5000 for
in-cluster).

---

Nitpick comments:
In `@hack/crc/04-expose-default-registry.sh`:
- Around line 90-96: Replace the predictable CERT_DIR assignment and sudo-based
stale-dir removal with a secure temporary directory created via mktemp -d (e.g.,
use mktemp -d -t registry-certs.XXXXXX) instead of
"${TMPDIR:-/tmp}/registry-certs-$(id -u)"; remove the sudo rm -rf path and the
writable check, and install a trap on EXIT to clean up the mktemp-created
directory; update uses of CERT_DIR (the mkdir -p and any subsequent usage) to
rely on the mktemp result and ensure the warn/error messages still reference
CERT_DIR where applicable.

In `@hack/run-e2e-local.sh`:
- Line 159: Increase the timeout on the oc wait call to avoid aborting runs on
slow CRC bring-ups: update the command using oc wait --for=condition=Ready nodes
--all --timeout=60s to a larger value (e.g., --timeout=10m) in
hack/run-e2e-local.sh so the single-node readiness wait in that script (the oc
wait invocation) has a generous upper bound but still short-circuits as soon as
the node becomes Ready.

In `@test/e2e/e2e_test.go`:
- Around line 459-471: Extract the hardcoded values "myorg" and
"automotive-os-test1" into constants (e.g., kindPushNamespace and
artifactImageName) in the existing top-level const block next to statusRunning,
then replace the literal usages: set pushNamespace's default to
kindPushNamespace and use artifactImageName in the registry push fmt.Sprintf and
in the OpenShift imagestream creation call so both places reference the same
constants (look for pushNamespace, registryHost and containerBuildName to locate
the push code and the imagestream creation near the earlier oc create call).
- Around line 282-284: The pre-creation of the ImageStream in the test currently
ignores all errors from exec.Command("oc", "create", "imagestream", ...),
causing unrelated failures later; change the call site in the test (the block
creating the imagestream) to check the command result and handle errors the same
way as utils.pushImageToOpenShiftRegistry: capture stderr/stdout from utils.Run,
detect the "AlreadyExists" condition and ignore only that case, but fail the
test (using the test harness' failure/assertion mechanism) for any other error
(RBAC, API outage, etc.) so root causes show up immediately in the test logs.
Ensure you reference the same helper behavior as
utils.pushImageToOpenShiftRegistry when implementing the check.

In `@test/utils/utils.go`:
- Around line 63-66: Update the documentation in Run and RunSafe to state that
if cmd.Env is non-empty it is used verbatim (only "GO111MODULE=on" is appended)
and therefore does not inherit the process environment (os.Environ()); callers
must seed PATH, HOME, KUBECONFIG, etc. themselves if they pre-populate cmd.Env
(refer to cmd.Env, Run, RunSafe and the GO111MODULE=on append logic).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8cdf6ec2-4c2a-425e-9b85-8c605b2f6b3e

📥 Commits

Reviewing files that changed from the base of the PR and between ea58884 and c948b17.

📒 Files selected for processing (7)
  • hack/crc/01-prep-host.sh
  • hack/crc/02-deploy-operator.sh
  • hack/crc/04-expose-default-registry.sh
  • hack/crc/README.md
  • hack/run-e2e-local.sh
  • test/e2e/e2e_test.go
  • test/utils/utils.go
✅ Files skipped from review due to trivial changes (2)
  • hack/crc/02-deploy-operator.sh
  • hack/crc/README.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (7)
test/utils/utils.go (4)

54-68: Doc comment slightly misleading: env is not used strictly "as-is".

The new comment says “If cmd.Env is non-empty it is used as-is (callers must include PATH, HOME, etc.).” However, line 68 still unconditionally appends GO111MODULE=on, so the caller-supplied env is always extended. Worth tweaking the wording so future readers don’t assume their env passes through untouched (and so they realize they shouldn’t set their own GO111MODULE expecting it to win — although later entries do override earlier ones in os/exec, so behavior is fine, the comment just lies a bit). Same comment applies to RunSafe at lines 81/89.

Suggested wording
-// If cmd.Env is non-empty it is used as-is (callers must include PATH, HOME, etc.).
+// If cmd.Env is non-empty it is used as the base environment (callers must include
+// PATH, HOME, etc.); GO111MODULE=on is always appended.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/utils/utils.go` around lines 54 - 68, Update the doc comments for Run
and RunSafe to accurately state that caller-supplied cmd.Env is not preserved
strictly "as-is" but is augmented by the function (the function appends the
current environment when cmd.Env is empty and always appends GO111MODULE=on), so
callers should not assume their env will be untouched or that their GO111MODULE
setting will prevail; reference the Run and RunSafe functions and adjust the
wording to say the env will be extended/augmented rather than used "as-is."

178-182: Don’t silently drop json.Marshal error.

out, _ := json.Marshal(obj) discards a real error path. In practice the input was just unmarshaled so re-marshaling rarely fails, but caller-supplied stepFields (the map[string]any argument) can introduce non-marshalable values; in that case out is the empty byte slice and kubectl replace -f - will fail with a confusing parse error rather than the actual cause.

Suggested fix
-	out, _ := json.Marshal(obj)
-	rep := exec.Command("kubectl", "replace", "-f", "-")
+	out, err := json.Marshal(obj)
+	if err != nil {
+		return fmt.Errorf("task %s: marshal patched task: %w", taskName, err)
+	}
+	rep := exec.Command("kubectl", "replace", "-f", "-")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/utils/utils.go` around lines 178 - 182, The code currently ignores the
json.Marshal error (out, _ := json.Marshal(obj)), causing misleading kubectl
parse errors; change to capture and handle the marshal error (e.g., out, err :=
json.Marshal(obj); if err != nil { return fmt.Errorf("marshal object for kubectl
replace: %w", err) }) before building rep and calling Run, referencing the
existing symbols json.Marshal, out, rep, and Run in test/utils/utils.go so the
real serialization failure is returned to callers.

185-205: Add a lower-bound check for stepIndex.

getTektonTaskStep only guards against stepIndex >= len(steps). A negative stepIndex (caller bug) would slip through and panic with an out-of-range index on line 200 (steps[stepIndex]). Cheap to harden:

Suggested fix
-	if stepIndex >= len(steps) {
+	if stepIndex < 0 || stepIndex >= len(steps) {
 		return nil, fmt.Errorf("task %s: step %d out of range (%d steps)", taskName, stepIndex, len(steps))
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/utils/utils.go` around lines 185 - 205, getTektonTaskStep currently only
checks stepIndex >= len(steps) and will panic for negative indices; add a
lower-bound check (stepIndex < 0) early after validating steps and return a
descriptive error (e.g. "task %s: step %d out of range (%d steps)") to match
existing error style so callers get a proper error instead of an out-of-bounds
panic. Reference: function getTektonTaskStep, the steps slice variable and the
stepIndex parameter.

209-218: NewCaibCommand with empty env produces a subprocess with no environment.

cmd.Env = append([]string{}, env...) always sets cmd.Env to a non-nil slice (even if env is nil/empty). os/exec only inherits the parent environment when cmd.Env == nil, so calling NewCaibCommand(ctx, nil, ...) would launch bin/caib with no PATH, HOME, KUBECONFIG, etc. All current callers in test/e2e/e2e_test.go pass a fully-seeded caibEnv, so this isn’t a live bug — but it is a sharp edge. Consider falling back to os.Environ() when env is empty, or documenting that callers must always seed it.

Suggested fix
-	cmd.Env = append([]string{}, env...)
-	return cmd
+	if len(env) == 0 {
+		cmd.Env = append([]string{}, os.Environ()...)
+	} else {
+		cmd.Env = append([]string{}, env...)
+	}
+	return cmd
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/utils/utils.go` around lines 209 - 218, NewCaibCommand currently always
sets cmd.Env to a non-nil slice (cmd.Env = append([]string{}, env...)), which
prevents os/exec from inheriting the parent environment when env is nil/empty;
update NewCaibCommand so that if the provided env is nil or has length 0 it
falls back to os.Environ() (so cmd.Env inherits the parent environment),
otherwise copy the provided env into cmd.Env (e.g., append to a new slice) to
avoid sharing the input slice; reference the NewCaibCommand function and the
cmd.Env assignment when making the change.
test/e2e/e2e_test.go (2)

58-66: Use utils.CleanupNamespace here too for consistency / robustness.

The OIDC suite's AfterAll (line 616) and the controller BeforeAll (line 51) both use utils.CleanupNamespace, which strips finalizers and polls until the namespace is gone. This AfterAll still does a one-shot kubectl delete ns ... --timeout=60s and discards the error, so a namespace stuck in Terminating (e.g. due to leftover OperatorConfig or TaskRun finalizers) silently leaks. Since the next suite (OIDC Authentication) re-creates the same namespace, this can also race with namespace teardown — CleanupNamespace already handles that wait.

Suggested change
 	AfterAll(func() {
 		By("deleting OperatorConfig resources")
 		cmd := exec.Command("kubectl", "delete", "operatorconfig", "--all", "-n", namespace, "--timeout=30s")
 		_, _ = utils.Run(cmd)

 		By("removing manager namespace")
-		cmd = exec.Command("kubectl", "delete", "ns", namespace, "--timeout=60s")
-		_, _ = utils.Run(cmd)
+		utils.CleanupNamespace(namespace)
 	})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/e2e_test.go` around lines 58 - 66, Replace the one-shot kubectl
delete calls in the AfterAll block with the existing cleanup helper: call
utils.CleanupNamespace(namespace) (or the appropriate signature used elsewhere)
instead of exec.Command("kubectl", "delete", "ns", ...) and remove the
operatorconfig delete/no-op error discard; if needed, ensure OperatorConfig
resources are deleted via utils.CleanupNamespace (or call utils.CleanupNamespace
after removing OperatorConfig) so finalizers are stripped and the code polls
until the namespace is fully removed—update the AfterAll that currently
references exec.Command and utils.Run to use utils.CleanupNamespace and remove
the discarded error handling.

282-287: Hardcoded ImageStream name should be derived from artifactImageName.

Line 286 hardcodes "automotive-os-test1", but the same repo is referenced via the new artifactImageName = "automotive-os-test1:latest" const used at line 478. If the artifact name ever changes, these two will drift. Either split a tektonArtifactRepo = "automotive-os-test1" constant (and reuse it in artifactImageName), or split at the use site:

Example fix
+const tektonArtifactRepo = "automotive-os-test1"
+const artifactImageName  = tektonArtifactRepo + ":latest"
-					cmd = exec.Command("oc", "create", "imagestream", "automotive-os-test1", "-n", namespace)
+					cmd = exec.Command("oc", "create", "imagestream", tektonArtifactRepo, "-n", namespace)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/e2e/e2e_test.go` around lines 282 - 287, The ImageStream name is
hardcoded ("automotive-os-test1") while the test already defines
artifactImageName, causing drift; update the ImageStream creation to derive the
repo name from artifactImageName (or introduce a tektonArtifactRepo constant and
build artifactImageName from it) and use that variable in the exec.Command call
that creates the imagestream (the code that sets cmd = exec.Command("oc",
"create", "imagestream", ...)). Ensure you extract the repository portion (strip
the :tag if present) so the same symbol (artifactImageName or new
tektonArtifactRepo) is reused for both the ImageStream creation and the later
artifact references.
hack/crc/04-expose-default-registry.sh (1)

14-14: Optional: allow CRC_API_URL to be overridden via env.

CRC_API_URL is hardcoded with = instead of ${CRC_API_URL:-...}. Other env-tunable knobs in this script (e.g., REGISTRY_TLS_VERIFY, DISABLE_REDIRECT) follow the override pattern, and hack/run-e2e-local.sh defines its own CRC_API_URL. Allowing override here keeps this script consistent and re-usable in non-default CRC setups.

Suggested change
-CRC_API_URL="https://api.crc.testing:6443"
+CRC_API_URL="${CRC_API_URL:-https://api.crc.testing:6443}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hack/crc/04-expose-default-registry.sh` at line 14, Replace the hardcoded
CRC_API_URL assignment with a shell parameter expansion that allows an
environment override: change the assignment of the CRC_API_URL variable (the
line currently setting CRC_API_URL="https://api.crc.testing:6443") to use
${CRC_API_URL:-https://api.crc.testing:6443} so callers can override it via env;
follow the same override pattern used by REGISTRY_TLS_VERIFY and
DISABLE_REDIRECT to keep the script consistent with hack/run-e2e-local.sh.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@hack/crc/04-expose-default-registry.sh`:
- Line 14: Replace the hardcoded CRC_API_URL assignment with a shell parameter
expansion that allows an environment override: change the assignment of the
CRC_API_URL variable (the line currently setting
CRC_API_URL="https://api.crc.testing:6443") to use
${CRC_API_URL:-https://api.crc.testing:6443} so callers can override it via env;
follow the same override pattern used by REGISTRY_TLS_VERIFY and
DISABLE_REDIRECT to keep the script consistent with hack/run-e2e-local.sh.

In `@test/e2e/e2e_test.go`:
- Around line 58-66: Replace the one-shot kubectl delete calls in the AfterAll
block with the existing cleanup helper: call utils.CleanupNamespace(namespace)
(or the appropriate signature used elsewhere) instead of exec.Command("kubectl",
"delete", "ns", ...) and remove the operatorconfig delete/no-op error discard;
if needed, ensure OperatorConfig resources are deleted via
utils.CleanupNamespace (or call utils.CleanupNamespace after removing
OperatorConfig) so finalizers are stripped and the code polls until the
namespace is fully removed—update the AfterAll that currently references
exec.Command and utils.Run to use utils.CleanupNamespace and remove the
discarded error handling.
- Around line 282-287: The ImageStream name is hardcoded ("automotive-os-test1")
while the test already defines artifactImageName, causing drift; update the
ImageStream creation to derive the repo name from artifactImageName (or
introduce a tektonArtifactRepo constant and build artifactImageName from it) and
use that variable in the exec.Command call that creates the imagestream (the
code that sets cmd = exec.Command("oc", "create", "imagestream", ...)). Ensure
you extract the repository portion (strip the :tag if present) so the same
symbol (artifactImageName or new tektonArtifactRepo) is reused for both the
ImageStream creation and the later artifact references.

In `@test/utils/utils.go`:
- Around line 54-68: Update the doc comments for Run and RunSafe to accurately
state that caller-supplied cmd.Env is not preserved strictly "as-is" but is
augmented by the function (the function appends the current environment when
cmd.Env is empty and always appends GO111MODULE=on), so callers should not
assume their env will be untouched or that their GO111MODULE setting will
prevail; reference the Run and RunSafe functions and adjust the wording to say
the env will be extended/augmented rather than used "as-is."
- Around line 178-182: The code currently ignores the json.Marshal error (out, _
:= json.Marshal(obj)), causing misleading kubectl parse errors; change to
capture and handle the marshal error (e.g., out, err := json.Marshal(obj); if
err != nil { return fmt.Errorf("marshal object for kubectl replace: %w", err) })
before building rep and calling Run, referencing the existing symbols
json.Marshal, out, rep, and Run in test/utils/utils.go so the real serialization
failure is returned to callers.
- Around line 185-205: getTektonTaskStep currently only checks stepIndex >=
len(steps) and will panic for negative indices; add a lower-bound check
(stepIndex < 0) early after validating steps and return a descriptive error
(e.g. "task %s: step %d out of range (%d steps)") to match existing error style
so callers get a proper error instead of an out-of-bounds panic. Reference:
function getTektonTaskStep, the steps slice variable and the stepIndex
parameter.
- Around line 209-218: NewCaibCommand currently always sets cmd.Env to a non-nil
slice (cmd.Env = append([]string{}, env...)), which prevents os/exec from
inheriting the parent environment when env is nil/empty; update NewCaibCommand
so that if the provided env is nil or has length 0 it falls back to os.Environ()
(so cmd.Env inherits the parent environment), otherwise copy the provided env
into cmd.Env (e.g., append to a new slice) to avoid sharing the input slice;
reference the NewCaibCommand function and the cmd.Env assignment when making the
change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 27bda775-3820-4fd0-8d56-c806b7e46711

📥 Commits

Reviewing files that changed from the base of the PR and between c948b17 and d45c9c5.

📒 Files selected for processing (3)
  • hack/crc/04-expose-default-registry.sh
  • test/e2e/e2e_test.go
  • test/utils/utils.go

@bennyz

bennyz commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

lgtm

@bkhizgiy please look as well

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
test/e2e/e2e_test.go (1)

379-395: Optional: simplify per-test env handling.

The setEnv closure uses an in-place filter (caibEnv[:0] aliases the backing array) and is correct, but it is non-obvious. Since caibEnv is consumed by NewCaibCommand which fully overrides cmd.Env, a map[string]string keyed by var name (rendered to a []string once before each NewCaibCommand call, or via a small helper) reads more clearly and makes intent (override-or-insert) explicit.

♻️ Sketch
-			By("setting caib environment variables")
-			caibEnv = append([]string{}, os.Environ()...)
-			setEnv := func(key, value string) {
-				prefix := key + "="
-				filtered := caibEnv[:0]
-				for _, entry := range caibEnv {
-					if !strings.HasPrefix(entry, prefix) {
-						filtered = append(filtered, entry)
-					}
-				}
-				caibEnv = append(filtered, prefix+value)
-			}
-			setEnv("CAIB_TOKEN", caibToken)
-			setEnv("CAIB_SERVER", caibServer)
-			if openShiftCluster {
-				setEnv("CAIB_INSECURE", "true")
-			}
+			By("setting caib environment variables")
+			overrides := map[string]string{
+				"CAIB_TOKEN":  caibToken,
+				"CAIB_SERVER": caibServer,
+			}
+			if openShiftCluster {
+				overrides["CAIB_INSECURE"] = "true"
+			}

…then materialize caibEnv once after the registry credential block (filtering os.Environ() keys present in overrides and appending the overrides).

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

In `@test/e2e/e2e_test.go` around lines 379 - 395, The test's setEnv closure
mutates caibEnv in-place which is non-obvious; replace this with a simple
map-based override approach: create a map[string]string (e.g., overrides) and
set keys "CAIB_TOKEN", "CAIB_SERVER" and conditionally "CAIB_INSECURE" into it,
then materialize caibEnv by starting from os.Environ(), filtering out any keys
present in overrides, and appending "KEY=VALUE" strings before calling
NewCaibCommand so intent (override-or-insert) is explicit and easier to read.
test/utils/utils.go (3)

103-113: Confusing override semantics for OPENSHIFT_CLUSTER.

Setting OPENSHIFT_CLUSTER=false (or 0/no) does not disable OpenShift detection — the env var is only honored when truthy, otherwise the function falls through to HasOpenShiftRouteCRD(). For an explicit override knob this is surprising; a reader might assume a falsy value forces non-OpenShift mode. Either tighten the doc to make the "truthy override only, otherwise probe" rule explicit, or use strconv.ParseBool and treat any successfully parsed value as authoritative.

♻️ Suggested fix
 func IsOpenShiftCluster() bool {
-	v := strings.TrimSpace(os.Getenv("OPENSHIFT_CLUSTER"))
-	if strings.EqualFold(v, "true") || v == "1" {
-		return true
-	}
-	return HasOpenShiftRouteCRD()
+	if v := strings.TrimSpace(os.Getenv("OPENSHIFT_CLUSTER")); v != "" {
+		if b, err := strconv.ParseBool(v); err == nil {
+			return b
+		}
+	}
+	return HasOpenShiftRouteCRD()
 }

(Requires import "strconv".)

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

In `@test/utils/utils.go` around lines 103 - 113, The IsOpenShiftCluster() helper
currently only honors truthy OPENSHIFT_CLUSTER values and otherwise probes with
HasOpenShiftRouteCRD(), which makes a falsy env var non-authoritative; change it
to parse the env var with strconv.ParseBool and, if parsing succeeds, return
that boolean (so explicit "false" disables OpenShift), otherwise fall back to
HasOpenShiftRouteCRD(); update imports to include "strconv" and keep the
function name IsOpenShiftCluster and the probe function HasOpenShiftRouteCRD
referenced exactly as-is.

154-210: Document that stepFields replaces, not merges.

PatchTektonTaskStep overwrites each top-level key in stepFields wholesale on the target step (e.g., passing {"securityContext": {"runAsUser": 0}} will drop any existing securityContext.runAsNonRoot/capabilities set by the operator). For the current Kind callsite this is fine since the generated step has no securityContext, but a brief godoc note on the function would prevent future foot-guns when callers want to merge into existing structured fields.

📝 Suggested doc tweak
 // PatchTektonTaskStep fetches a Tekton Task, applies script replacements and optional
 // field overrides on step[stepIndex], then runs kubectl replace.
+// stepFields entries are assigned as-is to the step map, replacing any existing value
+// at that top-level key (no recursive merge); pass a fully-formed sub-tree if you need
+// to preserve sibling keys.
 func PatchTektonTaskStep(namespace, taskName string, stepIndex int, scriptReplacements map[string]string, stepFields map[string]any) error {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/utils/utils.go` around lines 154 - 210, Add a short godoc to
PatchTektonTaskStep stating that the stepFields map overwrites top-level keys on
the target step rather than merging nested objects (e.g., providing
{"securityContext": {"runAsUser": 0}} will replace any existing securityContext
rather than merge runAsNonRoot/capabilities); mention callers should merge
structured fields themselves if they need preservation or perform a deep-merge
before calling PatchTektonTaskStep. Include the note near the
PatchTektonTaskStep declaration so it's visible to callers and reference that
behavior applies to the step mutation performed after getTektonTaskStep returns
the step map.

351-356: Add a comment explaining the intentional CRC-specific default, or consider flipping the default to match podman.

The function defaults to --tls-verify=false, which contradicts podman's default of --tls-verify=true. This intentional insecure default makes sense for CRC's self-signed certificates (documented in hack/crc/README.md), but risks silently disabling cert verification when the code is used against a non-CRC OpenShift cluster unless callers explicitly set REGISTRY_TLS_VERIFY=true. Either add a code comment documenting that this is CRC-specific behavior, or flip the default to require opt-out via env var for backward compatibility.

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

In `@test/utils/utils.go` around lines 351 - 356, The tlsVerifyArgs() function
currently returns "--tls-verify=false" by default which is CRC-specific; update
the function tlsVerifyArgs() to either (A) add a clear code comment above
tlsVerifyArgs() stating this intentional CRC-specific insecure default and
referencing hack/crc/README.md so callers know why the default differs from
podman, or (B) flip the default to "--tls-verify=true" and require callers to
opt-out via REGISTRY_TLS_VERIFY=false; choose one approach and make the change
consistently where tlsVerifyArgs() is used.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/e2e/e2e_test.go`:
- Around line 379-395: The test's setEnv closure mutates caibEnv in-place which
is non-obvious; replace this with a simple map-based override approach: create a
map[string]string (e.g., overrides) and set keys "CAIB_TOKEN", "CAIB_SERVER" and
conditionally "CAIB_INSECURE" into it, then materialize caibEnv by starting from
os.Environ(), filtering out any keys present in overrides, and appending
"KEY=VALUE" strings before calling NewCaibCommand so intent (override-or-insert)
is explicit and easier to read.

In `@test/utils/utils.go`:
- Around line 103-113: The IsOpenShiftCluster() helper currently only honors
truthy OPENSHIFT_CLUSTER values and otherwise probes with
HasOpenShiftRouteCRD(), which makes a falsy env var non-authoritative; change it
to parse the env var with strconv.ParseBool and, if parsing succeeds, return
that boolean (so explicit "false" disables OpenShift), otherwise fall back to
HasOpenShiftRouteCRD(); update imports to include "strconv" and keep the
function name IsOpenShiftCluster and the probe function HasOpenShiftRouteCRD
referenced exactly as-is.
- Around line 154-210: Add a short godoc to PatchTektonTaskStep stating that the
stepFields map overwrites top-level keys on the target step rather than merging
nested objects (e.g., providing {"securityContext": {"runAsUser": 0}} will
replace any existing securityContext rather than merge
runAsNonRoot/capabilities); mention callers should merge structured fields
themselves if they need preservation or perform a deep-merge before calling
PatchTektonTaskStep. Include the note near the PatchTektonTaskStep declaration
so it's visible to callers and reference that behavior applies to the step
mutation performed after getTektonTaskStep returns the step map.
- Around line 351-356: The tlsVerifyArgs() function currently returns
"--tls-verify=false" by default which is CRC-specific; update the function
tlsVerifyArgs() to either (A) add a clear code comment above tlsVerifyArgs()
stating this intentional CRC-specific insecure default and referencing
hack/crc/README.md so callers know why the default differs from podman, or (B)
flip the default to "--tls-verify=true" and require callers to opt-out via
REGISTRY_TLS_VERIFY=false; choose one approach and make the change consistently
where tlsVerifyArgs() is used.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e3dda217-5a44-4cde-aad7-d00729cb9bb3

📥 Commits

Reviewing files that changed from the base of the PR and between d45c9c5 and bb0aadb.

📒 Files selected for processing (3)
  • hack/crc/04-expose-default-registry.sh
  • test/e2e/e2e_test.go
  • test/utils/utils.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • hack/crc/04-expose-default-registry.sh

@maboras-rh maboras-rh force-pushed the localtest-infra branch 3 times, most recently from fb9c2d3 to 4b51aa6 Compare April 27, 2026 09:46
Leverage CRC OpenShift cluster into local E2e Test execution, instead of using kind cluster.
while keeping E2E Tests workflow in Github Actions using kind cluster.

Assisted-by: Claude-4.6 (Cursor AI)
Signed-off-by: Mohamad Abo Ras <maboras@redhat.com>

---------

Signed-off-by: Mohamad Abo Ras <maboras@redhat.com>

@bkhizgiy bkhizgiy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm, approved

@bennyz bennyz merged commit bab8a41 into centos-automotive-suite:main Apr 27, 2026
4 checks passed
@maboras-rh maboras-rh deleted the localtest-infra branch April 27, 2026 10:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants