diff --git a/.github/workflows/avenger.lock.yml b/.github/workflows/avenger.lock.yml index 1faa56f7c1c..6b92ea07251 100644 --- a/.github/workflows/avenger.lock.yml +++ b/.github/workflows/avenger.lock.yml @@ -1792,6 +1792,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index 17846934d93..52f22b6aa90 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -1722,6 +1722,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') env: diff --git a/.github/workflows/chaos-pr-bundle-fuzzer.lock.yml b/.github/workflows/chaos-pr-bundle-fuzzer.lock.yml index fa0d3b97d34..35821799cdf 100644 --- a/.github/workflows/chaos-pr-bundle-fuzzer.lock.yml +++ b/.github/workflows/chaos-pr-bundle-fuzzer.lock.yml @@ -1662,6 +1662,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/ci-coach.lock.yml b/.github/workflows/ci-coach.lock.yml index e7f873b84a8..45284c37e70 100644 --- a/.github/workflows/ci-coach.lock.yml +++ b/.github/workflows/ci-coach.lock.yml @@ -1820,6 +1820,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index 4e820062c8c..437938398ad 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -2102,6 +2102,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/code-scanning-fixer.lock.yml b/.github/workflows/code-scanning-fixer.lock.yml index 378db6d3277..c011e6ada26 100644 --- a/.github/workflows/code-scanning-fixer.lock.yml +++ b/.github/workflows/code-scanning-fixer.lock.yml @@ -1869,6 +1869,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/code-simplifier.lock.yml b/.github/workflows/code-simplifier.lock.yml index deff4ebf7df..9f7a6e9319f 100644 --- a/.github/workflows/code-simplifier.lock.yml +++ b/.github/workflows/code-simplifier.lock.yml @@ -1739,6 +1739,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index 678c1006d41..3f7a69f2f4c 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -1762,6 +1762,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') env: 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 e2c6ce86a0b..7cc940a21eb 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 @@ -1971,6 +1971,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/daily-architecture-diagram.lock.yml b/.github/workflows/daily-architecture-diagram.lock.yml index 35a85977544..ab28dc0036c 100644 --- a/.github/workflows/daily-architecture-diagram.lock.yml +++ b/.github/workflows/daily-architecture-diagram.lock.yml @@ -1858,6 +1858,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/daily-astrostylelite-markdown-spellcheck.lock.yml b/.github/workflows/daily-astrostylelite-markdown-spellcheck.lock.yml index e9945af081c..5271fd2bc51 100644 --- a/.github/workflows/daily-astrostylelite-markdown-spellcheck.lock.yml +++ b/.github/workflows/daily-astrostylelite-markdown-spellcheck.lock.yml @@ -1809,6 +1809,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/daily-caveman-optimizer.lock.yml b/.github/workflows/daily-caveman-optimizer.lock.yml index ebf5f1a38c1..81ed242e1b0 100644 --- a/.github/workflows/daily-caveman-optimizer.lock.yml +++ b/.github/workflows/daily-caveman-optimizer.lock.yml @@ -1851,6 +1851,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/daily-community-attribution.lock.yml b/.github/workflows/daily-community-attribution.lock.yml index ac6992d8fb3..5002b6161fc 100644 --- a/.github/workflows/daily-community-attribution.lock.yml +++ b/.github/workflows/daily-community-attribution.lock.yml @@ -1956,6 +1956,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/daily-compiler-threat-spec-optimizer.lock.yml b/.github/workflows/daily-compiler-threat-spec-optimizer.lock.yml index fdd53250608..2d8e7684c1f 100644 --- a/.github/workflows/daily-compiler-threat-spec-optimizer.lock.yml +++ b/.github/workflows/daily-compiler-threat-spec-optimizer.lock.yml @@ -1693,6 +1693,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/daily-doc-healer.lock.yml b/.github/workflows/daily-doc-healer.lock.yml index 855c671c9cb..1609d491f0b 100644 --- a/.github/workflows/daily-doc-healer.lock.yml +++ b/.github/workflows/daily-doc-healer.lock.yml @@ -1960,6 +1960,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml index f684964a3d9..315fd8ac13e 100644 --- a/.github/workflows/daily-doc-updater.lock.yml +++ b/.github/workflows/daily-doc-updater.lock.yml @@ -1886,6 +1886,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/daily-rendering-scripts-verifier.lock.yml b/.github/workflows/daily-rendering-scripts-verifier.lock.yml index 56ef591318f..f1bf5e9c976 100644 --- a/.github/workflows/daily-rendering-scripts-verifier.lock.yml +++ b/.github/workflows/daily-rendering-scripts-verifier.lock.yml @@ -1965,6 +1965,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/daily-safe-output-integrator.lock.yml b/.github/workflows/daily-safe-output-integrator.lock.yml index 291effaa080..62f53f984fa 100644 --- a/.github/workflows/daily-safe-output-integrator.lock.yml +++ b/.github/workflows/daily-safe-output-integrator.lock.yml @@ -1693,6 +1693,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/daily-safeoutputs-git-simulator.lock.yml b/.github/workflows/daily-safeoutputs-git-simulator.lock.yml index 404e9f4a22f..6e3d2b7f8c4 100644 --- a/.github/workflows/daily-safeoutputs-git-simulator.lock.yml +++ b/.github/workflows/daily-safeoutputs-git-simulator.lock.yml @@ -1855,6 +1855,7 @@ jobs: with: persist-credentials: true fetch-depth: 0 + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Fetch additional refs if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') env: diff --git a/.github/workflows/daily-workflow-updater.lock.yml b/.github/workflows/daily-workflow-updater.lock.yml index 00a16097196..46d19bb55e6 100644 --- a/.github/workflows/daily-workflow-updater.lock.yml +++ b/.github/workflows/daily-workflow-updater.lock.yml @@ -1619,6 +1619,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/dead-code-remover.lock.yml b/.github/workflows/dead-code-remover.lock.yml index ad37d83758d..403644a96e8 100644 --- a/.github/workflows/dead-code-remover.lock.yml +++ b/.github/workflows/dead-code-remover.lock.yml @@ -1744,6 +1744,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/dependabot-repair.lock.yml b/.github/workflows/dependabot-repair.lock.yml index 31d1cfaef40..83e772c3d80 100644 --- a/.github/workflows/dependabot-repair.lock.yml +++ b/.github/workflows/dependabot-repair.lock.yml @@ -1769,6 +1769,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/dependabot-worker.lock.yml b/.github/workflows/dependabot-worker.lock.yml index f6782bfdd68..fac79238fe2 100644 --- a/.github/workflows/dependabot-worker.lock.yml +++ b/.github/workflows/dependabot-worker.lock.yml @@ -1809,6 +1809,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/design-decision-gate.lock.yml b/.github/workflows/design-decision-gate.lock.yml index 7c9c4cfac40..143c03a9d66 100644 --- a/.github/workflows/design-decision-gate.lock.yml +++ b/.github/workflows/design-decision-gate.lock.yml @@ -1893,6 +1893,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') env: diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index e3ea43bc1dd..6cbc11746ac 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -1966,6 +1966,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index 4c7029022fa..ed7a9041c56 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -1615,6 +1615,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/functional-pragmatist.lock.yml b/.github/workflows/functional-pragmatist.lock.yml index bfe5d306f4d..76af4012f86 100644 --- a/.github/workflows/functional-pragmatist.lock.yml +++ b/.github/workflows/functional-pragmatist.lock.yml @@ -1626,6 +1626,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml index 9428e4f8eb2..bfa55e4bffe 100644 --- a/.github/workflows/github-mcp-tools-report.lock.yml +++ b/.github/workflows/github-mcp-tools-report.lock.yml @@ -1769,6 +1769,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/glossary-maintainer.lock.yml b/.github/workflows/glossary-maintainer.lock.yml index 671f2c27326..43d71a363d7 100644 --- a/.github/workflows/glossary-maintainer.lock.yml +++ b/.github/workflows/glossary-maintainer.lock.yml @@ -1862,6 +1862,7 @@ jobs: with: persist-credentials: true fetch-depth: 0 + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index 73caf5c668d..c41c96b13c0 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -1782,6 +1782,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/hourly-ci-cleaner.lock.yml b/.github/workflows/hourly-ci-cleaner.lock.yml index 62c5b6702c3..1ebe4b9711c 100644 --- a/.github/workflows/hourly-ci-cleaner.lock.yml +++ b/.github/workflows/hourly-ci-cleaner.lock.yml @@ -1787,6 +1787,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml index 75c9584009f..9cfa1fde7e7 100644 --- a/.github/workflows/instructions-janitor.lock.yml +++ b/.github/workflows/instructions-janitor.lock.yml @@ -1757,6 +1757,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/jsweep.lock.yml b/.github/workflows/jsweep.lock.yml index 729bdc192c8..3e2a0e273dc 100644 --- a/.github/workflows/jsweep.lock.yml +++ b/.github/workflows/jsweep.lock.yml @@ -1681,6 +1681,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/layout-spec-maintainer.lock.yml b/.github/workflows/layout-spec-maintainer.lock.yml index 84b4fd516de..cc427a85cda 100644 --- a/.github/workflows/layout-spec-maintainer.lock.yml +++ b/.github/workflows/layout-spec-maintainer.lock.yml @@ -1666,6 +1666,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/linter-miner.lock.yml b/.github/workflows/linter-miner.lock.yml index 6d8f7781047..8e10a4af6eb 100644 --- a/.github/workflows/linter-miner.lock.yml +++ b/.github/workflows/linter-miner.lock.yml @@ -1711,6 +1711,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml index c22ecf883c6..50cac23d71a 100644 --- a/.github/workflows/mergefest.lock.yml +++ b/.github/workflows/mergefest.lock.yml @@ -1773,6 +1773,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') env: diff --git a/.github/workflows/necromancer.lock.yml b/.github/workflows/necromancer.lock.yml index 48e0bb0a8ce..bc2747d4c90 100644 --- a/.github/workflows/necromancer.lock.yml +++ b/.github/workflows/necromancer.lock.yml @@ -1848,6 +1848,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') env: diff --git a/.github/workflows/pr-sous-chef.lock.yml b/.github/workflows/pr-sous-chef.lock.yml index 619fc251c7b..1f3c2fd09f6 100644 --- a/.github/workflows/pr-sous-chef.lock.yml +++ b/.github/workflows/pr-sous-chef.lock.yml @@ -1802,6 +1802,7 @@ jobs: with: persist-credentials: true fetch-depth: 0 + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Fetch additional refs if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') env: diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index cb9181755c2..c7f1e5f208c 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -1925,6 +1925,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/refiner.lock.yml b/.github/workflows/refiner.lock.yml index 9aa00a6eac4..d8cb617a59c 100644 --- a/.github/workflows/refiner.lock.yml +++ b/.github/workflows/refiner.lock.yml @@ -1793,6 +1793,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/ruflo-backed-task.lock.yml b/.github/workflows/ruflo-backed-task.lock.yml index 7f48c2f9a27..6a91afd32f2 100644 --- a/.github/workflows/ruflo-backed-task.lock.yml +++ b/.github/workflows/ruflo-backed-task.lock.yml @@ -1892,6 +1892,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/schema-feature-coverage.lock.yml b/.github/workflows/schema-feature-coverage.lock.yml index bf03810ad0d..74d3b99f063 100644 --- a/.github/workflows/schema-feature-coverage.lock.yml +++ b/.github/workflows/schema-feature-coverage.lock.yml @@ -1733,6 +1733,7 @@ jobs: with: persist-credentials: true fetch-depth: 1 + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/slide-deck-maintainer.lock.yml b/.github/workflows/slide-deck-maintainer.lock.yml index adac4c9d98d..8af260ca886 100644 --- a/.github/workflows/slide-deck-maintainer.lock.yml +++ b/.github/workflows/slide-deck-maintainer.lock.yml @@ -1817,6 +1817,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/smoke-create-cross-repo-pr.lock.yml b/.github/workflows/smoke-create-cross-repo-pr.lock.yml index faaaa154e30..1ce6fa51eb3 100644 --- a/.github/workflows/smoke-create-cross-repo-pr.lock.yml +++ b/.github/workflows/smoke-create-cross-repo-pr.lock.yml @@ -1866,6 +1866,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_SIDE_REPO_PAT }} - name: Checkout github/gh-aw-side-repo if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 diff --git a/.github/workflows/smoke-multi-pr.lock.yml b/.github/workflows/smoke-multi-pr.lock.yml index 77a064f65a9..e5a9f6404de 100644 --- a/.github/workflows/smoke-multi-pr.lock.yml +++ b/.github/workflows/smoke-multi-pr.lock.yml @@ -1808,6 +1808,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/smoke-project.lock.yml b/.github/workflows/smoke-project.lock.yml index e6d9379e6a9..59c564c0ae5 100644 --- a/.github/workflows/smoke-project.lock.yml +++ b/.github/workflows/smoke-project.lock.yml @@ -2069,6 +2069,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/smoke-update-cross-repo-pr.lock.yml b/.github/workflows/smoke-update-cross-repo-pr.lock.yml index 1847d6694e6..5c76f233b80 100644 --- a/.github/workflows/smoke-update-cross-repo-pr.lock.yml +++ b/.github/workflows/smoke-update-cross-repo-pr.lock.yml @@ -1900,6 +1900,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_SIDE_REPO_PAT }} - name: Checkout github/gh-aw-side-repo if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 diff --git a/.github/workflows/spec-enforcer.lock.yml b/.github/workflows/spec-enforcer.lock.yml index a6612602ff3..92346737e8e 100644 --- a/.github/workflows/spec-enforcer.lock.yml +++ b/.github/workflows/spec-enforcer.lock.yml @@ -1794,6 +1794,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/spec-extractor.lock.yml b/.github/workflows/spec-extractor.lock.yml index 91685b86b3c..6d2829133a8 100644 --- a/.github/workflows/spec-extractor.lock.yml +++ b/.github/workflows/spec-extractor.lock.yml @@ -1745,6 +1745,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index 68c9d849243..d0ace4b5d15 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -1866,6 +1866,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/test-create-pr-error-handling.lock.yml b/.github/workflows/test-create-pr-error-handling.lock.yml index 6c7629cb3d5..0e9030540ba 100644 --- a/.github/workflows/test-create-pr-error-handling.lock.yml +++ b/.github/workflows/test-create-pr-error-handling.lock.yml @@ -1725,6 +1725,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index 847395ecced..701c71d1e1d 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -1819,6 +1819,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') env: diff --git a/.github/workflows/ubuntu-image-analyzer.lock.yml b/.github/workflows/ubuntu-image-analyzer.lock.yml index 0bdfa250ad9..865f51beb36 100644 --- a/.github/workflows/ubuntu-image-analyzer.lock.yml +++ b/.github/workflows/ubuntu-image-analyzer.lock.yml @@ -1717,6 +1717,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index 65140598889..8d337e47561 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -1964,6 +1964,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/update-astro.lock.yml b/.github/workflows/update-astro.lock.yml index 1e9d68ddddc..ff923f73458 100644 --- a/.github/workflows/update-astro.lock.yml +++ b/.github/workflows/update-astro.lock.yml @@ -1742,6 +1742,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/weekly-blog-post-writer.lock.yml b/.github/workflows/weekly-blog-post-writer.lock.yml index 63e45d6b374..14f34ad5b70 100644 --- a/.github/workflows/weekly-blog-post-writer.lock.yml +++ b/.github/workflows/weekly-blog-post-writer.lock.yml @@ -1997,6 +1997,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/weekly-editors-health-check.lock.yml b/.github/workflows/weekly-editors-health-check.lock.yml index 248b4af2515..e5b92a7b27a 100644 --- a/.github/workflows/weekly-editors-health-check.lock.yml +++ b/.github/workflows/weekly-editors-health-check.lock.yml @@ -1695,6 +1695,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/.github/workflows/weekly-safe-outputs-spec-review.lock.yml b/.github/workflows/weekly-safe-outputs-spec-review.lock.yml index 336b31ebc17..c7dcc41d58d 100644 --- a/.github/workflows/weekly-safe-outputs-spec-review.lock.yml +++ b/.github/workflows/weekly-safe-outputs-spec-review.lock.yml @@ -1618,6 +1618,7 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: true + token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Configure Git credentials if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') env: diff --git a/actions/setup/js/dynamic_checkout.cjs b/actions/setup/js/dynamic_checkout.cjs index ef47a8fbae5..2587d8fde46 100644 --- a/actions/setup/js/dynamic_checkout.cjs +++ b/actions/setup/js/dynamic_checkout.cjs @@ -46,6 +46,31 @@ async function getCurrentCheckoutRepo() { } } +/** + * Determine whether the current checkout already has a persisted + * http./.extraheader credential in .git/config. + * + * When actions/checkout runs with persist-credentials: true (as the safe_outputs job + * does), it writes an http./.extraheader entry that authenticates every + * URL. In that case a dynamic repo switch must NOT inject a second + * extraheader, because git treats the key as multi-valued and would send two + * Authorization headers, which GitHub rejects with "Duplicate header: 'Authorization'". + * + * @param {string} serverUrl - GitHub server URL (e.g. "https://github.com") + * @returns {Promise} true if a non-empty extraheader is already configured + */ +async function checkoutHasPersistedExtraheader(serverUrl) { + try { + const result = await exec.getExecOutput("git", ["config", "--get-all", `http.${serverUrl}/.extraheader`], { + silent: true, + ignoreReturnCode: true, + }); + return result.exitCode === 0 && result.stdout.trim() !== ""; + } catch { + return false; + } +} + /** * Checkout a different repository for patch application * This is used when processing entries with a `repo` parameter that differs from the current checkout @@ -86,18 +111,33 @@ async function checkoutRepo(repoSlug, token, options = {}) { // Get GitHub server URL (for GHES support) const serverUrl = process.env.GITHUB_SERVER_URL || "https://github.com"; - // Configure the new remote URL - // Use token in URL for authentication since we're not using credential helper + // Configure the new remote URL (no embedded credentials). Authentication is + // provided by the http./.extraheader credential that the safe_outputs + // checkout persisted into .git/config (persist-credentials: true with the resolved + // push token). That extraheader applies to every URL, so it already + // authenticates the repository we are switching to. const remoteUrl = `${serverUrl}/${repoSlug}.git`; - // Change remote origin to the new repo + // Change remote origin to the new repo. Replacing the URL also drops any + // embedded-credential URL configure_git_credentials.sh may have set, leaving the + // persisted extraheader as the single source of auth. core.info(`Configuring remote origin to: ${repoSlug}`); await exec.exec("git", ["remote", "set-url", "origin", remoteUrl]); - // Configure token for authentication - // Use extraheader to pass token without embedding in URL (more secure) - const tokenBase64 = Buffer.from(`x-access-token:${token}`).toString("base64"); - await exec.exec("git", ["config", `http.${serverUrl}/.extraheader`, `Authorization: basic ${tokenBase64}`]); + // Trust the persisted credential rather than injecting a second one. git treats + // http..extraheader as multi-valued, so adding our own header on top of the + // checkout's persisted header would put two Authorization headers on the wire, + // which GitHub rejects with "Duplicate header: 'Authorization'" (HTTP 400). Only + // configure an extraheader when the checkout did not already persist one (e.g. a + // caller that runs without persist-credentials). + const hasPersistedAuth = await checkoutHasPersistedExtraheader(serverUrl); + if (!hasPersistedAuth) { + // Use extraheader to pass the token without embedding it in the URL (more secure). + const tokenBase64 = Buffer.from(`x-access-token:${token}`).toString("base64"); + await exec.exec("git", ["config", `http.${serverUrl}/.extraheader`, `Authorization: basic ${tokenBase64}`]); + } else { + core.info("Reusing persisted git credential for authentication (skipping extraheader injection)"); + } // Fetch the new repo core.info(`Fetching repository: ${repoSlug}`); diff --git a/actions/setup/js/dynamic_checkout.test.cjs b/actions/setup/js/dynamic_checkout.test.cjs index d983058fe3b..8213320a40b 100644 --- a/actions/setup/js/dynamic_checkout.test.cjs +++ b/actions/setup/js/dynamic_checkout.test.cjs @@ -203,6 +203,66 @@ describe("checkoutRepo slug validation", () => { }); }); +describe("checkoutRepo extraheader credential handling", () => { + let mockExec; + let mockCore; + let originalExec; + let originalCore; + + /** Build an exec mock whose `git config --get-all ...extraheader` returns `persisted`. */ + function makeExec(persisted) { + return { + exec: vi.fn().mockResolvedValue(0), + getExecOutput: vi.fn().mockImplementation((_cmd, args) => { + if (args && args[0] === "config" && args.includes("--get-all")) { + return Promise.resolve({ stdout: persisted, stderr: "", exitCode: persisted ? 0 : 1 }); + } + return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 }); + }), + }; + } + + /** Returns true if any exec.exec call configured an http.<...>.extraheader. */ + function injectedExtraheader(exec) { + return exec.exec.mock.calls.some(([, args]) => Array.isArray(args) && args[0] === "config" && args.some(a => typeof a === "string" && a.endsWith(".extraheader"))); + } + + beforeEach(() => { + originalExec = global.exec; + originalCore = global.core; + mockCore = { info: vi.fn(), error: vi.fn(), warning: vi.fn(), debug: vi.fn() }; + global.core = mockCore; + }); + + afterEach(() => { + global.exec = originalExec; + global.core = originalCore; + }); + + it("does not inject a second extraheader when the checkout already persisted one", async () => { + mockExec = makeExec("AUTHORIZATION: basic PERSISTED"); + global.exec = mockExec; + + const result = await checkoutRepo("owner/repo", "fake-token", { baseBranch: "main" }); + + expect(result.success).toBe(true); + expect(injectedExtraheader(mockExec)).toBe(false); + // origin is still repointed at the target repo so the persisted credential applies + const setUrl = mockExec.exec.mock.calls.find(([, args]) => Array.isArray(args) && args[0] === "remote" && args[1] === "set-url"); + expect(setUrl).toBeDefined(); + }); + + it("injects an extraheader when no credential is persisted", async () => { + mockExec = makeExec(""); + global.exec = mockExec; + + const result = await checkoutRepo("owner/repo", "fake-token", { baseBranch: "main" }); + + expect(result.success).toBe(true); + expect(injectedExtraheader(mockExec)).toBe(true); + }); +}); + describe("getCurrentCheckoutRepo URL parsing", () => { let mockCore; let originalExec; diff --git a/actions/setup/js/push_to_pull_request_branch.cjs b/actions/setup/js/push_to_pull_request_branch.cjs index 1e5f0278461..9708860df9f 100644 --- a/actions/setup/js/push_to_pull_request_branch.cjs +++ b/actions/setup/js/push_to_pull_request_branch.cjs @@ -17,7 +17,7 @@ const { createAuthenticatedGitHubClient } = require("./handler_auth.cjs"); const { checkFileProtection, checkFileProtectionPostApply } = require("./manifest_file_helpers.cjs"); const { buildWorkflowRunUrl } = require("./workflow_metadata_helpers.cjs"); const { renderTemplateFromFile, buildProtectedFileList, getPromptPath } = require("./messages_core.cjs"); -const { ensureFullHistoryForBundle, getGitAuthEnv, extractBundlePrerequisiteCommits, isShallowOrSparseCheckout, linearizeRangeAsCommit } = require("./git_helpers.cjs"); +const { ensureFullHistoryForBundle, extractBundlePrerequisiteCommits, isShallowOrSparseCheckout, linearizeRangeAsCommit } = require("./git_helpers.cjs"); const { normalizeCommitSHA } = require("./commit_sha_helpers.cjs"); const { findRepoCheckout } = require("./find_repo_checkout.cjs"); const { getThreatDetectedMarker } = require("./threat_detection_warning.cjs"); @@ -127,12 +127,14 @@ async function main(config = {}) { const { defaultTargetRepo, allowedRepos } = resolveTargetRepoConfig(config); const githubClient = await createAuthenticatedGitHubClient(config); - // Build git auth env once for all network operations in this handler. - // clean_git_credentials.sh removes credentials from .git/config before the - // agent runs, so git fetch/push must authenticate via GIT_CONFIG_* env vars. - // Use the per-handler github-token (for cross-repo PAT) when available, - // falling back to GITHUB_TOKEN for the default workflow token. - const gitAuthEnv = getGitAuthEnv(config["github-token"]); + // Git network operations authenticate using the credentials actions/checkout + // persisted into .git/config for the safe_outputs job (persist-credentials: true, + // using the resolved push token). We intentionally do NOT inject an additional + // http.extraheader via GIT_CONFIG_* here: doing so duplicates the Authorization + // header already present in .git/config and causes the server to reject the request + // with "Duplicate header: Authorization" (HTTP 400) on git fetch/push. GitHub API + // ("gh") operations authenticate separately via the authenticated Octokit client above. + const gitAuthEnv = {}; // Base branch from config (if set) - used only for logging at factory level // Dynamic base branch resolution happens per-message after resolving the actual target repo @@ -641,8 +643,8 @@ async function main(config = {}) { } // Fetch the specific target branch from origin - // Use GIT_CONFIG_* env vars for auth because .git/config credentials are - // cleaned by clean_git_credentials.sh before the agent runs. + // Authenticate using the credentials actions/checkout persisted into .git/config + // for the safe_outputs job; no GIT_CONFIG_* extraheader is injected (see gitAuthEnv above). try { core.info(`Fetching branch: ${branchName}`); await exec.exec("git", ["fetch", "origin", `${branchName}:refs/remotes/origin/${branchName}`], { diff --git a/docs/src/content/docs/reference/safe-outputs-pull-requests.md b/docs/src/content/docs/reference/safe-outputs-pull-requests.md index 5bc695a693a..45998017d27 100644 --- a/docs/src/content/docs/reference/safe-outputs-pull-requests.md +++ b/docs/src/content/docs/reference/safe-outputs-pull-requests.md @@ -353,6 +353,22 @@ See [Cross-Repository Operations](/gh-aw/reference/cross-repository/) for a comp Like `create-pull-request`, pushes with GitHub Agentic Workflows do not trigger CI. See [Triggering CI](/gh-aw/reference/triggering-ci/) for how to enable automatic CI triggers. +### Checkout token for git operations + +`create-pull-request` and `push-to-pull-request-branch` run their git operations (fetch/push) against a repository that the `safe_outputs` job checks out with credentials persisted in `.git/config`. A **single** token is persisted into that checkout, resolved with this precedence: + +1. `create-pull-request.github-token` +2. `push-to-pull-request-branch.github-token` +3. The `safe-outputs.github-app` minted token (when a GitHub App is configured) +4. `safe-outputs.github-token` +5. The default `${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}` + +Because only one token can govern the shared checkout, **if you configure both `create-pull-request` and `push-to-pull-request-branch` for the same repository, give them the same token.** If they specify different `github-token` values, the higher-precedence one wins for the checkout, so the other output's git operations run with a token you did not intend. Set the token once at `safe-outputs.github-token` (or `safe-outputs.github-app`) and let both outputs inherit it, or set identical `github-token` values on each. + +:::note +This applies to the git checkout used by the handlers' `fetch`/`push`. The GitHub API calls each handler makes still honor that handler's own `github-token` precedence. +::: + ## Add Reviewer (`add-reviewer:`) Adds reviewers to pull requests. Specify `allowed-reviewers` to restrict to specific GitHub usernames and `allowed-team-reviewers` to restrict to specific team slugs. diff --git a/pkg/workflow/checkout_manager.go b/pkg/workflow/checkout_manager.go index 0c232b56855..678d5f5254e 100644 --- a/pkg/workflow/checkout_manager.go +++ b/pkg/workflow/checkout_manager.go @@ -170,6 +170,14 @@ type CheckoutManager struct { // The agent job leaves this false: the untrusted agent must not be able to read // credentials from disk, so its checkouts use persist-credentials: false. keepCredentialsForPush bool + // pushToken is the token expression persisted into .git/config by every generated + // checkout step when keepCredentialsForPush is enabled and the checkout entry does + // not carry its own explicit token/app auth. Setting this ensures the credential + // retained on disk matches the token the safe_outputs handlers use to push, so a + // single (correct) Authorization header is sent and no separate per-command + // http.extraheader injection is required. Empty means "fall back to the + // actions/checkout default token". + pushToken string } // NewCheckoutManager creates a new CheckoutManager pre-loaded with user-supplied @@ -229,6 +237,15 @@ func (cm *CheckoutManager) SetKeepCredentialsForPush(keep bool) { cm.keepCredentialsForPush = keep } +// SetPushToken sets the token expression persisted into .git/config by the generated +// checkout steps when keepCredentialsForPush is enabled. Call this for the safe_outputs +// job with the resolved PR push token so the retained credential matches the token the +// handlers use to fetch/push. Has no effect on entries that declare their own token/app. +func (cm *CheckoutManager) SetPushToken(token string) { + checkoutManagerLog.Printf("Setting pushToken: present=%t", token != "") + cm.pushToken = token +} + // add processes a single CheckoutConfig and either creates a new entry or merges // it into an existing entry with the same key. func (cm *CheckoutManager) add(cfg *CheckoutConfig) { diff --git a/pkg/workflow/checkout_manager_test.go b/pkg/workflow/checkout_manager_test.go index 9ab8c22d4fe..8719ec84463 100644 --- a/pkg/workflow/checkout_manager_test.go +++ b/pkg/workflow/checkout_manager_test.go @@ -234,6 +234,85 @@ func TestGenerateDefaultCheckoutStep(t *testing.T) { }) } +// TestCheckoutPushTokenFallback verifies the safe_outputs push-token fallback that +// persists the resolved PR push token into the checkout when keepCredentialsForPush is +// enabled and no explicit checkout token (or app auth) already governs the checkout. +func TestCheckoutPushTokenFallback(t *testing.T) { + getPin := func(action string) string { return action + "@v4" } + const pushToken = "${{ secrets.PUSH_TOKEN }}" + + t.Run("default checkout with no explicit token emits pushToken once", func(t *testing.T) { + cm := NewCheckoutManager(nil) + cm.SetKeepCredentialsForPush(true) + cm.SetPushToken(pushToken) + lines := cm.GenerateDefaultCheckoutStep(false, "", getPin) + combined := strings.Join(lines, "") + assert.Contains(t, combined, "persist-credentials: true", "keepCredentialsForPush should retain credentials") + assert.Contains(t, combined, "token: "+pushToken, "should persist the push token") + assert.Equal(t, 1, strings.Count(combined, "token: "), "token must be emitted exactly once") + }) + + t.Run("default checkout with explicit token does not override with pushToken", func(t *testing.T) { + cm := NewCheckoutManager([]*CheckoutConfig{ + {GitHubToken: "${{ secrets.MY_TOKEN }}"}, + }) + cm.SetKeepCredentialsForPush(true) + cm.SetPushToken(pushToken) + lines := cm.GenerateDefaultCheckoutStep(false, "", getPin) + combined := strings.Join(lines, "") + assert.Contains(t, combined, "token: ${{ secrets.MY_TOKEN }}", "explicit checkout token should win") + assert.NotContains(t, combined, pushToken, "pushToken must not override an explicit checkout token") + assert.Equal(t, 1, strings.Count(combined, "token: "), "token must be emitted exactly once") + }) + + t.Run("default checkout with app auth does not override with pushToken", func(t *testing.T) { + cm := NewCheckoutManager([]*CheckoutConfig{ + {GitHubApp: &GitHubAppConfig{AppID: "${{ vars.APP_ID }}", PrivateKey: "${{ secrets.APP_KEY }}"}}, + }) + cm.SetKeepCredentialsForPush(true) + cm.SetPushToken(pushToken) + lines := cm.GenerateDefaultCheckoutStep(false, "", getPin) + combined := strings.Join(lines, "") + assert.Contains(t, combined, "checkout-app-token-0.outputs.token", "app-minted token should govern the checkout") + assert.NotContains(t, combined, pushToken, "pushToken must not override an app-minted token") + }) + + t.Run("default checkout does not emit pushToken when keepCredentialsForPush is false", func(t *testing.T) { + cm := NewCheckoutManager(nil) + cm.SetPushToken(pushToken) + lines := cm.GenerateDefaultCheckoutStep(false, "", getPin) + combined := strings.Join(lines, "") + assert.Contains(t, combined, "persist-credentials: false", "agent-style checkout strips credentials") + assert.NotContains(t, combined, pushToken, "pushToken must not be persisted when credentials are not retained") + }) + + t.Run("additional checkout with no token uses pushToken", func(t *testing.T) { + cm := NewCheckoutManager([]*CheckoutConfig{ + {Repository: "owner/libs", Path: "./libs"}, + }) + cm.SetKeepCredentialsForPush(true) + cm.SetPushToken(pushToken) + lines := cm.GenerateAdditionalCheckoutSteps(getPin) + combined := strings.Join(lines, "") + assert.Contains(t, combined, "persist-credentials: true", "keepCredentialsForPush should retain credentials") + assert.Contains(t, combined, "token: "+pushToken, "additional checkout should fall back to the push token") + assert.Equal(t, 1, strings.Count(combined, "token: "), "token must be emitted exactly once") + }) + + t.Run("additional checkout with explicit token does not override with pushToken", func(t *testing.T) { + cm := NewCheckoutManager([]*CheckoutConfig{ + {Repository: "owner/libs", Path: "./libs", GitHubToken: "${{ secrets.MY_TOKEN }}"}, + }) + cm.SetKeepCredentialsForPush(true) + cm.SetPushToken(pushToken) + lines := cm.GenerateAdditionalCheckoutSteps(getPin) + combined := strings.Join(lines, "") + assert.Contains(t, combined, "token: ${{ secrets.MY_TOKEN }}", "explicit checkout token should win") + assert.NotContains(t, combined, pushToken, "pushToken must not override an explicit checkout token") + assert.Equal(t, 1, strings.Count(combined, "token: "), "token must be emitted exactly once") + }) +} + // TestGenerateAdditionalCheckoutSteps verifies that non-default checkouts are emitted correctly. func TestGenerateAdditionalCheckoutSteps(t *testing.T) { getPin := func(action string) string { return action + "@v4" } diff --git a/pkg/workflow/checkout_step_generator.go b/pkg/workflow/checkout_step_generator.go index a2f1494c79e..3a95890ccb8 100644 --- a/pkg/workflow/checkout_step_generator.go +++ b/pkg/workflow/checkout_step_generator.go @@ -82,7 +82,7 @@ func (cm *CheckoutManager) GenerateAdditionalCheckoutSteps(getActionPin func(str if entry.key.path == "" && entry.key.repository == "" { continue } - lines = append(lines, generateCheckoutStepLines(entry, checkoutIndex, cm.keepCredentialsForPush, getActionPin)...) + lines = append(lines, generateCheckoutStepLines(entry, checkoutIndex, cm.keepCredentialsForPush, cm.pushToken, getActionPin)...) } checkoutManagerLog.Printf("Generated %d additional checkout step(s)", len(lines)) return lines @@ -323,6 +323,10 @@ func (cm *CheckoutManager) GenerateDefaultCheckoutStep( sb.WriteString(" persist-credentials: false\n") } + // Track whether a token has been written to the checkout step so the safe_outputs + // push-token fallback below does not double-emit. + tokenEmitted := false + // Apply trial mode overrides if trialMode { if trialLogicalRepoSlug != "" { @@ -330,6 +334,7 @@ func (cm *CheckoutManager) GenerateDefaultCheckoutStep( } effectiveToken := getEffectiveGitHubToken("") fmt.Fprintf(&sb, " token: %s\n", effectiveToken) + tokenEmitted = true } // Apply user overrides (only when NOT in trial mode to avoid conflicts) @@ -370,6 +375,7 @@ func (cm *CheckoutManager) GenerateDefaultCheckoutStep( } if effectiveOverrideToken != "" { fmt.Fprintf(&sb, " token: %s\n", effectiveOverrideToken) + tokenEmitted = true } if override.fetchDepth != nil { fmt.Fprintf(&sb, " fetch-depth: %d\n", *override.fetchDepth) @@ -388,6 +394,14 @@ func (cm *CheckoutManager) GenerateDefaultCheckoutStep( } } + // safe_outputs job: when no explicit token was written above, persist the resolved + // push token so the credential retained in .git/config matches the token the + // safe-output handlers use to fetch/push (avoiding both a wrong-token push and the + // duplicate Authorization header that a separate per-command extraheader would add). + if !trialMode && !tokenEmitted && cm.keepCredentialsForPush && cm.pushToken != "" { + fmt.Fprintf(&sb, " token: %s\n", cm.pushToken) + } + steps := []string{sb.String()} if override != nil && len(override.sparsePatterns) > 0 { steps = append(steps, generateSparseCheckoutPartialCloneResetStep("")) @@ -418,7 +432,7 @@ func (cm *CheckoutManager) GenerateDefaultCheckoutStep( // When keepCredentialsForPush is true (safe_outputs job), credentials are retained // (persist-credentials: true) and the post-checkout cleanup step is suppressed so a later // git fetch/push can authenticate. -func generateCheckoutStepLines(entry *resolvedCheckout, index int, keepCredentialsForPush bool, getActionPin func(string) string) []string { +func generateCheckoutStepLines(entry *resolvedCheckout, index int, keepCredentialsForPush bool, pushToken string, getActionPin func(string) string) []string { checkoutManagerLog.Printf("Generating checkout step lines: index=%d, repo=%q, path=%q, ref=%q, appAuth=%v", index, entry.key.repository, entry.key.path, entry.ref, entry.githubApp != nil) name := "Checkout " + checkoutStepName(entry.key) @@ -451,6 +465,12 @@ func generateCheckoutStepLines(entry *resolvedCheckout, index int, keepCredentia } // Determine effective token: github-app-minted token takes precedence effectiveToken := resolveCheckoutTokenExpression(entry, index, false) + // safe_outputs job: when this checkout declares no token/app of its own, persist the + // resolved push token so the retained .git/config credential matches the token the + // safe-output handlers use to fetch/push. + if effectiveToken == "" && keepCredentialsForPush && pushToken != "" { + effectiveToken = pushToken + } if effectiveToken != "" { fmt.Fprintf(&sb, " token: %s\n", effectiveToken) } diff --git a/pkg/workflow/compiler_safe_outputs_steps.go b/pkg/workflow/compiler_safe_outputs_steps.go index db5db02fb4e..cb6f5e49bb6 100644 --- a/pkg/workflow/compiler_safe_outputs_steps.go +++ b/pkg/workflow/compiler_safe_outputs_steps.go @@ -38,6 +38,15 @@ func (c *Compiler) buildSharedPRCheckoutSteps(data *WorkflowData) []string { // safe_outputs handler code (not the untrusted agent) is the only consumer. checkoutMgr.SetKeepCredentialsForPush(true) + // Persist the resolved PR push token (not just the default GITHUB_TOKEN) into + // .git/config so the retained credential matches the token the handlers use to + // fetch/push. This keeps a single, correct Authorization header on the wire and + // removes the need for the handlers to inject a separate http.extraheader. The + // same token is reused below for the "Configure Git credentials" step so both the + // persisted checkout credential and the push remote agree on a single token. + prCheckoutToken, _ := resolvePRCheckoutToken(data.SafeOutputs) + checkoutMgr.SetPushToken(prCheckoutToken) + // Combined condition: run the checkout/git-config steps only when a create_pull_request // or push_to_pull_request_branch output will be processed. condition := buildPRCheckoutCondition(data.SafeOutputs) @@ -64,9 +73,9 @@ func (c *Compiler) buildSharedPRCheckoutSteps(data *WorkflowData) []string { )...) // Configure Git credentials so the safe_outputs job can push. The agent job never - // pushes, so this step has no agent-job equivalent. - gitRemoteToken, _ := resolvePRCheckoutToken(data.SafeOutputs) - steps = append(steps, checkoutMgr.GenerateConfigureGitCredentialsSteps(gitRemoteToken, condition)...) + // pushes, so this step has no agent-job equivalent. Reuse the token resolved above so + // the push remote and the persisted checkout credential use the same token. + steps = append(steps, checkoutMgr.GenerateConfigureGitCredentialsSteps(prCheckoutToken, condition)...) consolidatedSafeOutputsStepsLog.Printf("Built shared PR checkout steps with condition: %s", condition.Render()) return steps