From 6f988c1bd444ae8cf9f587af1f0bd984fd0b4c44 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 22 Jul 2026 23:04:30 +0000
Subject: [PATCH 1/2] Initial plan


From 8ee5126d42b9d7c504527f58efcaa2a3dd3be025 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 22 Jul 2026 23:17:26 +0000
Subject: [PATCH 2/2] Fix container scan exit handling

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 .../workflows/daily-squid-image-scan.lock.yml | 31 ++++++++++++++-----
 .github/workflows/daily-squid-image-scan.md   | 27 +++++++++++++---
 2 files changed, 46 insertions(+), 12 deletions(-)

diff --git a/.github/workflows/daily-squid-image-scan.lock.yml b/.github/workflows/daily-squid-image-scan.lock.yml
index 56521350037..1f6f005f36e 100644
--- a/.github/workflows/daily-squid-image-scan.lock.yml
+++ b/.github/workflows/daily-squid-image-scan.lock.yml
@@ -1,4 +1,4 @@
-# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"2fdca74fe22075f66004cc1d12d83c98bce3aee24e184763ac92e74333ec743c","body_hash":"7a1f8b7d3ba999bc2945954c493e41a43a33b260a3374e9b0d67958617da65db","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.73"}}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"152685b4f0cd2413c50576d7177b63b1ea7d54bcd367ad48a705623da70497a9","body_hash":"7a1f8b7d3ba999bc2945954c493e41a43a33b260a3374e9b0d67958617da65db","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.73"}}
 # gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.37","digest":"sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.37@sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37","digest":"sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37@sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.37","digest":"sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.37@sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.3","digest":"sha256:3c744710ea275cd5ee65db92a1099e0d980754bd9fafda9ce67704c67004dc83","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.3@sha256:3c744710ea275cd5ee65db92a1099e0d980754bd9fafda9ce67704c67004dc83"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]}
 # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md
 #
@@ -984,9 +984,15 @@ jobs:
           if [ ! -f /tmp/gh-aw/agent_output.json ]; then
             echo '{"items":[]}' > /tmp/gh-aw/agent_output.json
           fi
-      - if: always()
+      - env:
+          SCAN_JOB_RESULT: ${{ needs.scan_image.result }}
+        if: always()
         name: Enforce critical vulnerability and license gates
         run: |-
+          if [ "$SCAN_JOB_RESULT" != "success" ]; then
+            echo "::error::Image scan job concluded with ${SCAN_JOB_RESULT}."
+            exit 1
+          fi
           summary="/tmp/gh-aw/agent/image-scan/summary.json"
           jq -e '
             (.critical_vulnerabilities == 0) and
@@ -1788,6 +1794,7 @@ jobs:
             image_tag=$(jq -r '.image' <<<"$image_entry")
             pinned_image=$(jq -r '.pinned_image' <<<"$image_entry")
             index_digest=$(jq -r '.digest' <<<"$image_entry")
+            echo "Scanning ${pinned_image}"
             image_errors="$output/${artifact_prefix}-errors.txt"
             image_platforms="$output/${artifact_prefix}-platforms.tsv"
             : > "$image_errors"
@@ -1871,12 +1878,14 @@ jobs:
               if ! syft "${syft_args[@]}" "$immutable_image" \
                 -o "syft-json=${syft_json}" \
                 -o "spdx-json=${spdx_json}" > "$output/syft-${suffix}.txt" 2>&1; then
+                cat "$output/syft-${suffix}.txt" >&2
                 record_image_error "Syft failed to scan ${image_tag} for ${platform} at ${child_digest}."
                 continue
               fi
 
               if ! GRYPE_DB_AUTO_UPDATE=false grype "sbom:${syft_json}" \
                 -o json > "$output/grype-${suffix}.json" 2> "$output/grype-${suffix}.stderr"; then
+                cat "$output/grype-${suffix}.stderr" >&2
                 record_image_error "Grype failed to produce JSON results for ${image_tag} on ${platform}."
                 continue
               fi
@@ -1894,34 +1903,42 @@ jobs:
               image_critical=$((image_critical + platform_critical))
               image_fixable=$((image_fixable + platform_fixable))
 
+              grype_exit=0
               GRYPE_DB_AUTO_UPDATE=false grype "sbom:${syft_json}" \
-                --fail-on critical -o table > "$output/grype-${suffix}.txt" 2>&1
-              grype_exit=$?
-              if [ "$grype_exit" -ne 0 ] && [ "$grype_exit" -ne 1 ]; then
+                --fail-on critical -o table > "$output/grype-${suffix}.txt" 2>&1 ||
+                grype_exit=$?
+              if [ "$grype_exit" -ne 0 ] && [ "$grype_exit" -ne 2 ]; then
+                cat "$output/grype-${suffix}.txt" >&2
                 record_image_error "Grype table scan failed unexpectedly for ${image_tag} on ${platform}."
               fi
 
               if ! grant list "$spdx_json" > "$output/grant-list-${suffix}.txt" 2>&1; then
+                cat "$output/grant-list-${suffix}.txt" >&2
                 record_image_error "Grant could not list licenses for ${image_tag} on ${platform}."
               fi
               grant_json="$output/grant-check-${suffix}.json"
               grant_stderr="$output/grant-check-${suffix}.stderr"
+              grant_exit=0
               grant check --config .grant.yaml --output json "$spdx_json" \
-                > "$grant_json" 2> "$grant_stderr"
-              grant_exit=$?
+                > "$grant_json" 2> "$grant_stderr" ||
+                grant_exit=$?
               if ! jq -e '.run.targets | length > 0' "$grant_json" > /dev/null 2>&1; then
