@@ -379,3 +379,227 @@ jobs:
379
379
echo "[Debug] PWD[${PWD}]";
380
380
echo "[Debug] ****************************";
381
381
git push
382
+
383
+
384
+ vulnerability-scan :
385
+ name : PIP file Scan (requirements.txt)
386
+ runs-on : ubuntu-latest
387
+ steps :
388
+
389
+
390
+ - uses : actions/checkout@v4
391
+
392
+
393
+ - name : Run Trivy vulnerability scanner against requirements.txt
394
+ uses : aquasecurity/trivy-action@0.20.0
395
+ with :
396
+ scan-type : ' fs'
397
+ ignore-unfixed : false
398
+ format : ' sarif'
399
+ output : ' trivy-results.sarif'
400
+ severity : ' LOW,MEDIUM,HIGH,CRITICAL'
401
+ scan-ref : requirements.txt
402
+ exit-code : 0
403
+
404
+
405
+ - name : Upload requirements.txt scan results to GitHub Security tab
406
+ uses : github/codeql-action/upload-sarif@v3
407
+ with :
408
+ sarif_file : ' trivy-results.sarif'
409
+
410
+
411
+ - name : Run Trivy vulnerability scanner against requirements.txt (json Report)
412
+ uses : aquasecurity/trivy-action@0.20.0
413
+ with :
414
+ scan-type : ' fs'
415
+ ignore-unfixed : false
416
+ format : ' json'
417
+ output : ' scan-results.json'
418
+ severity : ' LOW,MEDIUM,HIGH,CRITICAL'
419
+ scan-ref : requirements.txt
420
+ exit-code : 0
421
+
422
+
423
+ - name : Upload scan results (json Report)
424
+ uses : actions/upload-artifact@v4
425
+ with :
426
+ name : python-scan-results-json
427
+ path : scan-results.json
428
+
429
+
430
+
431
+ vulnerability-report :
432
+ name : Create Reports
433
+ needs :
434
+ - vulnerability-scan
435
+ runs-on : ubuntu-latest
436
+ steps :
437
+
438
+
439
+ - name : Fetch scan results (json Report)
440
+ uses : actions/download-artifact@v4
441
+ with :
442
+ name : python-scan-results-json
443
+
444
+
445
+ - name : Create Vulnerabilities (Critical/High)
446
+ run : |
447
+ echo "[Debug] jq -r '.Results'=$(jq -r '.Results' scan-results.json)";
448
+
449
+ if [ "$(jq -r '.Results' scan-results.json)" ]; then
450
+
451
+ not_empty="$(jq -r '.Results[] | .Vulnerabilities[]' scan-results.json)";
452
+
453
+ else
454
+
455
+ not_empty="";
456
+
457
+ fi
458
+
459
+ echo "[Debug] not_empty=${not_empty}";
460
+
461
+ jq -r '
462
+ [
463
+ "# Python Scan Results (requirements.txt)",
464
+ "",
465
+ "**Scan Date:** _" + ( .CreatedAt // "" ) + "_",
466
+ "**File:** _" + ( .ArtifactName // "" ) + "_",
467
+ ""
468
+ ] | join("\n")
469
+ ' scan-results.json > vulnerability-report.md
470
+
471
+ if [ "$not_empty" ]; then
472
+ jq -r '
473
+ def hr(severity):
474
+ if severity == "HIGH" or severity == "CRITICAL" then true else false end;
475
+ def to_md:
476
+ "| " + (.VulnerabilityID // "") + " | " + (.PkgName // "") + " | " + (.InstalledVersion // "") + " | " + (.Severity // "") + " | " + (.Title // "") + " |";
477
+ [
478
+ "## High and Critical Vulnerabilities",
479
+ "",
480
+ "| Vulnerability ID | Package | Version | Severity | Description |",
481
+ "| --------- | ----- | ----- | ----- | -------|",
482
+ (.Results[] | .Vulnerabilities[] | select(hr(.Severity)) | to_md),
483
+ ""
484
+ ] | join("\n")
485
+ ' scan-results.json >> vulnerability-report.md
486
+
487
+ else
488
+
489
+ echo "**Nothing Found**" >> vulnerability-report.md
490
+
491
+ fi;
492
+
493
+
494
+
495
+ - name : Create Full Vulnerabilities
496
+ run : |
497
+ echo "[Debug] jq -r '.Results'=$(jq -r '.Results' scan-results.json)";
498
+
499
+ if [ "$(jq -r '.Results' scan-results.json)" ]; then
500
+
501
+ not_empty="$(jq -r '.Results[] | .Vulnerabilities[]' scan-results.json)";
502
+
503
+ else
504
+
505
+ not_empty="";
506
+
507
+ fi
508
+
509
+ echo "[Debug] not_empty=${not_empty}";
510
+
511
+
512
+ jq -r '
513
+ [
514
+ "# Full Scan Results",
515
+ "",
516
+ "**Scan Date:** _" + ( .CreatedAt // "" ) + "_",
517
+ "**File:** _" + ( .ArtifactName // "" ) + "_",
518
+ ""
519
+ ] | join("\n")
520
+ ' scan-results.json > full-vulnerability-report.md
521
+
522
+ if [ "$not_empty" ]; then
523
+ jq -r '
524
+ def hr(severity):
525
+ if severity == "HIGH" or severity == "CRITICAL" then true else true end;
526
+ def to_md:
527
+ "| " + (.VulnerabilityID // "") + " | " + (.PkgName // "") + " | " + (.InstalledVersion // "") + " | " + (.Severity // "") + " | " + (.Title // "") + " |";
528
+ [
529
+ "## Vulnerabilities",
530
+ "",
531
+ "| Vulnerability ID | Package | Version | Severity | Description |",
532
+ "| --------- | ----- | ----- | ----- | -------|",
533
+ (.Results[] | .Vulnerabilities[] | select(.Severity) | to_md),
534
+ ""
535
+ ] | join("\n")
536
+ ' scan-results.json >> full-vulnerability-report.md
537
+
538
+ else
539
+
540
+ echo "**Nothing Found**" >> full-vulnerability-report.md
541
+
542
+ fi;
543
+
544
+
545
+ - name : Upload scan results
546
+ uses : actions/upload-artifact@v4
547
+ with :
548
+ name : python-vulnerability-report
549
+ path : vulnerability-report.md
550
+
551
+
552
+ - name : Upload scan results
553
+ uses : actions/upload-artifact@v4
554
+ with :
555
+ name : python-vulnerability-report-full
556
+ path : full-vulnerability-report.md
557
+
558
+
559
+ - uses : dtinth/markdown-report-action@v1
560
+ with :
561
+ name : Python Vulnerability Report
562
+ title : Python Vulnerability Report
563
+ body-file : full-vulnerability-report.md
564
+
565
+
566
+
567
+ pull-request-report-comment :
568
+ if : ${{ github.ref_type != 'tag' }}
569
+ needs :
570
+ - vulnerability-scan
571
+ - vulnerability-report
572
+ runs-on : ubuntu-latest
573
+ name : Comment on Pull Request (Python Scan)
574
+ steps :
575
+
576
+
577
+ - name : Find Current Pull Request
578
+ uses : jwalton/gh-find-current-pr@v1
579
+ id : finder
580
+
581
+
582
+ - name : Fetch Vulnerability Report
583
+ if : ${{ steps.finder.outputs.pr != '' }}
584
+ uses : actions/download-artifact@v4
585
+ with :
586
+ name : python-vulnerability-report
587
+
588
+
589
+ - name : Capture scan results
590
+ if : ${{ steps.finder.outputs.pr != '' }}
591
+ run : |
592
+ content=$(cat vulnerability-report.md | head -c 65000)
593
+ echo "report<<EOF" >> $GITHUB_ENV
594
+ echo "$content" >> $GITHUB_ENV
595
+ echo "EOF" >> $GITHUB_ENV
596
+
597
+
598
+ - name : Comment scan results on PR
599
+ if : ${{ steps.finder.outputs.pr != '' }}
600
+ uses : marocchino/sticky-pull-request-comment@v2
601
+ with :
602
+ number : ${{ steps.finder.outputs.pr }}
603
+ header : Python requirements.txt Scan Results
604
+ message : |
605
+ ${{ env.report }}
0 commit comments