diff --git a/.github/workflows/security-guard.lock.yml b/.github/workflows/security-guard.lock.yml index 8b0a8104..b686c4fa 100644 --- a/.github/workflows/security-guard.lock.yml +++ b/.github/workflows/security-guard.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"63cc172791a82ec99a045fc47b4c1795a26d0b395df926d1a12c83b84bf62b4a","body_hash":"b2dd15b1cd5808e4f168d734d5e825ab399cf007c1632fb05b4a792c8574a6b3","compiler_version":"v0.80.6","agent_id":"copilot","agent_model":"claude-haiku-4-5","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"96b63631bdb5dda236711e8a38014e751325929817a755ea4905c78ab442d1aa","body_hash":"1756b99e401a8885594db7030409d0d3ee2ed11c8485823ddc787aa647297f28","compiler_version":"v0.80.6","agent_id":"copilot","agent_model":"claude-haiku-4-5","engine_versions":{"copilot":"1.0.63"}} # 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":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/cache/save","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"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/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"c20f9e750acfb2da7ce8698626ebeb65efb33300","version":"v0.80.6"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.7","digest":"sha256:4757f198a3fa20f88bdbe70be7ae1a05f127d9c0a9e96a5d6460ef40c08fc83d","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.7@sha256:4757f198a3fa20f88bdbe70be7ae1a05f127d9c0a9e96a5d6460ef40c08fc83d"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:latest","digest":"sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa","pinned_image":"ghcr.io/github/gh-aw-mcpg:latest@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa"},{"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.3.0","digest":"sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80","pinned_image":"ghcr.io/github/github-mcp-server:v1.3.0@sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80"}]} # This file was automatically generated by gh-aw (v0.80.6). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -493,7 +493,7 @@ jobs: id: pr-diff if: github.event.pull_request.number name: Fetch PR changed files - run: "DELIM=\"GHAW_PR_FILES_$(date +%s)\"\nDIFF_LIMIT=100000\nDIFF_TMP=\"$(mktemp)\"\n{\n echo \"PR_FILES<<${DELIM}\"\n gh api \"repos/${GH_REPO}/pulls/${PR_NUMBER}/files\" \\\n --paginate --jq '.[] | \"### \" + .filename + \" (+\" + (.additions|tostring) + \"/-\" + (.deletions|tostring) + \")\\n\" + (.patch // \"\") + \"\\n\"' \\\n > \"$DIFF_TMP\" || true\n DIFF_SIZE=\"$(wc -c < \"$DIFF_TMP\" | tr -d ' ')\"\n head -c \"$DIFF_LIMIT\" \"$DIFF_TMP\" || true\n if [ \"$DIFF_SIZE\" -gt \"$DIFF_LIMIT\" ]; then\n echo -e \"\\n[DIFF TRUNCATED at ${DIFF_LIMIT} bytes — use mcp__github__get_pull_request_diff for full context]\"\n fi\n echo \"\"\n echo \"${DELIM}\"\n} >> \"$GITHUB_OUTPUT\"\nrm -f \"$DIFF_TMP\"\n" + run: "DELIM=\"GHAW_PR_FILES_$(date +%s)\"\nDIFF_LIMIT=100000\nSECURITY_RE='host-iptables|setup-iptables|squid-config|docker-manager|seccomp-profile|domain-patterns|entrypoint\\.sh|Dockerfile|(^|/)containers/'\nTEST_EXCLUDE_RE='(^|/)tests?/|\\.test\\.'\nDIFF_TMP=\"$(mktemp)\"\n# Include full patches only for security-relevant files (largest first);\n# list every other changed file by name so large non-security refactors\n# don't bloat the prompt.\ngh api \"repos/${GH_REPO}/pulls/${PR_NUMBER}/files\" --paginate --slurp \\\n | jq -r --arg re \"$SECURITY_RE\" --arg test_ex \"$TEST_EXCLUDE_RE\" '\n ([.[][]]) as $files\n | ([$files[] | select((.filename | test($re)) and (.filename | test($test_ex) | not))] | sort_by(-(.additions + .deletions))) as $sec\n | ([$files[] | select(((.filename | test($re)) and (.filename | test($test_ex) | not)) | not)]) as $other\n | ( $sec[]\n | \"### \" + .filename + \" (+\" + (.additions|tostring) + \"/-\" + (.deletions|tostring) + \") [security-relevant]\\n\" + (.patch // \"(binary or no textual patch)\") + \"\\n\" ),\n ( if ($other | length) > 0\n then \"\\n### Other changed files (not security-relevant — patches omitted to save context):\\n\"\n + ([$other[] | \"- \" + .filename + \" (+\" + (.additions|tostring) + \"/-\" + (.deletions|tostring) + \")\"] | join(\"\\n\")) + \"\\n\"\n else empty end )\n ' > \"$DIFF_TMP\" || true\nDIFF_SIZE=\"$(wc -c < \"$DIFF_TMP\" | tr -d ' ')\"\n{\n echo \"PR_FILES<<${DELIM}\"\n head -c \"$DIFF_LIMIT\" \"$DIFF_TMP\" || true\n if [ \"$DIFF_SIZE\" -gt \"$DIFF_LIMIT\" ]; then\n echo -e \"\\n[DIFF TRUNCATED at ${DIFF_LIMIT} bytes — security-relevant patches are shown first; if one is still missing, fetch the full PR diff once via mcp__github__get_pull_request_diff and locate that file section]\"\n fi\n echo \"\"\n echo \"${DELIM}\"\n} >> \"$GITHUB_OUTPUT\"\nrm -f \"$DIFF_TMP\"\n" - env: GH_REPO: ${{ github.repository }} GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/security-guard.md b/.github/workflows/security-guard.md index 60177a14..c0bd28a2 100644 --- a/.github/workflows/security-guard.md +++ b/.github/workflows/security-guard.md @@ -67,16 +67,30 @@ steps: run: | DELIM="GHAW_PR_FILES_$(date +%s)" DIFF_LIMIT=100000 + SECURITY_RE='host-iptables|setup-iptables|squid-config|docker-manager|seccomp-profile|domain-patterns|entrypoint\.sh|Dockerfile|(^|/)containers/' + TEST_EXCLUDE_RE='(^|/)tests?/|\.test\.' DIFF_TMP="$(mktemp)" + # Include full patches only for security-relevant files (largest first); + # list every other changed file by name so large non-security refactors + # don't bloat the prompt. + gh api "repos/${GH_REPO}/pulls/${PR_NUMBER}/files" --paginate --slurp \ + | jq -r --arg re "$SECURITY_RE" --arg test_ex "$TEST_EXCLUDE_RE" ' + ([.[][]]) as $files + | ([$files[] | select((.filename | test($re)) and (.filename | test($test_ex) | not))] | sort_by(-(.additions + .deletions))) as $sec + | ([$files[] | select(((.filename | test($re)) and (.filename | test($test_ex) | not)) | not)]) as $other + | ( $sec[] + | "### " + .filename + " (+" + (.additions|tostring) + "/-" + (.deletions|tostring) + ") [security-relevant]\n" + (.patch // "(binary or no textual patch)") + "\n" ), + ( if ($other | length) > 0 + then "\n### Other changed files (not security-relevant — patches omitted to save context):\n" + + ([$other[] | "- " + .filename + " (+" + (.additions|tostring) + "/-" + (.deletions|tostring) + ")"] | join("\n")) + "\n" + else empty end ) + ' > "$DIFF_TMP" || true + DIFF_SIZE="$(wc -c < "$DIFF_TMP" | tr -d ' ')" { echo "PR_FILES<<${DELIM}" - gh api "repos/${GH_REPO}/pulls/${PR_NUMBER}/files" \ - --paginate --jq '.[] | "### " + .filename + " (+" + (.additions|tostring) + "/-" + (.deletions|tostring) + ")\n" + (.patch // "") + "\n"' \ - > "$DIFF_TMP" || true - DIFF_SIZE="$(wc -c < "$DIFF_TMP" | tr -d ' ')" head -c "$DIFF_LIMIT" "$DIFF_TMP" || true if [ "$DIFF_SIZE" -gt "$DIFF_LIMIT" ]; then - echo -e "\n[DIFF TRUNCATED at ${DIFF_LIMIT} bytes — use mcp__github__get_pull_request_diff for full context]" + echo -e "\n[DIFF TRUNCATED at ${DIFF_LIMIT} bytes — security-relevant patches are shown first; if one is still missing, fetch the full PR diff once via mcp__github__get_pull_request_diff and locate that file section]" fi echo "" echo "${DELIM}" @@ -126,7 +140,7 @@ steps: ## ⚡ Fast Path -Read the pre-fetched diff below first. If you see `[DIFF TRUNCATED ...]`, fetch full context once with `mcp__github__get_pull_request_diff` before deciding to noop. Only use the fast path when the full diff contains **no** security-weakening changes: no weakened DROP/REJECT or expanded ACCEPT, no egress/domain allowlist expansion, no firewall chain changes, no capability additions, no ACL regressions, no seccomp relaxations, no DNS/wildcard bypass, no input validation weakening, and no secrets. Then call `safeoutputs noop` immediately — do not read additional files or make further tool calls. +Read the pre-fetched diff below first. Security-relevant files are included in full; other changed files are listed by name only. If you see `[DIFF TRUNCATED ...]` and a **security-relevant** patch is missing, fetch the full PR diff once with `mcp__github__get_pull_request_diff` and locate that file section before deciding to noop. Only use the fast path when the security-relevant changes contain **no** security-weakening changes: no weakened DROP/REJECT or expanded ACCEPT, no egress/domain allowlist expansion, no firewall chain changes, no capability additions, no ACL regressions, no seccomp relaxations, no DNS/wildcard bypass, no input validation weakening, and no secrets. Then call `safeoutputs noop` immediately — do not read additional files or make further tool calls. ## Repository Context @@ -137,9 +151,9 @@ Security-critical files: `src/host-iptables.ts`, `containers/agent/setup-iptable Analyze PR #${{ github.event.pull_request.number }} in repository ${{ github.repository }}. -1. **Review the pre-fetched diff below** (up to 100 KB of changes are included) +1. **Review the pre-fetched diff below** (security-relevant files in full; other files listed by name) 2. **Batch all independent reads** in a single tool-use block rather than making sequential calls -3. **Use ONLY the pre-fetched diff below.** Do NOT call `gh pr diff`, `gh pr view`, `gh api`, `git diff`, `git log`, or `git show`. Do NOT read files from the checkout. If `[DIFF TRUNCATED ...]` appears, call `mcp__github__get_pull_request_diff` once — then stop making tool calls and analyze inline. +3. **Use ONLY the pre-fetched diff below.** Do NOT call `gh pr diff`, `gh pr view`, `gh api`, `git diff`, `git log`, or `git show`. Do NOT read files from the checkout. If `[DIFF TRUNCATED ...]` appears and a security-relevant patch is missing, call `mcp__github__get_pull_request_diff` once (it returns the full PR diff), locate the missing security-relevant file section, then stop making tool calls and analyze inline. 4. **Collect evidence** with specific file names, line numbers, and code snippets ## Security Checks @@ -149,7 +163,7 @@ Focus: weakened DROP/REJECT, added capabilities (SYS_ADMIN/NET_RAW), expanded AC ## Output Format **IMPORTANT: Be concise.** Report each security finding in ≤ 150 words. Maximum 5 findings total. -If `[DIFF TRUNCATED ...]` is present, fetch full context once with `mcp__github__get_pull_request_diff` before deciding to noop. +If `[DIFF TRUNCATED ...]` is present and a security-relevant patch is missing, fetch the full PR diff once with `mcp__github__get_pull_request_diff`, locate that file section, then decide whether to noop. If you find security concerns: 1. Add a comment to the PR explaining each concern @@ -165,7 +179,7 @@ If no security issues are found: **SECURITY**: Be thorough but avoid false positives. Focus on actual security weakening, not code style or refactoring that maintains the same security level. -## Changed Files (Pre-fetched, up to 100 KB) +## Changed Files (Pre-fetched; security-relevant patches in full) The following PR diff has been pre-computed. Focus your security analysis on these changes: