Skip to content

Add smoke test infrastructure #8

Add smoke test infrastructure

Add smoke test infrastructure #8

Workflow file for this run

name: Smoke Tests
on:
push:
branches:
- main
pull_request:
types:
- opened
- reopened
- synchronize
jobs:
smoke:
name: Run Smoke Tests
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Download dependencies
run: go mod download
- name: Create kind cluster
uses: helm/kind-action@v1
with:
cluster_name: stackrox-mcp-smoke
- name: Clone StackRox repository
run: git clone --depth 1 https://github.com/stackrox/stackrox.git stackrox-repo
- name: Deploy StackRox Central
env:
MAIN_IMAGE_TAG: latest
SENSOR_HELM_DEPLOY: "true"
ROX_SCANNER_V4: "false"
run: |
cd stackrox-repo
./deploy/k8s/deploy-local.sh
- name: Deploy vulnerable workload
run: kubectl apply -f smoke/testdata/vulnerable-deployment.yaml
- name: Wait for vulnerable deployment
run: kubectl wait --for=condition=available --timeout=120s deployment/vulnerable-app -n vulnerable-apps
- name: Wait for Central pods ready
run: kubectl wait --for=condition=ready --timeout=180s pod -l app=central -n stackrox
- name: Extract Central password
id: extract-password
run: |
PASSWORD="$(kubectl get secret -n stackrox central-htpasswd -o json | jq -r '.data.password' | base64 -d)"
echo "::add-mask::${PASSWORD}"
echo "password=${PASSWORD}" >> "$GITHUB_OUTPUT"
- name: Wait for Central API and generate token
id: generate-token
run: |
set -e
echo "Waiting for Central API to be ready at localhost:8000..."
echo "Note: deploy-local.sh automatically set up port-forwarding"
PASSWORD="${{ steps.extract-password.outputs.password }}"
# Poll for API readiness with exponential backoff
MAX_ATTEMPTS=12
ATTEMPT=0
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
echo "Attempt $((ATTEMPT + 1))/${MAX_ATTEMPTS} to check API readiness..."
if curl -k -s -f --max-time 5 -u "admin:${PASSWORD}" \
https://localhost:8000/v1/ping > /dev/null 2>&1; then
echo "Central API is ready"
break
fi
ATTEMPT=$((ATTEMPT + 1))
if [ $ATTEMPT -ge $MAX_ATTEMPTS ]; then
echo "ERROR: Central API did not become ready after ${MAX_ATTEMPTS} attempts"
echo "Checking if port-forward is running..."
netstat -tlnp 2>/dev/null | grep :8000 || echo "Port 8000 not listening"
exit 1
fi
# Exponential backoff: 2, 4, 8, 16... seconds (max 30)
SLEEP_TIME=$((2 ** ATTEMPT))
if [ $SLEEP_TIME -gt 30 ]; then
SLEEP_TIME=30
fi
echo "Waiting ${SLEEP_TIME} seconds before retry..."
sleep $SLEEP_TIME
done
echo "Generating API token..."
TOKEN_RESPONSE=$(curl -k -s -w "\n%{http_code}" -u "admin:${PASSWORD}" \
-X POST \
-H "Content-Type: application/json" \
-d '{"name":"smoke-test-token","role":"Admin"}' \
https://localhost:8000/v1/apitokens)
HTTP_CODE=$(echo "${TOKEN_RESPONSE}" | tail -n1)
TOKEN_BODY=$(echo "${TOKEN_RESPONSE}" | sed '$d')
echo "API response status: ${HTTP_CODE}"
if [ "${HTTP_CODE}" != "200" ]; then
echo "ERROR: Failed to generate token. HTTP status: ${HTTP_CODE}"
echo "Response: ${TOKEN_BODY}"
exit 1
fi
if ! echo "${TOKEN_BODY}" | jq -e . > /dev/null 2>&1; then
echo "ERROR: Invalid JSON response from token generation"
echo "Response: ${TOKEN_BODY}"
exit 1
fi
API_TOKEN=$(echo "${TOKEN_BODY}" | jq -r '.token')
if [ -z "${API_TOKEN}" ] || [ "${API_TOKEN}" = "null" ]; then
echo "ERROR: Generated token is null or empty"
echo "Response: ${TOKEN_BODY}"
exit 1
fi
echo "Token generated successfully"
echo "::add-mask::${API_TOKEN}"
echo "token=${API_TOKEN}" >> "$GITHUB_OUTPUT"
- name: Install go-junit-report
run: go install github.com/jstemmer/go-junit-report/v2@v2.1.0
- name: Run smoke tests with JUnit output
env:
ROX_ENDPOINT: localhost:8000
ROX_API_TOKEN: ${{ steps.generate-token.outputs.token }}
run: |
go test -v -tags=smoke -cover -race -coverprofile=coverage-smoke.out -timeout=20m ./smoke 2>&1 | \
tee /dev/stderr | \
go-junit-report -set-exit-code -out junit-smoke.xml
- name: Upload JUnit test results
if: always()
uses: actions/upload-artifact@v4
with:
name: junit-smoke-results
path: junit-smoke.xml
if-no-files-found: error
- name: Upload test results to Codecov
if: always()
uses: codecov/test-results-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: junit-smoke.xml
- name: Upload coverage to Codecov
if: always()
uses: codecov/codecov-action@v5
with:
files: ./coverage-smoke.out
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
flags: smoke
name: smoke-tests
- name: Collect logs
if: always()
run: |
mkdir -p logs
kubectl get pods -A > logs/pods.txt || true
kubectl get events -A --sort-by='.lastTimestamp' > logs/events.txt || true
kubectl logs -n vulnerable-apps deployment/vulnerable-app --all-containers=true > logs/vulnerable-app.log || true
kubectl logs -n stackrox deployment/central > logs/central.log || true
kubectl logs -n stackrox deployment/scanner > logs/scanner.log || true
kubectl describe pod -n vulnerable-apps > logs/vulnerable-app-describe.txt || true
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: smoke-test-logs
path: logs/
if-no-files-found: ignore