Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,17 @@ images:
from: cli
optional: true
to: cli-with-git
- dockerfile_literal: |
FROM registry.access.redhat.com/ubi9/openjdk-17:1.21
USER root
RUN microdnf install -y git && microdnf clean all
RUN cd /tmp \
&& curl -sLO https://mirror.openshift.com/pub/openshift-v4/clients/ocp/stable/openshift-client-linux.tar.gz \
&& curl -sL https://mirror.openshift.com/pub/openshift-v4/clients/ocp/stable/sha256sum.txt | grep openshift-client-linux.tar.gz | sha256sum -c - \
&& tar xzf openshift-client-linux.tar.gz -C /usr/local/bin oc kubectl \
&& rm -f openshift-client-linux.tar.gz
USER 1001
to: acs-smoke-runner
releases:
latest:
candidate:
Expand Down Expand Up @@ -119,6 +130,8 @@ tests:
- ref: acm-policies-openshift-plus-setup
- ref: acm-policies-openshift-plus
- chain: cucushift-installer-check-cluster-health
- ref: stackrox-opp-readiness
- ref: stackrox-opp-smoke
- ref: acm-tests-clc-create
- ref: acm-fetch-managed-clusters
- ref: acm-opp-app
Expand Down
4 changes: 4 additions & 0 deletions ci-operator/step-registry/stackrox/opp-readiness/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
approvers:
- cspi-qe-ocp-lp
reviewers:
- cspi-qe-ocp-lp
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#!/bin/bash
set -euo pipefail

# ---------------------------------------------------------------------------
# ACS OPP Readiness Gate
#
# Verifies that ACS Central and SecuredCluster are operational before
# running SMOKE tests. Discovers namespaces dynamically via CRs.
# Writes credentials and connection details to $SHARED_DIR for
# downstream steps.
# ---------------------------------------------------------------------------

if [[ -f "${SHARED_DIR}/kubeconfig" ]]; then
export KUBECONFIG="${SHARED_DIR}/kubeconfig"
fi

POLL_INTERVAL=30
TIMEOUT=300 # 5 minutes
ELAPSED=0

# ---------------------------------------------------------------------------
# wait_for - retry a check function with backoff until TIMEOUT
# ---------------------------------------------------------------------------
wait_for() {
local description="$1"
shift
local check_fn="$1"
shift

ELAPSED=0
echo "[readiness] Waiting for: ${description}"
while true; do
if "${check_fn}" "$@"; then
echo "[readiness] OK: ${description}"
return 0
fi
ELAPSED=$((ELAPSED + POLL_INTERVAL))
if [[ ${ELAPSED} -ge ${TIMEOUT} ]]; then
echo "[readiness] TIMEOUT after ${TIMEOUT}s waiting for: ${description}"
return 1
fi
echo "[readiness] ...retrying in ${POLL_INTERVAL}s (${ELAPSED}/${TIMEOUT}s)"
sleep "${POLL_INTERVAL}"
done
}

# ---------------------------------------------------------------------------
# Namespace discovery via CRs (never hardcode)
# ---------------------------------------------------------------------------
discover_central_ns() {
CENTRAL_NS="$(oc get centrals.platform.stackrox.io --all-namespaces \
-o jsonpath='{.items[0].metadata.namespace}' 2>/dev/null)" \
&& [[ -n "${CENTRAL_NS}" ]]
}

discover_sc_ns() {
SC_NS="$(oc get securedclusters.platform.stackrox.io --all-namespaces \
-o jsonpath='{.items[0].metadata.namespace}' 2>/dev/null)" \
&& [[ -n "${SC_NS}" ]]
}

CENTRAL_NS=""
SC_NS=""

wait_for "Central CR namespace discovery" discover_central_ns
echo "[readiness] Central namespace discovered"

wait_for "SecuredCluster CR namespace discovery" discover_sc_ns
echo "[readiness] SecuredCluster namespace discovered"

# ---------------------------------------------------------------------------
# Check 1: Central route exists
# ---------------------------------------------------------------------------
check_central_route() {
oc get route central -n "${CENTRAL_NS}" -o jsonpath='{.spec.host}' >/dev/null 2>&1
}

wait_for "Central route" check_central_route

CENTRAL_URL="$(oc get route central -n "${CENTRAL_NS}" -o jsonpath='{.spec.host}')"
echo "[readiness] Central route discovered"

# ---------------------------------------------------------------------------
# Check 2: Central API health (v1/metadata returns 200)
# ---------------------------------------------------------------------------
check_central_api() {
local http_code
http_code="$(curl -sk -o /dev/null -w '%{http_code}' \
"https://${CENTRAL_URL}/v1/metadata" --max-time 10)" || return 1
[[ "${http_code}" == "200" ]]
}

wait_for "Central API health (v1/metadata)" check_central_api