+                cat "$grant_stderr" >&2
                 record_image_error "Grant did not produce valid results for ${image_tag} on ${platform}."
               elif jq -e '
                 any(.run.targets[]; .evaluation.status == "error")
               ' "$grant_json" > /dev/null; then
+                cat "$grant_stderr" >&2
                 record_image_error "Grant encountered an evaluation error for ${image_tag} on ${platform}."
               elif jq -e '
                 any(.run.targets[]; .evaluation.status == "noncompliant")
               ' "$grant_json" > /dev/null; then
                 image_license_rejected=true
               elif [ "$grant_exit" -ne 0 ]; then
+                cat "$grant_stderr" >&2
                 record_image_error "Grant failed unexpectedly for ${image_tag} on ${platform}."
               fi
+              echo "${image_tag} ${platform}: ${platform_total} vulnerabilities, ${platform_critical} critical, ${platform_fixable} fixable"
             done < "$image_platforms"
 
             total_vulnerabilities=$((total_vulnerabilities + image_total))
diff --git a/.github/workflows/daily-squid-image-scan.md b/.github/workflows/daily-squid-image-scan.md
index 02fa00413fc..9935ce4c249 100644
--- a/.github/workflows/daily-squid-image-scan.md
+++ b/.github/workflows/daily-squid-image-scan.md
@@ -61,7 +61,13 @@ steps:
 post-steps:
   - name: Enforce critical vulnerability and license gates
     if: always()
+    env:
+      SCAN_JOB_RESULT: ${{ needs.scan_image.result }}
     run: |
+      if [ "$SCAN_JOB_RESULT" != "success" ]; then
+        echo "::error::Image scan job concluded with ${SCAN_JOB_RESULT}."
+        exit 1
+      fi
       summary="/tmp/gh-aw/agent/image-scan/summary.json"
       jq -e '
         (.critical_vulnerabilities == 0) and
@@ -194,6 +200,7 @@ jobs:
             image_tag=$(jq -r '.image' <<<"$image_entry")
             pinned_image=$(jq -r '.pinned_image' <<<"$image_entry")
             index_digest=$(jq -r '.digest' <<<"$image_entry")
+            echo "Scanning ${pinned_image}"
             image_errors="$output/${artifact_prefix}-errors.txt"
             image_platforms="$output/${artifact_prefix}-platforms.tsv"
             : > "$image_errors"
@@ -277,12 +284,14 @@ jobs:
               if ! syft "${syft_args[@]}" "$immutable_image" \
                 -o "syft-json=${syft_json}" \
                 -o "spdx-json=${spdx_json}" > "$output/syft-${suffix}.txt" 2>&1; then
+                cat "$output/syft-${suffix}.txt" >&2
                 record_image_error "Syft failed to scan ${image_tag} for ${platform} at ${child_digest}."
                 continue
               fi
 
               if ! GRYPE_DB_AUTO_UPDATE=false grype "sbom:${syft_json}" \
                 -o json > "$output/grype-${suffix}.json" 2> "$output/grype-${suffix}.stderr"; then
+                cat "$output/grype-${suffix}.stderr" >&2
                 record_image_error "Grype failed to produce JSON results for ${image_tag} on ${platform}."
                 continue
               fi
@@ -300,34 +309,42 @@ jobs:
               image_critical=$((image_critical + platform_critical))
               image_fixable=$((image_fixable + platform_fixable))
 
+              grype_exit=0
               GRYPE_DB_AUTO_UPDATE=false grype "sbom:${syft_json}" \
-                --fail-on critical -o table > "$output/grype-${suffix}.txt" 2>&1
-              grype_exit=$?
-              if [ "$grype_exit" -ne 0 ] && [ "$grype_exit" -ne 1 ]; then
+                --fail-on critical -o table > "$output/grype-${suffix}.txt" 2>&1 ||
+                grype_exit=$?
+              if [ "$grype_exit" -ne 0 ] && [ "$grype_exit" -ne 2 ]; then
+                cat "$output/grype-${suffix}.txt" >&2
                 record_image_error "Grype table scan failed unexpectedly for ${image_tag} on ${platform}."
               fi
 
               if ! grant list "$spdx_json" > "$output/grant-list-${suffix}.txt" 2>&1; then
+                cat "$output/grant-list-${suffix}.txt" >&2
                 record_image_error "Grant could not list licenses for ${image_tag} on ${platform}."
               fi
               grant_json="$output/grant-check-${suffix}.json"
               grant_stderr="$output/grant-check-${suffix}.stderr"
+              grant_exit=0
               grant check --config .grant.yaml --output json "$spdx_json" \
-                > "$grant_json" 2> "$grant_stderr"
-              grant_exit=$?
+                > "$grant_json" 2> "$grant_stderr" ||
+                grant_exit=$?
               if ! jq -e '.run.targets | length > 0' "$grant_json" > /dev/null 2>&1; then
+                cat "$grant_stderr" >&2
                 record_image_error "Grant did not produce valid results for ${image_tag} on ${platform}."
               elif jq -e '
                 any(.run.targets[]; .evaluation.status == "error")
               ' "$grant_json" > /dev/null; then
+                cat "$grant_stderr" >&2
                 record_image_error "Grant encountered an evaluation error for ${image_tag} on ${platform}."
               elif jq -e '
                 any(.run.targets[]; .evaluation.status == "noncompliant")
               ' "$grant_json" > /dev/null; then
                 image_license_rejected=true
               elif [ "$grant_exit" -ne 0 ]; then
+                cat "$grant_stderr" >&2
                 record_image_error "Grant failed unexpectedly for ${image_tag} on ${platform}."
               fi
+              echo "${image_tag} ${platform}: ${platform_total} vulnerabilities, ${platform_critical} critical, ${platform_fixable} fixable"
             done < "$image_platforms"
 
             total_vulnerabilities=$((total_vulnerabilities + image_total))
