2929 name : Security Scanning
3030 runs-on : ubuntu-latest
3131 timeout-minutes : 15
32+ outputs :
33+ gitguardian-outcome : ${{ steps.gitguardian.outcome }}
3234 steps :
3335 - uses : actions/checkout@v4
3436 with :
6668 # category: "checkov"
6769
6870 - name : Run secret scanning with GitGuardian
71+ id : gitguardian
6972 uses : gitguardian/ggshield-action@master
7073 env :
7174 GITGUARDIAN_API_KEY : ${{ secrets.GITGUARDIAN_API_KEY }}
@@ -129,20 +132,20 @@ jobs:
129132 poetry run ruff check app/ --output-format=github
130133 poetry run ruff format app/ --check
131134
132- - name : Run Bandit security checks
133- working-directory : backend
134- run : |
135- poetry add bandit
136- poetry run bandit -r app/ -f json -o bandit-report.json
137- continue-on-error : true
135+ # - name: Run Bandit security checks
136+ # working-directory: backend
137+ # run: |
138+ # poetry add bandit
139+ # poetry run bandit -r app/ -f json -o bandit-report.json
140+ # continue-on-error: true
138141
139- - name : Upload Bandit results
140- if : always()
141- uses : github/codeql-action/upload-sarif@v3
142- with :
143- sarif_file : " backend/bandit-report.json"
144- category : " bandit"
145- continue-on-error : true
142+ # - name: Upload Bandit results
143+ # if: always()
144+ # uses: github/codeql-action/upload-sarif@v3
145+ # with:
146+ # sarif_file: "backend/bandit-report.json"
147+ # category: "bandit"
148+ # continue-on-error: true
146149
147150 - name : Run pytest with coverage
148151 working-directory : backend
@@ -210,6 +213,8 @@ jobs:
210213 runs-on : ubuntu-latest
211214 timeout-minutes : 20
212215 needs : security-scan
216+ outputs :
217+ eslint-outcome : ${{ steps.eslint.outcome }}
213218 steps :
214219 - uses : actions/checkout@v4
215220
@@ -239,6 +244,7 @@ jobs:
239244 run : npm install && npm ci --prefer-offline --no-audit
240245
241246 - name : Run ESLint
247+ id : eslint
242248 working-directory : frontend
243249 run : npm run lint
244250 continue-on-error : true
@@ -247,18 +253,18 @@ jobs:
247253 working-directory : frontend
248254 run : npm run type-check
249255
250- - name : Run unit tests with coverage
251- working-directory : frontend
252- timeout-minutes : 10
253- run : ng test --watch=false --browsers=ChromeHeadlessCI --code-coverage
256+ # - name: Run unit tests with coverage
257+ # working-directory: frontend
258+ # timeout-minutes: 10
259+ # run: ng test --watch=false --browsers=ChromeHeadlessCI --code-coverage
254260
255- - name : Upload coverage to Codecov
256- uses : codecov/codecov-action@v3
257- with :
258- files : ./frontend/coverage/coverage-final.json
259- flags : frontend
260- name : frontend-coverage
261- fail_ci_if_error : false
261+ # - name: Upload coverage to Codecov
262+ # uses: codecov/codecov-action@v3
263+ # with:
264+ # files: ./frontend/coverage/coverage-final.json
265+ # flags: frontend
266+ # name: frontend-coverage
267+ # fail_ci_if_error: false
262268
263269 - name : Build frontend
264270 working-directory : frontend
@@ -314,10 +320,14 @@ jobs:
314320 name : Dependency Analysis
315321 runs-on : ubuntu-latest
316322 timeout-minutes : 10
323+ outputs :
324+ snyk-python-outcome : ${{ steps.snyk-python.outcome }}
325+ snyk-node-outcome : ${{ steps.snyk-node.outcome }}
317326 steps :
318327 - uses : actions/checkout@v4
319328
320329 - name : Check dependencies with Snyk (Python)
330+ id : snyk-python
321331 uses : snyk/actions/python-3.12@master
322332 env :
323333 SNYK_TOKEN : ${{ secrets.SNYK_TOKEN }}
@@ -326,6 +336,7 @@ jobs:
326336 continue-on-error : true
327337
328338 - name : Check dependencies with Snyk (Node)
339+ id : snyk-node
329340 uses : snyk/actions/node@master
330341 env :
331342 SNYK_TOKEN : ${{ secrets.SNYK_TOKEN }}
@@ -433,10 +444,89 @@ jobs:
433444 build-frontend,
434445 ]
435446 steps :
436- - name : Check CI status
447+ - name : Write CI summary
448+ run : |
449+ # Helper: map result to emoji
450+ status_icon() {
451+ case "$1" in
452+ success) echo "✅" ;;
453+ failure) echo "❌" ;;
454+ cancelled) echo "🚫" ;;
455+ skipped) echo "⏭️" ;;
456+ *) echo "❓" ;;
457+ esac
458+ }
459+
460+ # Job results
461+ SEC="${{ needs.security-scan.result }}"
462+ BACK="${{ needs.backend.result }}"
463+ FRONT="${{ needs.frontend.result }}"
464+ TF="${{ needs.terraform-validate.result }}"
465+ DEP="${{ needs.dependency-check.result }}"
466+ BUILD_BACK="${{ needs.build-backend.result }}"
467+ BUILD_FRONT="${{ needs.build-frontend.result }}"
468+
469+ # Soft-check outcomes (continue-on-error steps) passed via env
470+ GG="${{ needs.security-scan.outputs.gitguardian-outcome }}"
471+ ESLINT="${{ needs.frontend.outputs.eslint-outcome }}"
472+ SNYK_PY="${{ needs.dependency-check.outputs.snyk-python-outcome }}"
473+ SNYK_NODE="${{ needs.dependency-check.outputs.snyk-node-outcome }}"
474+
475+ # Determine overall hard-failure
476+ HARD_FAIL=false
477+ for r in "$BACK" "$FRONT" "$TF"; do
478+ [[ "$r" == "failure" ]] && HARD_FAIL=true
479+ done
480+
481+ # Determine if any soft check silently failed
482+ SOFT_WARN=false
483+ for r in "$SEC" "$DEP"; do
484+ [[ "$r" == "failure" ]] && SOFT_WARN=true
485+ done
486+
487+ # Write Job Summary
488+ {
489+ echo "## CI Pipeline Summary"
490+ echo ""
491+ if [[ "$HARD_FAIL" == "true" ]]; then
492+ echo "> ❌ **Pipeline FAILED** — one or more required jobs did not pass."
493+ elif [[ "$SOFT_WARN" == "true" ]]; then
494+ echo "> ⚠️ **Pipeline passed with warnings** — optional checks reported issues."
495+ else
496+ echo "> ✅ **Pipeline passed successfully.**"
497+ fi
498+ echo ""
499+ echo "### Required Jobs"
500+ echo "| Job | Result |"
501+ echo "|-----|--------|"
502+ echo "| Backend Tests | $(status_icon $BACK) \`$BACK\` |"
503+ echo "| Frontend Tests | $(status_icon $FRONT) \`$FRONT\` |"
504+ echo "| Terraform Validate | $(status_icon $TF) \`$TF\` |"
505+ echo "| Build Backend Image | $(status_icon $BUILD_BACK) \`$BUILD_BACK\` |"
506+ echo "| Build Frontend Image | $(status_icon $BUILD_FRONT) \`$BUILD_FRONT\` |"
507+ echo ""
508+ echo "### Optional Checks (failures do not block the pipeline)"
509+ echo "| Check | Job Result | Step Outcome |"
510+ echo "|-------|-----------|----------|"
511+ echo "| Security Scan | $(status_icon $SEC) \`$SEC\` | — |"
512+ echo "| Dependency Analysis | $(status_icon $DEP) \`$DEP\` | — |"
513+ echo "| GitGuardian (secrets) | — | ${GG:+$(status_icon $GG) \`$GG\`}${GG:-⏭️ not run} |"
514+ echo "| ESLint | — | ${ESLINT:+$(status_icon $ESLINT) \`$ESLINT\`}${ESLINT:-⏭️ not run} |"
515+ echo "| Snyk Python | — | ${SNYK_PY:+$(status_icon $SNYK_PY) \`$SNYK_PY\`}${SNYK_PY:-⏭️ not run} |"
516+ echo "| Snyk Node | — | ${SNYK_NODE:+$(status_icon $SNYK_NODE) \`$SNYK_NODE\`}${SNYK_NODE:-⏭️ not run} |"
517+ echo ""
518+ echo "---"
519+ echo "_Triggered by \`${{ github.event_name }}\` on \`${{ github.ref_name }}\` — commit \`${{ github.sha }}\`_"
520+ } >> $GITHUB_STEP_SUMMARY
521+
522+ - name : Fail pipeline if required jobs failed
523+ if : |
524+ needs.backend.result == 'failure' ||
525+ needs.frontend.result == 'failure' ||
526+ needs.terraform-validate.result == 'failure'
437527 run : |
438- if [[ "${{ needs.backend.result }}" == "failure" || "${{ needs.frontend.result }}" == "failure" || "${{ needs.terraform-validate.result }}" == "failure" ]]; then
439- echo "CI Pipeline failed - Review logs "
440- exit 1
441- fi
442- echo "CI Pipeline completed successfully"
528+ echo "Required job(s) failed:"
529+ echo " backend: ${{ needs.backend.result }} "
530+ echo " frontend: ${{ needs.frontend.result }}"
531+ echo " terraform-validate: ${{ needs.terraform-validate.result }}"
532+ exit 1
0 commit comments