# ---------------------------------------------------------------------------
# Check 3: At least 1 secured cluster connected
# ---------------------------------------------------------------------------
check_clusters_connected() {
# Disable xtrace to protect admin password in curl args
set +x
local cluster_count
cluster_count="$(curl -sk -u "admin:${ROX_ADMIN_PASSWORD}" \
"https://${CENTRAL_URL}/v1/clusters" --max-time 10 \
| jq '.clusters | length' 2>/dev/null)" || return 1
[[ "${cluster_count}" -ge 1 ]]
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# ---------------------------------------------------------------------------
# Check 6 (early): Extract ROX_ADMIN_PASSWORD before cluster check
# ---------------------------------------------------------------------------
echo "[readiness] Extracting ROX_ADMIN_PASSWORD..."
ROX_ADMIN_PASSWORD=""
set +x
ROX_ADMIN_PASSWORD="$(oc get secret -n "${CENTRAL_NS}" central-htpasswd \
-o json | jq -r '.data.password' | base64 -d)"

if [[ -z "${ROX_ADMIN_PASSWORD}" ]]; then
echo "[readiness] FATAL: could not extract ROX_ADMIN_PASSWORD"
exit 1
fi
echo "[readiness] ROX_ADMIN_PASSWORD extracted successfully"

wait_for "secured cluster connected (v1/clusters)" check_clusters_connected

# ---------------------------------------------------------------------------
# Check 4: Sensor pods Running (detect OOMKilled)
# ---------------------------------------------------------------------------
check_sensor_pods() {
local pod_json
pod_json="$(oc get pods -n "${SC_NS}" -l app=sensor -o json 2>/dev/null)"

local pod_count
pod_count="$(echo "${pod_json}" | jq '.items | length')"
if [[ "${pod_count}" -eq 0 ]]; then
echo "[readiness] no sensor pods found yet"
return 1
fi

# Check for OOMKilled containers
local oom
oom="$(echo "${pod_json}" | jq -r '
.items[].status.containerStatuses[]?
| select(.lastState.terminated.reason == "OOMKilled")
| .name
')"
if [[ -n "${oom}" ]]; then
echo "[readiness] WARNING: OOMKilled detected in sensor containers: ${oom}"
fi

# All sensor pods must be Running
local not_running
not_running="$(echo "${pod_json}" | jq -r '
.items[] | select(.status.phase != "Running")
| "\(.metadata.name):\(.status.phase)"
')"
[[ -z "${not_running}" ]]
}

wait_for "sensor pods Running in ${SC_NS}" check_sensor_pods

# ---------------------------------------------------------------------------
# Check 5: Default policies loaded (count > 80)
# ---------------------------------------------------------------------------
check_policies_loaded() {
set +x
local policy_count
policy_count="$(curl -sk -u "admin:${ROX_ADMIN_PASSWORD}" \
"https://${CENTRAL_URL}/v1/policies?query=" --max-time 10 \
| jq '.policies | length' 2>/dev/null)" || return 1
echo "[readiness] policy count: ${policy_count}"
[[ "${policy_count}" -gt 80 ]]
}

wait_for "default policies loaded (>80)" check_policies_loaded

# ---------------------------------------------------------------------------
# Write outputs to SHARED_DIR for downstream steps
# ---------------------------------------------------------------------------
echo "[readiness] Writing connection details to SHARED_DIR..."

set +x
echo "${ROX_ADMIN_PASSWORD}" > "${SHARED_DIR}/ROX_ADMIN_PASSWORD"

echo "${CENTRAL_URL}" > "${SHARED_DIR}/CENTRAL_URL"
echo "${CENTRAL_NS}" > "${SHARED_DIR}/CENTRAL_NS"
echo "${SC_NS}" > "${SHARED_DIR}/SC_NS"

