From d3b56e18d95e594cab16c6092dd9c4f33fcaba56 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 16:15:28 +0000 Subject: [PATCH 01/29] Plan copilot compat-driven installer update Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- .github/workflows/agent-performance-analyzer.lock.yml | 2 +- .github/workflows/architecture-guardian.lock.yml | 2 +- .github/workflows/artifacts-summary.lock.yml | 2 +- .github/workflows/brave.lock.yml | 2 +- .github/workflows/breaking-change-checker.lock.yml | 2 +- .github/workflows/ci-coach.lock.yml | 2 +- .github/workflows/cli-consistency-checker.lock.yml | 2 +- .github/workflows/code-scanning-fixer.lock.yml | 2 +- .github/workflows/copilot-cli-deep-research.lock.yml | 2 +- .github/workflows/copilot-opt.lock.yml | 2 +- .github/workflows/copilot-pr-merged-report.lock.yml | 2 +- .github/workflows/copilot-pr-nlp-analysis.lock.yml | 2 +- .github/workflows/copilot-pr-prompt-analysis.lock.yml | 2 +- .github/workflows/craft.lock.yml | 2 +- .github/workflows/daily-agent-of-the-day-blog-writer.lock.yml | 2 +- .github/workflows/daily-architecture-diagram.lock.yml | 2 +- .github/workflows/daily-assign-issue-to-user.lock.yml | 2 +- .github/workflows/daily-cli-performance.lock.yml | 2 +- .github/workflows/daily-compiler-quality.lock.yml | 2 +- .github/workflows/daily-compiler-threat-spec-optimizer.lock.yml | 2 +- .github/workflows/daily-experiment-report.lock.yml | 2 +- .github/workflows/daily-geo-optimizer.lock.yml | 2 +- .github/workflows/daily-issues-report.lock.yml | 2 +- .github/workflows/daily-malicious-code-scan.lock.yml | 2 +- .github/workflows/daily-mcp-concurrency-analysis.lock.yml | 2 +- .github/workflows/daily-model-inventory.lock.yml | 2 +- .github/workflows/daily-performance-summary.lock.yml | 2 +- .github/workflows/daily-repo-chronicle.lock.yml | 2 +- .github/workflows/daily-safe-output-integrator.lock.yml | 2 +- .github/workflows/daily-secrets-analysis.lock.yml | 2 +- .github/workflows/daily-security-observability.lock.yml | 2 +- .github/workflows/daily-sentrux-report.lock.yml | 2 +- .github/workflows/daily-skill-optimizer.lock.yml | 2 +- .github/workflows/daily-spdd-spec-planner.lock.yml | 2 +- .github/workflows/daily-syntax-error-quality.lock.yml | 2 +- .github/workflows/daily-testify-uber-super-expert.lock.yml | 2 +- .github/workflows/daily-workflow-updater.lock.yml | 2 +- .github/workflows/dead-code-remover.lock.yml | 2 +- .github/workflows/delight.lock.yml | 2 +- .github/workflows/deployment-incident-monitor.lock.yml | 2 +- .github/workflows/dev-hawk.lock.yml | 2 +- .github/workflows/dictation-prompt.lock.yml | 2 +- .github/workflows/discussion-task-miner.lock.yml | 2 +- .github/workflows/docs-noob-tester.lock.yml | 2 +- .github/workflows/draft-pr-cleanup.lock.yml | 2 +- .github/workflows/firewall-escape.lock.yml | 2 +- .github/workflows/firewall.lock.yml | 2 +- .github/workflows/jsweep.lock.yml | 2 +- .github/workflows/layout-spec-maintainer.lock.yml | 2 +- .github/workflows/linter-miner.lock.yml | 2 +- .github/workflows/mcp-inspector.lock.yml | 2 +- .github/workflows/mergefest.lock.yml | 2 +- .github/workflows/metrics-collector.lock.yml | 2 +- .github/workflows/org-health-report.lock.yml | 2 +- .github/workflows/pdf-summary.lock.yml | 2 +- .github/workflows/plan.lock.yml | 2 +- .github/workflows/pr-code-quality-reviewer.lock.yml | 2 +- .github/workflows/pr-nitpick-reviewer.lock.yml | 2 +- .github/workflows/pr-triage-agent.lock.yml | 2 +- .github/workflows/python-data-charts.lock.yml | 2 +- .github/workflows/q.lock.yml | 2 +- .github/workflows/smoke-copilot-sdk.lock.yml | 2 +- 62 files changed, 62 insertions(+), 62 deletions(-) diff --git a/.github/workflows/agent-performance-analyzer.lock.yml b/.github/workflows/agent-performance-analyzer.lock.yml index 3c56b0cbd39..49d0c612032 100644 --- a/.github/workflows/agent-performance-analyzer.lock.yml +++ b/.github/workflows/agent-performance-analyzer.lock.yml @@ -562,7 +562,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/architecture-guardian.lock.yml b/.github/workflows/architecture-guardian.lock.yml index bbb1138d6ab..0615c8541ad 100644 --- a/.github/workflows/architecture-guardian.lock.yml +++ b/.github/workflows/architecture-guardian.lock.yml @@ -480,7 +480,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml index 464c467cc10..94fac02a75b 100644 --- a/.github/workflows/artifacts-summary.lock.yml +++ b/.github/workflows/artifacts-summary.lock.yml @@ -460,7 +460,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml index fe83efd03f0..23467e58fb3 100644 --- a/.github/workflows/brave.lock.yml +++ b/.github/workflows/brave.lock.yml @@ -521,7 +521,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/breaking-change-checker.lock.yml b/.github/workflows/breaking-change-checker.lock.yml index c40c6c6825d..fd983a18db2 100644 --- a/.github/workflows/breaking-change-checker.lock.yml +++ b/.github/workflows/breaking-change-checker.lock.yml @@ -470,7 +470,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/ci-coach.lock.yml b/.github/workflows/ci-coach.lock.yml index b932d35d6df..75103afd1f3 100644 --- a/.github/workflows/ci-coach.lock.yml +++ b/.github/workflows/ci-coach.lock.yml @@ -577,7 +577,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml index 9b5aa1013f1..cf5ef20396b 100644 --- a/.github/workflows/cli-consistency-checker.lock.yml +++ b/.github/workflows/cli-consistency-checker.lock.yml @@ -458,7 +458,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/code-scanning-fixer.lock.yml b/.github/workflows/code-scanning-fixer.lock.yml index 32c9dd9b321..eab97d35afe 100644 --- a/.github/workflows/code-scanning-fixer.lock.yml +++ b/.github/workflows/code-scanning-fixer.lock.yml @@ -507,7 +507,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/copilot-cli-deep-research.lock.yml b/.github/workflows/copilot-cli-deep-research.lock.yml index 1f95a1e6329..8d2536848c9 100644 --- a/.github/workflows/copilot-cli-deep-research.lock.yml +++ b/.github/workflows/copilot-cli-deep-research.lock.yml @@ -487,7 +487,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/copilot-opt.lock.yml b/.github/workflows/copilot-opt.lock.yml index 9a73567e4a4..8db5738a337 100644 --- a/.github/workflows/copilot-opt.lock.yml +++ b/.github/workflows/copilot-opt.lock.yml @@ -512,7 +512,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/copilot-pr-merged-report.lock.yml b/.github/workflows/copilot-pr-merged-report.lock.yml index 1e4b7da316c..a2ab9c5ec10 100644 --- a/.github/workflows/copilot-pr-merged-report.lock.yml +++ b/.github/workflows/copilot-pr-merged-report.lock.yml @@ -452,7 +452,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index 11cd4186275..f11c88283f8 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -558,7 +558,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index 44dd1ad8e71..c34f684e481 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -526,7 +526,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index 61906de90b0..3ea37194161 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -528,7 +528,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-agent-of-the-day-blog-writer.lock.yml b/.github/workflows/daily-agent-of-the-day-blog-writer.lock.yml index 5889643cf78..1adcc95c8b1 100644 --- a/.github/workflows/daily-agent-of-the-day-blog-writer.lock.yml +++ b/.github/workflows/daily-agent-of-the-day-blog-writer.lock.yml @@ -536,7 +536,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Parse integrity filter lists id: parse-guard-vars diff --git a/.github/workflows/daily-architecture-diagram.lock.yml b/.github/workflows/daily-architecture-diagram.lock.yml index b9bbac2213a..770d823d439 100644 --- a/.github/workflows/daily-architecture-diagram.lock.yml +++ b/.github/workflows/daily-architecture-diagram.lock.yml @@ -526,7 +526,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-assign-issue-to-user.lock.yml b/.github/workflows/daily-assign-issue-to-user.lock.yml index 048ee27701f..6e123b2bb01 100644 --- a/.github/workflows/daily-assign-issue-to-user.lock.yml +++ b/.github/workflows/daily-assign-issue-to-user.lock.yml @@ -455,7 +455,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-cli-performance.lock.yml b/.github/workflows/daily-cli-performance.lock.yml index 53f282b7a02..5ed4f7bafb0 100644 --- a/.github/workflows/daily-cli-performance.lock.yml +++ b/.github/workflows/daily-cli-performance.lock.yml @@ -523,7 +523,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-compiler-quality.lock.yml b/.github/workflows/daily-compiler-quality.lock.yml index 59e1d810041..e8f8e4749f7 100644 --- a/.github/workflows/daily-compiler-quality.lock.yml +++ b/.github/workflows/daily-compiler-quality.lock.yml @@ -564,7 +564,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-compiler-threat-spec-optimizer.lock.yml b/.github/workflows/daily-compiler-threat-spec-optimizer.lock.yml index 3515fb97dc9..17111bd6473 100644 --- a/.github/workflows/daily-compiler-threat-spec-optimizer.lock.yml +++ b/.github/workflows/daily-compiler-threat-spec-optimizer.lock.yml @@ -471,7 +471,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-experiment-report.lock.yml b/.github/workflows/daily-experiment-report.lock.yml index 1278eee8393..23bf0038d25 100644 --- a/.github/workflows/daily-experiment-report.lock.yml +++ b/.github/workflows/daily-experiment-report.lock.yml @@ -514,7 +514,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-geo-optimizer.lock.yml b/.github/workflows/daily-geo-optimizer.lock.yml index 2b980fbf702..e2344744a8a 100644 --- a/.github/workflows/daily-geo-optimizer.lock.yml +++ b/.github/workflows/daily-geo-optimizer.lock.yml @@ -477,7 +477,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-issues-report.lock.yml b/.github/workflows/daily-issues-report.lock.yml index a4248079606..ed7560033cf 100644 --- a/.github/workflows/daily-issues-report.lock.yml +++ b/.github/workflows/daily-issues-report.lock.yml @@ -718,7 +718,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Parse integrity filter lists id: parse-guard-vars diff --git a/.github/workflows/daily-malicious-code-scan.lock.yml b/.github/workflows/daily-malicious-code-scan.lock.yml index f884441e578..d1776fcc966 100644 --- a/.github/workflows/daily-malicious-code-scan.lock.yml +++ b/.github/workflows/daily-malicious-code-scan.lock.yml @@ -461,7 +461,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-mcp-concurrency-analysis.lock.yml b/.github/workflows/daily-mcp-concurrency-analysis.lock.yml index 114122f0b43..5c7336cf90d 100644 --- a/.github/workflows/daily-mcp-concurrency-analysis.lock.yml +++ b/.github/workflows/daily-mcp-concurrency-analysis.lock.yml @@ -521,7 +521,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-model-inventory.lock.yml b/.github/workflows/daily-model-inventory.lock.yml index cdfd753c0d4..48ca19bc64b 100644 --- a/.github/workflows/daily-model-inventory.lock.yml +++ b/.github/workflows/daily-model-inventory.lock.yml @@ -488,7 +488,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Install Playwright CLI run: npm install -g @playwright/cli@0.1.13 diff --git a/.github/workflows/daily-performance-summary.lock.yml b/.github/workflows/daily-performance-summary.lock.yml index ae5818c330b..cfe583ac86b 100644 --- a/.github/workflows/daily-performance-summary.lock.yml +++ b/.github/workflows/daily-performance-summary.lock.yml @@ -516,7 +516,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml index e4a3a0ea8f4..e88f34dd3d1 100644 --- a/.github/workflows/daily-repo-chronicle.lock.yml +++ b/.github/workflows/daily-repo-chronicle.lock.yml @@ -509,7 +509,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-safe-output-integrator.lock.yml b/.github/workflows/daily-safe-output-integrator.lock.yml index 645eba48cd4..4811d2f19a8 100644 --- a/.github/workflows/daily-safe-output-integrator.lock.yml +++ b/.github/workflows/daily-safe-output-integrator.lock.yml @@ -462,7 +462,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-secrets-analysis.lock.yml b/.github/workflows/daily-secrets-analysis.lock.yml index ffb8e5cf1b0..a826c382ce9 100644 --- a/.github/workflows/daily-secrets-analysis.lock.yml +++ b/.github/workflows/daily-secrets-analysis.lock.yml @@ -460,7 +460,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-security-observability.lock.yml b/.github/workflows/daily-security-observability.lock.yml index 5087f7fd158..de3968eb380 100644 --- a/.github/workflows/daily-security-observability.lock.yml +++ b/.github/workflows/daily-security-observability.lock.yml @@ -587,7 +587,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-sentrux-report.lock.yml b/.github/workflows/daily-sentrux-report.lock.yml index c5f3645e1f4..56619b26352 100644 --- a/.github/workflows/daily-sentrux-report.lock.yml +++ b/.github/workflows/daily-sentrux-report.lock.yml @@ -495,7 +495,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-skill-optimizer.lock.yml b/.github/workflows/daily-skill-optimizer.lock.yml index 33067da92f3..14dbb045cf9 100644 --- a/.github/workflows/daily-skill-optimizer.lock.yml +++ b/.github/workflows/daily-skill-optimizer.lock.yml @@ -467,7 +467,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-spdd-spec-planner.lock.yml b/.github/workflows/daily-spdd-spec-planner.lock.yml index 1bc444832ba..d230594b6ff 100644 --- a/.github/workflows/daily-spdd-spec-planner.lock.yml +++ b/.github/workflows/daily-spdd-spec-planner.lock.yml @@ -488,7 +488,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-syntax-error-quality.lock.yml b/.github/workflows/daily-syntax-error-quality.lock.yml index f25b336c86a..b3fd4965a4c 100644 --- a/.github/workflows/daily-syntax-error-quality.lock.yml +++ b/.github/workflows/daily-syntax-error-quality.lock.yml @@ -469,7 +469,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-testify-uber-super-expert.lock.yml b/.github/workflows/daily-testify-uber-super-expert.lock.yml index 699a1660c5d..ac7a2ec8460 100644 --- a/.github/workflows/daily-testify-uber-super-expert.lock.yml +++ b/.github/workflows/daily-testify-uber-super-expert.lock.yml @@ -530,7 +530,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/daily-workflow-updater.lock.yml b/.github/workflows/daily-workflow-updater.lock.yml index b1054ebb2e1..5f83a15fa3d 100644 --- a/.github/workflows/daily-workflow-updater.lock.yml +++ b/.github/workflows/daily-workflow-updater.lock.yml @@ -457,7 +457,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/dead-code-remover.lock.yml b/.github/workflows/dead-code-remover.lock.yml index 93669f535c6..983ed540b4a 100644 --- a/.github/workflows/dead-code-remover.lock.yml +++ b/.github/workflows/dead-code-remover.lock.yml @@ -509,7 +509,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/delight.lock.yml b/.github/workflows/delight.lock.yml index 95e4a32c3f8..3545e876927 100644 --- a/.github/workflows/delight.lock.yml +++ b/.github/workflows/delight.lock.yml @@ -485,7 +485,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/deployment-incident-monitor.lock.yml b/.github/workflows/deployment-incident-monitor.lock.yml index f916e47a119..9ffcb91c6e2 100644 --- a/.github/workflows/deployment-incident-monitor.lock.yml +++ b/.github/workflows/deployment-incident-monitor.lock.yml @@ -472,7 +472,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml index 9414139878f..470cdfebbc9 100644 --- a/.github/workflows/dev-hawk.lock.yml +++ b/.github/workflows/dev-hawk.lock.yml @@ -526,7 +526,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index e07e8bd6f09..724c2932fe6 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -459,7 +459,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/discussion-task-miner.lock.yml b/.github/workflows/discussion-task-miner.lock.yml index 36325872c86..e2fa5bd6cda 100644 --- a/.github/workflows/discussion-task-miner.lock.yml +++ b/.github/workflows/discussion-task-miner.lock.yml @@ -484,7 +484,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Parse integrity filter lists id: parse-guard-vars diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml index 15da8a93199..519de0a0b83 100644 --- a/.github/workflows/docs-noob-tester.lock.yml +++ b/.github/workflows/docs-noob-tester.lock.yml @@ -470,7 +470,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Install Playwright CLI run: npm install -g @playwright/cli@0.1.13 diff --git a/.github/workflows/draft-pr-cleanup.lock.yml b/.github/workflows/draft-pr-cleanup.lock.yml index d34c81cd80d..0dad82ec569 100644 --- a/.github/workflows/draft-pr-cleanup.lock.yml +++ b/.github/workflows/draft-pr-cleanup.lock.yml @@ -454,7 +454,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/firewall-escape.lock.yml b/.github/workflows/firewall-escape.lock.yml index 3360990777e..bd21888a7d5 100644 --- a/.github/workflows/firewall-escape.lock.yml +++ b/.github/workflows/firewall-escape.lock.yml @@ -529,7 +529,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/firewall.lock.yml b/.github/workflows/firewall.lock.yml index ed6ae9db0ad..997599e4371 100644 --- a/.github/workflows/firewall.lock.yml +++ b/.github/workflows/firewall.lock.yml @@ -455,7 +455,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/jsweep.lock.yml b/.github/workflows/jsweep.lock.yml index d6f1de2a507..dad2e571140 100644 --- a/.github/workflows/jsweep.lock.yml +++ b/.github/workflows/jsweep.lock.yml @@ -497,7 +497,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/layout-spec-maintainer.lock.yml b/.github/workflows/layout-spec-maintainer.lock.yml index 6d866656da7..4f02516fe01 100644 --- a/.github/workflows/layout-spec-maintainer.lock.yml +++ b/.github/workflows/layout-spec-maintainer.lock.yml @@ -473,7 +473,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/linter-miner.lock.yml b/.github/workflows/linter-miner.lock.yml index 3013a1b309d..cbc23241602 100644 --- a/.github/workflows/linter-miner.lock.yml +++ b/.github/workflows/linter-miner.lock.yml @@ -523,7 +523,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index 9670eb238e3..de66c110425 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -620,7 +620,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml index d52cdb115d4..cc9284590ec 100644 --- a/.github/workflows/mergefest.lock.yml +++ b/.github/workflows/mergefest.lock.yml @@ -526,7 +526,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/metrics-collector.lock.yml b/.github/workflows/metrics-collector.lock.yml index af2fe05d472..e7ec44a33dc 100644 --- a/.github/workflows/metrics-collector.lock.yml +++ b/.github/workflows/metrics-collector.lock.yml @@ -527,7 +527,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/org-health-report.lock.yml b/.github/workflows/org-health-report.lock.yml index 7fa8a32f031..d3e907fd920 100644 --- a/.github/workflows/org-health-report.lock.yml +++ b/.github/workflows/org-health-report.lock.yml @@ -514,7 +514,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Parse integrity filter lists id: parse-guard-vars diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml index 99b1bb0343c..4398f8b3125 100644 --- a/.github/workflows/pdf-summary.lock.yml +++ b/.github/workflows/pdf-summary.lock.yml @@ -567,7 +567,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml index b36120f14b7..a868b8e9074 100644 --- a/.github/workflows/plan.lock.yml +++ b/.github/workflows/plan.lock.yml @@ -524,7 +524,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Parse integrity filter lists id: parse-guard-vars diff --git a/.github/workflows/pr-code-quality-reviewer.lock.yml b/.github/workflows/pr-code-quality-reviewer.lock.yml index 35359326316..09a7fa6c56d 100644 --- a/.github/workflows/pr-code-quality-reviewer.lock.yml +++ b/.github/workflows/pr-code-quality-reviewer.lock.yml @@ -523,7 +523,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Parse integrity filter lists id: parse-guard-vars diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml index 5988d320ab4..a04dcd172b0 100644 --- a/.github/workflows/pr-nitpick-reviewer.lock.yml +++ b/.github/workflows/pr-nitpick-reviewer.lock.yml @@ -526,7 +526,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Parse integrity filter lists id: parse-guard-vars diff --git a/.github/workflows/pr-triage-agent.lock.yml b/.github/workflows/pr-triage-agent.lock.yml index 851b4511a69..08dd253b942 100644 --- a/.github/workflows/pr-triage-agent.lock.yml +++ b/.github/workflows/pr-triage-agent.lock.yml @@ -492,7 +492,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Parse integrity filter lists id: parse-guard-vars diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index a95771d61cd..f22195905cd 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -541,7 +541,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index d5332c0c0b3..dbc2393a37a 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -596,7 +596,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Parse integrity filter lists id: parse-guard-vars diff --git a/.github/workflows/smoke-copilot-sdk.lock.yml b/.github/workflows/smoke-copilot-sdk.lock.yml index c866bf30780..f20ae0a6c12 100644 --- a/.github/workflows/smoke-copilot-sdk.lock.yml +++ b/.github/workflows/smoke-copilot-sdk.lock.yml @@ -510,7 +510,7 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58 - - name: Install GitHub Copilot SDK + - name: Install GitHub Copilot SDK (Node.js) run: cd "${GITHUB_WORKSPACE}" && npm install --ignore-scripts --no-save @github/copilot-sdk@1.0.0 - name: Determine automatic lockdown mode for GitHub MCP Server id: determine-automatic-lockdown From 547e903795626081e78c1b170a1bcd744b2ce31b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 16:19:28 +0000 Subject: [PATCH 02/29] Use compat matrix for Copilot CLI resolution Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- .github/aw/compat.json | 3 + .github/aw/compat.schema.json | 23 +++ .github/workflows/cgo.yml | 40 ++++- actions/setup/js/check_version_updates.cjs | 4 +- actions/setup/sh/install_copilot_cli.sh | 177 ++++++++++++++++++++ docs/src/content/docs/reference/releases.md | 2 +- pkg/cli/install_copilot_cli_test.go | 87 ++++++++++ 7 files changed, 332 insertions(+), 4 deletions(-) diff --git a/.github/aw/compat.json b/.github/aw/compat.json index c17e3e349a8..b0551b4678c 100644 --- a/.github/aw/compat.json +++ b/.github/aw/compat.json @@ -1,5 +1,8 @@ { "$schema": "./compat.schema.json", + "blockedVersions": [], + "minimumVersion": "v0.65.3", + "minRecommendedVersion": "v0.65.3", "agent-compat-v1": { "cache-ttl-days": 14, "copilot": [ diff --git a/.github/aw/compat.schema.json b/.github/aw/compat.schema.json index b3f8e83ae18..12a933a1aed 100644 --- a/.github/aw/compat.schema.json +++ b/.github/aw/compat.schema.json @@ -10,6 +10,29 @@ "$schema": { "type": "string" }, + "blockedVersions": { + "type": "array", + "description": "List of blocked compile-agentic versions that are not allowed to run (e.g. due to a security compromise). Workflows compiled with a blocked version will fail at activation.", + "items": { + "type": "string", + "pattern": "^v[0-9]+\\.[0-9]+\\.[0-9]+$", + "description": "A blocked version string in vMAJOR.MINOR.PATCH format (e.g. 'v1.2.3')" + }, + "uniqueItems": true, + "default": [] + }, + "minimumVersion": { + "type": "string", + "description": "The minimum supported compile-agentic version in vMAJOR.MINOR.PATCH format. Workflows compiled with a version below this will fail at activation. Use an empty string to disable this check.", + "pattern": "^(v[0-9]+\\.[0-9]+\\.[0-9]+)?$", + "default": "" + }, + "minRecommendedVersion": { + "type": "string", + "description": "The minimum recommended compile-agentic version in vMAJOR.MINOR.PATCH format. Workflows compiled with a version below this will emit a warning (but not fail) at activation, nudging users to upgrade. Use an empty string to disable this check.", + "pattern": "^(v[0-9]+\\.[0-9]+\\.[0-9]+)?$", + "default": "" + }, "agent-compat-v1": { "type": "object", "additionalProperties": false, diff --git a/.github/workflows/cgo.yml b/.github/workflows/cgo.yml index b99bba4d955..b5df1ca8b13 100644 --- a/.github/workflows/cgo.yml +++ b/.github/workflows/cgo.yml @@ -669,13 +669,51 @@ jobs: core.info(`✅ ${CONFIG_FILE} is valid JSON`); const errors = []; - const allowedTopKeys = new Set(['$schema', 'agent-compat-v1']); + const allowedTopKeys = new Set(['$schema', 'blockedVersions', 'minimumVersion', 'minRecommendedVersion', 'agent-compat-v1']); for (const key of Object.keys(config)) { if (!allowedTopKeys.has(key)) { errors.push(`Unknown top-level property: '${key}'`); } } + const releaseVersionRe = /^v[0-9]+\.[0-9]+\.[0-9]+$/; + if ('blockedVersions' in config) { + if (!Array.isArray(config.blockedVersions)) { + errors.push("'blockedVersions' must be an array"); + } else { + const seenBlocked = new Set(); + config.blockedVersions.forEach((v, i) => { + if (typeof v !== 'string') { + errors.push(`blockedVersions[${i}] must be a string`); + return; + } + if (!releaseVersionRe.test(v)) { + errors.push(`blockedVersions[${i}] ('${v}') must match vMAJOR.MINOR.PATCH`); + } + if (seenBlocked.has(v)) { + errors.push(`blockedVersions contains duplicate entry '${v}'`); + } + seenBlocked.add(v); + }); + } + } + if ('minimumVersion' in config) { + const mv = config.minimumVersion; + if (typeof mv !== 'string') { + errors.push("'minimumVersion' must be a string"); + } else if (!(mv === '' || releaseVersionRe.test(mv))) { + errors.push(`'minimumVersion' ('${mv}') does not match expected version pattern (vMAJOR.MINOR.PATCH or empty string)`); + } + } + if ('minRecommendedVersion' in config) { + const mrv = config.minRecommendedVersion; + if (typeof mrv !== 'string') { + errors.push("'minRecommendedVersion' must be a string"); + } else if (!(mrv === '' || releaseVersionRe.test(mrv))) { + errors.push(`'minRecommendedVersion' ('${mrv}') does not match expected version pattern (vMAJOR.MINOR.PATCH or empty string)`); + } + } + const matrix = config['agent-compat-v1']; if (typeof matrix !== 'object' || matrix === null || Array.isArray(matrix)) { core.setFailed(`ERROR: 'agent-compat-v1' must be an object`); diff --git a/actions/setup/js/check_version_updates.cjs b/actions/setup/js/check_version_updates.cjs index 9113c07d5b5..1e2c6d8c700 100644 --- a/actions/setup/js/check_version_updates.cjs +++ b/actions/setup/js/check_version_updates.cjs @@ -7,7 +7,7 @@ * This script: * 1. Reads the compiled version from GH_AW_COMPILED_VERSION env var. * 2. Skips the check if the version is not in vMAJOR.MINOR.PATCH official release format. - * 3. Fetches .github/aw/releases.json from the gh-aw repository via raw.githubusercontent.com. + * 3. Fetches .github/aw/compat.json from the gh-aw repository via raw.githubusercontent.com. * - Uses withRetry to handle transient network failures. * 4. If the download fails or config is invalid JSON, the check is skipped (soft failure). * 5. Validates that the compiled version is not in the blocked list. @@ -18,7 +18,7 @@ const { withRetry, isTransientError } = require("./error_recovery.cjs"); -const CONFIG_URL = "https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/releases.json"; +const CONFIG_URL = "https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/compat.json"; /** * Parse an official version string (must be in vMAJOR.MINOR.PATCH format). diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index b9281dacf4e..056031d1203 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -24,6 +24,9 @@ COPILOT_REPO="github/copilot-cli" INSTALL_DIR="/usr/local/bin" COPILOT_DIR="${HOME}/.copilot" COPILOT_TOOLCACHE_MAX_DEPTH=4 +COMPAT_URL_PRIMARY="${COPILOT_COMPAT_URL:-https://raw.githubusercontent.com/github/gh-aw-actions/main/.github/aw/compat.json}" +COMPAT_URL_FALLBACK="${COPILOT_COMPAT_FALLBACK_URL:-https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/compat.json}" +COMPILED_GH_AW_VERSION="${GH_AW_COMPILED_VERSION:-}" # Fix directory ownership before installation # This is needed because a previous AWF run on the same runner may have used @@ -132,6 +135,165 @@ version_is_greater() { return 1 } +# Download compatibility matrix with fallback URLs. +download_compat_json() { + local compat_file="$1" + local source_file="$2" + local url="" + local urls=("$COMPAT_URL_PRIMARY") + + if [ "$COMPAT_URL_FALLBACK" != "$COMPAT_URL_PRIMARY" ]; then + urls+=("$COMPAT_URL_FALLBACK") + fi + + for url in "${urls[@]}"; do + echo "Attempting to download compatibility matrix from ${url}..." >&2 + if curl -fsSL --retry 3 --retry-delay 5 -o "$compat_file" "$url"; then + echo "$url" > "$source_file" + echo "Successfully downloaded compatibility matrix from ${url}" >&2 + return 0 + fi + echo "Compatibility matrix download failed from ${url}" >&2 + done + + return 1 +} + +# Resolve Copilot version from compat matrix using GH_AW_COMPILED_VERSION. +resolve_version_from_compat() { + local compiled_version="${1:-}" + local compat_file="$2" + local resolved_info="" + local compat_source="" + + if [ -z "$compiled_version" ]; then + echo "No GH_AW_COMPILED_VERSION provided, skipping compatibility matrix resolution." >&2 + return 1 + fi + + if [[ ! "$compiled_version" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "GH_AW_COMPILED_VERSION '${compiled_version}' is not in vMAJOR.MINOR.PATCH format; skipping compatibility matrix resolution." >&2 + return 1 + fi + + compat_source="${compat_file}.source" + if ! download_compat_json "$compat_file" "$compat_source"; then + echo "Could not download compatibility matrix from primary or fallback URL; using release latest fallback." >&2 + return 1 + fi + + resolved_info="$(python3 - "$compat_file" "$compiled_version" <<'PY' +import json +import re +import sys + +compat_path = sys.argv[1] +compiled = sys.argv[2] +semver_re = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$") + +def parse(v): + m = re.match(r"^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z.-]+))?$", v) + if not m: + return None + pre = m.group(4).split(".") if m.group(4) else None + return (int(m.group(1)), int(m.group(2)), int(m.group(3)), pre) + +def cmp(a, b): + pa = parse(a) + pb = parse(b) + if pa is None or pb is None: + return 0 + for i in range(3): + if pa[i] != pb[i]: + return pa[i] - pb[i] + apre = pa[3] + bpre = pb[3] + if apre is None and bpre is None: + return 0 + if apre is None: + return 1 + if bpre is None: + return -1 + length = max(len(apre), len(bpre)) + for i in range(length): + if i >= len(apre): + return -1 + if i >= len(bpre): + return 1 + ai = apre[i] + bi = bpre[i] + ai_n = ai.isdigit() + bi_n = bi.isdigit() + if ai_n and bi_n: + da = int(ai) + db = int(bi) + if da != db: + return da - db + elif ai_n: + return -1 + elif bi_n: + return 1 + elif ai != bi: + return -1 if ai < bi else 1 + return 0 + +compiled_no_v = compiled[1:] +if parse(compiled_no_v) is None: + print("") + sys.exit(0) + +with open(compat_path, "r", encoding="utf-8") as f: + data = json.load(f) + +rows = ( + data.get("agent-compat-v1", {}) + .get("copilot", []) +) +if not isinstance(rows, list): + print("") + sys.exit(0) + +for i, row in enumerate(rows): + if not isinstance(row, dict): + continue + min_aw = row.get("min-gh-aw") + max_aw = row.get("max-gh-aw") + min_agent = row.get("min-agent") + max_agent = row.get("max-agent") + if not all(isinstance(v, str) for v in [min_aw, max_aw, min_agent, max_agent]): + continue + if parse(min_aw) is None: + continue + if max_aw != "*" and parse(max_aw) is None: + continue + if not semver_re.match(max_agent): + continue + + if cmp(compiled_no_v, min_aw) < 0: + continue + if max_aw != "*" and cmp(compiled_no_v, max_aw) > 0: + continue + + print(f"{max_agent}|{i}|{min_aw}|{max_aw}|{min_agent}|{max_agent}") + sys.exit(0) + +print("") +PY +)" + + if [ -z "$resolved_info" ]; then + echo "Compatibility matrix lookup found no matching copilot window for gh-aw ${compiled_version}; using release latest fallback." >&2 + return 1 + fi + + IFS='|' read -r resolved_version row_index row_min_aw row_max_aw row_min_agent row_max_agent <<< "$resolved_info" + echo "Compatibility matrix source: $(cat "$compat_source")" >&2 + echo "Compatibility matrix matched row ${row_index}: gh-aw ${row_min_aw}..${row_max_aw}, copilot ${row_min_agent}..${row_max_agent}" >&2 + echo "Resolved Copilot CLI version from compatibility matrix: ${resolved_version}" >&2 + printf '%s\n' "$resolved_version" + return 0 +} + # Look up a compatible Copilot CLI from the Actions toolcache before downloading a release tarball. find_cached_copilot_bin() { local requested_version="${1:-latest}" @@ -246,6 +408,21 @@ EOF TEMP_DIR=$(mktemp -d) trap 'rm -rf "$TEMP_DIR"' EXIT +# Resolve a compatible Copilot version from compat matrix unless the caller passed an explicit version. +if [ -z "$VERSION" ]; then + echo "No explicit Copilot CLI version requested. Attempting compat-driven version resolution..." + if RESOLVED_COMPAT_VERSION="$(resolve_version_from_compat "$COMPILED_GH_AW_VERSION" "${TEMP_DIR}/compat.json")"; then + VERSION="$RESOLVED_COMPAT_VERSION" + REQUESTED_VERSION="$RESOLVED_COMPAT_VERSION" + echo "Using compat-resolved Copilot CLI version: ${REQUESTED_VERSION}" + else + REQUESTED_VERSION="latest" + echo "Falling back to latest Copilot CLI release because compat resolution did not produce a version." + fi +else + echo "Explicit Copilot CLI version argument provided (${VERSION}); skipping compat matrix resolution." +fi + # Prefer the runner toolcache when a compatible Copilot CLI is already available. if CACHED_COPILOT_BIN="$(find_cached_copilot_bin "$REQUESTED_VERSION")"; then echo "Using cached GitHub Copilot CLI from ${CACHED_COPILOT_BIN}" diff --git a/docs/src/content/docs/reference/releases.md b/docs/src/content/docs/reference/releases.md index 01b0b5b21ca..bf029701579 100644 --- a/docs/src/content/docs/reference/releases.md +++ b/docs/src/content/docs/reference/releases.md @@ -62,7 +62,7 @@ Every compiled `.lock.yml` embeds the gh-aw version used to produce it: GH_AW_INFO_AWF_VERSION: "v0.64.5" ``` -At runtime, the activation job fetches `.github/aw/releases.json` and compares the embedded version against three policies: +At runtime, the activation job fetches `.github/aw/compat.json` and compares the embedded version against three policies: | Policy | Effect | |--------|--------| diff --git a/pkg/cli/install_copilot_cli_test.go b/pkg/cli/install_copilot_cli_test.go index f4d5085fcbf..deba9e8e5aa 100644 --- a/pkg/cli/install_copilot_cli_test.go +++ b/pkg/cli/install_copilot_cli_test.go @@ -62,3 +62,90 @@ exit 97 require.NoError(t, err, "Expected the script to append the cached bin dir to GITHUB_PATH") assert.Contains(t, string(githubPathContent), toolcacheBin, "cached Copilot bin directory should be exported for later steps") } + +func TestInstallCopilotCLIScriptResolvesCompatVersionBeforeToolcacheLookup(t *testing.T) { + wd, err := os.Getwd() + require.NoError(t, err, "Failed to get working directory") + + projectRoot := filepath.Join(wd, "..", "..") + installScript := filepath.Join(projectRoot, "actions", "setup", "sh", "install_copilot_cli.sh") + + tempDir := t.TempDir() + toolcacheBin := filepath.Join(tempDir, "toolcache", "copilot-cli", "1.0.51", "x64", "bin") + require.NoError(t, os.MkdirAll(toolcacheBin, 0o755)) + + cachedCopilot := filepath.Join(toolcacheBin, "copilot") + require.NoError(t, os.WriteFile(cachedCopilot, []byte("#!/usr/bin/env bash\necho 'copilot 1.0.51'\n"), 0o755)) + + fakeBinDir := filepath.Join(tempDir, "fake-bin") + require.NoError(t, os.MkdirAll(fakeBinDir, 0o755)) + + curlLog := filepath.Join(tempDir, "curl.log") + sudoScript := filepath.Join(fakeBinDir, "sudo") + curlScript := filepath.Join(fakeBinDir, "curl") + + require.NoError(t, os.WriteFile(sudoScript, []byte(`#!/usr/bin/env bash +if [ "${1:-}" = "chown" ]; then + exit 0 +fi +exec "$@" +`), 0o755)) + require.NoError(t, os.WriteFile(curlScript, []byte(`#!/usr/bin/env bash +set -euo pipefail +output_file="" +url="" +while [ "$#" -gt 0 ]; do + case "$1" in + -o) + output_file="$2" + shift 2 + ;; + *) + url="$1" + shift + ;; + esac +done +echo "$url" >> "`+curlLog+`" +if [[ "$url" == *"/compat.json" ]]; then + cat > "$output_file" <<'JSON' +{ + "agent-compat-v1": { + "copilot": [ + { + "min-gh-aw": "0.72.0", + "max-gh-aw": "*", + "min-agent": "1.0.21", + "max-agent": "1.0.51" + } + ] + } +} +JSON + exit 0 +fi +echo "unexpected URL: $url" >&2 +exit 97 +`), 0o755)) + + githubPath := filepath.Join(tempDir, "github-path") + cmd := exec.Command("bash", installScript) + cmd.Env = append(os.Environ(), + "RUNNER_TOOL_CACHE="+filepath.Join(tempDir, "toolcache"), + "GITHUB_PATH="+githubPath, + "GH_AW_COMPILED_VERSION=v0.72.5", + "PATH="+fakeBinDir+":"+os.Getenv("PATH"), + ) + + output, err := cmd.CombinedOutput() + require.NoError(t, err, "install_copilot_cli.sh should resolve compat version and use toolcache: %s", output) + + assert.Contains(t, string(output), "Resolved Copilot CLI version from compatibility matrix: 1.0.51") + assert.Contains(t, string(output), "Using compat-resolved Copilot CLI version: 1.0.51") + assert.Contains(t, string(output), "Using cached GitHub Copilot CLI") + + curlLogContent, err := os.ReadFile(curlLog) + require.NoError(t, err, "Expected curl to fetch compatibility matrix") + assert.Contains(t, string(curlLogContent), "/compat.json", "compat matrix should be downloaded") + assert.NotContains(t, string(curlLogContent), "SHA256SUMS.txt", "release downloads should not run when toolcache is hit") +} From 950c7a234201492ef103a5b679d09703c46c256a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 16:25:29 +0000 Subject: [PATCH 03/29] Harden compat semver parsing and test constants Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 6 ++---- pkg/cli/install_copilot_cli_test.go | 12 +++++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 056031d1203..49354bd6a93 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -189,10 +189,8 @@ import sys compat_path = sys.argv[1] compiled = sys.argv[2] -semver_re = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$") - def parse(v): - m = re.match(r"^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z.-]+))?$", v) + m = re.match(r"^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$", v) if not m: return None pre = m.group(4).split(".") if m.group(4) else None @@ -266,7 +264,7 @@ for i, row in enumerate(rows): continue if max_aw != "*" and parse(max_aw) is None: continue - if not semver_re.match(max_agent): + if parse(min_agent) is None or parse(max_agent) is None: continue if cmp(compiled_no_v, min_aw) < 0: diff --git a/pkg/cli/install_copilot_cli_test.go b/pkg/cli/install_copilot_cli_test.go index deba9e8e5aa..d8a8f519c56 100644 --- a/pkg/cli/install_copilot_cli_test.go +++ b/pkg/cli/install_copilot_cli_test.go @@ -64,6 +64,8 @@ exit 97 } func TestInstallCopilotCLIScriptResolvesCompatVersionBeforeToolcacheLookup(t *testing.T) { + const compatVersion = "1.0.51" + wd, err := os.Getwd() require.NoError(t, err, "Failed to get working directory") @@ -71,11 +73,11 @@ func TestInstallCopilotCLIScriptResolvesCompatVersionBeforeToolcacheLookup(t *te installScript := filepath.Join(projectRoot, "actions", "setup", "sh", "install_copilot_cli.sh") tempDir := t.TempDir() - toolcacheBin := filepath.Join(tempDir, "toolcache", "copilot-cli", "1.0.51", "x64", "bin") + toolcacheBin := filepath.Join(tempDir, "toolcache", "copilot-cli", compatVersion, "x64", "bin") require.NoError(t, os.MkdirAll(toolcacheBin, 0o755)) cachedCopilot := filepath.Join(toolcacheBin, "copilot") - require.NoError(t, os.WriteFile(cachedCopilot, []byte("#!/usr/bin/env bash\necho 'copilot 1.0.51'\n"), 0o755)) + require.NoError(t, os.WriteFile(cachedCopilot, []byte("#!/usr/bin/env bash\necho 'copilot "+compatVersion+"'\n"), 0o755)) fakeBinDir := filepath.Join(tempDir, "fake-bin") require.NoError(t, os.MkdirAll(fakeBinDir, 0o755)) @@ -116,7 +118,7 @@ if [[ "$url" == *"/compat.json" ]]; then "min-gh-aw": "0.72.0", "max-gh-aw": "*", "min-agent": "1.0.21", - "max-agent": "1.0.51" + "max-agent": "`+compatVersion+`" } ] } @@ -140,8 +142,8 @@ exit 97 output, err := cmd.CombinedOutput() require.NoError(t, err, "install_copilot_cli.sh should resolve compat version and use toolcache: %s", output) - assert.Contains(t, string(output), "Resolved Copilot CLI version from compatibility matrix: 1.0.51") - assert.Contains(t, string(output), "Using compat-resolved Copilot CLI version: 1.0.51") + assert.Contains(t, string(output), "Resolved Copilot CLI version from compatibility matrix: "+compatVersion) + assert.Contains(t, string(output), "Using compat-resolved Copilot CLI version: "+compatVersion) assert.Contains(t, string(output), "Using cached GitHub Copilot CLI") curlLogContent, err := os.ReadFile(curlLog) From d5cded8ae9b87eeb112dcf5903e9194b89847bd8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:39:35 +0000 Subject: [PATCH 04/29] Align compat install flow with runtime plan Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 65 ++++++++++++++++++++----- pkg/cli/install_copilot_cli_test.go | 14 ++++-- 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 49354bd6a93..9292bae089c 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -27,6 +27,11 @@ COPILOT_TOOLCACHE_MAX_DEPTH=4 COMPAT_URL_PRIMARY="${COPILOT_COMPAT_URL:-https://raw.githubusercontent.com/github/gh-aw-actions/main/.github/aw/compat.json}" COMPAT_URL_FALLBACK="${COPILOT_COMPAT_FALLBACK_URL:-https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/compat.json}" COMPILED_GH_AW_VERSION="${GH_AW_COMPILED_VERSION:-}" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" +COMPAT_BUNDLED_PATH="${COPILOT_COMPAT_BUNDLED_PATH:-${REPO_ROOT}/.github/aw/compat.json}" +COMPAT_MATCHED_MIN_AGENT="" +COMPAT_MATCHED_MAX_AGENT="" # Fix directory ownership before installation # This is needed because a previous AWF run on the same runner may have used @@ -156,6 +161,14 @@ download_compat_json() { echo "Compatibility matrix download failed from ${url}" >&2 done + if [ -f "$COMPAT_BUNDLED_PATH" ]; then + echo "Falling back to bundled compatibility matrix at ${COMPAT_BUNDLED_PATH}" >&2 + cp "$COMPAT_BUNDLED_PATH" "$compat_file" + echo "bundled:${COMPAT_BUNDLED_PATH}" > "$source_file" + return 0 + fi + + echo "Bundled compatibility matrix not found at ${COMPAT_BUNDLED_PATH}" >&2 return 1 } @@ -178,11 +191,16 @@ resolve_version_from_compat() { compat_source="${compat_file}.source" if ! download_compat_json "$compat_file" "$compat_source"; then - echo "Could not download compatibility matrix from primary or fallback URL; using release latest fallback." >&2 + echo "Could not resolve compatibility matrix from network or bundled fallback; using release latest fallback." >&2 + return 1 + fi + + if ! command -v python3 >/dev/null 2>&1; then + echo "python3 is unavailable; skipping compatibility matrix resolution." >&2 return 1 fi - resolved_info="$(python3 - "$compat_file" "$compiled_version" <<'PY' + if ! resolved_info="$(python3 - "$compat_file" "$compiled_version" <<'PY' import json import re import sys @@ -240,8 +258,16 @@ if parse(compiled_no_v) is None: print("") sys.exit(0) -with open(compat_path, "r", encoding="utf-8") as f: - data = json.load(f) +try: + with open(compat_path, "r", encoding="utf-8") as f: + data = json.load(f) +except Exception: + print("") + sys.exit(0) + +if not isinstance(data, dict): + print("") + sys.exit(0) rows = ( data.get("agent-compat-v1", {}) @@ -277,7 +303,10 @@ for i, row in enumerate(rows): print("") PY -)" + )"; then + echo "Compatibility matrix resolver failed unexpectedly; using release latest fallback." >&2 + return 1 + fi if [ -z "$resolved_info" ]; then echo "Compatibility matrix lookup found no matching copilot window for gh-aw ${compiled_version}; using release latest fallback." >&2 @@ -288,13 +317,15 @@ PY echo "Compatibility matrix source: $(cat "$compat_source")" >&2 echo "Compatibility matrix matched row ${row_index}: gh-aw ${row_min_aw}..${row_max_aw}, copilot ${row_min_agent}..${row_max_agent}" >&2 echo "Resolved Copilot CLI version from compatibility matrix: ${resolved_version}" >&2 - printf '%s\n' "$resolved_version" + printf '%s|%s|%s\n' "$resolved_version" "$row_min_agent" "$row_max_agent" return 0 } # Look up a compatible Copilot CLI from the Actions toolcache before downloading a release tarball. find_cached_copilot_bin() { local requested_version="${1:-latest}" + local min_version="${2:-}" + local max_version="${3:-}" local requested_version_normalized="" local tool_cache_root="" local candidate="" @@ -305,7 +336,7 @@ find_cached_copilot_bin() { local best_candidate="" local best_version="" - echo "Searching toolcache for GitHub Copilot CLI (requested: ${requested_version}, arch: ${ARCH_NAME})..." >&2 + echo "Searching toolcache for GitHub Copilot CLI (requested: ${requested_version}, arch: ${ARCH_NAME}, range: ${min_version:-none}..${max_version:-none})..." >&2 if [ "$requested_version" != "latest" ]; then requested_version_normalized="$(normalize_version "$requested_version")" @@ -355,6 +386,16 @@ find_cached_copilot_bin() { continue fi + if [ -n "$min_version" ] && version_is_greater "$min_version" "$candidate_version_normalized"; then + echo " Skipping candidate (below compat minimum: ${candidate_version_normalized} < ${min_version})" >&2 + continue + fi + + if [ -n "$max_version" ] && version_is_greater "$candidate_version_normalized" "$max_version"; then + echo " Skipping candidate (above compat maximum: ${candidate_version_normalized} > ${max_version})" >&2 + continue + fi + if [ -z "$best_candidate" ] || version_is_greater "$candidate_version_normalized" "$best_version"; then echo " New best candidate: ${candidate} (${candidate_version_normalized} > ${best_version:-none})" >&2 best_candidate="$candidate" @@ -409,10 +450,12 @@ trap 'rm -rf "$TEMP_DIR"' EXIT # Resolve a compatible Copilot version from compat matrix unless the caller passed an explicit version. if [ -z "$VERSION" ]; then echo "No explicit Copilot CLI version requested. Attempting compat-driven version resolution..." - if RESOLVED_COMPAT_VERSION="$(resolve_version_from_compat "$COMPILED_GH_AW_VERSION" "${TEMP_DIR}/compat.json")"; then + if RESOLVED_COMPAT_INFO="$(resolve_version_from_compat "$COMPILED_GH_AW_VERSION" "${TEMP_DIR}/compat.json")"; then + IFS='|' read -r RESOLVED_COMPAT_VERSION COMPAT_MATCHED_MIN_AGENT COMPAT_MATCHED_MAX_AGENT <<< "$RESOLVED_COMPAT_INFO" VERSION="$RESOLVED_COMPAT_VERSION" - REQUESTED_VERSION="$RESOLVED_COMPAT_VERSION" - echo "Using compat-resolved Copilot CLI version: ${REQUESTED_VERSION}" + REQUESTED_VERSION="latest" + echo "Using compat-resolved Copilot CLI window: ${COMPAT_MATCHED_MIN_AGENT}..${COMPAT_MATCHED_MAX_AGENT}" + echo "Will install compat max-agent ${VERSION} if no cached version satisfies the window." else REQUESTED_VERSION="latest" echo "Falling back to latest Copilot CLI release because compat resolution did not produce a version." @@ -422,7 +465,7 @@ else fi # Prefer the runner toolcache when a compatible Copilot CLI is already available. -if CACHED_COPILOT_BIN="$(find_cached_copilot_bin "$REQUESTED_VERSION")"; then +if CACHED_COPILOT_BIN="$(find_cached_copilot_bin "$REQUESTED_VERSION" "${COMPAT_MATCHED_MIN_AGENT}" "${COMPAT_MATCHED_MAX_AGENT}")"; then echo "Using cached GitHub Copilot CLI from ${CACHED_COPILOT_BIN}" activate_cached_copilot_bin "$CACHED_COPILOT_BIN" diff --git a/pkg/cli/install_copilot_cli_test.go b/pkg/cli/install_copilot_cli_test.go index d8a8f519c56..e2676d847ea 100644 --- a/pkg/cli/install_copilot_cli_test.go +++ b/pkg/cli/install_copilot_cli_test.go @@ -65,6 +65,8 @@ exit 97 func TestInstallCopilotCLIScriptResolvesCompatVersionBeforeToolcacheLookup(t *testing.T) { const compatVersion = "1.0.51" + const cachedCompatibleVersion = "1.0.40" + const cachedTooNewVersion = "1.0.60" wd, err := os.Getwd() require.NoError(t, err, "Failed to get working directory") @@ -73,11 +75,15 @@ func TestInstallCopilotCLIScriptResolvesCompatVersionBeforeToolcacheLookup(t *te installScript := filepath.Join(projectRoot, "actions", "setup", "sh", "install_copilot_cli.sh") tempDir := t.TempDir() - toolcacheBin := filepath.Join(tempDir, "toolcache", "copilot-cli", compatVersion, "x64", "bin") + toolcacheBin := filepath.Join(tempDir, "toolcache", "copilot-cli", cachedCompatibleVersion, "x64", "bin") + tooNewToolcacheBin := filepath.Join(tempDir, "toolcache", "copilot-cli", cachedTooNewVersion, "x64", "bin") require.NoError(t, os.MkdirAll(toolcacheBin, 0o755)) + require.NoError(t, os.MkdirAll(tooNewToolcacheBin, 0o755)) cachedCopilot := filepath.Join(toolcacheBin, "copilot") - require.NoError(t, os.WriteFile(cachedCopilot, []byte("#!/usr/bin/env bash\necho 'copilot "+compatVersion+"'\n"), 0o755)) + tooNewCachedCopilot := filepath.Join(tooNewToolcacheBin, "copilot") + require.NoError(t, os.WriteFile(cachedCopilot, []byte("#!/usr/bin/env bash\necho 'copilot "+cachedCompatibleVersion+"'\n"), 0o755)) + require.NoError(t, os.WriteFile(tooNewCachedCopilot, []byte("#!/usr/bin/env bash\necho 'copilot "+cachedTooNewVersion+"'\n"), 0o755)) fakeBinDir := filepath.Join(tempDir, "fake-bin") require.NoError(t, os.MkdirAll(fakeBinDir, 0o755)) @@ -143,7 +149,9 @@ exit 97 require.NoError(t, err, "install_copilot_cli.sh should resolve compat version and use toolcache: %s", output) assert.Contains(t, string(output), "Resolved Copilot CLI version from compatibility matrix: "+compatVersion) - assert.Contains(t, string(output), "Using compat-resolved Copilot CLI version: "+compatVersion) + assert.Contains(t, string(output), "Using compat-resolved Copilot CLI window: 1.0.21.."+compatVersion) + assert.Contains(t, string(output), "Skipping candidate (above compat maximum: "+cachedTooNewVersion+" > "+compatVersion+")") + assert.Contains(t, string(output), "Selected best cached version: "+cachedCompatibleVersion) assert.Contains(t, string(output), "Using cached GitHub Copilot CLI") curlLogContent, err := os.ReadFile(curlLog) From 578846860168a5c88e34f584070bf54f962e8afb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:41:04 +0000 Subject: [PATCH 05/29] Harden compat fallback and cache window matching Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 1 + pkg/cli/install_copilot_cli_test.go | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 9292bae089c..2de06a2a879 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -262,6 +262,7 @@ try: with open(compat_path, "r", encoding="utf-8") as f: data = json.load(f) except Exception: + sys.stderr.write(f"Compatibility matrix parse failed for {compat_path}\n") print("") sys.exit(0) diff --git a/pkg/cli/install_copilot_cli_test.go b/pkg/cli/install_copilot_cli_test.go index e2676d847ea..1533a253a1b 100644 --- a/pkg/cli/install_copilot_cli_test.go +++ b/pkg/cli/install_copilot_cli_test.go @@ -66,6 +66,8 @@ exit 97 func TestInstallCopilotCLIScriptResolvesCompatVersionBeforeToolcacheLookup(t *testing.T) { const compatVersion = "1.0.51" const cachedCompatibleVersion = "1.0.40" + const cachedBoundaryMinVersion = "1.0.21" + const cachedTooOldVersion = "1.0.20" const cachedTooNewVersion = "1.0.60" wd, err := os.Getwd() @@ -76,13 +78,21 @@ func TestInstallCopilotCLIScriptResolvesCompatVersionBeforeToolcacheLookup(t *te tempDir := t.TempDir() toolcacheBin := filepath.Join(tempDir, "toolcache", "copilot-cli", cachedCompatibleVersion, "x64", "bin") + minBoundaryToolcacheBin := filepath.Join(tempDir, "toolcache", "copilot-cli", cachedBoundaryMinVersion, "x64", "bin") + tooOldToolcacheBin := filepath.Join(tempDir, "toolcache", "copilot-cli", cachedTooOldVersion, "x64", "bin") tooNewToolcacheBin := filepath.Join(tempDir, "toolcache", "copilot-cli", cachedTooNewVersion, "x64", "bin") require.NoError(t, os.MkdirAll(toolcacheBin, 0o755)) + require.NoError(t, os.MkdirAll(minBoundaryToolcacheBin, 0o755)) + require.NoError(t, os.MkdirAll(tooOldToolcacheBin, 0o755)) require.NoError(t, os.MkdirAll(tooNewToolcacheBin, 0o755)) cachedCopilot := filepath.Join(toolcacheBin, "copilot") + minBoundaryCachedCopilot := filepath.Join(minBoundaryToolcacheBin, "copilot") + tooOldCachedCopilot := filepath.Join(tooOldToolcacheBin, "copilot") tooNewCachedCopilot := filepath.Join(tooNewToolcacheBin, "copilot") require.NoError(t, os.WriteFile(cachedCopilot, []byte("#!/usr/bin/env bash\necho 'copilot "+cachedCompatibleVersion+"'\n"), 0o755)) + require.NoError(t, os.WriteFile(minBoundaryCachedCopilot, []byte("#!/usr/bin/env bash\necho 'copilot "+cachedBoundaryMinVersion+"'\n"), 0o755)) + require.NoError(t, os.WriteFile(tooOldCachedCopilot, []byte("#!/usr/bin/env bash\necho 'copilot "+cachedTooOldVersion+"'\n"), 0o755)) require.NoError(t, os.WriteFile(tooNewCachedCopilot, []byte("#!/usr/bin/env bash\necho 'copilot "+cachedTooNewVersion+"'\n"), 0o755)) fakeBinDir := filepath.Join(tempDir, "fake-bin") @@ -150,7 +160,9 @@ exit 97 assert.Contains(t, string(output), "Resolved Copilot CLI version from compatibility matrix: "+compatVersion) assert.Contains(t, string(output), "Using compat-resolved Copilot CLI window: 1.0.21.."+compatVersion) + assert.Contains(t, string(output), "Skipping candidate (below compat minimum: "+cachedTooOldVersion+" < 1.0.21)") assert.Contains(t, string(output), "Skipping candidate (above compat maximum: "+cachedTooNewVersion+" > "+compatVersion+")") + assert.NotContains(t, string(output), "Skipping candidate (below compat minimum: "+cachedBoundaryMinVersion+" < 1.0.21)") assert.Contains(t, string(output), "Selected best cached version: "+cachedCompatibleVersion) assert.Contains(t, string(output), "Using cached GitHub Copilot CLI") From 74e05024f539372517eb1a24fc220f9a5c4172ef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:58:41 +0000 Subject: [PATCH 06/29] Add GitHub Actions warning when using bundled compat fallback Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 2de06a2a879..9a174353aab 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -162,6 +162,7 @@ download_compat_json() { done if [ -f "$COMPAT_BUNDLED_PATH" ]; then + echo "::warning::Compatibility matrix network fetch failed; using bundled fallback at ${COMPAT_BUNDLED_PATH}" echo "Falling back to bundled compatibility matrix at ${COMPAT_BUNDLED_PATH}" >&2 cp "$COMPAT_BUNDLED_PATH" "$compat_file" echo "bundled:${COMPAT_BUNDLED_PATH}" > "$source_file" From b2aefd5806fa0092ca0125a153d11e04b83f0f6f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 18:09:05 +0000 Subject: [PATCH 07/29] Remove dangerous fallback to latest Copilot CLI when compat resolution fails When compatibility matrix resolution fails (no bundled file, parse error, no matching row, or missing python3), the installer now exits with a clear error instead of falling back to "latest", which could install an incompatible version that breaks the compatibility guarantees the matrix is designed to enforce. Explicit version arguments still bypass compat resolution as before. Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 9a174353aab..efe1dd9e0a0 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -192,7 +192,7 @@ resolve_version_from_compat() { compat_source="${compat_file}.source" if ! download_compat_json "$compat_file" "$compat_source"; then - echo "Could not resolve compatibility matrix from network or bundled fallback; using release latest fallback." >&2 + echo "Could not resolve compatibility matrix from network or bundled fallback." >&2 return 1 fi @@ -306,12 +306,12 @@ for i, row in enumerate(rows): print("") PY )"; then - echo "Compatibility matrix resolver failed unexpectedly; using release latest fallback." >&2 + echo "Compatibility matrix resolver failed unexpectedly." >&2 return 1 fi if [ -z "$resolved_info" ]; then - echo "Compatibility matrix lookup found no matching copilot window for gh-aw ${compiled_version}; using release latest fallback." >&2 + echo "Compatibility matrix lookup found no matching copilot window for gh-aw ${compiled_version}." >&2 return 1 fi @@ -459,8 +459,9 @@ if [ -z "$VERSION" ]; then echo "Using compat-resolved Copilot CLI window: ${COMPAT_MATCHED_MIN_AGENT}..${COMPAT_MATCHED_MAX_AGENT}" echo "Will install compat max-agent ${VERSION} if no cached version satisfies the window." else - REQUESTED_VERSION="latest" - echo "Falling back to latest Copilot CLI release because compat resolution did not produce a version." + echo "ERROR: Failed to resolve Copilot CLI version from compatibility matrix." >&2 + echo "ERROR: Cannot install without a compatible version. Please provide an explicit version or fix the compatibility matrix." >&2 + exit 1 fi else echo "Explicit Copilot CLI version argument provided (${VERSION}); skipping compat matrix resolution." From d378dfa0a321b7267da89bb31f41444e4d452914 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 18:10:14 +0000 Subject: [PATCH 08/29] Make compat resolution failure error more actionable Added concrete examples and guidance on how to fix the error: - Shows explicit version argument syntax - Points to compat.json location for debugging - Makes it clear what users need to check Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index efe1dd9e0a0..918a664d3a0 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -460,7 +460,9 @@ if [ -z "$VERSION" ]; then echo "Will install compat max-agent ${VERSION} if no cached version satisfies the window." else echo "ERROR: Failed to resolve Copilot CLI version from compatibility matrix." >&2 - echo "ERROR: Cannot install without a compatible version. Please provide an explicit version or fix the compatibility matrix." >&2 + echo "ERROR: Cannot install without a compatible version." >&2 + echo "To fix: Pass an explicit version as an argument (e.g., 'install_copilot_cli.sh 1.0.51')" >&2 + echo " or ensure GH_AW_COMPILED_VERSION matches a row in .github/aw/compat.json" >&2 exit 1 fi else From a17dc79780db0b82f1fa5124f81cf49f33dff8e8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 18:19:40 +0000 Subject: [PATCH 09/29] Implement cache TTL expiry based on compat.json cache-ttl-days Added soft cache expiry logic that: - Extracts cache-ttl-days from compat.json (e.g., 14 days) - Checks cached binary age using filesystem modification time - Skips expired cache entries UNLESS: 1. Cached version equals max-agent (already latest in compat window), OR 2. Explicit version was requested (explicit pin bypasses TTL) This encourages users to upgrade to newer Copilot CLI versions within the compat window while respecting explicit version pins and not forcing upgrades when already at max-agent. Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 78 ++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 918a664d3a0..e65bed9d3aa 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -32,6 +32,7 @@ REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" COMPAT_BUNDLED_PATH="${COPILOT_COMPAT_BUNDLED_PATH:-${REPO_ROOT}/.github/aw/compat.json}" COMPAT_MATCHED_MIN_AGENT="" COMPAT_MATCHED_MAX_AGENT="" +COMPAT_CACHE_TTL_DAYS="" # Fix directory ownership before installation # This is needed because a previous AWF run on the same runner may have used @@ -271,10 +272,9 @@ if not isinstance(data, dict): print("") sys.exit(0) -rows = ( - data.get("agent-compat-v1", {}) - .get("copilot", []) -) +agent_compat = data.get("agent-compat-v1", {}) +cache_ttl_days = agent_compat.get("cache-ttl-days", "") +rows = agent_compat.get("copilot", []) if not isinstance(rows, list): print("") sys.exit(0) @@ -300,7 +300,7 @@ for i, row in enumerate(rows): if max_aw != "*" and cmp(compiled_no_v, max_aw) > 0: continue - print(f"{max_agent}|{i}|{min_aw}|{max_aw}|{min_agent}|{max_agent}") + print(f"{max_agent}|{i}|{min_aw}|{max_aw}|{min_agent}|{max_agent}|{cache_ttl_days}") sys.exit(0) print("") @@ -315,19 +315,61 @@ PY return 1 fi - IFS='|' read -r resolved_version row_index row_min_aw row_max_aw row_min_agent row_max_agent <<< "$resolved_info" + IFS='|' read -r resolved_version row_index row_min_aw row_max_aw row_min_agent row_max_agent cache_ttl_days <<< "$resolved_info" echo "Compatibility matrix source: $(cat "$compat_source")" >&2 echo "Compatibility matrix matched row ${row_index}: gh-aw ${row_min_aw}..${row_max_aw}, copilot ${row_min_agent}..${row_max_agent}" >&2 echo "Resolved Copilot CLI version from compatibility matrix: ${resolved_version}" >&2 - printf '%s|%s|%s\n' "$resolved_version" "$row_min_agent" "$row_max_agent" + if [ -n "$cache_ttl_days" ]; then + echo "Cache TTL: ${cache_ttl_days} days" >&2 + fi + printf '%s|%s|%s|%s\n' "$resolved_version" "$row_min_agent" "$row_max_agent" "$cache_ttl_days" return 0 } +# Check if a cached binary has exceeded the cache TTL (in days). +# Returns 0 (expired) or 1 (not expired). +is_cache_expired() { + local cached_binary="$1" + local ttl_days="$2" + local now_epoch="" + local file_epoch="" + local age_days="" + + # If TTL is not set or not numeric, consider cache as not expired + if [ -z "$ttl_days" ] || ! [[ "$ttl_days" =~ ^[0-9]+$ ]]; then + return 1 + fi + + # Get current time and file modification time as epoch seconds + now_epoch="$(date +%s)" + + # Try to get file modification time (platform-portable) + if file_epoch="$(stat -c %Y "$cached_binary" 2>/dev/null)"; then + : # Linux stat format worked + elif file_epoch="$(stat -f %m "$cached_binary" 2>/dev/null)"; then + : # macOS stat format worked + else + # Cannot determine file age, consider not expired + return 1 + fi + + age_days=$(( (now_epoch - file_epoch) / 86400 )) + + if [ "$age_days" -ge "$ttl_days" ]; then + echo " Cache age: ${age_days} days (exceeds TTL of ${ttl_days} days)" >&2 + return 0 # Expired + else + echo " Cache age: ${age_days} days (within TTL of ${ttl_days} days)" >&2 + return 1 # Not expired + fi +} + # Look up a compatible Copilot CLI from the Actions toolcache before downloading a release tarball. find_cached_copilot_bin() { local requested_version="${1:-latest}" local min_version="${2:-}" local max_version="${3:-}" + local cache_ttl_days="${4:-}" local requested_version_normalized="" local tool_cache_root="" local candidate="" @@ -339,6 +381,9 @@ find_cached_copilot_bin() { local best_version="" echo "Searching toolcache for GitHub Copilot CLI (requested: ${requested_version}, arch: ${ARCH_NAME}, range: ${min_version:-none}..${max_version:-none})..." >&2 + if [ -n "$cache_ttl_days" ]; then + echo " Cache TTL enabled: ${cache_ttl_days} days" >&2 + fi if [ "$requested_version" != "latest" ]; then requested_version_normalized="$(normalize_version "$requested_version")" @@ -398,6 +443,21 @@ find_cached_copilot_bin() { continue fi + # Apply cache TTL expiry check UNLESS: + # 1. Cached version equals max-agent (already latest in compat window), OR + # 2. Explicit version was requested (requested_version != "latest") + if [ -n "$cache_ttl_days" ] && [ "$requested_version" = "latest" ]; then + # Check if this candidate is NOT the max-agent version + if [ -n "$max_version" ] && [ "$candidate_version_normalized" != "$max_version" ]; then + if is_cache_expired "$candidate" "$cache_ttl_days"; then + echo " Skipping candidate (cache expired and not max-agent: ${candidate_version_normalized} != ${max_version})" >&2 + continue + fi + else + echo " Cache TTL skipped (candidate equals max-agent: ${candidate_version_normalized})" >&2 + fi + fi + if [ -z "$best_candidate" ] || version_is_greater "$candidate_version_normalized" "$best_version"; then echo " New best candidate: ${candidate} (${candidate_version_normalized} > ${best_version:-none})" >&2 best_candidate="$candidate" @@ -453,7 +513,7 @@ trap 'rm -rf "$TEMP_DIR"' EXIT if [ -z "$VERSION" ]; then echo "No explicit Copilot CLI version requested. Attempting compat-driven version resolution..." if RESOLVED_COMPAT_INFO="$(resolve_version_from_compat "$COMPILED_GH_AW_VERSION" "${TEMP_DIR}/compat.json")"; then - IFS='|' read -r RESOLVED_COMPAT_VERSION COMPAT_MATCHED_MIN_AGENT COMPAT_MATCHED_MAX_AGENT <<< "$RESOLVED_COMPAT_INFO" + IFS='|' read -r RESOLVED_COMPAT_VERSION COMPAT_MATCHED_MIN_AGENT COMPAT_MATCHED_MAX_AGENT COMPAT_CACHE_TTL_DAYS <<< "$RESOLVED_COMPAT_INFO" VERSION="$RESOLVED_COMPAT_VERSION" REQUESTED_VERSION="latest" echo "Using compat-resolved Copilot CLI window: ${COMPAT_MATCHED_MIN_AGENT}..${COMPAT_MATCHED_MAX_AGENT}" @@ -470,7 +530,7 @@ else fi # Prefer the runner toolcache when a compatible Copilot CLI is already available. -if CACHED_COPILOT_BIN="$(find_cached_copilot_bin "$REQUESTED_VERSION" "${COMPAT_MATCHED_MIN_AGENT}" "${COMPAT_MATCHED_MAX_AGENT}")"; then +if CACHED_COPILOT_BIN="$(find_cached_copilot_bin "$REQUESTED_VERSION" "${COMPAT_MATCHED_MIN_AGENT}" "${COMPAT_MATCHED_MAX_AGENT}" "${COMPAT_CACHE_TTL_DAYS}")"; then echo "Using cached GitHub Copilot CLI from ${CACHED_COPILOT_BIN}" activate_cached_copilot_bin "$CACHED_COPILOT_BIN" From 680f2cdca0ad1f9c311826805173633db6a0d49c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 18:21:18 +0000 Subject: [PATCH 10/29] Improve cache TTL implementation readability - Define SECONDS_PER_DAY constant for magic number 86400 - Simplify version equality check for max-agent comparison - Improve code clarity while maintaining the same behavior Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index e65bed9d3aa..2f89c271f0b 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -19,6 +19,7 @@ set +o histexpand set -euo pipefail # Configuration +SECONDS_PER_DAY=86400 VERSION="${1:-}" COPILOT_REPO="github/copilot-cli" INSTALL_DIR="/usr/local/bin" @@ -353,7 +354,7 @@ is_cache_expired() { return 1 fi - age_days=$(( (now_epoch - file_epoch) / 86400 )) + age_days=$(( (now_epoch - file_epoch) / SECONDS_PER_DAY )) if [ "$age_days" -ge "$ttl_days" ]; then echo " Cache age: ${age_days} days (exceeds TTL of ${ttl_days} days)" >&2 @@ -446,15 +447,16 @@ find_cached_copilot_bin() { # Apply cache TTL expiry check UNLESS: # 1. Cached version equals max-agent (already latest in compat window), OR # 2. Explicit version was requested (requested_version != "latest") - if [ -n "$cache_ttl_days" ] && [ "$requested_version" = "latest" ]; then - # Check if this candidate is NOT the max-agent version - if [ -n "$max_version" ] && [ "$candidate_version_normalized" != "$max_version" ]; then + if [ -n "$cache_ttl_days" ] && [ "$requested_version" = "latest" ] && [ -n "$max_version" ]; then + # Check if candidate version equals max-agent + if [ "$candidate_version_normalized" = "$max_version" ]; then + echo " Cache TTL skipped (candidate equals max-agent: ${candidate_version_normalized})" >&2 + else + # Candidate is not max-agent, apply TTL check if is_cache_expired "$candidate" "$cache_ttl_days"; then echo " Skipping candidate (cache expired and not max-agent: ${candidate_version_normalized} != ${max_version})" >&2 continue fi - else - echo " Cache TTL skipped (candidate equals max-agent: ${candidate_version_normalized})" >&2 fi fi From e301163f0525e016c44894529fdc67fba1231e49 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 18:22:16 +0000 Subject: [PATCH 11/29] Document partial day truncation in cache age calculation Added inline comment clarifying that integer division intentionally truncates partial days (e.g., 1.9 days counts as 1 day) for cache TTL checks. Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 2f89c271f0b..6968bcd3d28 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -354,6 +354,7 @@ is_cache_expired() { return 1 fi + # Calculate age in days (integer division truncates partial days, e.g., 1.9 days → 1 day) age_days=$(( (now_epoch - file_epoch) / SECONDS_PER_DAY )) if [ "$age_days" -ge "$ttl_days" ]; then From 5cb3c3fba601d036f1733266fcdecd7777f44233 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 21:09:56 +0000 Subject: [PATCH 12/29] Add jq-based compat resolution to support environments without python3 Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 72 ++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 6968bcd3d28..4d7db041eb4 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -175,6 +175,48 @@ download_compat_json() { return 1 } +# Resolve compat using jq (faster and more portable than python3). +# Returns: "max_agent|row_index|min_aw|max_aw|min_agent|max_agent|cache_ttl_days" +resolve_compat_with_jq() { + local compat_file="$1" + local compiled_version="$2" + local compiled_no_v="${compiled_version#v}" + + jq -r --arg compiled "$compiled_no_v" ' + # Semver comparison: returns -1 if ab + def semver_cmp(a; b): + (a | split(".") | map(tonumber)) as $a_parts | + (b | split(".") | map(tonumber)) as $b_parts | + if ($a_parts[0] < $b_parts[0]) then -1 + elif ($a_parts[0] > $b_parts[0]) then 1 + elif ($a_parts[1] < $b_parts[1]) then -1 + elif ($a_parts[1] > $b_parts[1]) then 1 + elif ($a_parts[2] < $b_parts[2]) then -1 + elif ($a_parts[2] > $b_parts[2]) then 1 + else 0 end; + + .["agent-compat-v1"] as $compat | + ($compat["cache-ttl-days"] // "") as $cache_ttl | + ($compat.copilot // []) as $rows | + + # Find first matching row + $rows | to_entries | map( + .value as $row | + .key as $idx | + $row["min-gh-aw"] as $min_aw | + $row["max-gh-aw"] as $max_aw | + $row["min-agent"] as $min_agent | + $row["max-agent"] as $max_agent | + + # Check if gh-aw version is in range + if (semver_cmp($compiled; $min_aw) >= 0) and + (($max_aw == "*") or (semver_cmp($compiled; $max_aw) <= 0)) then + "\($max_agent)|\($idx)|\($min_aw)|\($max_aw)|\($min_agent)|\($max_agent)|\($cache_ttl)" + else empty end + ) | first // "" + ' "$compat_file" 2>&1 || echo "" +} + # Resolve Copilot version from compat matrix using GH_AW_COMPILED_VERSION. resolve_version_from_compat() { local compiled_version="${1:-}" @@ -198,8 +240,36 @@ resolve_version_from_compat() { return 1 fi + # Try jq first (more commonly available than python3 on minimal runners) + if command -v jq >/dev/null 2>&1; then + if resolved_info="$(resolve_compat_with_jq "$compat_file" "$compiled_version" 2>&1)"; then + if [ -n "$resolved_info" ]; then + # Parse the 7-field jq output + IFS='|' read -r resolved_version row_index row_min_aw row_max_aw row_min_agent row_max_agent cache_ttl_days <<< "$resolved_info" + + # Display the same logging as python path + echo "Compatibility matrix source: $(cat "$compat_source")" >&2 + echo "Compatibility matrix matched row ${row_index}: gh-aw ${row_min_aw}..${row_max_aw}, copilot ${row_min_agent}..${row_max_agent}" >&2 + echo "Resolved Copilot CLI version from compatibility matrix: ${resolved_version}" >&2 + if [ -n "$cache_ttl_days" ]; then + echo "Cache TTL: ${cache_ttl_days} days" >&2 + fi + + # Return the same 4-field format as python path + printf '%s|%s|%s|%s\n' "$resolved_version" "$row_min_agent" "$row_max_agent" "$cache_ttl_days" + return 0 + else + echo "Compatibility matrix lookup found no matching copilot window for gh-aw ${compiled_version}." >&2 + return 1 + fi + fi + echo "jq-based compat resolution failed, trying python3 fallback..." >&2 + fi + + # Fall back to python3 if jq is unavailable or failed if ! command -v python3 >/dev/null 2>&1; then - echo "python3 is unavailable; skipping compatibility matrix resolution." >&2 + echo "ERROR: Neither jq nor python3 is available for compatibility matrix resolution." >&2 + echo "ERROR: Install jq or python3, or pass an explicit Copilot CLI version to bypass compat resolution." >&2 return 1 fi From 71c97ccab6c151a521ccf7bfdc13b6915519182f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 01:02:47 +0000 Subject: [PATCH 13/29] Remove obsolete releases.json and schema files after migration to compat.json Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- .github/aw/releases.json | 6 --- .github/aw/releases.schema.json | 36 ------------- .github/workflows/cgo.yml | 89 --------------------------------- 3 files changed, 131 deletions(-) delete mode 100644 .github/aw/releases.json delete mode 100644 .github/aw/releases.schema.json diff --git a/.github/aw/releases.json b/.github/aw/releases.json deleted file mode 100644 index 3ab333d230e..00000000000 --- a/.github/aw/releases.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "./releases.schema.json", - "blockedVersions": [], - "minimumVersion": "v0.65.3", - "minRecommendedVersion": "v0.65.3" -} diff --git a/.github/aw/releases.schema.json b/.github/aw/releases.schema.json deleted file mode 100644 index c1ebba7027d..00000000000 --- a/.github/aw/releases.schema.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "gh-aw update check configuration", - "description": "Configuration for the compile-agentic version update check. This file is fetched at runtime by the activation job to validate that the compiled version is still supported.", - "type": "object", - "additionalProperties": false, - "properties": { - "$schema": { - "type": "string", - "description": "JSON Schema reference" - }, - "blockedVersions": { - "type": "array", - "description": "List of blocked compile-agentic versions that are not allowed to run (e.g. due to a security compromise). Workflows compiled with a blocked version will fail at activation.", - "items": { - "type": "string", - "pattern": "^v[0-9]+\\.[0-9]+\\.[0-9]+$", - "description": "A blocked version string in vMAJOR.MINOR.PATCH format (e.g. 'v1.2.3')" - }, - "uniqueItems": true, - "default": [] - }, - "minimumVersion": { - "type": "string", - "description": "The minimum supported compile-agentic version in vMAJOR.MINOR.PATCH format. Workflows compiled with a version below this will fail at activation. Use an empty string to disable this check.", - "pattern": "^(v[0-9]+\\.[0-9]+\\.[0-9]+)?$", - "default": "" - }, - "minRecommendedVersion": { - "type": "string", - "description": "The minimum recommended compile-agentic version in vMAJOR.MINOR.PATCH format. Workflows compiled with a version below this will emit a warning (but not fail) at activation, nudging users to upgrade. Use an empty string to disable this check.", - "pattern": "^(v[0-9]+\\.[0-9]+\\.[0-9]+)?$", - "default": "" - } - } -} diff --git a/.github/workflows/cgo.yml b/.github/workflows/cgo.yml index 15b507312e6..093f05cc9e8 100644 --- a/.github/workflows/cgo.yml +++ b/.github/workflows/cgo.yml @@ -17,8 +17,6 @@ on: - '.github/workflows/ci.yml' - '.github/workflows/cgo.yml' - '.github/workflows/**/*.md' - - '.github/aw/releases.json' - - '.github/aw/releases.schema.json' - '.github/aw/compat.json' - '.github/aw/compat.schema.json' - 'install-gh-aw.sh' @@ -553,93 +551,6 @@ jobs: echo "✅ All URLs in $AGENT_FILE correctly use 'main' branch" - - name: Validate releases.json structure and version formats - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 - with: - script: | - const fs = require('fs'); - const CONFIG_FILE = '.github/aw/releases.json'; - const SCHEMA_FILE = '.github/aw/releases.schema.json'; - - core.info(`🔍 Validating ${CONFIG_FILE} against ${SCHEMA_FILE}...`); - - if (!fs.existsSync(CONFIG_FILE)) { - core.setFailed(`ERROR: ${CONFIG_FILE} not found`); - return; - } - if (!fs.existsSync(SCHEMA_FILE)) { - core.setFailed(`ERROR: ${SCHEMA_FILE} not found`); - return; - } - - let config; - try { - config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); - } catch (err) { - core.setFailed(`ERROR: ${CONFIG_FILE} is not valid JSON: ${err.message}`); - return; - } - core.info(`✅ ${CONFIG_FILE} is valid JSON`); - - const errors = []; - - // Check additionalProperties (only allow known keys) - const allowedKeys = new Set(['$schema', 'blockedVersions', 'minimumVersion', 'minRecommendedVersion']); - for (const key of Object.keys(config)) { - if (!allowedKeys.has(key)) { - errors.push(`Unknown property: '${key}'`); - } - } - - // Validate blockedVersions - if ('blockedVersions' in config) { - const bv = config.blockedVersions; - if (!Array.isArray(bv)) { - errors.push("'blockedVersions' must be an array"); - } else { - const versionPattern = /^v[0-9]+\.[0-9]+\.[0-9]+$/; - const seen = new Set(); - bv.forEach((v, i) => { - if (typeof v !== 'string') { - errors.push(`'blockedVersions[${i}]' must be a string`); - } else if (!versionPattern.test(v)) { - errors.push(`'blockedVersions[${i}]' ('${v}') does not match expected version pattern (vMAJOR.MINOR.PATCH, e.g. 'v1.2.3')`); - } else if (seen.has(v)) { - errors.push(`'blockedVersions' contains duplicate entry: '${v}'`); - } else { - seen.add(v); - } - }); - } - } - - // Validate minimumVersion - if ('minimumVersion' in config) { - const mv = config.minimumVersion; - if (typeof mv !== 'string') { - errors.push("'minimumVersion' must be a string"); - } else if (mv !== '' && !/^v[0-9]+\.[0-9]+\.[0-9]+$/.test(mv)) { - errors.push(`'minimumVersion' ('${mv}') does not match expected version pattern (vMAJOR.MINOR.PATCH, e.g. 'v1.2.3' or empty string)`); - } - } - - // Validate minRecommendedVersion - if ('minRecommendedVersion' in config) { - const mrv = config.minRecommendedVersion; - if (typeof mrv !== 'string') { - errors.push("'minRecommendedVersion' must be a string"); - } else if (mrv !== '' && !/^v[0-9]+\.[0-9]+\.[0-9]+$/.test(mrv)) { - errors.push(`'minRecommendedVersion' ('${mrv}') does not match expected version pattern (vMAJOR.MINOR.PATCH, e.g. 'v1.2.3' or empty string)`); - } - } - - if (errors.length > 0) { - core.setFailed(`❌ ${CONFIG_FILE} schema validation failed:\n${errors.map(e => ` - ${e}`).join('\n')}`); - return; - } - - core.info(`✅ ${CONFIG_FILE} is valid and conforms to ${SCHEMA_FILE}`); - - name: Validate compat.json structure and version formats uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 with: From e7ec812b26ab2ce326734c1818db852314f73e02 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 01:42:30 +0000 Subject: [PATCH 14/29] Document canary push model for compat matrix updates Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- .github/aw/compat-update-model.md | 227 ++++++++++++++++++++++++ .github/aw/compat.schema.json | 2 +- actions/setup/sh/install_copilot_cli.sh | 9 +- 3 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 .github/aw/compat-update-model.md diff --git a/.github/aw/compat-update-model.md b/.github/aw/compat-update-model.md new file mode 100644 index 00000000000..456ae527216 --- /dev/null +++ b/.github/aw/compat-update-model.md @@ -0,0 +1,227 @@ +# Compatibility Matrix Update Model + +## Overview + +The `.github/aw/compat.json` file serves as the source of truth for agent compatibility with gh-aw versions. This document describes how compatibility matrix updates are driven by canary testing and the security model that keeps gh-aw free of cross-repo secrets. + +## Architecture: Push Model (Canary-Driven Bumping) + +### Design + +The compatibility matrix uses a **push model** where the private `agentic-workflows-canary` repository drives updates: + +``` +agentic-workflows-canary (private) + ↓ (1) Run canary scenarios + ↓ (2) Evaluate health within freshness window + ↓ (3) Emit repository_dispatch event + ↓ +github/gh-aw (public) + ↓ (4) Receive dispatch event + ↓ (5) Open/update guarded compat bump PR + ↓ (6) Automated review + manual approval + ↓ (7) Merge to main +``` + +### What is "Bumping"? + +**Bumping** refers to updating the `max-agent` field in a compat row when: + +1. A new agent version (e.g., Copilot CLI 1.0.52) is released +2. Canary scenarios pass with the new version + current gh-aw +3. The compat row has `"open": true` (indicating it accepts automatic bumps) + +Example bump: +```json +// Before: +{ + "min-gh-aw": "0.72.0", + "max-gh-aw": "*", + "min-agent": "1.0.21", + "max-agent": "1.0.51", // ← Old max + "open": true +} + +// After: +{ + "min-gh-aw": "0.72.0", + "max-gh-aw": "*", + "min-agent": "1.0.21", + "max-agent": "1.0.52", // ← Bumped to new version + "open": true +} +``` + +## Guard Conditions + +The canary repository emits a `repository_dispatch` event **only when ALL** of the following conditions are met: + +### 1. Scenario Pass Criteria + +All required canary scenarios must pass for the candidate agent version: + +- **Core functionality**: Basic workflow execution (compile, activate, run) +- **Security validation**: No new security alerts from CodeQL/secret scanning +- **Compatibility tests**: Agent works with current gh-aw release range +- **Performance benchmarks**: No significant regressions in latency/memory +- **Integration tests**: MCP server communication, SDK driver compatibility + +### 2. Freshness Window + +Results must be within the freshness window to prevent stale data from triggering bumps: + +- **Maximum age**: Scenario results must be ≤ 24 hours old +- **Minimum coverage**: All required scenarios must have fresh results +- **Health check**: Canary infrastructure itself must be healthy + +### 3. Version Eligibility + +The candidate agent version must meet release criteria: + +- **Stable release**: No pre-release tags (e.g., `-alpha`, `-beta`) +- **Not blocked**: Not in `blockedVersions` list +- **Newer than current**: Version > current `max-agent` in compat.json +- **Row is open**: Target compat row has `"open": true` + +### 4. No Active Incidents + +No active incident or rollback in progress: + +- **Incident status**: No P0/P1 incidents affecting gh-aw or the agent +- **Rollback state**: No ongoing rollback of previous bump +- **Manual freeze**: No operator-initiated freeze flag + +## Dispatch Payload + +When all guard conditions pass, canary emits: + +```json +{ + "event_type": "compat-bump", + "client_payload": { + "agent": "copilot", + "version": "1.0.52", + "canary_run_id": "12345678", + "canary_scenarios_url": "https://github.com/github/agentic-workflows-canary/actions/runs/12345678", + "freshness_timestamp": "2026-06-04T01:00:00Z", + "guard_conditions": { + "scenarios_passed": true, + "within_freshness_window": true, + "version_eligible": true, + "no_active_incidents": true + } + } +} +``` + +## gh-aw Bump Workflow + +When gh-aw receives the `repository_dispatch`: + +1. **Validate payload**: Verify all guard conditions are still true +2. **Fetch current compat.json**: Read current `max-agent` value +3. **Generate PR**: Create or update a PR with the new `max-agent` +4. **Automated checks**: Run validation workflow (schema check, test suite) +5. **Human review**: Require manual approval from compat maintainers +6. **Merge**: Automated merge after approval + passing checks + +## Security Model + +### Why This Model? + +The push model is chosen for three key reasons: + +1. **Minimize secret sprawl**: Only the canary repo needs credentials +2. **Single source of truth**: Canary owns health determination logic +3. **Principle of least privilege**: gh-aw doesn't need to read private canary data + +### Credential Flow + +``` +┌─────────────────────────────────┐ +│ agentic-workflows-canary │ +│ (private repo) │ +│ │ +│ ✓ Has: DISPATCH_TOKEN │ ← Only place with cross-repo secret +│ - Scope: public_repo │ +│ - Can: send repository_dispatch to github/gh-aw +│ - Cannot: read/write gh-aw branches +└─────────────────────────────────┘ + │ + │ repository_dispatch (no authentication required to receive) + ↓ +┌─────────────────────────────────┐ +│ github/gh-aw │ +│ (public repo) │ +│ │ +│ ✗ No secrets to canary │ ← Keeps gh-aw secret-free +│ ✓ Has: GITHUB_TOKEN (default) │ +│ - Can: create PRs in gh-aw │ +│ - Cannot: read canary data │ +└─────────────────────────────────┘ +``` + +### Token Scope and Blast Radius + +**DISPATCH_TOKEN** (stored in canary repo): +- **Required scope**: `public_repo` (or `repo` if gh-aw were private) +- **Blast radius if leaked**: + - ✗ Can send repository_dispatch to github/gh-aw (trigger bump workflow) + - ✗ Can send repository_dispatch to other public repos (if configured) + - ✓ CANNOT read canary scenarios (private repo) + - ✓ CANNOT push to gh-aw branches (no write access) + - ✓ CANNOT modify gh-aw PRs directly + +**Mitigation if token leaks**: +1. Revoke and rotate token immediately +2. Review recent repository_dispatch events in gh-aw +3. Revert any unauthorized compat bumps +4. No canary data exposure (private repo remains protected) + +### Alternative: Polling (Not Chosen) + +We explicitly **rejected** a polling model where gh-aw fetches canary status: + +``` +❌ Polling Model (Rejected): + gh-aw (public) → poll → agentic-workflows-canary (private) + + Problems: + - Requires gh-aw to have secrets for canary access + - Increases secret sprawl in public repo + - More complex secret rotation + - Larger blast radius if gh-aw is compromised +``` + +## Operational Notes + +### Manual Bumps + +Operators can manually bump compat.json by: + +1. Opening a PR directly in gh-aw +2. Bypassing the canary dispatch (for emergency updates) +3. Following the same review/approval process + +### Freezing Automatic Bumps + +To temporarily stop automatic bumps: + +1. Set `"open": false` on the target compat row +2. Canary will skip dispatch for that agent +3. Re-enable by setting `"open": true` in a subsequent PR + +### Rollback + +If a bumped version causes issues: + +1. Revert the compat.json PR in gh-aw +2. Set `"open": false` to prevent re-bump +3. Add problematic version to `blockedVersions` if necessary +4. Investigate root cause in canary scenarios + +## References + +- Compatibility matrix schema: `.github/aw/compat.schema.json` +- Installer implementation: `actions/setup/sh/install_copilot_cli.sh` +- Canary repository: `github/agentic-workflows-canary` (private) diff --git a/.github/aw/compat.schema.json b/.github/aw/compat.schema.json index 12a933a1aed..5b805b3685b 100644 --- a/.github/aw/compat.schema.json +++ b/.github/aw/compat.schema.json @@ -2,7 +2,7 @@ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://github.com/github/gh-aw/.github/aw/compat.schema.json", "title": "gh-aw agent compatibility matrix", - "description": "Pins agentic CLI versions to gh-aw release ranges. Consumed by the setup action to install a known-good agent version per gh-aw release. See ADR for the design rationale.", + "description": "Pins agentic CLI versions to gh-aw release ranges. Consumed by the setup action to install a known-good agent version per gh-aw release. Updates are driven by canary testing via repository_dispatch (push model). See compat-update-model.md for the security model and bump workflow.", "type": "object", "required": ["agent-compat-v1"], "additionalProperties": false, diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 4d7db041eb4..479c8414932 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -8,13 +8,20 @@ set +o histexpand # releases with SHA256 checksum verification, following the secure pattern from # install_awf_binary.sh to avoid executing unverified downloaded scripts. # +# Compatibility-driven version selection: +# When VERSION is not provided, the installer resolves the Copilot CLI version +# from the compatibility matrix (.github/aw/compat.json) based on GH_AW_COMPILED_VERSION. +# The compat matrix is updated via canary-driven repository_dispatch events. +# See .github/aw/compat-update-model.md for the push model and security architecture. +# # Arguments: -# VERSION - Optional Copilot CLI version to install (default: latest release) +# VERSION - Optional Copilot CLI version to install (default: compat-matrix-driven) # # Security features: # - Downloads binary directly from GitHub releases (no installer script execution) # - Verifies SHA256 checksum against official SHA256SUMS.txt # - Fails fast if checksum verification fails +# - Respects compatibility matrix to prevent incompatible agent/gh-aw pairings set -euo pipefail From c81a7585d1d28bb2b14e96cc5d61b1f66c87efdb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 02:04:15 +0000 Subject: [PATCH 15/29] Apply remaining changes Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- .github/skills/agentic-workflows/SKILL.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/skills/agentic-workflows/SKILL.md b/.github/skills/agentic-workflows/SKILL.md index 623b3db448e..84c905c3877 100644 --- a/.github/skills/agentic-workflows/SKILL.md +++ b/.github/skills/agentic-workflows/SKILL.md @@ -27,6 +27,7 @@ Load these files from `github/gh-aw` (they are not available locally). - `.github/aw/github-agentic-workflows.md` - `.github/aw/github-mcp-server.md` - `.github/aw/llms.md` +- `.github/aw/mcp-clis.md` - `.github/aw/memory.md` - `.github/aw/messages.md` - `.github/aw/network.md` From 87eaedbcd33c025c0df11a372600d82d58f2659d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 02:57:17 +0000 Subject: [PATCH 16/29] Plan dispatch-driven compat bump workflow Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- .github/skills/agentic-workflows/SKILL.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/skills/agentic-workflows/SKILL.md b/.github/skills/agentic-workflows/SKILL.md index 84c905c3877..0e5802ec146 100644 --- a/.github/skills/agentic-workflows/SKILL.md +++ b/.github/skills/agentic-workflows/SKILL.md @@ -12,6 +12,7 @@ This skill is a dispatcher: identify the task type, load the matching `.github/a Read only the files you need: Load these files from `github/gh-aw` (they are not available locally). - `.github/aw/agentic-chat.md` +- `.github/aw/agentic-workflows-mcp.md` - `.github/aw/asciicharts.md` - `.github/aw/campaign.md` - `.github/aw/charts-trending.md` From ba6887005d8832069da22adb39fee94762092347 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 02:58:28 +0000 Subject: [PATCH 17/29] Add canary repository_dispatch compat bump workflow Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- .github/aw/compat-update-model.md | 2 +- .../compat-bump-from-canary-dispatch.yml | 271 ++++++++++++++++++ 2 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/compat-bump-from-canary-dispatch.yml diff --git a/.github/aw/compat-update-model.md b/.github/aw/compat-update-model.md index 456ae527216..489210c89bb 100644 --- a/.github/aw/compat-update-model.md +++ b/.github/aw/compat-update-model.md @@ -116,7 +116,7 @@ When all guard conditions pass, canary emits: ## gh-aw Bump Workflow -When gh-aw receives the `repository_dispatch`: +When gh-aw receives the `repository_dispatch` (workflow: `.github/workflows/compat-bump-from-canary-dispatch.yml`): 1. **Validate payload**: Verify all guard conditions are still true 2. **Fetch current compat.json**: Read current `max-agent` value diff --git a/.github/workflows/compat-bump-from-canary-dispatch.yml b/.github/workflows/compat-bump-from-canary-dispatch.yml new file mode 100644 index 00000000000..94ff4b0e758 --- /dev/null +++ b/.github/workflows/compat-bump-from-canary-dispatch.yml @@ -0,0 +1,271 @@ +name: Compat Bump From Canary Dispatch + +on: + repository_dispatch: + types: [compat-bump] + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + compat-bump: + name: Apply canary compat bump + runs-on: ubuntu-latest + if: github.repository == 'github/gh-aw' + steps: + - name: Validate dispatch payload and open/update bump PR + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + with: + script: | + const owner = context.repo.owner; + const repo = context.repo.repo; + const path = ".github/aw/compat.json"; + const eventName = context.eventName; + + if (eventName !== "repository_dispatch") { + core.notice("Manual workflow_dispatch run: payload validation/update skipped."); + return; + } + + const payload = context.payload.client_payload || {}; + const sourceRepository = typeof payload.source_repository === "string" ? payload.source_repository.trim() : ""; + const expectedSourceRepository = "github/agentic-workflows-canary"; + if (sourceRepository !== expectedSourceRepository) { + core.setFailed(`Invalid source_repository: expected "${expectedSourceRepository}", got "${sourceRepository || ""}"`); + return; + } + + const requiredGuards = [ + "scenarios_passed", + "within_freshness_window", + "version_eligible", + "no_active_incidents", + ]; + const guardConditions = payload.guard_conditions || {}; + for (const guard of requiredGuards) { + if (guardConditions[guard] !== true) { + core.setFailed(`Guard condition failed or missing: guard_conditions.${guard} must be true`); + return; + } + } + + const freshnessTimestamp = typeof payload.freshness_timestamp === "string" ? payload.freshness_timestamp : ""; + const freshnessMillis = Date.parse(freshnessTimestamp); + if (!Number.isFinite(freshnessMillis)) { + core.setFailed("Invalid or missing freshness_timestamp in payload"); + return; + } + const ageMs = Date.now() - freshnessMillis; + const maxAgeMs = 24 * 60 * 60 * 1000; + if (ageMs < -5 * 60 * 1000) { + core.setFailed("freshness_timestamp is unexpectedly in the future"); + return; + } + if (ageMs > maxAgeMs) { + core.setFailed(`freshness_timestamp is stale (age ${Math.floor(ageMs / 1000)}s > 86400s)`); + return; + } + + const normalizeVersion = (version) => (typeof version === "string" ? version.trim().replace(/^v/, "") : ""); + const semverPattern = /^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/; + const candidateVersion = normalizeVersion(payload.version); + if (!semverPattern.test(candidateVersion)) { + core.setFailed(`Invalid or missing version in payload: "${payload.version ?? ""}"`); + return; + } + + const agent = (typeof payload.agent === "string" && payload.agent.trim()) ? payload.agent.trim().toLowerCase() : "copilot"; + + const parseSemver = (version) => { + const normalized = normalizeVersion(version); + const match = normalized.match(/^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z.-]+))?$/); + if (!match) return null; + return { + major: Number(match[1]), + minor: Number(match[2]), + patch: Number(match[3]), + pre: match[4] || "", + }; + }; + + const compareSemver = (a, b) => { + const pa = parseSemver(a); + const pb = parseSemver(b); + if (!pa || !pb) throw new Error(`Cannot compare invalid semver values: "${a}" vs "${b}"`); + for (const key of ["major", "minor", "patch"]) { + if (pa[key] < pb[key]) return -1; + if (pa[key] > pb[key]) return 1; + } + if (pa.pre === pb.pre) return 0; + if (!pa.pre) return 1; + if (!pb.pre) return -1; + return pa.pre < pb.pre ? -1 : 1; + }; + + const repoInfo = await github.rest.repos.get({ owner, repo }); + const defaultBranch = repoInfo.data.default_branch; + const defaultRef = await github.rest.git.getRef({ + owner, + repo, + ref: `heads/${defaultBranch}`, + }); + const defaultBranchSha = defaultRef.data.object.sha; + + const compatFile = await github.rest.repos.getContent({ + owner, + repo, + path, + ref: defaultBranch, + }); + + if (!("content" in compatFile.data) || typeof compatFile.data.content !== "string") { + core.setFailed(`Unable to read ${path}`); + return; + } + + const compatRaw = Buffer.from(compatFile.data.content, compatFile.data.encoding || "base64").toString("utf8"); + const compat = JSON.parse(compatRaw); + const matrix = compat["agent-compat-v1"]; + if (!matrix || typeof matrix !== "object") { + core.setFailed("compat.json missing agent-compat-v1 object"); + return; + } + + const rows = matrix[agent]; + if (!Array.isArray(rows) || rows.length === 0) { + core.setFailed(`compat.json has no rows for agent "${agent}"`); + return; + } + + let rowIndex = rows.findIndex((row) => row && row["max-gh-aw"] === "*" && row.open === true); + if (rowIndex < 0) { + rowIndex = rows.findIndex((row) => row && row.open === true); + } + if (rowIndex < 0) { + core.setFailed(`No open compat row found for agent "${agent}"`); + return; + } + + const targetRow = rows[rowIndex]; + const currentMaxAgent = normalizeVersion(targetRow["max-agent"]); + const minAgent = normalizeVersion(targetRow["min-agent"]); + if (!semverPattern.test(currentMaxAgent) || !semverPattern.test(minAgent)) { + core.setFailed(`Target compat row has invalid min/max agent values: min-agent="${targetRow["min-agent"]}", max-agent="${targetRow["max-agent"]}"`); + return; + } + + if (compareSemver(candidateVersion, minAgent) < 0) { + core.setFailed(`Candidate version ${candidateVersion} is below min-agent ${minAgent} for target row`); + return; + } + + const comparison = compareSemver(candidateVersion, currentMaxAgent); + if (comparison <= 0) { + core.notice(`No update needed: candidate ${candidateVersion} is not newer than current max-agent ${currentMaxAgent}`); + return; + } + + targetRow["max-agent"] = candidateVersion; + const updatedCompatRaw = `${JSON.stringify(compat, null, 2)}\n`; + + const safeVersion = candidateVersion.replace(/[^0-9A-Za-z.-]/g, "-"); + const branchName = `automation/compat-bump-${agent}-${safeVersion}`; + const commitMessage = `chore(compat): bump ${agent} max-agent to ${candidateVersion}`; + + try { + await github.rest.git.getRef({ + owner, + repo, + ref: `heads/${branchName}`, + }); + } catch (error) { + if (error.status !== 404) throw error; + await github.rest.git.createRef({ + owner, + repo, + ref: `refs/heads/${branchName}`, + sha: defaultBranchSha, + }); + } + + let currentBranchFileSha; + try { + const existingBranchFile = await github.rest.repos.getContent({ + owner, + repo, + path, + ref: branchName, + }); + if ("sha" in existingBranchFile.data) { + currentBranchFileSha = existingBranchFile.data.sha; + } + } catch (error) { + if (error.status !== 404) throw error; + } + + await github.rest.repos.createOrUpdateFileContents({ + owner, + repo, + path, + branch: branchName, + message: commitMessage, + content: Buffer.from(updatedCompatRaw, "utf8").toString("base64"), + sha: currentBranchFileSha, + }); + + const canaryRunId = payload.canary_run_id ? String(payload.canary_run_id) : ""; + const canaryScenariosUrl = payload.canary_scenarios_url ? String(payload.canary_scenarios_url) : ""; + const title = `chore(compat): bump ${agent} max-agent to ${candidateVersion}`; + const body = [ + "## Summary", + `Update \`.github/aw/compat.json\` for **${agent}** by bumping \`max-agent\` from \`${currentMaxAgent}\` to \`${candidateVersion}\` in the open row.", + "", + "## Dispatch guard checks", + "- source repository: `github/agentic-workflows-canary`", + "- `guard_conditions.scenarios_passed`: `true`", + "- `guard_conditions.within_freshness_window`: `true`", + "- `guard_conditions.version_eligible`: `true`", + "- `guard_conditions.no_active_incidents`: `true`", + `- freshness timestamp: \`${freshnessTimestamp}\` (age ${Math.floor(ageMs / 1000)}s)`, + "", + "## Canary context", + `- canary run id: ${canaryRunId || "n/a"}`, + `- canary scenarios url: ${canaryScenariosUrl || "n/a"}`, + "", + "_Auto-generated from repository_dispatch event `compat-bump`._", + ].join("\n"); + + const existingPrs = await github.paginate(github.rest.pulls.list, { + owner, + repo, + state: "open", + head: `${owner}:${branchName}`, + base: defaultBranch, + per_page: 100, + }); + + let prNumber; + if (existingPrs.length > 0) { + prNumber = existingPrs[0].number; + await github.rest.pulls.update({ + owner, + repo, + pull_number: prNumber, + title, + body, + }); + core.notice(`Updated existing PR #${prNumber}`); + } else { + const createdPr = await github.rest.pulls.create({ + owner, + repo, + title, + head: branchName, + base: defaultBranch, + body, + }); + prNumber = createdPr.data.number; + core.notice(`Created PR #${prNumber}`); + } From df83eba54ff98b2e9bb75d8f7a3498e8aebb6905 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 03:01:58 +0000 Subject: [PATCH 18/29] Refine dispatch workflow constants and branch name sanitization Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- .github/workflows/compat-bump-from-canary-dispatch.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compat-bump-from-canary-dispatch.yml b/.github/workflows/compat-bump-from-canary-dispatch.yml index 94ff4b0e758..242697c4423 100644 --- a/.github/workflows/compat-bump-from-canary-dispatch.yml +++ b/.github/workflows/compat-bump-from-canary-dispatch.yml @@ -58,8 +58,9 @@ jobs: return; } const ageMs = Date.now() - freshnessMillis; + const maxFutureSkewMs = 5 * 60 * 1000; const maxAgeMs = 24 * 60 * 60 * 1000; - if (ageMs < -5 * 60 * 1000) { + if (ageMs < -maxFutureSkewMs) { core.setFailed("freshness_timestamp is unexpectedly in the future"); return; } @@ -170,7 +171,7 @@ jobs: targetRow["max-agent"] = candidateVersion; const updatedCompatRaw = `${JSON.stringify(compat, null, 2)}\n`; - const safeVersion = candidateVersion.replace(/[^0-9A-Za-z.-]/g, "-"); + const safeVersion = candidateVersion.replace(/[^0-9A-Za-z-]/g, "-"); const branchName = `automation/compat-bump-${agent}-${safeVersion}`; const commitMessage = `chore(compat): bump ${agent} max-agent to ${candidateVersion}`; From 1ae521e8394e124df8b70d0efaef73344566255b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 03:27:39 +0000 Subject: [PATCH 19/29] revert: undo canary dispatch auto-bump changes and restore releases.json Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- .github/aw/compat-update-model.md | 227 --------------- .github/aw/compat.schema.json | 2 +- .github/aw/releases.json | 6 + .github/aw/releases.schema.json | 36 +++ .github/skills/agentic-workflows/SKILL.md | 1 - .github/workflows/cgo.yml | 89 ++++++ .../compat-bump-from-canary-dispatch.yml | 272 ------------------ actions/setup/sh/install_copilot_cli.sh | 9 +- 8 files changed, 133 insertions(+), 509 deletions(-) delete mode 100644 .github/aw/compat-update-model.md create mode 100644 .github/aw/releases.json create mode 100644 .github/aw/releases.schema.json delete mode 100644 .github/workflows/compat-bump-from-canary-dispatch.yml diff --git a/.github/aw/compat-update-model.md b/.github/aw/compat-update-model.md deleted file mode 100644 index 489210c89bb..00000000000 --- a/.github/aw/compat-update-model.md +++ /dev/null @@ -1,227 +0,0 @@ -# Compatibility Matrix Update Model - -## Overview - -The `.github/aw/compat.json` file serves as the source of truth for agent compatibility with gh-aw versions. This document describes how compatibility matrix updates are driven by canary testing and the security model that keeps gh-aw free of cross-repo secrets. - -## Architecture: Push Model (Canary-Driven Bumping) - -### Design - -The compatibility matrix uses a **push model** where the private `agentic-workflows-canary` repository drives updates: - -``` -agentic-workflows-canary (private) - ↓ (1) Run canary scenarios - ↓ (2) Evaluate health within freshness window - ↓ (3) Emit repository_dispatch event - ↓ -github/gh-aw (public) - ↓ (4) Receive dispatch event - ↓ (5) Open/update guarded compat bump PR - ↓ (6) Automated review + manual approval - ↓ (7) Merge to main -``` - -### What is "Bumping"? - -**Bumping** refers to updating the `max-agent` field in a compat row when: - -1. A new agent version (e.g., Copilot CLI 1.0.52) is released -2. Canary scenarios pass with the new version + current gh-aw -3. The compat row has `"open": true` (indicating it accepts automatic bumps) - -Example bump: -```json -// Before: -{ - "min-gh-aw": "0.72.0", - "max-gh-aw": "*", - "min-agent": "1.0.21", - "max-agent": "1.0.51", // ← Old max - "open": true -} - -// After: -{ - "min-gh-aw": "0.72.0", - "max-gh-aw": "*", - "min-agent": "1.0.21", - "max-agent": "1.0.52", // ← Bumped to new version - "open": true -} -``` - -## Guard Conditions - -The canary repository emits a `repository_dispatch` event **only when ALL** of the following conditions are met: - -### 1. Scenario Pass Criteria - -All required canary scenarios must pass for the candidate agent version: - -- **Core functionality**: Basic workflow execution (compile, activate, run) -- **Security validation**: No new security alerts from CodeQL/secret scanning -- **Compatibility tests**: Agent works with current gh-aw release range -- **Performance benchmarks**: No significant regressions in latency/memory -- **Integration tests**: MCP server communication, SDK driver compatibility - -### 2. Freshness Window - -Results must be within the freshness window to prevent stale data from triggering bumps: - -- **Maximum age**: Scenario results must be ≤ 24 hours old -- **Minimum coverage**: All required scenarios must have fresh results -- **Health check**: Canary infrastructure itself must be healthy - -### 3. Version Eligibility - -The candidate agent version must meet release criteria: - -- **Stable release**: No pre-release tags (e.g., `-alpha`, `-beta`) -- **Not blocked**: Not in `blockedVersions` list -- **Newer than current**: Version > current `max-agent` in compat.json -- **Row is open**: Target compat row has `"open": true` - -### 4. No Active Incidents - -No active incident or rollback in progress: - -- **Incident status**: No P0/P1 incidents affecting gh-aw or the agent -- **Rollback state**: No ongoing rollback of previous bump -- **Manual freeze**: No operator-initiated freeze flag - -## Dispatch Payload - -When all guard conditions pass, canary emits: - -```json -{ - "event_type": "compat-bump", - "client_payload": { - "agent": "copilot", - "version": "1.0.52", - "canary_run_id": "12345678", - "canary_scenarios_url": "https://github.com/github/agentic-workflows-canary/actions/runs/12345678", - "freshness_timestamp": "2026-06-04T01:00:00Z", - "guard_conditions": { - "scenarios_passed": true, - "within_freshness_window": true, - "version_eligible": true, - "no_active_incidents": true - } - } -} -``` - -## gh-aw Bump Workflow - -When gh-aw receives the `repository_dispatch` (workflow: `.github/workflows/compat-bump-from-canary-dispatch.yml`): - -1. **Validate payload**: Verify all guard conditions are still true -2. **Fetch current compat.json**: Read current `max-agent` value -3. **Generate PR**: Create or update a PR with the new `max-agent` -4. **Automated checks**: Run validation workflow (schema check, test suite) -5. **Human review**: Require manual approval from compat maintainers -6. **Merge**: Automated merge after approval + passing checks - -## Security Model - -### Why This Model? - -The push model is chosen for three key reasons: - -1. **Minimize secret sprawl**: Only the canary repo needs credentials -2. **Single source of truth**: Canary owns health determination logic -3. **Principle of least privilege**: gh-aw doesn't need to read private canary data - -### Credential Flow - -``` -┌─────────────────────────────────┐ -│ agentic-workflows-canary │ -│ (private repo) │ -│ │ -│ ✓ Has: DISPATCH_TOKEN │ ← Only place with cross-repo secret -│ - Scope: public_repo │ -│ - Can: send repository_dispatch to github/gh-aw -│ - Cannot: read/write gh-aw branches -└─────────────────────────────────┘ - │ - │ repository_dispatch (no authentication required to receive) - ↓ -┌─────────────────────────────────┐ -│ github/gh-aw │ -│ (public repo) │ -│ │ -│ ✗ No secrets to canary │ ← Keeps gh-aw secret-free -│ ✓ Has: GITHUB_TOKEN (default) │ -│ - Can: create PRs in gh-aw │ -│ - Cannot: read canary data │ -└─────────────────────────────────┘ -``` - -### Token Scope and Blast Radius - -**DISPATCH_TOKEN** (stored in canary repo): -- **Required scope**: `public_repo` (or `repo` if gh-aw were private) -- **Blast radius if leaked**: - - ✗ Can send repository_dispatch to github/gh-aw (trigger bump workflow) - - ✗ Can send repository_dispatch to other public repos (if configured) - - ✓ CANNOT read canary scenarios (private repo) - - ✓ CANNOT push to gh-aw branches (no write access) - - ✓ CANNOT modify gh-aw PRs directly - -**Mitigation if token leaks**: -1. Revoke and rotate token immediately -2. Review recent repository_dispatch events in gh-aw -3. Revert any unauthorized compat bumps -4. No canary data exposure (private repo remains protected) - -### Alternative: Polling (Not Chosen) - -We explicitly **rejected** a polling model where gh-aw fetches canary status: - -``` -❌ Polling Model (Rejected): - gh-aw (public) → poll → agentic-workflows-canary (private) - - Problems: - - Requires gh-aw to have secrets for canary access - - Increases secret sprawl in public repo - - More complex secret rotation - - Larger blast radius if gh-aw is compromised -``` - -## Operational Notes - -### Manual Bumps - -Operators can manually bump compat.json by: - -1. Opening a PR directly in gh-aw -2. Bypassing the canary dispatch (for emergency updates) -3. Following the same review/approval process - -### Freezing Automatic Bumps - -To temporarily stop automatic bumps: - -1. Set `"open": false` on the target compat row -2. Canary will skip dispatch for that agent -3. Re-enable by setting `"open": true` in a subsequent PR - -### Rollback - -If a bumped version causes issues: - -1. Revert the compat.json PR in gh-aw -2. Set `"open": false` to prevent re-bump -3. Add problematic version to `blockedVersions` if necessary -4. Investigate root cause in canary scenarios - -## References - -- Compatibility matrix schema: `.github/aw/compat.schema.json` -- Installer implementation: `actions/setup/sh/install_copilot_cli.sh` -- Canary repository: `github/agentic-workflows-canary` (private) diff --git a/.github/aw/compat.schema.json b/.github/aw/compat.schema.json index 5b805b3685b..12a933a1aed 100644 --- a/.github/aw/compat.schema.json +++ b/.github/aw/compat.schema.json @@ -2,7 +2,7 @@ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://github.com/github/gh-aw/.github/aw/compat.schema.json", "title": "gh-aw agent compatibility matrix", - "description": "Pins agentic CLI versions to gh-aw release ranges. Consumed by the setup action to install a known-good agent version per gh-aw release. Updates are driven by canary testing via repository_dispatch (push model). See compat-update-model.md for the security model and bump workflow.", + "description": "Pins agentic CLI versions to gh-aw release ranges. Consumed by the setup action to install a known-good agent version per gh-aw release. See ADR for the design rationale.", "type": "object", "required": ["agent-compat-v1"], "additionalProperties": false, diff --git a/.github/aw/releases.json b/.github/aw/releases.json new file mode 100644 index 00000000000..3ab333d230e --- /dev/null +++ b/.github/aw/releases.json @@ -0,0 +1,6 @@ +{ + "$schema": "./releases.schema.json", + "blockedVersions": [], + "minimumVersion": "v0.65.3", + "minRecommendedVersion": "v0.65.3" +} diff --git a/.github/aw/releases.schema.json b/.github/aw/releases.schema.json new file mode 100644 index 00000000000..c1ebba7027d --- /dev/null +++ b/.github/aw/releases.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "gh-aw update check configuration", + "description": "Configuration for the compile-agentic version update check. This file is fetched at runtime by the activation job to validate that the compiled version is still supported.", + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "type": "string", + "description": "JSON Schema reference" + }, + "blockedVersions": { + "type": "array", + "description": "List of blocked compile-agentic versions that are not allowed to run (e.g. due to a security compromise). Workflows compiled with a blocked version will fail at activation.", + "items": { + "type": "string", + "pattern": "^v[0-9]+\\.[0-9]+\\.[0-9]+$", + "description": "A blocked version string in vMAJOR.MINOR.PATCH format (e.g. 'v1.2.3')" + }, + "uniqueItems": true, + "default": [] + }, + "minimumVersion": { + "type": "string", + "description": "The minimum supported compile-agentic version in vMAJOR.MINOR.PATCH format. Workflows compiled with a version below this will fail at activation. Use an empty string to disable this check.", + "pattern": "^(v[0-9]+\\.[0-9]+\\.[0-9]+)?$", + "default": "" + }, + "minRecommendedVersion": { + "type": "string", + "description": "The minimum recommended compile-agentic version in vMAJOR.MINOR.PATCH format. Workflows compiled with a version below this will emit a warning (but not fail) at activation, nudging users to upgrade. Use an empty string to disable this check.", + "pattern": "^(v[0-9]+\\.[0-9]+\\.[0-9]+)?$", + "default": "" + } + } +} diff --git a/.github/skills/agentic-workflows/SKILL.md b/.github/skills/agentic-workflows/SKILL.md index 0e5802ec146..84c905c3877 100644 --- a/.github/skills/agentic-workflows/SKILL.md +++ b/.github/skills/agentic-workflows/SKILL.md @@ -12,7 +12,6 @@ This skill is a dispatcher: identify the task type, load the matching `.github/a Read only the files you need: Load these files from `github/gh-aw` (they are not available locally). - `.github/aw/agentic-chat.md` -- `.github/aw/agentic-workflows-mcp.md` - `.github/aw/asciicharts.md` - `.github/aw/campaign.md` - `.github/aw/charts-trending.md` diff --git a/.github/workflows/cgo.yml b/.github/workflows/cgo.yml index 093f05cc9e8..15b507312e6 100644 --- a/.github/workflows/cgo.yml +++ b/.github/workflows/cgo.yml @@ -17,6 +17,8 @@ on: - '.github/workflows/ci.yml' - '.github/workflows/cgo.yml' - '.github/workflows/**/*.md' + - '.github/aw/releases.json' + - '.github/aw/releases.schema.json' - '.github/aw/compat.json' - '.github/aw/compat.schema.json' - 'install-gh-aw.sh' @@ -551,6 +553,93 @@ jobs: echo "✅ All URLs in $AGENT_FILE correctly use 'main' branch" + - name: Validate releases.json structure and version formats + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + with: + script: | + const fs = require('fs'); + const CONFIG_FILE = '.github/aw/releases.json'; + const SCHEMA_FILE = '.github/aw/releases.schema.json'; + + core.info(`🔍 Validating ${CONFIG_FILE} against ${SCHEMA_FILE}...`); + + if (!fs.existsSync(CONFIG_FILE)) { + core.setFailed(`ERROR: ${CONFIG_FILE} not found`); + return; + } + if (!fs.existsSync(SCHEMA_FILE)) { + core.setFailed(`ERROR: ${SCHEMA_FILE} not found`); + return; + } + + let config; + try { + config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); + } catch (err) { + core.setFailed(`ERROR: ${CONFIG_FILE} is not valid JSON: ${err.message}`); + return; + } + core.info(`✅ ${CONFIG_FILE} is valid JSON`); + + const errors = []; + + // Check additionalProperties (only allow known keys) + const allowedKeys = new Set(['$schema', 'blockedVersions', 'minimumVersion', 'minRecommendedVersion']); + for (const key of Object.keys(config)) { + if (!allowedKeys.has(key)) { + errors.push(`Unknown property: '${key}'`); + } + } + + // Validate blockedVersions + if ('blockedVersions' in config) { + const bv = config.blockedVersions; + if (!Array.isArray(bv)) { + errors.push("'blockedVersions' must be an array"); + } else { + const versionPattern = /^v[0-9]+\.[0-9]+\.[0-9]+$/; + const seen = new Set(); + bv.forEach((v, i) => { + if (typeof v !== 'string') { + errors.push(`'blockedVersions[${i}]' must be a string`); + } else if (!versionPattern.test(v)) { + errors.push(`'blockedVersions[${i}]' ('${v}') does not match expected version pattern (vMAJOR.MINOR.PATCH, e.g. 'v1.2.3')`); + } else if (seen.has(v)) { + errors.push(`'blockedVersions' contains duplicate entry: '${v}'`); + } else { + seen.add(v); + } + }); + } + } + + // Validate minimumVersion + if ('minimumVersion' in config) { + const mv = config.minimumVersion; + if (typeof mv !== 'string') { + errors.push("'minimumVersion' must be a string"); + } else if (mv !== '' && !/^v[0-9]+\.[0-9]+\.[0-9]+$/.test(mv)) { + errors.push(`'minimumVersion' ('${mv}') does not match expected version pattern (vMAJOR.MINOR.PATCH, e.g. 'v1.2.3' or empty string)`); + } + } + + // Validate minRecommendedVersion + if ('minRecommendedVersion' in config) { + const mrv = config.minRecommendedVersion; + if (typeof mrv !== 'string') { + errors.push("'minRecommendedVersion' must be a string"); + } else if (mrv !== '' && !/^v[0-9]+\.[0-9]+\.[0-9]+$/.test(mrv)) { + errors.push(`'minRecommendedVersion' ('${mrv}') does not match expected version pattern (vMAJOR.MINOR.PATCH, e.g. 'v1.2.3' or empty string)`); + } + } + + if (errors.length > 0) { + core.setFailed(`❌ ${CONFIG_FILE} schema validation failed:\n${errors.map(e => ` - ${e}`).join('\n')}`); + return; + } + + core.info(`✅ ${CONFIG_FILE} is valid and conforms to ${SCHEMA_FILE}`); + - name: Validate compat.json structure and version formats uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 with: diff --git a/.github/workflows/compat-bump-from-canary-dispatch.yml b/.github/workflows/compat-bump-from-canary-dispatch.yml deleted file mode 100644 index 242697c4423..00000000000 --- a/.github/workflows/compat-bump-from-canary-dispatch.yml +++ /dev/null @@ -1,272 +0,0 @@ -name: Compat Bump From Canary Dispatch - -on: - repository_dispatch: - types: [compat-bump] - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -jobs: - compat-bump: - name: Apply canary compat bump - runs-on: ubuntu-latest - if: github.repository == 'github/gh-aw' - steps: - - name: Validate dispatch payload and open/update bump PR - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 - with: - script: | - const owner = context.repo.owner; - const repo = context.repo.repo; - const path = ".github/aw/compat.json"; - const eventName = context.eventName; - - if (eventName !== "repository_dispatch") { - core.notice("Manual workflow_dispatch run: payload validation/update skipped."); - return; - } - - const payload = context.payload.client_payload || {}; - const sourceRepository = typeof payload.source_repository === "string" ? payload.source_repository.trim() : ""; - const expectedSourceRepository = "github/agentic-workflows-canary"; - if (sourceRepository !== expectedSourceRepository) { - core.setFailed(`Invalid source_repository: expected "${expectedSourceRepository}", got "${sourceRepository || ""}"`); - return; - } - - const requiredGuards = [ - "scenarios_passed", - "within_freshness_window", - "version_eligible", - "no_active_incidents", - ]; - const guardConditions = payload.guard_conditions || {}; - for (const guard of requiredGuards) { - if (guardConditions[guard] !== true) { - core.setFailed(`Guard condition failed or missing: guard_conditions.${guard} must be true`); - return; - } - } - - const freshnessTimestamp = typeof payload.freshness_timestamp === "string" ? payload.freshness_timestamp : ""; - const freshnessMillis = Date.parse(freshnessTimestamp); - if (!Number.isFinite(freshnessMillis)) { - core.setFailed("Invalid or missing freshness_timestamp in payload"); - return; - } - const ageMs = Date.now() - freshnessMillis; - const maxFutureSkewMs = 5 * 60 * 1000; - const maxAgeMs = 24 * 60 * 60 * 1000; - if (ageMs < -maxFutureSkewMs) { - core.setFailed("freshness_timestamp is unexpectedly in the future"); - return; - } - if (ageMs > maxAgeMs) { - core.setFailed(`freshness_timestamp is stale (age ${Math.floor(ageMs / 1000)}s > 86400s)`); - return; - } - - const normalizeVersion = (version) => (typeof version === "string" ? version.trim().replace(/^v/, "") : ""); - const semverPattern = /^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/; - const candidateVersion = normalizeVersion(payload.version); - if (!semverPattern.test(candidateVersion)) { - core.setFailed(`Invalid or missing version in payload: "${payload.version ?? ""}"`); - return; - } - - const agent = (typeof payload.agent === "string" && payload.agent.trim()) ? payload.agent.trim().toLowerCase() : "copilot"; - - const parseSemver = (version) => { - const normalized = normalizeVersion(version); - const match = normalized.match(/^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z.-]+))?$/); - if (!match) return null; - return { - major: Number(match[1]), - minor: Number(match[2]), - patch: Number(match[3]), - pre: match[4] || "", - }; - }; - - const compareSemver = (a, b) => { - const pa = parseSemver(a); - const pb = parseSemver(b); - if (!pa || !pb) throw new Error(`Cannot compare invalid semver values: "${a}" vs "${b}"`); - for (const key of ["major", "minor", "patch"]) { - if (pa[key] < pb[key]) return -1; - if (pa[key] > pb[key]) return 1; - } - if (pa.pre === pb.pre) return 0; - if (!pa.pre) return 1; - if (!pb.pre) return -1; - return pa.pre < pb.pre ? -1 : 1; - }; - - const repoInfo = await github.rest.repos.get({ owner, repo }); - const defaultBranch = repoInfo.data.default_branch; - const defaultRef = await github.rest.git.getRef({ - owner, - repo, - ref: `heads/${defaultBranch}`, - }); - const defaultBranchSha = defaultRef.data.object.sha; - - const compatFile = await github.rest.repos.getContent({ - owner, - repo, - path, - ref: defaultBranch, - }); - - if (!("content" in compatFile.data) || typeof compatFile.data.content !== "string") { - core.setFailed(`Unable to read ${path}`); - return; - } - - const compatRaw = Buffer.from(compatFile.data.content, compatFile.data.encoding || "base64").toString("utf8"); - const compat = JSON.parse(compatRaw); - const matrix = compat["agent-compat-v1"]; - if (!matrix || typeof matrix !== "object") { - core.setFailed("compat.json missing agent-compat-v1 object"); - return; - } - - const rows = matrix[agent]; - if (!Array.isArray(rows) || rows.length === 0) { - core.setFailed(`compat.json has no rows for agent "${agent}"`); - return; - } - - let rowIndex = rows.findIndex((row) => row && row["max-gh-aw"] === "*" && row.open === true); - if (rowIndex < 0) { - rowIndex = rows.findIndex((row) => row && row.open === true); - } - if (rowIndex < 0) { - core.setFailed(`No open compat row found for agent "${agent}"`); - return; - } - - const targetRow = rows[rowIndex]; - const currentMaxAgent = normalizeVersion(targetRow["max-agent"]); - const minAgent = normalizeVersion(targetRow["min-agent"]); - if (!semverPattern.test(currentMaxAgent) || !semverPattern.test(minAgent)) { - core.setFailed(`Target compat row has invalid min/max agent values: min-agent="${targetRow["min-agent"]}", max-agent="${targetRow["max-agent"]}"`); - return; - } - - if (compareSemver(candidateVersion, minAgent) < 0) { - core.setFailed(`Candidate version ${candidateVersion} is below min-agent ${minAgent} for target row`); - return; - } - - const comparison = compareSemver(candidateVersion, currentMaxAgent); - if (comparison <= 0) { - core.notice(`No update needed: candidate ${candidateVersion} is not newer than current max-agent ${currentMaxAgent}`); - return; - } - - targetRow["max-agent"] = candidateVersion; - const updatedCompatRaw = `${JSON.stringify(compat, null, 2)}\n`; - - const safeVersion = candidateVersion.replace(/[^0-9A-Za-z-]/g, "-"); - const branchName = `automation/compat-bump-${agent}-${safeVersion}`; - const commitMessage = `chore(compat): bump ${agent} max-agent to ${candidateVersion}`; - - try { - await github.rest.git.getRef({ - owner, - repo, - ref: `heads/${branchName}`, - }); - } catch (error) { - if (error.status !== 404) throw error; - await github.rest.git.createRef({ - owner, - repo, - ref: `refs/heads/${branchName}`, - sha: defaultBranchSha, - }); - } - - let currentBranchFileSha; - try { - const existingBranchFile = await github.rest.repos.getContent({ - owner, - repo, - path, - ref: branchName, - }); - if ("sha" in existingBranchFile.data) { - currentBranchFileSha = existingBranchFile.data.sha; - } - } catch (error) { - if (error.status !== 404) throw error; - } - - await github.rest.repos.createOrUpdateFileContents({ - owner, - repo, - path, - branch: branchName, - message: commitMessage, - content: Buffer.from(updatedCompatRaw, "utf8").toString("base64"), - sha: currentBranchFileSha, - }); - - const canaryRunId = payload.canary_run_id ? String(payload.canary_run_id) : ""; - const canaryScenariosUrl = payload.canary_scenarios_url ? String(payload.canary_scenarios_url) : ""; - const title = `chore(compat): bump ${agent} max-agent to ${candidateVersion}`; - const body = [ - "## Summary", - `Update \`.github/aw/compat.json\` for **${agent}** by bumping \`max-agent\` from \`${currentMaxAgent}\` to \`${candidateVersion}\` in the open row.", - "", - "## Dispatch guard checks", - "- source repository: `github/agentic-workflows-canary`", - "- `guard_conditions.scenarios_passed`: `true`", - "- `guard_conditions.within_freshness_window`: `true`", - "- `guard_conditions.version_eligible`: `true`", - "- `guard_conditions.no_active_incidents`: `true`", - `- freshness timestamp: \`${freshnessTimestamp}\` (age ${Math.floor(ageMs / 1000)}s)`, - "", - "## Canary context", - `- canary run id: ${canaryRunId || "n/a"}`, - `- canary scenarios url: ${canaryScenariosUrl || "n/a"}`, - "", - "_Auto-generated from repository_dispatch event `compat-bump`._", - ].join("\n"); - - const existingPrs = await github.paginate(github.rest.pulls.list, { - owner, - repo, - state: "open", - head: `${owner}:${branchName}`, - base: defaultBranch, - per_page: 100, - }); - - let prNumber; - if (existingPrs.length > 0) { - prNumber = existingPrs[0].number; - await github.rest.pulls.update({ - owner, - repo, - pull_number: prNumber, - title, - body, - }); - core.notice(`Updated existing PR #${prNumber}`); - } else { - const createdPr = await github.rest.pulls.create({ - owner, - repo, - title, - head: branchName, - base: defaultBranch, - body, - }); - prNumber = createdPr.data.number; - core.notice(`Created PR #${prNumber}`); - } diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 479c8414932..4d7db041eb4 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -8,20 +8,13 @@ set +o histexpand # releases with SHA256 checksum verification, following the secure pattern from # install_awf_binary.sh to avoid executing unverified downloaded scripts. # -# Compatibility-driven version selection: -# When VERSION is not provided, the installer resolves the Copilot CLI version -# from the compatibility matrix (.github/aw/compat.json) based on GH_AW_COMPILED_VERSION. -# The compat matrix is updated via canary-driven repository_dispatch events. -# See .github/aw/compat-update-model.md for the push model and security architecture. -# # Arguments: -# VERSION - Optional Copilot CLI version to install (default: compat-matrix-driven) +# VERSION - Optional Copilot CLI version to install (default: latest release) # # Security features: # - Downloads binary directly from GitHub releases (no installer script execution) # - Verifies SHA256 checksum against official SHA256SUMS.txt # - Fails fast if checksum verification fails -# - Respects compatibility matrix to prevent incompatible agent/gh-aw pairings set -euo pipefail From 3f0e29dd14c45742c44fbf0637305bad660b8a35 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 03:28:21 +0000 Subject: [PATCH 20/29] chore: remove ADR reference from compat.schema.json description Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- .github/aw/compat.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/aw/compat.schema.json b/.github/aw/compat.schema.json index 12a933a1aed..6a8e16afa9e 100644 --- a/.github/aw/compat.schema.json +++ b/.github/aw/compat.schema.json @@ -2,7 +2,7 @@ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://github.com/github/gh-aw/.github/aw/compat.schema.json", "title": "gh-aw agent compatibility matrix", - "description": "Pins agentic CLI versions to gh-aw release ranges. Consumed by the setup action to install a known-good agent version per gh-aw release. See ADR for the design rationale.", + "description": "Pins agentic CLI versions to gh-aw release ranges. Consumed by the setup action to install a known-good agent version per gh-aw release.", "type": "object", "required": ["agent-compat-v1"], "additionalProperties": false, From 6ab648d2cb019231c69ea25a6c98a481e7e7dbb0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 03:40:54 +0000 Subject: [PATCH 21/29] Apply remaining changes Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- .github/skills/agentic-workflows/SKILL.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/skills/agentic-workflows/SKILL.md b/.github/skills/agentic-workflows/SKILL.md index 84c905c3877..0e5802ec146 100644 --- a/.github/skills/agentic-workflows/SKILL.md +++ b/.github/skills/agentic-workflows/SKILL.md @@ -12,6 +12,7 @@ This skill is a dispatcher: identify the task type, load the matching `.github/a Read only the files you need: Load these files from `github/gh-aw` (they are not available locally). - `.github/aw/agentic-chat.md` +- `.github/aw/agentic-workflows-mcp.md` - `.github/aw/asciicharts.md` - `.github/aw/campaign.md` - `.github/aw/charts-trending.md` From 24198efafd231a30318d92392d521972663a34e8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 03:59:54 +0000 Subject: [PATCH 22/29] fix: remove double network fallback in compat.json download; add single-fetch assertion to test Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 25 ++++++++----------------- pkg/cli/install_copilot_cli_test.go | 11 +++++++++++ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 4d7db041eb4..7b07dde8ee4 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -25,8 +25,7 @@ COPILOT_REPO="github/copilot-cli" INSTALL_DIR="/usr/local/bin" COPILOT_DIR="${HOME}/.copilot" COPILOT_TOOLCACHE_MAX_DEPTH=4 -COMPAT_URL_PRIMARY="${COPILOT_COMPAT_URL:-https://raw.githubusercontent.com/github/gh-aw-actions/main/.github/aw/compat.json}" -COMPAT_URL_FALLBACK="${COPILOT_COMPAT_FALLBACK_URL:-https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/compat.json}" +COMPAT_URL="${COPILOT_COMPAT_URL:-https://raw.githubusercontent.com/github/gh-aw-actions/main/.github/aw/compat.json}" COMPILED_GH_AW_VERSION="${GH_AW_COMPILED_VERSION:-}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" @@ -142,26 +141,18 @@ version_is_greater() { return 1 } -# Download compatibility matrix with fallback URLs. +# Download compatibility matrix with bundled fallback. download_compat_json() { local compat_file="$1" local source_file="$2" - local url="" - local urls=("$COMPAT_URL_PRIMARY") - if [ "$COMPAT_URL_FALLBACK" != "$COMPAT_URL_PRIMARY" ]; then - urls+=("$COMPAT_URL_FALLBACK") + echo "Attempting to download compatibility matrix from ${COMPAT_URL}..." >&2 + if curl -fsSL --retry 3 --retry-delay 5 -o "$compat_file" "$COMPAT_URL"; then + echo "$COMPAT_URL" > "$source_file" + echo "Successfully downloaded compatibility matrix from ${COMPAT_URL}" >&2 + return 0 fi - - for url in "${urls[@]}"; do - echo "Attempting to download compatibility matrix from ${url}..." >&2 - if curl -fsSL --retry 3 --retry-delay 5 -o "$compat_file" "$url"; then - echo "$url" > "$source_file" - echo "Successfully downloaded compatibility matrix from ${url}" >&2 - return 0 - fi - echo "Compatibility matrix download failed from ${url}" >&2 - done + echo "Compatibility matrix download failed from ${COMPAT_URL}" >&2 if [ -f "$COMPAT_BUNDLED_PATH" ]; then echo "::warning::Compatibility matrix network fetch failed; using bundled fallback at ${COMPAT_BUNDLED_PATH}" diff --git a/pkg/cli/install_copilot_cli_test.go b/pkg/cli/install_copilot_cli_test.go index 1533a253a1b..5a336b57a06 100644 --- a/pkg/cli/install_copilot_cli_test.go +++ b/pkg/cli/install_copilot_cli_test.go @@ -6,6 +6,7 @@ import ( "os" "os/exec" "path/filepath" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -170,4 +171,14 @@ exit 97 require.NoError(t, err, "Expected curl to fetch compatibility matrix") assert.Contains(t, string(curlLogContent), "/compat.json", "compat matrix should be downloaded") assert.NotContains(t, string(curlLogContent), "SHA256SUMS.txt", "release downloads should not run when toolcache is hit") + + // Ensure compat.json is only fetched once — no double network fallback. + curlLines := strings.Split(strings.TrimSpace(string(curlLogContent)), "\n") + compatFetches := 0 + for _, line := range curlLines { + if strings.Contains(line, "/compat.json") { + compatFetches++ + } + } + assert.Equal(t, 1, compatFetches, "compat.json should be fetched exactly once (no double fallback)") } From 464ad27e5b9f99b645201485fc2443e8217b0725 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 04:12:29 +0000 Subject: [PATCH 23/29] chore: plan remove python fallback from install_copilot_cli.sh Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- .github/skills/agentic-workflows/SKILL.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/skills/agentic-workflows/SKILL.md b/.github/skills/agentic-workflows/SKILL.md index 0e5802ec146..623b3db448e 100644 --- a/.github/skills/agentic-workflows/SKILL.md +++ b/.github/skills/agentic-workflows/SKILL.md @@ -12,7 +12,6 @@ This skill is a dispatcher: identify the task type, load the matching `.github/a Read only the files you need: Load these files from `github/gh-aw` (they are not available locally). - `.github/aw/agentic-chat.md` -- `.github/aw/agentic-workflows-mcp.md` - `.github/aw/asciicharts.md` - `.github/aw/campaign.md` - `.github/aw/charts-trending.md` @@ -28,7 +27,6 @@ Load these files from `github/gh-aw` (they are not available locally). - `.github/aw/github-agentic-workflows.md` - `.github/aw/github-mcp-server.md` - `.github/aw/llms.md` -- `.github/aw/mcp-clis.md` - `.github/aw/memory.md` - `.github/aw/messages.md` - `.github/aw/network.md` From acc684560b71283f8263906361876603ca969452 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 04:13:12 +0000 Subject: [PATCH 24/29] refactor: remove python fallback from compat resolution Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 140 +----------------------- 1 file changed, 5 insertions(+), 135 deletions(-) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 7b07dde8ee4..26f1e561b92 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -166,7 +166,7 @@ download_compat_json() { return 1 } -# Resolve compat using jq (faster and more portable than python3). +# Resolve compat using jq. # Returns: "max_agent|row_index|min_aw|max_aw|min_agent|max_agent|cache_ttl_days" resolve_compat_with_jq() { local compat_file="$1" @@ -231,143 +231,13 @@ resolve_version_from_compat() { return 1 fi - # Try jq first (more commonly available than python3 on minimal runners) - if command -v jq >/dev/null 2>&1; then - if resolved_info="$(resolve_compat_with_jq "$compat_file" "$compiled_version" 2>&1)"; then - if [ -n "$resolved_info" ]; then - # Parse the 7-field jq output - IFS='|' read -r resolved_version row_index row_min_aw row_max_aw row_min_agent row_max_agent cache_ttl_days <<< "$resolved_info" - - # Display the same logging as python path - echo "Compatibility matrix source: $(cat "$compat_source")" >&2 - echo "Compatibility matrix matched row ${row_index}: gh-aw ${row_min_aw}..${row_max_aw}, copilot ${row_min_agent}..${row_max_agent}" >&2 - echo "Resolved Copilot CLI version from compatibility matrix: ${resolved_version}" >&2 - if [ -n "$cache_ttl_days" ]; then - echo "Cache TTL: ${cache_ttl_days} days" >&2 - fi - - # Return the same 4-field format as python path - printf '%s|%s|%s|%s\n' "$resolved_version" "$row_min_agent" "$row_max_agent" "$cache_ttl_days" - return 0 - else - echo "Compatibility matrix lookup found no matching copilot window for gh-aw ${compiled_version}." >&2 - return 1 - fi - fi - echo "jq-based compat resolution failed, trying python3 fallback..." >&2 - fi - - # Fall back to python3 if jq is unavailable or failed - if ! command -v python3 >/dev/null 2>&1; then - echo "ERROR: Neither jq nor python3 is available for compatibility matrix resolution." >&2 - echo "ERROR: Install jq or python3, or pass an explicit Copilot CLI version to bypass compat resolution." >&2 + if ! command -v jq >/dev/null 2>&1; then + echo "ERROR: jq is required for compatibility matrix resolution." >&2 + echo "ERROR: Install jq, or pass an explicit Copilot CLI version to bypass compat resolution." >&2 return 1 fi - if ! resolved_info="$(python3 - "$compat_file" "$compiled_version" <<'PY' -import json -import re -import sys - -compat_path = sys.argv[1] -compiled = sys.argv[2] -def parse(v): - m = re.match(r"^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$", v) - if not m: - return None - pre = m.group(4).split(".") if m.group(4) else None - return (int(m.group(1)), int(m.group(2)), int(m.group(3)), pre) - -def cmp(a, b): - pa = parse(a) - pb = parse(b) - if pa is None or pb is None: - return 0 - for i in range(3): - if pa[i] != pb[i]: - return pa[i] - pb[i] - apre = pa[3] - bpre = pb[3] - if apre is None and bpre is None: - return 0 - if apre is None: - return 1 - if bpre is None: - return -1 - length = max(len(apre), len(bpre)) - for i in range(length): - if i >= len(apre): - return -1 - if i >= len(bpre): - return 1 - ai = apre[i] - bi = bpre[i] - ai_n = ai.isdigit() - bi_n = bi.isdigit() - if ai_n and bi_n: - da = int(ai) - db = int(bi) - if da != db: - return da - db - elif ai_n: - return -1 - elif bi_n: - return 1 - elif ai != bi: - return -1 if ai < bi else 1 - return 0 - -compiled_no_v = compiled[1:] -if parse(compiled_no_v) is None: - print("") - sys.exit(0) - -try: - with open(compat_path, "r", encoding="utf-8") as f: - data = json.load(f) -except Exception: - sys.stderr.write(f"Compatibility matrix parse failed for {compat_path}\n") - print("") - sys.exit(0) - -if not isinstance(data, dict): - print("") - sys.exit(0) - -agent_compat = data.get("agent-compat-v1", {}) -cache_ttl_days = agent_compat.get("cache-ttl-days", "") -rows = agent_compat.get("copilot", []) -if not isinstance(rows, list): - print("") - sys.exit(0) - -for i, row in enumerate(rows): - if not isinstance(row, dict): - continue - min_aw = row.get("min-gh-aw") - max_aw = row.get("max-gh-aw") - min_agent = row.get("min-agent") - max_agent = row.get("max-agent") - if not all(isinstance(v, str) for v in [min_aw, max_aw, min_agent, max_agent]): - continue - if parse(min_aw) is None: - continue - if max_aw != "*" and parse(max_aw) is None: - continue - if parse(min_agent) is None or parse(max_agent) is None: - continue - - if cmp(compiled_no_v, min_aw) < 0: - continue - if max_aw != "*" and cmp(compiled_no_v, max_aw) > 0: - continue - - print(f"{max_agent}|{i}|{min_aw}|{max_aw}|{min_agent}|{max_agent}|{cache_ttl_days}") - sys.exit(0) - -print("") -PY - )"; then + if ! resolved_info="$(resolve_compat_with_jq "$compat_file" "$compiled_version" 2>&1)"; then echo "Compatibility matrix resolver failed unexpectedly." >&2 return 1 fi From a93a978f0b2e07ea9d8c1c190b854be111db8873 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 04:14:00 +0000 Subject: [PATCH 25/29] fix: improve jq resolution error reporting Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 26f1e561b92..1b53e267245 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -205,7 +205,7 @@ resolve_compat_with_jq() { "\($max_agent)|\($idx)|\($min_aw)|\($max_aw)|\($min_agent)|\($max_agent)|\($cache_ttl)" else empty end ) | first // "" - ' "$compat_file" 2>&1 || echo "" + ' "$compat_file" 2>&1 } # Resolve Copilot version from compat matrix using GH_AW_COMPILED_VERSION. @@ -233,11 +233,15 @@ resolve_version_from_compat() { if ! command -v jq >/dev/null 2>&1; then echo "ERROR: jq is required for compatibility matrix resolution." >&2 + echo "ERROR: Install jq from https://jqlang.github.io/jq/download/" >&2 echo "ERROR: Install jq, or pass an explicit Copilot CLI version to bypass compat resolution." >&2 return 1 fi if ! resolved_info="$(resolve_compat_with_jq "$compat_file" "$compiled_version" 2>&1)"; then + if [ -n "$resolved_info" ]; then + echo "$resolved_info" >&2 + fi echo "Compatibility matrix resolver failed unexpectedly." >&2 return 1 fi From 376e0e1a20df2f2d4bf0e0ac7f589b2c1ef85a4c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 04:14:39 +0000 Subject: [PATCH 26/29] fix: clarify compat resolver errors and simplify jq stderr capture Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index 1b53e267245..aa9ddfb307d 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -205,7 +205,7 @@ resolve_compat_with_jq() { "\($max_agent)|\($idx)|\($min_aw)|\($max_aw)|\($min_agent)|\($max_agent)|\($cache_ttl)" else empty end ) | first // "" - ' "$compat_file" 2>&1 + ' "$compat_file" } # Resolve Copilot version from compat matrix using GH_AW_COMPILED_VERSION. @@ -242,7 +242,7 @@ resolve_version_from_compat() { if [ -n "$resolved_info" ]; then echo "$resolved_info" >&2 fi - echo "Compatibility matrix resolver failed unexpectedly." >&2 + echo "ERROR: Compatibility matrix resolution failed." >&2 return 1 fi From c37df0c61f09800944ab117d55564f1bdc507f59 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 04:20:24 +0000 Subject: [PATCH 27/29] fix: consolidate jq and compat resolution errors Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/sh/install_copilot_cli.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/actions/setup/sh/install_copilot_cli.sh b/actions/setup/sh/install_copilot_cli.sh index aa9ddfb307d..39487d95911 100755 --- a/actions/setup/sh/install_copilot_cli.sh +++ b/actions/setup/sh/install_copilot_cli.sh @@ -233,16 +233,16 @@ resolve_version_from_compat() { if ! command -v jq >/dev/null 2>&1; then echo "ERROR: jq is required for compatibility matrix resolution." >&2 - echo "ERROR: Install jq from https://jqlang.github.io/jq/download/" >&2 - echo "ERROR: Install jq, or pass an explicit Copilot CLI version to bypass compat resolution." >&2 + echo "ERROR: Install jq from https://jqlang.github.io/jq/download/ or pass an explicit Copilot CLI version to bypass compat resolution." >&2 return 1 fi if ! resolved_info="$(resolve_compat_with_jq "$compat_file" "$compiled_version" 2>&1)"; then if [ -n "$resolved_info" ]; then - echo "$resolved_info" >&2 + echo "ERROR: Compatibility matrix resolution failed: ${resolved_info}" >&2 + else + echo "ERROR: Compatibility matrix resolution failed." >&2 fi - echo "ERROR: Compatibility matrix resolution failed." >&2 return 1 fi From 91abc5447468c1cda6ac55d9e0271616b979402a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 04:45:02 +0000 Subject: [PATCH 28/29] chore: prepare updated PR messaging Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- .github/skills/agentic-workflows/SKILL.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/skills/agentic-workflows/SKILL.md b/.github/skills/agentic-workflows/SKILL.md index 623b3db448e..0e5802ec146 100644 --- a/.github/skills/agentic-workflows/SKILL.md +++ b/.github/skills/agentic-workflows/SKILL.md @@ -12,6 +12,7 @@ This skill is a dispatcher: identify the task type, load the matching `.github/a Read only the files you need: Load these files from `github/gh-aw` (they are not available locally). - `.github/aw/agentic-chat.md` +- `.github/aw/agentic-workflows-mcp.md` - `.github/aw/asciicharts.md` - `.github/aw/campaign.md` - `.github/aw/charts-trending.md` @@ -27,6 +28,7 @@ Load these files from `github/gh-aw` (they are not available locally). - `.github/aw/github-agentic-workflows.md` - `.github/aw/github-mcp-server.md` - `.github/aw/llms.md` +- `.github/aw/mcp-clis.md` - `.github/aw/memory.md` - `.github/aw/messages.md` - `.github/aw/network.md` From 36b62d9fc30adc5b7d9ee55c0dd6ad258197b538 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 06:21:12 +0000 Subject: [PATCH 29/29] fix: source compat config from gh-aw-actions Co-authored-by: salmanmkc <32169182+salmanmkc@users.noreply.github.com> --- actions/setup/js/check_version_updates.cjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/check_version_updates.cjs b/actions/setup/js/check_version_updates.cjs index 1e2c6d8c700..8fda5989ab2 100644 --- a/actions/setup/js/check_version_updates.cjs +++ b/actions/setup/js/check_version_updates.cjs @@ -7,7 +7,7 @@ * This script: * 1. Reads the compiled version from GH_AW_COMPILED_VERSION env var. * 2. Skips the check if the version is not in vMAJOR.MINOR.PATCH official release format. - * 3. Fetches .github/aw/compat.json from the gh-aw repository via raw.githubusercontent.com. + * 3. Fetches .github/aw/compat.json from the gh-aw-actions repository via raw.githubusercontent.com. * - Uses withRetry to handle transient network failures. * 4. If the download fails or config is invalid JSON, the check is skipped (soft failure). * 5. Validates that the compiled version is not in the blocked list. @@ -18,7 +18,7 @@ const { withRetry, isTransientError } = require("./error_recovery.cjs"); -const CONFIG_URL = "https://raw.githubusercontent.com/github/gh-aw/main/.github/aw/compat.json"; +const CONFIG_URL = "https://raw.githubusercontent.com/github/gh-aw-actions/main/.github/aw/compat.json"; /** * Parse an official version string (must be in vMAJOR.MINOR.PATCH format).