diff --git a/.github/workflows/test-coverage-reporter.lock.yml b/.github/workflows/test-coverage-reporter.lock.yml index 5e73597f..5200fb8e 100644 --- a/.github/workflows/test-coverage-reporter.lock.yml +++ b/.github/workflows/test-coverage-reporter.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"8d4ddfeefb4a7e658949c722a183155e7c66c25541c48597d5a5b5436fd19726","body_hash":"3a6fc0c9f156ba0097f1f4f7470adf217d22e60cbfe1ad58a8b6239511884bf4","compiler_version":"v0.79.6","agent_id":"copilot","engine_versions":{"copilot":"1.0.60"}} -# 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":"df4cb1c069e1874edd31b4311f1884172cec0e10","version":"v6.0.3"},{"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":"5c2fe865bb4dc46e1450f6ee0d0541d759aea73a","version":"v0.79.6"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2","digest":"sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2","digest":"sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2","digest":"sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591"},{"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/github-mcp-server:v1.1.2","digest":"sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c","pinned_image":"ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c"}]} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"1073842863720a291e0c8ebe7e323215e882beb821aa2d560afd003af99c91bc","body_hash":"3a6fc0c9f156ba0097f1f4f7470adf217d22e60cbfe1ad58a8b6239511884bf4","compiler_version":"v0.79.6","agent_id":"copilot","engine_versions":{"copilot":"1.0.60"}} +# 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":"df4cb1c069e1874edd31b4311f1884172cec0e10","version":"v6.0.3"},{"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":"5c2fe865bb4dc46e1450f6ee0d0541d759aea73a","version":"v0.79.6"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2","digest":"sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2","digest":"sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2","digest":"sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591"},{"image":"ghcr.io/github/gh-aw-mcpg:latest","digest":"sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa","pinned_image":"ghcr.io/github/gh-aw-mcpg:latest@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -38,7 +38,6 @@ # - actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 -# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) # - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6 @@ -48,7 +47,6 @@ # - ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4 # - ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591 # - ghcr.io/github/gh-aw-mcpg:latest@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa -# - ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c name: "Test Coverage Reporter" on: @@ -201,71 +199,33 @@ jobs: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl GH_AW_EXPR_14C2CEC4: ${{ steps.recent-changes.outputs.RECENT_FILES }} - GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_38DC592D: ${{ steps.critical-gaps.outputs.CRITICAL_GAPS }} - GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_6760DA50: ${{ steps.func-audit.outputs.FUNC_AUDIT }} - GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_D05879D3: ${{ steps.coverage-table.outputs.COVERAGE_TABLE }} GH_AW_EXPR_E085E874: ${{ steps.coverage-json.outputs.COVERAGE_JSON }} - GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} - GH_AW_GITHUB_ACTOR: ${{ github.actor }} GH_AW_GITHUB_EVENT_NAME: ${{ github.event_name }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} - GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} - GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} # poutine:ignore untrusted_checkout_exec run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_04ac0c20729b574c_EOF' + cat << 'GH_AW_PROMPT_341b91c3043f9b66_EOF' - GH_AW_PROMPT_04ac0c20729b574c_EOF + GH_AW_PROMPT_341b91c3043f9b66_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_04ac0c20729b574c_EOF' + cat << 'GH_AW_PROMPT_341b91c3043f9b66_EOF' Tools: create_discussion, missing_tool, missing_data, noop - GH_AW_PROMPT_04ac0c20729b574c_EOF + GH_AW_PROMPT_341b91c3043f9b66_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_04ac0c20729b574c_EOF' - - The following GitHub context information is available for this workflow: - {{#if github.actor}} - - **actor**: __GH_AW_GITHUB_ACTOR__ - {{/if}} - {{#if github.repository}} - - **repository**: __GH_AW_GITHUB_REPOSITORY__ - {{/if}} - {{#if github.workspace}} - - **workspace**: __GH_AW_GITHUB_WORKSPACE__ - {{/if}} - {{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}} - - **issue-number**: #__GH_AW_EXPR_802A9F6A__ - {{/if}} - {{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}} - - **discussion-number**: #__GH_AW_EXPR_1A3A194A__ - {{/if}} - {{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}} - - **pull-request-number**: #__GH_AW_EXPR_463A214A__ - {{/if}} - {{#if github.event.comment.id || github.aw.context.comment_id}} - - **comment-id**: __GH_AW_EXPR_FF1D34CE__ - {{/if}} - {{#if github.run_id}} - - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ - {{/if}} - - - GH_AW_PROMPT_04ac0c20729b574c_EOF - cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_04ac0c20729b574c_EOF' + cat << 'GH_AW_PROMPT_341b91c3043f9b66_EOF' {{#runtime-import .github/workflows/test-coverage-reporter.md}} - GH_AW_PROMPT_04ac0c20729b574c_EOF + GH_AW_PROMPT_341b91c3043f9b66_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -290,19 +250,12 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_EXPR_14C2CEC4: ${{ steps.recent-changes.outputs.RECENT_FILES }} - GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_38DC592D: ${{ steps.critical-gaps.outputs.CRITICAL_GAPS }} - GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_6760DA50: ${{ steps.func-audit.outputs.FUNC_AUDIT }} - GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} GH_AW_EXPR_D05879D3: ${{ steps.coverage-table.outputs.COVERAGE_TABLE }} GH_AW_EXPR_E085E874: ${{ steps.coverage-json.outputs.COVERAGE_JSON }} - GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} - GH_AW_GITHUB_ACTOR: ${{ github.actor }} GH_AW_GITHUB_EVENT_NAME: ${{ github.event_name }} GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} - GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} - GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools' GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }} with: @@ -317,19 +270,12 @@ jobs: file: process.env.GH_AW_PROMPT, substitutions: { GH_AW_EXPR_14C2CEC4: process.env.GH_AW_EXPR_14C2CEC4, - GH_AW_EXPR_1A3A194A: process.env.GH_AW_EXPR_1A3A194A, GH_AW_EXPR_38DC592D: process.env.GH_AW_EXPR_38DC592D, - GH_AW_EXPR_463A214A: process.env.GH_AW_EXPR_463A214A, GH_AW_EXPR_6760DA50: process.env.GH_AW_EXPR_6760DA50, - GH_AW_EXPR_802A9F6A: process.env.GH_AW_EXPR_802A9F6A, GH_AW_EXPR_D05879D3: process.env.GH_AW_EXPR_D05879D3, GH_AW_EXPR_E085E874: process.env.GH_AW_EXPR_E085E874, - GH_AW_EXPR_FF1D34CE: process.env.GH_AW_EXPR_FF1D34CE, - GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, GH_AW_GITHUB_EVENT_NAME: process.env.GH_AW_GITHUB_EVENT_NAME, GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, - GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, - GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE, GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST, GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED } @@ -445,10 +391,10 @@ jobs: run: set -o pipefail && npm run test:coverage 2>&1 | tail -20 - id: coverage-json name: Capture coverage summary JSON - run: "{\n echo \"COVERAGE_JSON<\n k === 'total' || (v.statements && v.statements.pct < 80)\n )\n );\n console.log(JSON.stringify(filtered, null, 2));\n \" 2>/dev/null || echo \"{}\"\n echo \"EOF\"\n} >> \"$GITHUB_OUTPUT\"\n" + run: "{\n echo \"COVERAGE_JSON<\n k === 'total' || (v.statements && v.statements.pct < 80)\n ).map(([k, v]) => [k === 'total' ? k : k.replace(process.cwd() + '/', ''), v])\n );\n console.log(JSON.stringify(filtered, null, 2));\n \" 2>/dev/null || echo \"{}\"\n echo \"EOF\"\n} >> \"$GITHUB_OUTPUT\"\n" - id: coverage-table name: Compute per-file coverage table - run: "{\n echo \"COVERAGE_TABLE< k !== 'total')\n .map(([k, v]) => ({\n file: k.replace(process.cwd() + '/', ''),\n stmts: v.statements.pct,\n branch: v.branches.pct,\n funcs: v.functions.pct,\n lines: v.lines.pct,\n }))\n .sort((a, b) => a.stmts - b.stmts);\n console.log('| File | Stmts | Branch | Funcs | Lines | Status |');\n console.log('|------|------:|-------:|------:|------:|--------|');\n rows.forEach(r => {\n const status = r.stmts >= 80 ? '✅' : r.stmts >= 50 ? '⚠️' : '❌';\n console.log(\\`| \\${r.file} | \\${r.stmts}% | \\${r.branch}% | \\${r.funcs}% | \\${r.lines}% | \\${status} |\\`);\n });\n const t = d.total;\n if (t) {\n console.log(\\`| **TOTAL** | **\\${t.statements.pct}%** | **\\${t.branches.pct}%** | **\\${t.functions.pct}%** | **\\${t.lines.pct}%** | |\\`);\n }\n \" 2>/dev/null || echo \"Coverage data not available\"\n echo \"EOF\"\n} >> \"$GITHUB_OUTPUT\"\n" + run: "{\n echo \"COVERAGE_TABLE< k !== 'total')\n .map(([k, v]) => ({\n file: k.replace(process.cwd() + '/', ''),\n stmts: v.statements.pct,\n branch: v.branches.pct,\n funcs: v.functions.pct,\n lines: v.lines.pct,\n }))\n .filter(r => r.stmts < 80 || SECURITY_CRITICAL.some(s => r.file.includes(s)))\n .sort((a, b) => a.stmts - b.stmts);\n console.log('| File | Stmts | Branch | Funcs | Lines | Status |');\n console.log('|------|------:|-------:|------:|------:|--------|');\n rows.forEach(r => {\n const status = r.stmts >= 80 ? '✅' : r.stmts >= 50 ? '⚠️' : '❌';\n console.log(\\`| \\${r.file} | \\${r.stmts}% | \\${r.branch}% | \\${r.funcs}% | \\${r.lines}% | \\${status} |\\`);\n });\n const t = d.total;\n if (t) {\n console.log(\\`| **TOTAL** | **\\${t.statements.pct}%** | **\\${t.branches.pct}%** | **\\${t.functions.pct}%** | **\\${t.lines.pct}%** | |\\`);\n }\n \" 2>/dev/null || echo \"Coverage data not available\"\n echo \"EOF\"\n} >> \"$GITHUB_OUTPUT\"\n" - id: critical-gaps name: Identify critical paths with low coverage run: "{\n echo \"CRITICAL_GAPS< {\n const key = Object.keys(d).find(k => k.includes(p.replace('src/', '')));\n if (key && d[key]) {\n const v = d[key];\n const label = v.statements.pct < 50 ? '🔴 CRITICAL' : v.statements.pct < 80 ? '🟡 LOW' : '🟢 OK';\n console.log(\\`\\${label} \\${p}: stmts=\\${v.statements.pct}% branch=\\${v.branches.pct}% funcs=\\${v.functions.pct}%\\`);\n } else {\n console.log(\\`⬜ NOT FOUND: \\${p}\\`);\n }\n });\n \" 2>/dev/null || echo \"Coverage data not available\"\n echo \"EOF\"\n} >> \"$GITHUB_OUTPUT\"\n" @@ -520,16 +466,6 @@ jobs: exec "${NODE_BIN}" "${WORKSPACE_PATH}/dist/cli.js" "\$@" EOF sudo chmod +x /usr/local/bin/awf - - name: Determine automatic lockdown mode for GitHub MCP Server - id: determine-automatic-lockdown - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) - env: - GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} - GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} - with: - script: | - const determineAutomaticLockdown = require('${{ runner.temp }}/gh-aw/actions/determine_automatic_lockdown.cjs'); - await determineAutomaticLockdown(github, context, core); - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -551,7 +487,7 @@ jobs: GH_AW_SKILL_DIR: ".github/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.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6 ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4 ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591 ghcr.io/github/gh-aw-mcpg:latest@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c + run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6 ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4 ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591 ghcr.io/github/gh-aw-mcpg:latest@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa - name: Generate Safe Outputs Config run: | mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" @@ -726,9 +662,6 @@ jobs: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} - GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }} - GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }} - GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} run: | set -eo pipefail mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-config" @@ -758,37 +691,14 @@ jobs: 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_dec0f3c248d4cfe0_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_f4cec3979114a9cb_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.1.2", - "env": { - "GITHUB_HOST": "\${GITHUB_SERVER_URL}", - "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", - "GITHUB_READ_ONLY": "1", - "GITHUB_TOOLSETS": "repos,discussions" - }, - "guard-policies": { - "allow-only": { - "min-integrity": "$GITHUB_MCP_GUARD_MIN_INTEGRITY", - "repos": "$GITHUB_MCP_GUARD_REPOS" - } - } - }, "safeoutputs": { "type": "http", "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", "headers": { "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" - }, - "guard-policies": { - "write-sink": { - "accept": [ - "*" - ] - } } } }, @@ -799,7 +709,7 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_dec0f3c248d4cfe0_EOF + GH_AW_MCP_CONFIG_f4cec3979114a9cb_EOF - name: Mount MCP servers as CLIs id: mount-mcp-clis continue-on-error: true @@ -824,6 +734,8 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): + # --allow-tool safeoutputs + # --allow-tool write timeout-minutes: 20 run: | set -o pipefail @@ -855,8 +767,8 @@ jobs: GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro" 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_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${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 --session-state-dir /tmp/gh-aw/sandbox/agent/session-state --enable-host-access --allow-host-ports 80,443,8080 --build-local \ - -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /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_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; 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_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_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 --session-state-dir /tmp/gh-aw/sandbox/agent/session-state --enable-host-access --allow-host-ports 80,443,8080 --build-local \ + -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /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_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; 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-tool safeoutputs --allow-tool write --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 env: AWF_REFLECT_ENABLED: 1 COPILOT_AGENT_RUNNER_TYPE: STANDALONE @@ -874,7 +786,6 @@ jobs: 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 diff --git a/.github/workflows/test-coverage-reporter.md b/.github/workflows/test-coverage-reporter.md index f624dcaa..08832f82 100644 --- a/.github/workflows/test-coverage-reporter.md +++ b/.github/workflows/test-coverage-reporter.md @@ -29,9 +29,8 @@ network: - github tools: - github: - toolsets: [repos, discussions] - bash: true + github: false + bash: false safe-outputs: threat-detection: @@ -65,7 +64,7 @@ steps: const filtered = Object.fromEntries( Object.entries(d).filter(([k, v]) => k === 'total' || (v.statements && v.statements.pct < 80) - ) + ).map(([k, v]) => [k === 'total' ? k : k.replace(process.cwd() + '/', ''), v]) ); console.log(JSON.stringify(filtered, null, 2)); " 2>/dev/null || echo "{}" @@ -81,6 +80,13 @@ steps: const fs = require('fs'); const raw = fs.readFileSync('coverage/coverage-summary.json', 'utf8'); const d = JSON.parse(raw); + const SECURITY_CRITICAL = [ + 'docker-manager', + 'host-iptables', + 'squid-config', + 'domain-patterns', + 'cli', + ]; const rows = Object.entries(d) .filter(([k]) => k !== 'total') .map(([k, v]) => ({ @@ -90,6 +96,7 @@ steps: funcs: v.functions.pct, lines: v.lines.pct, })) + .filter(r => r.stmts < 80 || SECURITY_CRITICAL.some(s => r.file.includes(s))) .sort((a, b) => a.stmts - b.stmts); console.log('| File | Stmts | Branch | Funcs | Lines | Status |'); console.log('|------|------:|-------:|------:|------:|--------|'); diff --git a/scripts/ci/test-coverage-reporter-workflow.test.ts b/scripts/ci/test-coverage-reporter-workflow.test.ts new file mode 100644 index 00000000..b47518ee --- /dev/null +++ b/scripts/ci/test-coverage-reporter-workflow.test.ts @@ -0,0 +1,40 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +const workflowsDir = path.resolve(__dirname, '../../.github/workflows'); +const sourcePath = path.join(workflowsDir, 'test-coverage-reporter.md'); +const lockPath = path.join(workflowsDir, 'test-coverage-reporter.lock.yml'); + +describe('test coverage reporter workflow token optimization config', () => { + it('removes unused tool injection and trims precomputed coverage context in source workflow', () => { + const source = fs.readFileSync(sourcePath, 'utf-8'); + + expect(source).toContain('github: false'); + expect(source).toContain('bash: false'); + expect(source).not.toContain('toolsets: [repos, discussions]'); + expect(source).not.toContain('bash: true'); + expect(source).toContain("k === 'total' ? k : k.replace(process.cwd() + '/', '')"); + expect(source).toContain('const SECURITY_CRITICAL = ['); + expect(source).toContain("'docker-manager'"); + expect(source).toContain("'host-iptables'"); + expect(source).toContain("'squid-config'"); + expect(source).toContain("'domain-patterns'"); + expect(source).toContain("'cli'"); + expect(source).toContain('.filter(r => r.stmts < 80 || SECURITY_CRITICAL.some(s => r.file.includes(s)))'); + }); + + it('compiles without GitHub MCP server injection while preserving safeoutputs reporting', () => { + const lock = fs.readFileSync(lockPath, 'utf-8'); + + expect(lock).not.toContain('ghcr.io/github/github-mcp-server'); + expect(lock).not.toContain('GITHUB_TOOLSETS'); + expect(lock).not.toContain('github_mcp_tools_with_safeoutputs_prompt.md'); + expect(lock).toContain('GH_AW_MCP_CLI_SERVERS_LIST: \'- `safeoutputs` — run `safeoutputs --help` to see available tools\''); + expect(lock).toContain('"safeoutputs": {'); + expect(lock).not.toContain('"github": {'); + expect(lock).not.toContain('shell('); + expect(lock).toContain('k === \'total\' ? k : k.replace(process.cwd() + \'/\', \'\')'); + expect(lock).toContain('const SECURITY_CRITICAL = ['); + expect(lock).toContain('.filter(r => r.stmts < 80 || SECURITY_CRITICAL.some(s => r.file.includes(s)))'); + }); +});