echo "[readiness] All checks passed. ACS is ready for SMOKE tests."
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"path": "stackrox/opp-readiness/stackrox-opp-readiness-ref.yaml",
"owners": {
"approvers": [
"cspi-qe-ocp-lp"
],
"reviewers": [
"cspi-qe-ocp-lp"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
ref:
as: stackrox-opp-readiness
commands: stackrox-opp-readiness-commands.sh
resources:
requests:
cpu: 100m
memory: 200Mi
from: cli
timeout: 40m0s
documentation: |-
Verify ACS Central and SecuredCluster are operational before running
SMOKE tests. Discovers namespaces dynamically via Central and
SecuredCluster CRs, then polls Central API health, secured-cluster
connectivity, sensor pod status, and default policy count. Writes
ROX_ADMIN_PASSWORD, CENTRAL_URL, CENTRAL_NS, and SC_NS to SHARED_DIR
for downstream steps.
4 changes: 4 additions & 0 deletions ci-operator/step-registry/stackrox/opp-smoke/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
approvers:
- cspi-qe-ocp-lp
reviewers:
- cspi-qe-ocp-lp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#!/bin/bash
set -euo pipefail

# ---------------------------------------------------------------------------
# ACS OPP SMOKE Test Runner
#
# Runs the stackrox qa-tests-backend testSMOKE suite against an ACS
# instance whose credentials were written to $SHARED_DIR by the
# stackrox-opp-readiness step.
#
# Image: acs-smoke-runner (UBI9 + OpenJDK 17 + git + oc)
# ---------------------------------------------------------------------------

if [[ -f "${SHARED_DIR}/kubeconfig" ]]; then
export KUBECONFIG="${SHARED_DIR}/kubeconfig"
fi

# ---------------------------------------------------------------------------
# Read credentials from SHARED_DIR (written by readiness gate)
# ---------------------------------------------------------------------------
echo "[smoke] Reading connection details from SHARED_DIR..."

CENTRAL_URL="$(cat "${SHARED_DIR}/CENTRAL_URL")"

set +x
ROX_ADMIN_PASSWORD="$(cat "${SHARED_DIR}/ROX_ADMIN_PASSWORD")"

echo "[smoke] Connection details loaded from SHARED_DIR"

# Allow pinning to a known-good ref for reproducibility
STACKROX_REF="${STACKROX_REF:-main}"
SCANNER_REF="${SCANNER_REF:-main}"

# ---------------------------------------------------------------------------
# Retry wrapper for network-dependent operations
# ---------------------------------------------------------------------------
retry_clone() {
local max_attempts=3
local attempt=1
while [[ $attempt -le $max_attempts ]]; do
if "$@"; then
return 0
fi
echo "[smoke] Clone attempt $attempt/$max_attempts failed, retrying in 10s..."
sleep 10
attempt=$((attempt + 1))
done
echo "[smoke] ERROR: Clone failed after $max_attempts attempts"
return 1
Comment on lines +37 to +49

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Remove failed clone directories before each retry.

If git clone fails after it creates its destination, the next attempt uses the same non-empty directory and fails immediately. Clean the known StackRox and Scanner clone destinations before rerunning each clone command, or clone into a new temporary directory for each attempt.

Also applies to: 55-57, 66-66

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ci-operator/step-registry/stackrox/opp-smoke/stackrox-opp-smoke-commands.sh`
around lines 37 - 49, Update retry_clone and its callers to remove the known
StackRox and Scanner clone destination directories before each retry attempt,
including the additional clone call sites noted in the review. Ensure cleanup
occurs only before rerunning a failed clone and preserves the existing retry
behavior.

}

# ---------------------------------------------------------------------------
# Sparse clone of stackrox/stackrox (qa-tests-backend + proto)
# ---------------------------------------------------------------------------
echo "[smoke] Sparse-cloning stackrox/stackrox..."
cd /tmp
retry_clone git clone --depth 1 --filter=blob:none --sparse --branch "${STACKROX_REF}" \
https://github.com/stackrox/stackrox.git stackrox
cd stackrox
git sparse-checkout set qa-tests-backend/ proto/

# ---------------------------------------------------------------------------
# Fetch scanner protos (no Go toolchain needed)
# ---------------------------------------------------------------------------
echo "[smoke] Fetching scanner protos..."
retry_clone git clone --depth 1 --filter=blob:none --sparse --branch "${SCANNER_REF}" \
https://github.com/stackrox/scanner.git /tmp/scanner
cd /tmp/scanner
git sparse-checkout set proto/scanner
cp -r proto/scanner /tmp/stackrox/qa-tests-backend/src/main/proto/scanner
chmod -R u+w /tmp/stackrox/qa-tests-backend/src/main/proto/scanner

# ---------------------------------------------------------------------------
# Set environment for the Gradle test suite
# ---------------------------------------------------------------------------
export API_HOSTNAME="${CENTRAL_URL}"
export API_PORT="443"
export ROX_USERNAME="admin"
export ROX_ADMIN_PASSWORD
export CLUSTER="OPENSHIFT"
export CI="true"

# ---------------------------------------------------------------------------
# Run testSMOKE
# ---------------------------------------------------------------------------
echo "[smoke] Running testSMOKE..."
cd /tmp/stackrox/qa-tests-backend

TEST_EXIT=0
./gradlew testSMOKE -i --no-daemon -Dorg.gradle.jvmargs="-Xmx3g" || TEST_EXIT=$?

# ---------------------------------------------------------------------------
# Copy JUnit XML results to ARTIFACT_DIR
# ---------------------------------------------------------------------------
collect_artifacts() {
if [[ -d build/test-results/testSMOKE ]]; then
cp -v build/test-results/testSMOKE/*.xml "${ARTIFACT_DIR}/" 2>/dev/null || true
fi
if [[ -d build/reports/tests/testSMOKE ]]; then
mkdir -p "${ARTIFACT_DIR}/smoke-report" 2>/dev/null || true
cp -r build/reports/tests/testSMOKE/* "${ARTIFACT_DIR}/smoke-report/" 2>/dev/null || true
fi
}
collect_artifacts || true

echo "[smoke] Test run finished with exit code: ${TEST_EXIT}"
exit "${TEST_EXIT}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"path": "stackrox/opp-smoke/stackrox-opp-smoke-ref.yaml",
"owners": {
"approvers": [
"cspi-qe-ocp-lp"
],
"reviewers": [
"cspi-qe-ocp-lp"
]
}
}
Loading