1+ name : C2 - SAST SonarQube Pipeline
2+
3+ on :
4+ workflow_dispatch :
5+ push :
6+ branches :
7+ - dev
8+
9+ env :
10+ SCENARIO : C2-sast
11+ RESULTS_FILE : analysis/raw/c2_sast_run.csv
12+ IMAGE_NAME : tcc-devsecops-api:local
13+ CLUSTER_NAME : tcc-devsecops
14+ SONAR_PROJECT_SETTINGS : ci/config/sonar-project.properties
15+
16+ jobs :
17+ c2-sast :
18+ name : C2 baseline plus SonarQube SAST
19+ runs-on : self-hosted
20+
21+ steps :
22+ - name : Checkout repository
23+ uses : actions/checkout@v5
24+
25+ - name : Cleanup previous kind cluster container
26+ run : |
27+ docker rm -f "${CLUSTER_NAME}-control-plane" 2>/dev/null || true
28+
29+ - name : Prepare results CSV
30+ run : |
31+ mkdir -p analysis/raw
32+ echo "WORKFLOW_START_SECONDS=$(date +%s)" >> "$GITHUB_ENV"
33+ echo "WORKFLOW_START_TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> "$GITHUB_ENV"
34+ echo "scenario,run_id,run_number,commit_sha,step_name,start_timestamp,end_timestamp,duration_seconds,status" > "$RESULTS_FILE"
35+
36+ - name : Setup Python
37+ uses : actions/setup-python@v6
38+ with :
39+ python-version : " 3.12"
40+
41+ - name : Make measurement script executable
42+ run : chmod +x ci/scripts/measure_step.sh
43+
44+ - name : Install Python dependencies
45+ run : |
46+ ./ci/scripts/measure_step.sh "install_dependencies" "$RESULTS_FILE" \
47+ python -m pip install -r app/requirements.txt
48+
49+ - name : Run unit tests
50+ run : |
51+ ./ci/scripts/measure_step.sh "unit_tests" "$RESULTS_FILE" \
52+ python -m pytest app -v
53+
54+ - name : Run SonarQube SAST analysis
55+ env :
56+ SONAR_TOKEN : ${{ secrets.SONAR_TOKEN }}
57+ SONAR_HOST_URL : ${{ secrets.SONAR_HOST_URL }}
58+ run : |
59+ SONARQUBE_NETWORK=$(docker inspect tcc-sonarqube --format '{{range $name, $_ := .NetworkSettings.Networks}}{{println $name}}{{end}}' | head -n 1)
60+ echo "Using SonarQube Docker network: $SONARQUBE_NETWORK"
61+
62+ ./ci/scripts/measure_step.sh "sonarqube_sast" "$RESULTS_FILE" \
63+ docker run --rm \
64+ --network "$SONARQUBE_NETWORK" \
65+ -e SONAR_HOST_URL="$SONAR_HOST_URL" \
66+ -e SONAR_TOKEN="$SONAR_TOKEN" \
67+ -v "$GITHUB_WORKSPACE:/usr/src" \
68+ sonarsource/sonar-scanner-cli \
69+ -Dproject.settings="$SONAR_PROJECT_SETTINGS"
70+
71+ - name : Build Docker image
72+ run : |
73+ ./ci/scripts/measure_step.sh "docker_build" "$RESULTS_FILE" \
74+ docker build -t "$IMAGE_NAME" ./app
75+
76+ - name : Install kind
77+ run : |
78+ mkdir -p "$HOME/.local/bin"
79+ curl -Lo "$HOME/.local/bin/kind" https://kind.sigs.k8s.io/dl/v0.30.0/kind-linux-amd64
80+ chmod +x "$HOME/.local/bin/kind"
81+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
82+ export PATH="$HOME/.local/bin:$PATH"
83+ kind version
84+
85+ - name : Create local Kubernetes cluster
86+ run : |
87+ kind create cluster --name "$CLUSTER_NAME" --config infra/kind/kind-cluster.yaml
88+ kubectl cluster-info
89+ kubectl get nodes
90+
91+ - name : Deploy to Kubernetes
92+ run : |
93+ ./ci/scripts/measure_step.sh "kubernetes_deploy" "$RESULTS_FILE" \
94+ bash -c 'kind load docker-image "$IMAGE_NAME" --name "$CLUSTER_NAME" && kubectl apply -f infra/k8s/namespace.yaml && kubectl apply -f infra/k8s/deployment.yaml && kubectl apply -f infra/k8s/service.yaml && kubectl rollout status deployment/tcc-api -n app --timeout=120s'
95+
96+ - name : Smoke test Kubernetes deployment
97+ run : |
98+ ./ci/scripts/measure_step.sh "kubernetes_smoke_test" "$RESULTS_FILE" \
99+ bash -c 'kubectl port-forward svc/tcc-api 8000:80 -n app > /tmp/port-forward.log 2>&1 & PF_PID=$!; sleep 5; curl -fsS http://localhost:8000/health; kill $PF_PID'
100+
101+ - name : Append workflow total duration
102+ if : always()
103+ run : |
104+ WORKFLOW_END_TIMESTAMP="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
105+ WORKFLOW_END_SECONDS="$(date +%s)"
106+ WORKFLOW_DURATION_SECONDS=$((WORKFLOW_END_SECONDS - WORKFLOW_START_SECONDS))
107+ echo "${SCENARIO},${GITHUB_RUN_ID},${GITHUB_RUN_NUMBER},${GITHUB_SHA},workflow_total,${WORKFLOW_START_TIMESTAMP},${WORKFLOW_END_TIMESTAMP},${WORKFLOW_DURATION_SECONDS},success" >> "$RESULTS_FILE"
108+
109+ - name : Show collected metrics
110+ if : always()
111+ run : |
112+ echo "Collected C2 SAST metrics:"
113+ cat "$RESULTS_FILE"
114+
115+ - name : Write GitHub Actions summary
116+ if : always()
117+ run : |
118+ echo "## C2 - SAST SonarQube Pipeline" >> "$GITHUB_STEP_SUMMARY"
119+ echo "" >> "$GITHUB_STEP_SUMMARY"
120+ echo "Scenario: $SCENARIO" >> "$GITHUB_STEP_SUMMARY"
121+ echo "" >> "$GITHUB_STEP_SUMMARY"
122+ echo "### Collected metrics" >> "$GITHUB_STEP_SUMMARY"
123+ echo "" >> "$GITHUB_STEP_SUMMARY"
124+ echo '```csv' >> "$GITHUB_STEP_SUMMARY"
125+ cat "$RESULTS_FILE" >> "$GITHUB_STEP_SUMMARY"
126+ echo '```' >> "$GITHUB_STEP_SUMMARY"
127+
128+ - name : Upload C2 metrics artifact
129+ if : always()
130+ uses : actions/upload-artifact@v6
131+ with :
132+ name : c2-sast-metrics
133+ path : analysis/raw/c2_sast_run.csv
0 commit comments