From fafcbfaee2f8a1dd98cff450072b15e0aeaff18f Mon Sep 17 00:00:00 2001 From: Oleksandr Shmaraiev Date: Wed, 4 Nov 2026 20:31:51 +0200 Subject: [PATCH 1/2] ci: harden the remote happy-path launcher invocation Download remote-launch.sh with 'curl -fsSL' to a file and run it instead of 'bash <(curl -s ...)': process substitution hides fetch failures from 'set -e' and an HTTP error body could be executed as a script. Run the remote scripts with a dedicated ARTIFACT_DIR subdirectory: they wipe and recreate ARTIFACT_DIR on startup, which deleted this job's already collected artifacts (attempt log, Che/OLM diagnostics) and broke the failure report. Also install unzip (needed by remote-launch.sh to unpack the che repository archive) and update the prow job link in the failure report to the v22 job name. Co-Authored-By: Claude Code --- .ci/oci-devworkspace-happy-path.sh | 17 ++++++++++++++--- .ci/oci.Dockerfile | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.ci/oci-devworkspace-happy-path.sh b/.ci/oci-devworkspace-happy-path.sh index 6dc88b4f7..9d7295413 100755 --- a/.ci/oci-devworkspace-happy-path.sh +++ b/.ci/oci-devworkspace-happy-path.sh @@ -253,8 +253,19 @@ runHappyPathTest() { return 1 fi - # Download and run the remote test script - if ! bash <(curl -s "https://raw.githubusercontent.com/eclipse/che/${CHE_REPO_BRANCH}/tests/devworkspace-happy-path/remote-launch.sh"); then + # Download the launcher to a file first: 'bash <(curl -s ...)' hides a fetch + # failure (set -e does not check process substitution exit codes, and an + # HTTP error body could be executed as a script). + local launcher="/tmp/che-remote-launch.sh" + if ! curl -fsSL "https://raw.githubusercontent.com/eclipse/che/${CHE_REPO_BRANCH}/tests/devworkspace-happy-path/remote-launch.sh" -o "${launcher}"; then + echo "ERROR: Failed to download remote-launch.sh from the che repository" + return 1 + fi + + # The remote test scripts wipe and recreate ARTIFACT_DIR when they start, + # which would delete the artifacts this job has already collected; give + # them a dedicated subdirectory instead. + if ! ARTIFACT_DIR="${ARTIFACT_DIR}/che-happy-path" bash "${launcher}"; then echo "ERROR: Happy path test failed" # Collect artifacts on test failure @@ -403,7 +414,7 @@ generateReport() { # Build Prow job link if available local prow_link="" if [ -n "${PROW_JOB_ID:-}" ]; then - prow_link="https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/devfile_devworkspace-operator/${PULL_NUMBER:-unknown}/pull-ci-devfile-devworkspace-operator-main-v14-che-happy-path/${BUILD_ID:-unknown}" + prow_link="https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/devfile_devworkspace-operator/${PULL_NUMBER:-unknown}/pull-ci-devfile-devworkspace-operator-main-v22-che-happy-path/${BUILD_ID:-unknown}" fi # Write JSON report diff --git a/.ci/oci.Dockerfile b/.ci/oci.Dockerfile index 107567654..67ff28874 100644 --- a/.ci/oci.Dockerfile +++ b/.ci/oci.Dockerfile @@ -48,7 +48,7 @@ RUN node --version && npm --version # Temporary workaround since mirror.centos.org is down and can be replaced with vault.centos.org RUN sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo && sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo && sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo -RUN yum install --assumeyes -d1 python3-pip gettext jq && \ +RUN yum install --assumeyes -d1 python3-pip gettext jq unzip && \ pip3 install --upgrade pip && \ pip3 install --ignore-installed --upgrade setuptools && \ # Install yq and jq From 6b057d5a223e5e09bc8fae573cf0618ee874405d Mon Sep 17 00:00:00 2001 From: Oleksandr Shmaraiev Date: Fri, 6 Nov 2026 10:54:21 +0200 Subject: [PATCH 2/2] ci: classify launcher download failures as INFRA in the failure report When the remote-launch.sh download fails, runHappyPathTest now returns a distinct exit code (2) so main() can tell it apart from a test failure: no test pod has run at that point, so classifying it from pod logs wrongly reported "Test execution failure" (TEST category, "Retryable: No") for what is a network/infrastructure issue. The new reason maps to the INFRA category in the failure report. Co-Authored-By: Claude Code --- .ci/oci-devworkspace-happy-path.sh | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/.ci/oci-devworkspace-happy-path.sh b/.ci/oci-devworkspace-happy-path.sh index 9d7295413..edd486047 100755 --- a/.ci/oci-devworkspace-happy-path.sh +++ b/.ci/oci-devworkspace-happy-path.sh @@ -256,10 +256,13 @@ runHappyPathTest() { # Download the launcher to a file first: 'bash <(curl -s ...)' hides a fetch # failure (set -e does not check process substitution exit codes, and an # HTTP error body could be executed as a script). + # Return 2 on a download failure so that main() can tell it apart from a + # test failure: no test pod has run at that point, so classifying it from + # pod logs would wrongly report a TEST failure instead of INFRA. local launcher="/tmp/che-remote-launch.sh" if ! curl -fsSL "https://raw.githubusercontent.com/eclipse/che/${CHE_REPO_BRANCH}/tests/devworkspace-happy-path/remote-launch.sh" -o "${launcher}"; then echo "ERROR: Failed to download remote-launch.sh from the che repository" - return 1 + return 2 fi # The remote test scripts wipe and recreate ARTIFACT_DIR when they start, @@ -354,7 +357,7 @@ classifyTestFailure() { categorizeFailure() { local reason="$1" case "$reason" in - *"reconciliation"*|*"Image pull"*|*"OLM"*|*"operator timeout"*) + *"reconciliation"*|*"Image pull"*|*"OLM"*|*"operator timeout"*|*"Launcher download"*) echo "INFRA" ;; *"Dashboard"*|*"Workspace start"*|*"Authentication"*|*"Test execution"*) @@ -526,15 +529,30 @@ main() { fi # Run the happy path test (with 1 retry) - if ! runHappyPathTest 1; then + # runHappyPathTest returns 2 when the launcher download failed: no test pod + # has run then, so classifying the failure from pod logs would wrongly + # report a TEST failure for what is a network/infrastructure issue. + runHappyPathTest 1 + local test_rc=$? + if [ "$test_rc" -ne 0 ]; then local test_reason - test_reason=$(classifyTestFailure) + if [ "$test_rc" -eq 2 ]; then + test_reason="Launcher download failure" + else + test_reason=$(classifyTestFailure) + fi recordAttempt "1/2" "runHappyPathTest" "FAILED" "$test_reason" echo "⚠️ Happy path test failed on first attempt, retrying..." sleep 30 - if ! runHappyPathTest 2; then - test_reason=$(classifyTestFailure) + runHappyPathTest 2 + test_rc=$? + if [ "$test_rc" -ne 0 ]; then + if [ "$test_rc" -eq 2 ]; then + test_reason="Launcher download failure" + else + test_reason=$(classifyTestFailure) + fi recordAttempt "2/2" "runHappyPathTest" "FAILED" "$test_reason" echo "❌ FAILED: Happy path test execution (2 attempts)" return 1