|
23 | 23 | type: boolean |
24 | 24 | description: Toggle to reinstall poetry on top of python version installed by asdf. |
25 | 25 | default: false |
| 26 | + run_docker_scan: |
| 27 | + type: boolean |
| 28 | + description: Toggle to run docker vulnerability scan on this repository. |
| 29 | + default: false |
| 30 | + required: false |
| 31 | + docker_images: |
| 32 | + type: string |
| 33 | + description: comma separated list of docker image references to scan when docker scanning is enabled. |
| 34 | + default: "" |
| 35 | + required: false |
26 | 36 |
|
27 | 37 | jobs: |
28 | 38 | quality_checks: |
@@ -237,7 +247,6 @@ jobs: |
237 | 247 |
|
238 | 248 | - name: Run unit tests |
239 | 249 | run: make test |
240 | | - |
241 | 250 | - name: Generate SBOM |
242 | 251 | uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 |
243 | 252 | with: |
@@ -344,7 +353,160 @@ jobs: |
344 | 353 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
345 | 354 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} |
346 | 355 |
|
347 | | - # CloudFormation validation (runs only if templates exist, ~3-5 minutes) |
| 356 | + get_docker_images_to_scan: |
| 357 | + outputs: |
| 358 | + docker_images: ${{ steps.normalized_docker_images.outputs.images }} |
| 359 | + runs-on: ubuntu-22.04 |
| 360 | + steps: |
| 361 | + - name: Checkout code |
| 362 | + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd |
| 363 | + with: |
| 364 | + ref: ${{ env.BRANCH_NAME }} |
| 365 | + fetch-depth: 0 |
| 366 | + - name: Determine docker images to scan |
| 367 | + id: normalized_docker_images |
| 368 | + env: |
| 369 | + DOCKER_IMAGES: ${{ inputs.docker_images }} |
| 370 | + run: | |
| 371 | + if [ "${{ inputs.run_docker_scan }}" != "true" ]; then |
| 372 | + echo "Docker scanning disabled; emitting empty image list." |
| 373 | + echo 'images=[]' >> "$GITHUB_OUTPUT" |
| 374 | + exit 0 |
| 375 | + fi |
| 376 | +
|
| 377 | + INPUT="${DOCKER_IMAGES}" |
| 378 | +
|
| 379 | + if [ -z "$INPUT" ]; then |
| 380 | + INPUT="[]" |
| 381 | + fi |
| 382 | +
|
| 383 | + normalize_to_json_array() { |
| 384 | + local raw="$1" |
| 385 | +
|
| 386 | + # If the input already looks like JSON, return as-is |
| 387 | + if echo "$raw" | grep -q '^[[:space:]]*\['; then |
| 388 | + echo "$raw" |
| 389 | + return |
| 390 | + fi |
| 391 | +
|
| 392 | + local json="[" |
| 393 | + local first=true |
| 394 | + IFS=',' read -ra ITEMS <<< "$raw" |
| 395 | + for item in "${ITEMS[@]}"; do |
| 396 | + # Trim whitespace around each image reference |
| 397 | + item=$(echo "$item" | xargs) |
| 398 | + if [ -z "$item" ]; then |
| 399 | + continue |
| 400 | + fi |
| 401 | + if [ "$first" = true ]; then |
| 402 | + first=false |
| 403 | + else |
| 404 | + json+=", " |
| 405 | + fi |
| 406 | + json+="\"$item\"" |
| 407 | + done |
| 408 | + json+="]" |
| 409 | + echo "$json" |
| 410 | + } |
| 411 | +
|
| 412 | + NORMALIZED=$(normalize_to_json_array "$INPUT") |
| 413 | +
|
| 414 | + if [ "$NORMALIZED" = "[]" ]; then |
| 415 | + echo "No docker images provided" |
| 416 | + exit 1 |
| 417 | + fi |
| 418 | +
|
| 419 | + echo "Using provided docker images: $NORMALIZED" |
| 420 | + echo "images=$NORMALIZED" >> "$GITHUB_OUTPUT" |
| 421 | +
|
| 422 | + docker_vulnerability_scan: |
| 423 | + runs-on: ubuntu-22.04 |
| 424 | + needs: get_docker_images_to_scan |
| 425 | + if: ${{ inputs.run_docker_scan == true }} |
| 426 | + strategy: |
| 427 | + matrix: |
| 428 | + docker_image: ${{ fromJson(needs.get_docker_images_to_scan.outputs.docker_images) }} |
| 429 | + steps: |
| 430 | + - name: Checkout code |
| 431 | + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd |
| 432 | + with: |
| 433 | + ref: ${{ env.BRANCH_NAME }} |
| 434 | + fetch-depth: 0 |
| 435 | + # using git commit sha for version of action to ensure we have stable version |
| 436 | + - name: Install asdf |
| 437 | + uses: asdf-vm/actions/setup@b7bcd026f18772e44fe1026d729e1611cc435d47 |
| 438 | + with: |
| 439 | + asdf_version: ${{ inputs.asdfVersion }} |
| 440 | + |
| 441 | + - name: Cache asdf |
| 442 | + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb |
| 443 | + with: |
| 444 | + path: | |
| 445 | + ~/.asdf |
| 446 | + key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }}-${{ inputs.asdfVersion }} |
| 447 | + restore-keys: | |
| 448 | + ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }}-${{ inputs.asdfVersion }} |
| 449 | +
|
| 450 | + - name: Install asdf dependencies in .tool-versions |
| 451 | + uses: asdf-vm/actions/install@b7bcd026f18772e44fe1026d729e1611cc435d47 |
| 452 | + with: |
| 453 | + asdf_version: ${{ inputs.asdfVersion }} |
| 454 | + env: |
| 455 | + PYTHON_CONFIGURE_OPTS: --enable-shared |
| 456 | + |
| 457 | + - name: Reinstall poetry |
| 458 | + if: ${{ inputs.reinstall_poetry }} |
| 459 | + run: | |
| 460 | + poetry_tool_version=$(cat .tool-versions | grep poetry) |
| 461 | + poetry_version=${poetry_tool_version//"poetry "} |
| 462 | + asdf uninstall poetry "$poetry_version" |
| 463 | + asdf install poetry |
| 464 | +
|
| 465 | + - name: Setting up .npmrc |
| 466 | + env: |
| 467 | + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 468 | + run: | |
| 469 | + echo "//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}" >> ~/.npmrc |
| 470 | + echo "@nhsdigital:registry=https://npm.pkg.github.com" >> ~/.npmrc |
| 471 | +
|
| 472 | + - name: Cache npm dependencies |
| 473 | + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb |
| 474 | + with: |
| 475 | + path: ./node_modules |
| 476 | + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} |
| 477 | + restore-keys: | |
| 478 | + ${{ runner.os }}-node- |
| 479 | +
|
| 480 | + - name: make install |
| 481 | + run: | |
| 482 | + make install |
| 483 | +
|
| 484 | + - name: Build docker images |
| 485 | + if: ${{ inputs.run_docker_scan == true }} |
| 486 | + run: | |
| 487 | + make docker-build |
| 488 | +
|
| 489 | + - name: Check docker vulnerabilities |
| 490 | + uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 |
| 491 | + with: |
| 492 | + scan-type: "image" |
| 493 | + image-ref: ${{ matrix.docker_image }} |
| 494 | + severity: "CRITICAL,HIGH" |
| 495 | + scanners: "vuln" |
| 496 | + vuln-type: "os,library" |
| 497 | + format: "table" |
| 498 | + output: "dependency_results_docker.txt" |
| 499 | + exit-code: "1" |
| 500 | + trivy-config: trivy.yaml |
| 501 | + |
| 502 | + - name: Show docker vulnerability output |
| 503 | + if: always() |
| 504 | + run: | |
| 505 | + echo "Scan output for ${{ matrix.docker_image }}" |
| 506 | + if [ -f dependency_results_docker.txt ]; then |
| 507 | + cat dependency_results_docker.txt |
| 508 | + fi |
| 509 | +
|
348 | 510 | IaC-validation: |
349 | 511 | runs-on: ubuntu-22.04 |
350 | 512 | steps: |
|
0 commit comments