From 3a8488114d3c17154270c1a872dc8946015c1fac Mon Sep 17 00:00:00 2001 From: Chai Bot Date: Thu, 21 May 2026 16:47:13 +0000 Subject: [PATCH 1/2] ci-config: integrate tls-scanner into fips-check-node-scan in parallel Modify the fips-check-node-scan step to launch the TLS scanner pod early and run it in parallel with the existing FIPS node scan. The TLS scanner deploys a privileged pod that enumerates all cluster pod TLS ports and validates cipher suites and protocol versions. Changes: - fips-check-node-scan-commands.sh: add start_tls_scanner() and collect_tls_scanner_results() functions that bracket the existing node scan logic. The scanner pod is launched before the node scan and its artifacts are collected after the node scan completes. - fips-check-node-scan-ref.yaml: add tls-scanner-tool dependency (PULL_SPEC_TLS_SCANNER_TOOL), increase timeout to 4h30m, update documentation. - openshift-release-main__nightly-4.22.yaml: add tls-scanner-tool base image from tls-scanner/tls-scanner. The TLS scanner exit code is intentionally ignored (informational only), matching the existing tls-scanner-run step behavior. If PULL_SPEC_TLS_SCANNER_TOOL is not set, the TLS scan is skipped gracefully. --- .../openshift-release-main__nightly-4.22.yaml | 4 + .../fips-check-node-scan-commands.sh | 140 ++++++++++++++++++ .../node-scan/fips-check-node-scan-ref.yaml | 7 + 3 files changed, 151 insertions(+) diff --git a/ci-operator/config/openshift/release/openshift-release-main__nightly-4.22.yaml b/ci-operator/config/openshift/release/openshift-release-main__nightly-4.22.yaml index f4ebd3499f0f2..2fb153f5d04ba 100644 --- a/ci-operator/config/openshift/release/openshift-release-main__nightly-4.22.yaml +++ b/ci-operator/config/openshift/release/openshift-release-main__nightly-4.22.yaml @@ -87,6 +87,10 @@ base_images: name: tests-private namespace: ci tag: "4.22" + tls-scanner-tool: + name: tls-scanner + namespace: tls-scanner + tag: tls-scanner-tool upi-installer: name: "4.22" namespace: ocp diff --git a/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-commands.sh b/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-commands.sh index b1fb84f60a872..d64b2cdba0716 100755 --- a/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-commands.sh +++ b/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-commands.sh @@ -19,9 +19,144 @@ function run_command() { eval "${CMD}" } +# --- TLS Scanner (parallel) --------------------------------------------------- +# Launch the TLS scanner early so it runs in parallel with the FIPS node scan. +# The scanner image is provided by the PULL_SPEC_TLS_SCANNER_TOOL dependency. +# Its exit code is intentionally ignored — it produces informational artifacts only. + +TLS_SCANNER_NS="tls-scanner" +TLS_SCANNER_IMAGE="${PULL_SPEC_TLS_SCANNER_TOOL:-}" +TLS_SCANNER_ARTIFACT_DIR="${ARTIFACT_DIR}/tls-scanner" +TLS_SCANNER_STARTED=false + +function start_tls_scanner() { + if [[ -z "${TLS_SCANNER_IMAGE}" ]]; then + echo "[tls-scanner] PULL_SPEC_TLS_SCANNER_TOOL not set — skipping TLS scan." + return + fi + + echo "=== Starting TLS Scanner (parallel) ===" + echo "[tls-scanner] Image: ${TLS_SCANNER_IMAGE}" + mkdir -p "${TLS_SCANNER_ARTIFACT_DIR}" + + # Create namespace + oc create namespace "${TLS_SCANNER_NS}" --dry-run=client -o yaml | oc apply -f - + + # Grant cluster-admin and privileged SCC + oc adm policy add-cluster-role-to-user cluster-admin -z default -n "${TLS_SCANNER_NS}" + oc adm policy add-scc-to-user privileged -z default -n "${TLS_SCANNER_NS}" + + # Wait for RBAC/SCC changes to propagate + sleep 10 + + # Deploy the scanner pod + cat <&1 | tee /results/output.log + SCAN_EXIT_CODE=\${PIPESTATUS[0]} + echo "Scan complete. Exit code: \${SCAN_EXIT_CODE}" | tee -a /results/output.log + touch /results/scan.done + # Keep pod alive for artifact collection + sleep 120 + resources: + requests: + cpu: "4" + memory: 4Gi + limits: + cpu: "4" + memory: 4Gi + securityContext: + privileged: true + runAsUser: 0 + volumeMounts: + - name: results + mountPath: /results + volumes: + - name: results + emptyDir: {} +EOF + + echo "[tls-scanner] Waiting for scanner pod to start..." + if oc wait --for=condition=Ready pod/tls-scanner -n "${TLS_SCANNER_NS}" --timeout=5m; then + TLS_SCANNER_STARTED=true + echo "[tls-scanner] Pod is running — scan will proceed in parallel." + else + echo "[tls-scanner] WARNING: Pod failed to start. Continuing without TLS scan." + oc describe pod/tls-scanner -n "${TLS_SCANNER_NS}" || true + fi +} + +function collect_tls_scanner_results() { + if [[ "${TLS_SCANNER_STARTED}" != "true" ]]; then + return + fi + + echo "=== Collecting TLS Scanner Results ===" + + # Wait for scan.done marker or pod exit + local max_wait=14400 # 4 hours + local elapsed=0 + while (( elapsed < max_wait )); do + if oc exec pod/tls-scanner -n "${TLS_SCANNER_NS}" -- test -f /results/scan.done 2>/dev/null; then + echo "[tls-scanner] scan.done found — collecting artifacts" + break + fi + local phase + phase=$(oc get pod/tls-scanner -n "${TLS_SCANNER_NS}" -o jsonpath='{.status.phase}' 2>/dev/null || echo "Unknown") + if [[ "$phase" == "Succeeded" || "$phase" == "Failed" ]]; then + echo "[tls-scanner] Pod ${phase} — attempting artifact collection" + break + fi + sleep 15 + elapsed=$((elapsed + 15)) + done + + # Copy artifacts + oc cp "${TLS_SCANNER_NS}/tls-scanner:/results/." "${TLS_SCANNER_ARTIFACT_DIR}/" || echo "[tls-scanner] WARNING: Failed to copy some artifacts" + + if [[ -f "${TLS_SCANNER_ARTIFACT_DIR}/junit_tls_scan.xml" ]]; then + cp "${TLS_SCANNER_ARTIFACT_DIR}/junit_tls_scan.xml" "${ARTIFACT_DIR}/junit_tls_scan.xml" + echo "[tls-scanner] JUnit results copied to ${ARTIFACT_DIR}/junit_tls_scan.xml" + fi + + echo "[tls-scanner] Artifacts saved to: ${TLS_SCANNER_ARTIFACT_DIR}" + ls -la "${TLS_SCANNER_ARTIFACT_DIR}" || true + + # Cleanup + oc delete namespace "${TLS_SCANNER_NS}" --ignore-not-found --wait=false || true + echo "=== TLS Scanner Complete ===" +} + +# --- Main: start TLS scanner, then run FIPS node scan ------------------------- + set_proxy run_command "oc whoami" run_command "oc version -o yaml" + +# Launch TLS scanner in the background (non-blocking) +start_tls_scanner + pass=true # skip for ARM64 @@ -31,6 +166,7 @@ NON_SUPPORTED_ARCHES=(arm64) for arch in "${node_archs[@]}"; do if [[ "${NON_SUPPORTED_ARCHES[*]}" =~ $arch ]]; then echo "Skip this test since it doesn't support $arch." + collect_tls_scanner_results exit 0 fi done @@ -56,6 +192,7 @@ if [[ $ret -eq 0 ]]; then auths=`cat /tmp/.dockerconfigjson` if [[ $auths =~ "5000" ]]; then echo "This is a disconnected env, skip it." + collect_tls_scanner_results exit 0 fi fi @@ -75,6 +212,9 @@ if [[ -n $res ]];then pass=false fi +# --- Collect TLS scanner results (waits for completion) ----------------------- +collect_tls_scanner_results + # generate report echo "Generating the Junit for fips check node scan" filename="junit_fips-check-node-scan" diff --git a/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-ref.yaml b/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-ref.yaml index 11577d7a90056..cfe5556de85ea 100644 --- a/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-ref.yaml +++ b/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-ref.yaml @@ -2,10 +2,17 @@ ref: as: fips-check-node-scan from: cli commands: fips-check-node-scan-commands.sh + dependencies: + - env: PULL_SPEC_TLS_SCANNER_TOOL + name: tls-scanner-tool resources: requests: cpu: 10m memory: 100Mi grace_period: 180s + timeout: 4h30m0s documentation: >- This step checks if the rpms on nodes are built correctly. + It also launches the TLS scanner in parallel to scan all cluster + pod TLS ports for cipher suite and protocol version compliance. + The TLS scanner image is provided via the tls-scanner-tool dependency. From 14e2b1eab2f6a41fcc9060694b2fe5181f6ac4c9 Mon Sep 17 00:00:00 2001 From: Chai Bot Date: Thu, 21 May 2026 17:00:09 +0000 Subject: [PATCH 2/2] =?UTF-8?q?fixup:=20address=20CodeRabbit=20review=20?= =?UTF-8?q?=E2=80=94=20fix=20cleanup=20leak=20and=20oc=20cp=20flakiness?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Cleanup leak: Introduce TLS_SCANNER_NS_CREATED flag and an EXIT trap (cleanup_tls_scanner) that always deletes the namespace, regardless of whether the pod became Ready. Make namespace creation and RBAC/SCC grants best-effort so failures skip the TLS scan instead of aborting the entire step. 2. oc cp flakiness: Replace the fixed 'sleep 120' in the scanner pod with a wait loop for /results/collect.done. The collector signals the pod after oc cp completes, so the container stays Running for as long as needed and exits cleanly afterward. --- .../fips-check-node-scan-commands.sh | 54 ++++++++++++++----- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-commands.sh b/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-commands.sh index d64b2cdba0716..43050d3cfff6b 100755 --- a/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-commands.sh +++ b/ci-operator/step-registry/fips-check/node-scan/fips-check-node-scan-commands.sh @@ -27,8 +27,19 @@ function run_command() { TLS_SCANNER_NS="tls-scanner" TLS_SCANNER_IMAGE="${PULL_SPEC_TLS_SCANNER_TOOL:-}" TLS_SCANNER_ARTIFACT_DIR="${ARTIFACT_DIR}/tls-scanner" +TLS_SCANNER_NS_CREATED=false TLS_SCANNER_STARTED=false +# Always clean up the TLS scanner namespace on exit, regardless of whether the +# scanner pod became Ready or artifacts were collected. +function cleanup_tls_scanner() { + if [[ "${TLS_SCANNER_NS_CREATED}" == "true" ]]; then + echo "[tls-scanner] Cleaning up namespace ${TLS_SCANNER_NS}..." + oc delete namespace "${TLS_SCANNER_NS}" --ignore-not-found --wait=false || true + fi +} +trap cleanup_tls_scanner EXIT + function start_tls_scanner() { if [[ -z "${TLS_SCANNER_IMAGE}" ]]; then echo "[tls-scanner] PULL_SPEC_TLS_SCANNER_TOOL not set — skipping TLS scan." @@ -39,17 +50,32 @@ function start_tls_scanner() { echo "[tls-scanner] Image: ${TLS_SCANNER_IMAGE}" mkdir -p "${TLS_SCANNER_ARTIFACT_DIR}" - # Create namespace - oc create namespace "${TLS_SCANNER_NS}" --dry-run=client -o yaml | oc apply -f - + # Create namespace (best-effort — failures here must not abort the step) + if oc create namespace "${TLS_SCANNER_NS}" --dry-run=client -o yaml | oc apply -f -; then + TLS_SCANNER_NS_CREATED=true + else + echo "[tls-scanner] WARNING: Failed to create namespace — skipping TLS scan." + return + fi - # Grant cluster-admin and privileged SCC - oc adm policy add-cluster-role-to-user cluster-admin -z default -n "${TLS_SCANNER_NS}" - oc adm policy add-scc-to-user privileged -z default -n "${TLS_SCANNER_NS}" + # Grant cluster-admin and privileged SCC (best-effort) + if ! oc adm policy add-cluster-role-to-user cluster-admin -z default -n "${TLS_SCANNER_NS}"; then + echo "[tls-scanner] WARNING: Failed to grant cluster-admin — skipping TLS scan." + return + fi + if ! oc adm policy add-scc-to-user privileged -z default -n "${TLS_SCANNER_NS}"; then + echo "[tls-scanner] WARNING: Failed to grant privileged SCC — skipping TLS scan." + return + fi # Wait for RBAC/SCC changes to propagate sleep 10 - # Deploy the scanner pod + # Deploy the scanner pod. + # The pod keeps running indefinitely (tail -f /dev/null) after the scan + # finishes so that oc cp can always exec into it to collect artifacts. + # The collector signals completion by writing /results/collect.done, which + # terminates the wait loop and lets the container exit cleanly. cat </dev/null; then @@ -132,7 +158,7 @@ function collect_tls_scanner_results() { elapsed=$((elapsed + 15)) done - # Copy artifacts + # Copy artifacts (pod is still running, waiting for collect.done signal) oc cp "${TLS_SCANNER_NS}/tls-scanner:/results/." "${TLS_SCANNER_ARTIFACT_DIR}/" || echo "[tls-scanner] WARNING: Failed to copy some artifacts" if [[ -f "${TLS_SCANNER_ARTIFACT_DIR}/junit_tls_scan.xml" ]]; then @@ -140,11 +166,13 @@ function collect_tls_scanner_results() { echo "[tls-scanner] JUnit results copied to ${ARTIFACT_DIR}/junit_tls_scan.xml" fi + # Signal the scanner pod that collection is complete so it can exit + oc exec pod/tls-scanner -n "${TLS_SCANNER_NS}" -- touch /results/collect.done 2>/dev/null || true + echo "[tls-scanner] Artifacts saved to: ${TLS_SCANNER_ARTIFACT_DIR}" ls -la "${TLS_SCANNER_ARTIFACT_DIR}" || true - # Cleanup - oc delete namespace "${TLS_SCANNER_NS}" --ignore-not-found --wait=false || true + # Namespace cleanup is handled by the EXIT trap (cleanup_tls_scanner) echo "=== TLS Scanner Complete ===" }