From 2696dc4f3b70c7eb99ebeb4088bad34bc8ca7ef4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 31 May 2026 13:15:03 +0000 Subject: [PATCH 1/3] Initial plan From 01af3646b3a141c7bbaf1edf2f2fac6e9eca23b9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 31 May 2026 13:19:43 +0000 Subject: [PATCH 2/3] chore: optimize export-audit token budget --- .github/workflows/export-audit.lock.yml | 375 ++++++++++++++++------- .github/workflows/export-audit.md | 49 ++- scripts/ci/export-audit-workflow.test.ts | 33 ++ 3 files changed, 334 insertions(+), 123 deletions(-) create mode 100644 scripts/ci/export-audit-workflow.test.ts diff --git a/.github/workflows/export-audit.lock.yml b/.github/workflows/export-audit.lock.yml index 54aa84171..1336235e0 100644 --- a/.github/workflows/export-audit.lock.yml +++ b/.github/workflows/export-audit.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"8aefa3ac7dcee3d54723b8155afc998c881dd970dfb07122e258d13fd6c7a4ef","compiler_version":"v0.76.1","strict":true,"agent_id":"copilot"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"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":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"46d564922b082d0db93244972e8005ea6904ee5f","version":"v0.76.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.55"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.55"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.55"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.19"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4","digest":"sha256:e3816a476a977cfb836e7d221510011436c654d11861db66ecfd826601aba6a4","pinned_image":"ghcr.io/github/github-mcp-server:v1.0.4@sha256:e3816a476a977cfb836e7d221510011436c654d11861db66ecfd826601aba6a4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"8e8de5a131f42f2c3bbf62fef1f1a8ffc769fa58ac53eea7ee484de17fc6e6f3","compiler_version":"v0.76.1","strict":true,"agent_id":"claude"} +# gh-aw-manifest: {"version":1,"secrets":["ANTHROPIC_API_KEY","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"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":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"46d564922b082d0db93244972e8005ea6904ee5f","version":"v0.76.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.55"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.55"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.55"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.19"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4","digest":"sha256:e3816a476a977cfb836e7d221510011436c654d11861db66ecfd826601aba6a4","pinned_image":"ghcr.io/github/github-mcp-server:v1.0.4@sha256:e3816a476a977cfb836e7d221510011436c654d11861db66ecfd826601aba6a4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -28,7 +28,7 @@ # to keep the API surface clean and prevent dead-code accumulation. # # Secrets used: -# - COPILOT_GITHUB_TOKEN +# - ANTHROPIC_API_KEY # - GH_AW_GITHUB_MCP_SERVER_TOKEN # - GH_AW_GITHUB_TOKEN # - GITHUB_TOKEN @@ -101,17 +101,17 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "API Surface & Export Audit" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/export-audit.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.52" + GH_AW_INFO_VERSION: "2.1.150" GH_AW_INFO_AWF_VERSION: "v0.25.55" - GH_AW_INFO_ENGINE_ID: "copilot" + GH_AW_INFO_ENGINE_ID: "claude" - name: Generate agentic run info id: generate_aw_info env: - GH_AW_INFO_ENGINE_ID: "copilot" - GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" - GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }} - GH_AW_INFO_VERSION: "1.0.52" - GH_AW_INFO_AGENT_VERSION: "1.0.52" + GH_AW_INFO_ENGINE_ID: "claude" + GH_AW_INFO_ENGINE_NAME: "Claude Code" + GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_CLAUDE || 'agent' }} + GH_AW_INFO_VERSION: "2.1.150" + GH_AW_INFO_AGENT_VERSION: "2.1.150" GH_AW_INFO_CLI_VERSION: "v0.76.1" GH_AW_INFO_WORKFLOW_NAME: "API Surface & Export Audit" GH_AW_INFO_EXPERIMENTAL: "false" @@ -130,11 +130,11 @@ jobs: setupGlobals(core, github, context, exec, io, getOctokit); const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); await main(core, context); - - name: Validate COPILOT_GITHUB_TOKEN secret + - name: Validate ANTHROPIC_API_KEY secret id: validate-secret - run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh" COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default + run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh" ANTHROPIC_API_KEY 'Claude Code' https://github.github.com/gh-aw/reference/engines/#anthropic-claude-code env: - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - name: Checkout .github and .agents folders uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -198,24 +198,25 @@ jobs: GH_AW_STEPS_NAMING_AUDIT_OUTPUTS_NAMING_ISSUES: ${{ steps.naming_audit.outputs.NAMING_ISSUES }} GH_AW_STEPS_TEST_IMPORTS_OUTPUTS_TEST_IMPORTS: ${{ steps.test_imports.outputs.TEST_IMPORTS }} GH_AW_STEPS_UNUSED_EXPORTS_OUTPUTS_UNUSED_EXPORTS: ${{ steps.unused_exports.outputs.UNUSED_EXPORTS }} + GH_AW_STEPS_VERIFIED_UNUSED_OUTPUTS_VERIFIED_UNUSED: ${{ steps.verified_unused.outputs.VERIFIED_UNUSED }} # poutine:ignore untrusted_checkout_exec run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_867465bd313589e9_EOF' + cat << 'GH_AW_PROMPT_9918201839a3620e_EOF' - GH_AW_PROMPT_867465bd313589e9_EOF + GH_AW_PROMPT_9918201839a3620e_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_867465bd313589e9_EOF' + cat << 'GH_AW_PROMPT_9918201839a3620e_EOF' Tools: create_issue(max:5), missing_tool, missing_data, noop - GH_AW_PROMPT_867465bd313589e9_EOF + GH_AW_PROMPT_9918201839a3620e_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_867465bd313589e9_EOF' + cat << 'GH_AW_PROMPT_9918201839a3620e_EOF' The following GitHub context information is available for this workflow: {{#if github.actor}} @@ -244,18 +245,18 @@ jobs: {{/if}} - GH_AW_PROMPT_867465bd313589e9_EOF + GH_AW_PROMPT_9918201839a3620e_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_867465bd313589e9_EOF' + cat << 'GH_AW_PROMPT_9918201839a3620e_EOF' {{#runtime-import .github/workflows/export-audit.md}} - GH_AW_PROMPT_867465bd313589e9_EOF + GH_AW_PROMPT_9918201839a3620e_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_ENGINE_ID: "copilot" + GH_AW_ENGINE_ID: "claude" GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_STEPS_APIP_EXPORTS_OUTPUTS_APIP_EXPORTS: ${{ steps.apip_exports.outputs.APIP_EXPORTS }} GH_AW_STEPS_CIRCULAR_DEPS_OUTPUTS_CIRCULAR_DEPS: ${{ steps.circular_deps.outputs.CIRCULAR_DEPS }} @@ -264,6 +265,7 @@ jobs: GH_AW_STEPS_TEST_IMPORTS_OUTPUTS_TEST_IMPORTS: ${{ steps.test_imports.outputs.TEST_IMPORTS }} GH_AW_EXPR_A04AFDAF: ${{ steps.ts-errors.outputs.TS_ERRORS }} GH_AW_STEPS_UNUSED_EXPORTS_OUTPUTS_UNUSED_EXPORTS: ${{ steps.unused_exports.outputs.UNUSED_EXPORTS }} + GH_AW_STEPS_VERIFIED_UNUSED_OUTPUTS_VERIFIED_UNUSED: ${{ steps.verified_unused.outputs.VERIFIED_UNUSED }} with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -291,6 +293,7 @@ jobs: GH_AW_STEPS_NAMING_AUDIT_OUTPUTS_NAMING_ISSUES: ${{ steps.naming_audit.outputs.NAMING_ISSUES }} GH_AW_STEPS_TEST_IMPORTS_OUTPUTS_TEST_IMPORTS: ${{ steps.test_imports.outputs.TEST_IMPORTS }} GH_AW_STEPS_UNUSED_EXPORTS_OUTPUTS_UNUSED_EXPORTS: ${{ steps.unused_exports.outputs.UNUSED_EXPORTS }} + GH_AW_STEPS_VERIFIED_UNUSED_OUTPUTS_VERIFIED_UNUSED: ${{ steps.verified_unused.outputs.VERIFIED_UNUSED }} with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); @@ -318,7 +321,8 @@ jobs: GH_AW_STEPS_EXPORTS_OUTPUTS_EXPORTS: process.env.GH_AW_STEPS_EXPORTS_OUTPUTS_EXPORTS, GH_AW_STEPS_NAMING_AUDIT_OUTPUTS_NAMING_ISSUES: process.env.GH_AW_STEPS_NAMING_AUDIT_OUTPUTS_NAMING_ISSUES, GH_AW_STEPS_TEST_IMPORTS_OUTPUTS_TEST_IMPORTS: process.env.GH_AW_STEPS_TEST_IMPORTS_OUTPUTS_TEST_IMPORTS, - GH_AW_STEPS_UNUSED_EXPORTS_OUTPUTS_UNUSED_EXPORTS: process.env.GH_AW_STEPS_UNUSED_EXPORTS_OUTPUTS_UNUSED_EXPORTS + GH_AW_STEPS_UNUSED_EXPORTS_OUTPUTS_UNUSED_EXPORTS: process.env.GH_AW_STEPS_UNUSED_EXPORTS_OUTPUTS_UNUSED_EXPORTS, + GH_AW_STEPS_VERIFIED_UNUSED_OUTPUTS_VERIFIED_UNUSED: process.env.GH_AW_STEPS_VERIFIED_UNUSED_OUTPUTS_VERIFIED_UNUSED } }); - name: Validate prompt placeholders @@ -344,8 +348,8 @@ jobs: /tmp/gh-aw/aw-prompts/prompt-import-tree.json /tmp/gh-aw/github_rate_limits.jsonl /tmp/gh-aw/base - /tmp/gh-aw/.github/agents - /tmp/gh-aw/.github/skills + /tmp/gh-aw/.claude/agents + /tmp/gh-aw/.claude/skills if-no-files-found: ignore retention-days: 1 @@ -363,15 +367,11 @@ jobs: GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs GH_AW_WORKFLOW_ID_SANITIZED: exportaudit outputs: - agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }} checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }} effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }} has_patch: ${{ steps.collect_output.outputs.has_patch }} - inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }} - mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }} model: ${{ needs.activation.outputs.model }} - model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }} output: ${{ steps.collect_output.outputs.output }} output_types: ${{ steps.collect_output.outputs.output_types }} setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} @@ -389,9 +389,9 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "API Surface & Export Audit" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/export-audit.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.52" + GH_AW_INFO_VERSION: "2.1.150" GH_AW_INFO_AWF_VERSION: "v0.25.55" - GH_AW_INFO_ENGINE_ID: "copilot" + GH_AW_INFO_ENGINE_ID: "claude" - name: Set runtime paths id: set-runtime-paths run: | @@ -422,25 +422,129 @@ jobs: run: set -o pipefail && npm run build 2>&1 | tail -10 - id: exports name: Collect export inventory - run: "{\n echo \"EXPORTS<> \"$GITHUB_OUTPUT\"\n" + run: | + { + echo "EXPORTS<> "$GITHUB_OUTPUT" - id: ts-errors name: Check for TypeScript compiler errors - run: "{\n echo \"TS_ERRORS<&1 | head -40 || true\n echo \"EOF\"\n} >> \"$GITHUB_OUTPUT\"\n" + run: | + { + echo "TS_ERRORS<&1 | head -40 || true + echo "EOF" + } >> "$GITHUB_OUTPUT" - id: unused_exports name: Detect unused exports (ts-prune) - run: "{\n echo \"UNUSED_EXPORTS<&1 | tail -5\n if command -v ts-prune >/dev/null 2>&1; then\n ts-prune | grep -v \"\\.test\\.ts\" | head -40\n else\n echo \"ts-prune unavailable, falling back to grep analysis\"\n grep -rn \"^export \" src/ --include=\"*.ts\" | grep -v \"\\.test\\.ts\" | \\\n while IFS=: read -r file line rest; do\n name=$(echo \"$rest\" | sed -n 's/.*export \\(function\\|class\\|const\\|type\\|interface\\|enum\\) \\([a-zA-Z_][a-zA-Z0-9_]*\\).*/\\2/p')\n [ -z \"$name\" ] && continue\n count=$(grep -rwn \"${name}\" src/ --include=\"*.ts\" 2>/dev/null | grep -v \"^${file}:\" | wc -l)\n [ \"$count\" -eq 0 ] && echo \"UNUSED: $name ($file:$line)\"\n done | head -30\n fi\n echo \"EOF\"\n} >> \"$GITHUB_OUTPUT\"\n" + run: | + { + echo "UNUSED_EXPORTS<&1 | tail -5 + if command -v ts-prune >/dev/null 2>&1; then + ts-prune | grep -v "\.test\.ts" | head -40 + else + echo "ts-prune unavailable, falling back to grep analysis" + grep -rn "^export " src/ --include="*.ts" | grep -v "\.test\.ts" | \ + while IFS=: read -r file line rest; do + name=$(echo "$rest" | sed -n 's/.*export \(function\|class\|const\|type\|interface\|enum\) \([a-zA-Z_][a-zA-Z0-9_]*\).*/\2/p') + [ -z "$name" ] && continue + count=$(grep -rwn "${name}" src/ --include="*.ts" 2>/dev/null | grep -v "^${file}:" | wc -l) + [ "$count" -eq 0 ] && echo "UNUSED: $name ($file:$line)" + done | head -30 + fi + echo "EOF" + } >> "$GITHUB_OUTPUT" + - env: + GH_AW_STEPS_UNUSED_EXPORTS_OUTPUTS_UNUSED_EXPORTS: ${{ steps.unused_exports.outputs.UNUSED_EXPORTS }} + id: verified_unused + name: Pre-verify unused exports (top 10) + run: | + { + echo "VERIFIED_UNUSED</dev/null | \ + grep -v "\.test\.ts" | wc -l) + echo "${sym}: used_in=${count}_files" + done + fi + echo "EOF" + } >> "$GITHUB_OUTPUT" - id: circular_deps name: Detect circular dependencies (madge) - run: "{\n echo \"CIRCULAR_DEPS<&1 | tail -5\n if command -v madge >/dev/null 2>&1; then\n madge --circular src/ 2>&1 | head -20\n else\n echo \"madge unavailable, cannot check circular deps\"\n fi\n echo \"EOF\"\n} >> \"$GITHUB_OUTPUT\"\n" + run: | + { + echo "CIRCULAR_DEPS<&1 | tail -5 + if command -v madge >/dev/null 2>&1; then + madge --circular src/ 2>&1 | head -20 + else + echo "madge unavailable, cannot check circular deps" + fi + echo "EOF" + } >> "$GITHUB_OUTPUT" - id: naming_audit name: Naming convention audit - run: "{\n echo \"NAMING_ISSUES<> \"$GITHUB_OUTPUT\"\n" + run: | + { + echo "NAMING_ISSUES<> "$GITHUB_OUTPUT" - id: test_imports name: Audit test file imports - run: "{\n echo \"TEST_IMPORTS</dev/null | head -5\n done\n echo \"=== Check for tests importing from dist/ ===\"\n grep -rn \"from '.*dist/\\|require('.*dist/\" src/ --include=\"*.test.ts\" | head -10\n echo \"=== Check for tests reaching into private implementation ===\"\n grep -rn \"from '\\.\\.\\/\\.\\.\\/\" src/ --include=\"*.test.ts\" | head -10\n echo \"EOF\"\n} >> \"$GITHUB_OUTPUT\"\n" + run: | + { + echo "TEST_IMPORTS</dev/null | head -5 + done + echo "=== Check for tests importing from dist/ ===" + grep -rn "from '.*dist/\|require('.*dist/" src/ --include="*.test.ts" | head -10 + echo "=== Check for tests reaching into private implementation ===" + grep -rn "from '\.\.\/\.\.\/" src/ --include="*.test.ts" | head -10 + echo "EOF" + } >> "$GITHUB_OUTPUT" - id: apip_exports name: Audit api-proxy module exports - run: "{\n echo \"APIP_EXPORTS</dev/null | grep -n \"require\\|createAdapter\\|register\" | head -20\n echo \"=== server.js: imports from providers ===\"\n grep -n \"require.*providers\\|from.*providers\" containers/api-proxy/server.js 2>/dev/null | head -10\n echo \"EOF\"\n} >> \"$GITHUB_OUTPUT\"\n" + run: | + { + echo "APIP_EXPORTS</dev/null | grep -n "require\|createAdapter\|register" | head -20 + echo "=== server.js: imports from providers ===" + grep -n "require.*providers\|from.*providers" containers/api-proxy/server.js 2>/dev/null | head -10 + echo "EOF" + } >> "$GITHUB_OUTPUT" - name: Configure Git credentials env: @@ -469,12 +573,15 @@ jobs: setupGlobals(core, github, context, exec, io, getOctokit); const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - - name: Install GitHub Copilot CLI - run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.52 - env: - GH_HOST: github.com + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '24' + package-manager-cache: false - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.55 + - name: Install Claude Code CLI + run: npm install -g @anthropic-ai/claude-code@2.1.150 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) @@ -498,12 +605,12 @@ jobs: run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh" - name: Restore inline sub-agents from activation artifact env: - GH_AW_SUB_AGENT_DIR: ".github/agents" - GH_AW_SUB_AGENT_EXT: ".agent.md" + GH_AW_SUB_AGENT_DIR: ".claude/agents" + GH_AW_SUB_AGENT_EXT: ".md" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh" - name: Restore inline skills from activation artifact env: - GH_AW_SKILL_DIR: ".github/skills" + GH_AW_SKILL_DIR: ".claude/skills" run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh" - name: Download container images run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.55 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.55 ghcr.io/github/gh-aw-firewall/squid:0.25.55 ghcr.io/github/gh-aw-mcpg:v0.3.19 ghcr.io/github/github-mcp-server:v1.0.4@sha256:e3816a476a977cfb836e7d221510011436c654d11861db66ecfd826601aba6a4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f @@ -512,9 +619,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_d9d66562d2801fb9_EOF' + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_a58ea953901a5d88_EOF' {"create_issue":{"expires":720,"labels":["code-quality"],"max":5,"title_prefix":"[Export Audit] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_d9d66562d2801fb9_EOF + GH_AW_SAFE_OUTPUTS_CONFIG_a58ea953901a5d88_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -709,7 +816,7 @@ jobs: export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288" export DEBUG="*" - export GH_AW_ENGINE="copilot" + export GH_AW_ENGINE="claude" MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') case "${DOCKER_HOST:-}" in @@ -720,17 +827,15 @@ jobs: DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0') export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.19' - mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_ee75605cd3eea274_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_4d2b998142875e8a_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "github": { - "type": "stdio", "container": "ghcr.io/github/github-mcp-server:v1.0.4", "env": { - "GITHUB_HOST": "\${GITHUB_SERVER_URL}", - "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", + "GITHUB_HOST": "$GITHUB_SERVER_URL", + "GITHUB_PERSONAL_ACCESS_TOKEN": "$GITHUB_MCP_SERVER_TOKEN", "GITHUB_READ_ONLY": "1", "GITHUB_TOOLSETS": "issues" }, @@ -745,7 +850,7 @@ jobs: "type": "http", "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", "headers": { - "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" + "Authorization": "$GH_AW_SAFE_OUTPUTS_API_KEY" }, "guard-policies": { "write-sink": { @@ -763,7 +868,7 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_ee75605cd3eea274_EOF + GH_AW_MCP_CONFIG_4d2b998142875e8a_EOF - name: Mount MCP servers as CLIs id: mount-mcp-clis continue-on-error: true @@ -785,57 +890,124 @@ jobs: id: pre_agent_audit continue-on-error: true run: bash "${RUNNER_TEMP}/gh-aw/actions/audit_pre_agent_workspace.sh" - - name: Execute GitHub Copilot CLI + - name: Execute Claude Code CLI id: agentic_execution - # Copilot CLI tool arguments (sorted): + # Allowed tools (sorted): + # - Bash + # - BashOutput + # - Edit + # - Edit(/tmp/*) + # - Edit(/tmp/gh-aw/agent/*) + # - ExitPlanMode + # - Glob + # - Grep + # - KillBash + # - LS + # - MultiEdit + # - MultiEdit(/tmp/*) + # - MultiEdit(/tmp/gh-aw/agent/*) + # - NotebookEdit + # - NotebookRead + # - Read + # - Read(/tmp/*) + # - Read(/tmp/gh-aw/agent/*) + # - Task + # - TodoWrite + # - Write + # - Write(/tmp/*) + # - Write(/tmp/gh-aw/agent/*) + # - mcp__github__download_workflow_run_artifact + # - mcp__github__get_code_scanning_alert + # - mcp__github__get_commit + # - mcp__github__get_dependabot_alert + # - mcp__github__get_discussion + # - mcp__github__get_discussion_comments + # - mcp__github__get_file_contents + # - mcp__github__get_job_logs + # - mcp__github__get_label + # - mcp__github__get_latest_release + # - mcp__github__get_me + # - mcp__github__get_notification_details + # - mcp__github__get_pull_request + # - mcp__github__get_pull_request_comments + # - mcp__github__get_pull_request_diff + # - mcp__github__get_pull_request_files + # - mcp__github__get_pull_request_review_comments + # - mcp__github__get_pull_request_reviews + # - mcp__github__get_pull_request_status + # - mcp__github__get_release_by_tag + # - mcp__github__get_secret_scanning_alert + # - mcp__github__get_tag + # - mcp__github__get_workflow_run + # - mcp__github__get_workflow_run_logs + # - mcp__github__get_workflow_run_usage + # - mcp__github__issue_read + # - mcp__github__list_branches + # - mcp__github__list_code_scanning_alerts + # - mcp__github__list_commits + # - mcp__github__list_dependabot_alerts + # - mcp__github__list_discussion_categories + # - mcp__github__list_discussions + # - mcp__github__list_issue_types + # - mcp__github__list_issues + # - mcp__github__list_label + # - mcp__github__list_notifications + # - mcp__github__list_pull_requests + # - mcp__github__list_releases + # - mcp__github__list_secret_scanning_alerts + # - mcp__github__list_starred_repositories + # - mcp__github__list_tags + # - mcp__github__list_workflow_jobs + # - mcp__github__list_workflow_run_artifacts + # - mcp__github__list_workflow_runs + # - mcp__github__list_workflows + # - mcp__github__pull_request_read + # - mcp__github__search_code + # - mcp__github__search_issues + # - mcp__github__search_orgs + # - mcp__github__search_pull_requests + # - mcp__github__search_repositories + # - mcp__github__search_users + # - mcp__safeoutputs timeout-minutes: 20 run: | set -o pipefail printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt touch /tmp/gh-aw/agent-step-summary.md - GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true) - export GH_AW_NODE_BIN - export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK" (umask 177 && touch /tmp/gh-aw/agent-stdio.log) - printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.55/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","codeload.github.com","docs.github.com","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","lfs.github.com","objects.githubusercontent.com","patch-diff.githubusercontent.com","raw.githubusercontent.com","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.55"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" + printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.55/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","anthropic.com","api.anthropic.com","api.github.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","cdn.playwright.dev","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","docs.github.com","files.pythonhosted.org","ghcr.io","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","patch-diff.githubusercontent.com","playwright.download.prss.microsoft.com","ppa.launchpad.net","pypi.org","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","sentry.io","statsig.anthropic.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.55"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="" if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw" fi # shellcheck disable=SC1003 - sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ - -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --tty --env-all --exclude-env ANTHROPIC_API_KEY --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \ + -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/claude_harness.cjs claude --print --no-chrome --max-turns 12 --allowed-tools '\''Bash,BashOutput,Edit,Edit(/tmp/*),Edit(/tmp/gh-aw/agent/*),ExitPlanMode,Glob,Grep,KillBash,LS,MultiEdit,MultiEdit(/tmp/*),MultiEdit(/tmp/gh-aw/agent/*),NotebookEdit,NotebookRead,Read,Read(/tmp/*),Read(/tmp/gh-aw/agent/*),Task,TodoWrite,Write,Write(/tmp/*),Write(/tmp/gh-aw/agent/*),mcp__github__download_workflow_run_artifact,mcp__github__get_code_scanning_alert,mcp__github__get_commit,mcp__github__get_dependabot_alert,mcp__github__get_discussion,mcp__github__get_discussion_comments,mcp__github__get_file_contents,mcp__github__get_job_logs,mcp__github__get_label,mcp__github__get_latest_release,mcp__github__get_me,mcp__github__get_notification_details,mcp__github__get_pull_request,mcp__github__get_pull_request_comments,mcp__github__get_pull_request_diff,mcp__github__get_pull_request_files,mcp__github__get_pull_request_review_comments,mcp__github__get_pull_request_reviews,mcp__github__get_pull_request_status,mcp__github__get_release_by_tag,mcp__github__get_secret_scanning_alert,mcp__github__get_tag,mcp__github__get_workflow_run,mcp__github__get_workflow_run_logs,mcp__github__get_workflow_run_usage,mcp__github__issue_read,mcp__github__list_branches,mcp__github__list_code_scanning_alerts,mcp__github__list_commits,mcp__github__list_dependabot_alerts,mcp__github__list_discussion_categories,mcp__github__list_discussions,mcp__github__list_issue_types,mcp__github__list_issues,mcp__github__list_label,mcp__github__list_notifications,mcp__github__list_pull_requests,mcp__github__list_releases,mcp__github__list_secret_scanning_alerts,mcp__github__list_starred_repositories,mcp__github__list_tags,mcp__github__list_workflow_jobs,mcp__github__list_workflow_run_artifacts,mcp__github__list_workflow_runs,mcp__github__list_workflows,mcp__github__pull_request_read,mcp__github__search_code,mcp__github__search_issues,mcp__github__search_orgs,mcp__github__search_pull_requests,mcp__github__search_repositories,mcp__github__search_users,mcp__safeoutputs'\'' --debug-file /tmp/gh-aw/agent-stdio.log --verbose --permission-mode acceptEdits --output-format stream-json --mcp-config "${RUNNER_TEMP}/gh-aw/mcp-config/mcp-servers.json" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt${GH_AW_MODEL_AGENT_CLAUDE:+ --model "$GH_AW_MODEL_AGENT_CLAUDE"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: - AWF_REFLECT_ENABLED: 1 - COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }} - GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + BASH_DEFAULT_TIMEOUT_MS: 60000 + BASH_MAX_TIMEOUT_MS: 60000 + CLAUDE_CODE_DISABLE_FAST_MODE: 1 + DISABLE_BUG_COMMAND: 1 + DISABLE_ERROR_REPORTING: 1 + DISABLE_TELEMETRY: 1 + GH_AW_MAX_TURNS: 12 + GH_AW_MCP_CONFIG: ${{ runner.temp }}/gh-aw/mcp-config/mcp-servers.json + GH_AW_MODEL_AGENT_CLAUDE: ${{ vars.GH_AW_MODEL_AGENT_CLAUDE || '' }} GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} GH_AW_VERSION: v0.76.1 - GITHUB_API_URL: ${{ github.api_url }} GITHUB_AW: true - GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows - GITHUB_HEAD_REF: ${{ github.head_ref }} - GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - GITHUB_REF_NAME: ${{ github.ref_name }} - GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md GITHUB_WORKSPACE: ${{ github.workspace }} GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com GIT_AUTHOR_NAME: github-actions[bot] GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com GIT_COMMITTER_NAME: github-actions[bot] - XDG_CONFIG_HOME: /home/runner - - name: Detect agent errors - if: always() - id: detect-agent-errors - continue-on-error: true - run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs" + MCP_TIMEOUT: 120000 + MCP_TOOL_TIMEOUT: 60000 - name: Configure Git credentials env: REPO_NAME: ${{ github.repository }} @@ -849,10 +1021,6 @@ jobs: SERVER_URL_STRIPPED="${SERVER_URL#https://}" git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" echo "Git configured with standard GitHub Actions identity" - - name: Copy Copilot session state files to logs - if: always() - continue-on-error: true - run: bash "${RUNNER_TEMP}/gh-aw/actions/copy_copilot_session_state.sh" - name: Stop MCP Gateway if: always() continue-on-error: true @@ -872,8 +1040,8 @@ jobs: const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs'); await main(); env: - GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' - SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + GH_AW_SECRET_NAMES: 'ANTHROPIC_API_KEY,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' + SECRET_ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -893,7 +1061,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,codeload.github.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,lfs.github.com,objects.githubusercontent.com,patch-diff.githubusercontent.com,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} with: @@ -906,12 +1074,12 @@ jobs: if: always() uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: - GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ + GH_AW_AGENT_OUTPUT: /tmp/gh-aw/agent-stdio.log with: script: | const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_copilot_log.cjs'); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_claude_log.cjs'); await main(); - name: Parse MCP Gateway logs for step summary if: always() @@ -972,8 +1140,6 @@ jobs: name: agent path: | /tmp/gh-aw/aw-prompts/prompt.txt - /tmp/gh-aw/sandbox/agent/logs/ - /tmp/gh-aw/redacted-urls.log /tmp/gh-aw/mcp-logs/ /tmp/gh-aw/agent_usage.json /tmp/gh-aw/agent-stdio.log @@ -1021,9 +1187,9 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "API Surface & Export Audit" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/export-audit.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.52" + GH_AW_INFO_VERSION: "2.1.150" GH_AW_INFO_AWF_VERSION: "v0.25.55" - GH_AW_INFO_ENGINE_ID: "copilot" + GH_AW_INFO_ENGINE_ID: "claude" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1098,16 +1264,12 @@ jobs: GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_WORKFLOW_ID: "export-audit" GH_AW_ACTION_FAILURE_ISSUE_EXPIRES_HOURS: "168" - GH_AW_ENGINE_ID: "copilot" + GH_AW_ENGINE_ID: "claude" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens || '' }} GH_AW_EFFECTIVE_TOKENS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.effective_tokens_rate_limit_error || 'false' }} - GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} - GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }} - GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }} - GH_AW_MODEL_NOT_SUPPORTED_ERROR: ${{ needs.agent.outputs.model_not_supported_error }} - GH_AW_ENGINE_API_HOSTS: "api.enterprise.githubcopilot.com,api.githubcopilot.com,api.business.githubcopilot.com,api.individual.githubcopilot.com" + GH_AW_ENGINE_API_HOSTS: "api.anthropic.com" GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }} GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} GH_AW_GROUP_REPORTS: "false" @@ -1142,9 +1304,9 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "API Surface & Export Audit" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/export-audit.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.52" + GH_AW_INFO_VERSION: "2.1.150" GH_AW_INFO_AWF_VERSION: "v0.25.55" - GH_AW_INFO_ENGINE_ID: "copilot" + GH_AW_INFO_ENGINE_ID: "claude" - name: Check team membership for workflow id: check_membership uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1171,9 +1333,8 @@ jobs: env: GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/export-audit" GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} - GH_AW_ENGINE_ID: "copilot" + GH_AW_ENGINE_ID: "claude" GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }} - GH_AW_ENGINE_VERSION: "1.0.52" GH_AW_WORKFLOW_ID: "export-audit" GH_AW_WORKFLOW_NAME: "API Surface & Export Audit" GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/export-audit.md" @@ -1198,9 +1359,9 @@ jobs: env: GH_AW_SETUP_WORKFLOW_NAME: "API Surface & Export Audit" GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/export-audit.lock.yml@${{ github.ref }} - GH_AW_INFO_VERSION: "1.0.52" + GH_AW_INFO_VERSION: "2.1.150" GH_AW_INFO_AWF_VERSION: "v0.25.55" - GH_AW_INFO_ENGINE_ID: "copilot" + GH_AW_INFO_ENGINE_ID: "claude" - name: Download agent output artifact id: download-agent-output continue-on-error: true @@ -1230,7 +1391,7 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,codeload.github.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,lfs.github.com,objects.githubusercontent.com,patch-diff.githubusercontent.com,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"expires\":720,\"labels\":[\"code-quality\"],\"max\":5,\"title_prefix\":\"[Export Audit] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" diff --git a/.github/workflows/export-audit.md b/.github/workflows/export-audit.md index b3b071a4e..86f0db6d7 100644 --- a/.github/workflows/export-audit.md +++ b/.github/workflows/export-audit.md @@ -14,6 +14,10 @@ permissions: contents: read issues: read +engine: + id: claude + max-turns: 12 + sandbox: agent: id: awf @@ -88,6 +92,23 @@ steps: echo "EOF" } >> "$GITHUB_OUTPUT" + - name: Pre-verify unused exports (top 10) + id: verified_unused + run: | + { + echo "VERIFIED_UNUSED</dev/null | \ + grep -v "\.test\.ts" | wc -l) + echo "${sym}: used_in=${count}_files" + done + fi + echo "EOF" + } >> "$GITHUB_OUTPUT" + - name: Detect circular dependencies (madge) id: circular_deps run: | @@ -170,7 +191,7 @@ This is **gh-aw-firewall**, a network firewall for GitHub Copilot CLI. The TypeS ## Phase 1: Review Unused Exports -The pre-computed unused exports analysis is provided in the **Pre-computed Data** section below (`UNUSED_EXPORTS`). Review the results and verify each finding by checking all import sites, including test files and barrel exports (`index.ts`). Pay special attention to multi-line import blocks — TypeScript imports often list each symbol on its own line, which a single-line grep will miss. Use `grep -w` (whole-word matching) for verification. +The pre-computed unused exports analysis is provided in the **Pre-computed Data** section below (`UNUSED_EXPORTS` and `VERIFIED_UNUSED`). Use `VERIFIED_UNUSED` directly as pre-confirmed evidence and do **not** run additional bash to re-verify those symbols. Only run bash if you need information not present in the pre-computed data. ## Phase 2: Review Naming Conventions @@ -221,10 +242,11 @@ File issues only for findings with score ≥ 3. Cap at 5 issues per run. ## Verification Budget -To control token usage, limit verification to the **top 5 candidates** by score. For each candidate: -- Run at most 2 bash commands to confirm (one bounded recursive `grep -rw` over relevant source paths, one targeted check) -- If not confirmed in 2 checks, mark as "unconfirmed" and skip filing -- Do NOT loop over all files for each candidate — use one whole-word grep across relevant source directories only (for example `src/`, `lib/`, `app/`, `test/`) or explicitly exclude generated/dependency directories such as `node_modules/`, `dist/`, `build/`, and `coverage/` +**STRICT token budget**: Verify at most **3 candidates total** (not 5). For each candidate: +- Run **exactly 1 bash command** — a single `grep -rw src/ --include="*.ts" | grep -v "test\|index"` across relevant source directories only +- If not confirmed in that 1 check, immediately mark as "unconfirmed" and move on — **do NOT run a second command** +- After verifying 3 candidates, file issues for confirmed ones and stop — **do not verify more candidates** +- **Total bash commands for verification: maximum 3** across all phases combined ### Issue Format @@ -246,13 +268,6 @@ Unused export / Naming inconsistency / Circular dependency / Import path issue -### Recommended Fix - -1. For **unused exports**: Remove the `export` keyword or delete the symbol if it's dead code -2. For **naming inconsistencies**: Rename to follow convention (types: PascalCase, functions: camelCase) -3. For **circular dependencies**: Extract the shared dependency into a new module -4. For **test imports**: Update the import path to reference the correct module - ### Impact - Dead code risk: - Maintenance burden: @@ -271,10 +286,7 @@ Unused export / Naming inconsistency / Circular dependency / Import path issue ## Edge Cases -- **Build fails (TypeScript errors)**: Report the build errors in the log; skip the audit since analysis would be unreliable. Do NOT create issues for TypeScript errors — those are tracked separately. -- **ts-prune / madge unavailable**: Fall back to grep-based analysis with a note that results may be incomplete -- **All findings already tracked**: Skip creation and log that existing issues cover the findings -- **No issues found**: Log a summary and exit without creating issues +If the build fails, report TypeScript errors and skip audit issue creation. If `ts-prune` or `madge` is unavailable, use the existing fallback output and note reduced confidence. If findings are already tracked or no actionable findings remain, log a concise summary and exit without creating issues. --- @@ -295,6 +307,11 @@ Unused exports: ${{ steps.unused_exports.outputs.UNUSED_EXPORTS }} ``` +Verified unused exports: +``` +${{ steps.verified_unused.outputs.VERIFIED_UNUSED }} +``` + Circular dependencies: ``` ${{ steps.circular_deps.outputs.CIRCULAR_DEPS }} diff --git a/scripts/ci/export-audit-workflow.test.ts b/scripts/ci/export-audit-workflow.test.ts new file mode 100644 index 000000000..4190641ce --- /dev/null +++ b/scripts/ci/export-audit-workflow.test.ts @@ -0,0 +1,33 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +const workflowsDir = path.resolve(__dirname, '../../.github/workflows'); +const sourcePath = path.join(workflowsDir, 'export-audit.md'); +const lockPath = path.join(workflowsDir, 'export-audit.lock.yml'); + +describe('export audit workflow optimization config', () => { + it('applies turn cap and strict verification constraints in source workflow', () => { + const source = fs.readFileSync(sourcePath, 'utf-8'); + + expect(source).toContain('max-turns: 12'); + expect(source).toContain('Pre-verify unused exports (top 10)'); + expect(source).toContain('id: verified_unused'); + expect(source).toContain('VERIFIED_UNUSED< { + const lock = fs.readFileSync(lockPath, 'utf-8'); + + expect(lock).toContain('--max-turns 12'); + expect(lock).toContain('GH_AW_STEPS_VERIFIED_UNUSED_OUTPUTS_VERIFIED_UNUSED'); + expect(lock).toContain('Pre-verify unused exports (top 10)'); + }); +}); From 9d7f2ea4c8ca0a80e905fcb6201b23b6522e50f8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 31 May 2026 14:03:42 +0000 Subject: [PATCH 3/3] Fix export-audit pre-verification parsing and guidance --- .github/workflows/export-audit.lock.yml | 51 ++++++++++++++++-------- .github/workflows/export-audit.md | 29 +++++++++++--- scripts/ci/export-audit-workflow.test.ts | 6 +++ 3 files changed, 63 insertions(+), 23 deletions(-) diff --git a/.github/workflows/export-audit.lock.yml b/.github/workflows/export-audit.lock.yml index 1336235e0..7f8e3ca72 100644 --- a/.github/workflows/export-audit.lock.yml +++ b/.github/workflows/export-audit.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"8e8de5a131f42f2c3bbf62fef1f1a8ffc769fa58ac53eea7ee484de17fc6e6f3","compiler_version":"v0.76.1","strict":true,"agent_id":"claude"} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"4ce6fff6ee2476affd460258de6e79ad8c850d0d436076792a9474904c3fa12a","compiler_version":"v0.76.1","strict":true,"agent_id":"claude"} # gh-aw-manifest: {"version":1,"secrets":["ANTHROPIC_API_KEY","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"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":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"46d564922b082d0db93244972e8005ea6904ee5f","version":"v0.76.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.55"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.55"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.55"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.19"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4","digest":"sha256:e3816a476a977cfb836e7d221510011436c654d11861db66ecfd826601aba6a4","pinned_image":"ghcr.io/github/github-mcp-server:v1.0.4@sha256:e3816a476a977cfb836e7d221510011436c654d11861db66ecfd826601aba6a4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]} # ___ _ _ # / _ \ | | (_) @@ -203,20 +203,20 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_9918201839a3620e_EOF' + cat << 'GH_AW_PROMPT_3e84c9458501f30e_EOF' - GH_AW_PROMPT_9918201839a3620e_EOF + GH_AW_PROMPT_3e84c9458501f30e_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_9918201839a3620e_EOF' + cat << 'GH_AW_PROMPT_3e84c9458501f30e_EOF' Tools: create_issue(max:5), missing_tool, missing_data, noop - GH_AW_PROMPT_9918201839a3620e_EOF + GH_AW_PROMPT_3e84c9458501f30e_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_9918201839a3620e_EOF' + cat << 'GH_AW_PROMPT_3e84c9458501f30e_EOF' The following GitHub context information is available for this workflow: {{#if github.actor}} @@ -245,12 +245,12 @@ jobs: {{/if}} - GH_AW_PROMPT_9918201839a3620e_EOF + GH_AW_PROMPT_3e84c9458501f30e_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_9918201839a3620e_EOF' + cat << 'GH_AW_PROMPT_3e84c9458501f30e_EOF' {{#runtime-import .github/workflows/export-audit.md}} - GH_AW_PROMPT_9918201839a3620e_EOF + GH_AW_PROMPT_3e84c9458501f30e_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -469,11 +469,28 @@ jobs: echo "VERIFIED_UNUSED</dev/null | \ - grep -v "\.test\.ts" | wc -l) - echo "${sym}: used_in=${count}_files" + grep -v "\.test\.ts" | \ + awk -v file="$file" '$0 != file' | \ + wc -l) + echo "${sym}: used_outside_defining_file=${count}_files" done fi echo "EOF" @@ -619,9 +636,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_a58ea953901a5d88_EOF' + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_eda9f239c9abeb8e_EOF' {"create_issue":{"expires":720,"labels":["code-quality"],"max":5,"title_prefix":"[Export Audit] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_a58ea953901a5d88_EOF + GH_AW_SAFE_OUTPUTS_CONFIG_eda9f239c9abeb8e_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -828,7 +845,7 @@ jobs: export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.19' GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_4d2b998142875e8a_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_b7a2483d07dd9048_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "github": { @@ -868,7 +885,7 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_4d2b998142875e8a_EOF + GH_AW_MCP_CONFIG_b7a2483d07dd9048_EOF - name: Mount MCP servers as CLIs id: mount-mcp-clis continue-on-error: true diff --git a/.github/workflows/export-audit.md b/.github/workflows/export-audit.md index 86f0db6d7..f3831d2bf 100644 --- a/.github/workflows/export-audit.md +++ b/.github/workflows/export-audit.md @@ -99,11 +99,28 @@ steps: echo "VERIFIED_UNUSED</dev/null | \ - grep -v "\.test\.ts" | wc -l) - echo "${sym}: used_in=${count}_files" + grep -v "\.test\.ts" | \ + awk -v file="$file" '$0 != file' | \ + wc -l) + echo "${sym}: used_outside_defining_file=${count}_files" done fi echo "EOF" @@ -191,7 +208,7 @@ This is **gh-aw-firewall**, a network firewall for GitHub Copilot CLI. The TypeS ## Phase 1: Review Unused Exports -The pre-computed unused exports analysis is provided in the **Pre-computed Data** section below (`UNUSED_EXPORTS` and `VERIFIED_UNUSED`). Use `VERIFIED_UNUSED` directly as pre-confirmed evidence and do **not** run additional bash to re-verify those symbols. Only run bash if you need information not present in the pre-computed data. +The pre-computed unused exports analysis is provided in the **Pre-computed Data** section below (`UNUSED_EXPORTS` and `VERIFIED_UNUSED`). Use `VERIFIED_UNUSED` directly as pre-confirmed evidence and do **not** run additional bash to re-verify those symbols. `VERIFIED_UNUSED` reports `used_outside_defining_file=N_files`; `used_outside_defining_file=0_files` means no external usage beyond the defining file. If `VERIFIED_UNUSED` is empty, fall back to the normal verification flow within the strict command budget. ## Phase 2: Review Naming Conventions @@ -243,7 +260,7 @@ File issues only for findings with score ≥ 3. Cap at 5 issues per run. ## Verification Budget **STRICT token budget**: Verify at most **3 candidates total** (not 5). For each candidate: -- Run **exactly 1 bash command** — a single `grep -rw src/ --include="*.ts" | grep -v "test\|index"` across relevant source directories only +- Run **exactly 1 bash command** — a single `grep -rw src/ --include="*.ts" | grep -vE "test|index"` across relevant source directories only - If not confirmed in that 1 check, immediately mark as "unconfirmed" and move on — **do NOT run a second command** - After verifying 3 candidates, file issues for confirmed ones and stop — **do not verify more candidates** - **Total bash commands for verification: maximum 3** across all phases combined diff --git a/scripts/ci/export-audit-workflow.test.ts b/scripts/ci/export-audit-workflow.test.ts index 4190641ce..fb414387b 100644 --- a/scripts/ci/export-audit-workflow.test.ts +++ b/scripts/ci/export-audit-workflow.test.ts @@ -14,8 +14,12 @@ describe('export audit workflow optimization config', () => { expect(source).toContain('id: verified_unused'); expect(source).toContain('VERIFIED_UNUSED< { expect(lock).toContain('--max-turns 12'); expect(lock).toContain('GH_AW_STEPS_VERIFIED_UNUSED_OUTPUTS_VERIFIED_UNUSED'); expect(lock).toContain('Pre-verify unused exports (top 10)'); + expect(lock).toContain('used_outside_defining_file=${count}_files'); + expect(lock).toContain("^UNUSED: [^[:space:]]+ \\([^)]*\\)$"); }); });