From 1d96f60f44bde912bfaafa56b879a2469082b438 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 26 Mar 2026 19:07:02 -0700 Subject: [PATCH 1/3] Add crossgen CI analysis agentic workflow --- .github/agents/agentic-workflows.agent.md | 102 +- .github/aw/actions-lock.json | 5 + .../workflows/crossgen2-ci-triage.lock.yml | 1226 +++++++++++++++++ .github/workflows/crossgen2-ci-triage.md | 257 ++++ 4 files changed, 1499 insertions(+), 91 deletions(-) create mode 100644 .github/workflows/crossgen2-ci-triage.lock.yml create mode 100644 .github/workflows/crossgen2-ci-triage.md diff --git a/.github/agents/agentic-workflows.agent.md b/.github/agents/agentic-workflows.agent.md index b8e305fc4628df..7ed300e00cc160 100644 --- a/.github/agents/agentic-workflows.agent.md +++ b/.github/agents/agentic-workflows.agent.md @@ -30,7 +30,7 @@ Workflows may optionally include: - Workflow files: `.github/workflows/*.md` and `.github/workflows/**/*.md` - Workflow lock files: `.github/workflows/*.lock.yml` - Shared components: `.github/workflows/shared/*.md` -- Configuration: https://github.com/github/gh-aw/blob/v0.63.0/.github/aw/github-agentic-workflows.md +- Configuration: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/github-agentic-workflows.md ## Problems This Solves @@ -52,7 +52,7 @@ When you interact with this agent, it will: ### Create New Workflow **Load when**: User wants to create a new workflow from scratch, add automation, or design a workflow that doesn't exist yet -**Prompt file**: https://github.com/github/gh-aw/blob/v0.63.0/.github/aw/create-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/create-agentic-workflow.md **Use cases**: - "Create a workflow that triages issues" @@ -62,7 +62,7 @@ When you interact with this agent, it will: ### Update Existing Workflow **Load when**: User wants to modify, improve, or refactor an existing workflow -**Prompt file**: https://github.com/github/gh-aw/blob/v0.63.0/.github/aw/update-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/update-agentic-workflow.md **Use cases**: - "Add web-fetch tool to the issue-classifier workflow" @@ -72,7 +72,7 @@ When you interact with this agent, it will: ### Debug Workflow **Load when**: User needs to investigate, audit, debug, or understand a workflow, troubleshoot issues, analyze logs, or fix errors -**Prompt file**: https://github.com/github/gh-aw/blob/v0.63.0/.github/aw/debug-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/debug-agentic-workflow.md **Use cases**: - "Why is this workflow failing?" @@ -82,7 +82,7 @@ When you interact with this agent, it will: ### Upgrade Agentic Workflows **Load when**: User wants to upgrade workflows to a new gh-aw version or fix deprecations -**Prompt file**: https://github.com/github/gh-aw/blob/v0.63.0/.github/aw/upgrade-agentic-workflows.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/upgrade-agentic-workflows.md **Use cases**: - "Upgrade all workflows to the latest version" @@ -92,7 +92,7 @@ When you interact with this agent, it will: ### Create a Report-Generating Workflow **Load when**: The workflow being created or updated produces reports — recurring status updates, audit summaries, analyses, or any structured output posted as a GitHub issue, discussion, or comment -**Prompt file**: https://github.com/github/gh-aw/blob/v0.63.0/.github/aw/report.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/report.md **Use cases**: - "Create a weekly CI health report" @@ -102,7 +102,7 @@ When you interact with this agent, it will: ### Create Shared Agentic Workflow **Load when**: User wants to create a reusable workflow component or wrap an MCP server -**Prompt file**: https://github.com/github/gh-aw/blob/v0.63.0/.github/aw/create-shared-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/create-shared-agentic-workflow.md **Use cases**: - "Create a shared component for Notion integration" @@ -112,7 +112,7 @@ When you interact with this agent, it will: ### Fix Dependabot PRs **Load when**: User needs to close or fix open Dependabot PRs that update dependencies in generated manifest files (`.github/workflows/package.json`, `.github/workflows/requirements.txt`, `.github/workflows/go.mod`) -**Prompt file**: https://github.com/github/gh-aw/blob/v0.63.0/.github/aw/dependabot.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/dependabot.md **Use cases**: - "Fix the open Dependabot PRs for npm dependencies" @@ -122,7 +122,7 @@ When you interact with this agent, it will: ### Analyze Test Coverage **Load when**: The workflow reads, analyzes, or reports test coverage — whether triggered by a PR, a schedule, or a slash command. Always consult this prompt before designing the coverage data strategy. -**Prompt file**: https://github.com/github/gh-aw/blob/v0.63.0/.github/aw/test-coverage.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/test-coverage.md **Use cases**: - "Create a workflow that comments coverage on PRs" @@ -169,90 +169,10 @@ gh aw compile --validate ## Important Notes -- Always reference the instructions file at https://github.com/github/gh-aw/blob/v0.63.0/.github/aw/github-agentic-workflows.md for complete documentation +- Always reference the instructions file at https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/github-agentic-workflows.md for complete documentation - Use the MCP tool `agentic-workflows` when running in GitHub Copilot Cloud - Workflows must be compiled to `.lock.yml` files before running in GitHub Actions - **Bash tools are enabled by default** - Don't restrict bash commands unnecessarily since workflows are sandboxed by the AWF - Follow security best practices: minimal permissions, explicit network access, no template injection -- **Network configuration**: Use ecosystem identifiers (`node`, `python`, `go`, etc.) or explicit FQDNs in `network.allowed`. Bare shorthands like `npm` or `pypi` are **not** valid. See https://github.com/github/gh-aw/blob/v0.63.0/.github/aw/network.md for the full list of valid ecosystem identifiers and domain patterns. +- **Network configuration**: Use ecosystem identifiers (`node`, `python`, `go`, etc.) or explicit FQDNs in `network.allowed`. Bare shorthands like `npm` or `pypi` are **not** valid. See https://github.com/github/gh-aw/blob/v0.64.2/.github/aw/network.md for the full list of valid ecosystem identifiers and domain patterns. - **Single-file output**: When creating a workflow, produce exactly **one** workflow `.md` file. Do not create separate documentation files (architecture docs, runbooks, usage guides, etc.). If documentation is needed, add a brief `## Usage` section inside the workflow file itself. - -## Repository-Specific Requirements: Copilot PAT Pool - -**⚠️ MANDATORY**: Every agentic workflow in this repository **must** include the `select-copilot-pat` integration. This selects a random Copilot PAT from a numbered pool of secrets to avoid rate-limiting from a single shared PAT. This is a stop-gap workaround until organization-level billing is offered for agentic workflows. - -These elements are **not supported through imports**, so they must be copied into the frontmatter of every agentic workflow. See `.github/actions/select-copilot-pat/README.md` for full documentation and `.github/workflows/copilot-echo.md` for a working example. - -When **creating** or **updating** an agentic workflow, always include the following three frontmatter blocks. These go between the `---` markers alongside the workflow's other frontmatter (permissions, safe-outputs, etc.). - -### Comment block (placed before the steps, inside the `on:` block) - -Always include this comment block before the steps to explain the PAT pool override: - -```yaml -# ############################################################### -# Override the COPILOT_GITHUB_TOKEN secret usage for the workflow -# with a randomly-selected token from a pool of secrets. -# -# As soon as organization-level billing is offered for Agentic -# Workflows, this stop-gap approach will be removed. -# -# See: /.github/actions/select-copilot-pat/README.md -# ############################################################### -``` - -### Block 1: Pre-activation steps (nested under `on:`) - -Add this under the `on:` key, at the same level as the trigger configuration, immediately after the comment block above: - -```yaml - # Add the pre-activation step of selecting a random PAT from the supplied secrets - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Checkout the select-copilot-pat action folder - with: - persist-credentials: false - sparse-checkout: .github/actions/select-copilot-pat - sparse-checkout-cone-mode: true - fetch-depth: 1 - - - id: select-copilot-pat - name: Select Copilot token from pool - uses: ./.github/actions/select-copilot-pat - env: - SECRET_0: ${{ secrets.COPILOT_PAT_0 }} - SECRET_1: ${{ secrets.COPILOT_PAT_1 }} - SECRET_2: ${{ secrets.COPILOT_PAT_2 }} - SECRET_3: ${{ secrets.COPILOT_PAT_3 }} - SECRET_4: ${{ secrets.COPILOT_PAT_4 }} - SECRET_5: ${{ secrets.COPILOT_PAT_5 }} - SECRET_6: ${{ secrets.COPILOT_PAT_6 }} - SECRET_7: ${{ secrets.COPILOT_PAT_7 }} - SECRET_8: ${{ secrets.COPILOT_PAT_8 }} - SECRET_9: ${{ secrets.COPILOT_PAT_9 }} -``` - -### Block 2: Pre-activation job outputs (top-level `jobs:`) - -```yaml -jobs: - pre-activation: - outputs: - copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }} -``` - -### Block 3: Engine configuration with PAT override (top-level `engine:`) - -```yaml -engine: - id: copilot - env: - # We cannot use line breaks in this expression as it leads to a syntax error in the compiled workflow - # If none of the `COPILOT_PAT_#` secrets were selected, then the default COPILOT_GITHUB_TOKEN is used - COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_PAT_0, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_PAT_1, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_PAT_2, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_PAT_3, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_PAT_4, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_PAT_5, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_PAT_6, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_PAT_7, needs.pre_activation.outputs.copilot_pat_number == '8', secrets.COPILOT_PAT_8, needs.pre_activation.outputs.copilot_pat_number == '9', secrets.COPILOT_PAT_9, secrets.COPILOT_GITHUB_TOKEN) }} -``` - -**Important notes about the engine block:** -- The `COPILOT_GITHUB_TOKEN` `case()` expression **must** remain on a single line — line breaks cause syntax errors in the compiled workflow. -- If no `COPILOT_PAT_#` secrets are configured, the expression falls back to the default `COPILOT_GITHUB_TOKEN` secret. -- Do **not** specify `engine: copilot` as a simple string — use the object form shown above so the `env:` override can be included. diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index 959efc4f8604ed..c19b6911647a53 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -14,6 +14,11 @@ "repo": "github/gh-aw-actions/setup", "version": "v0.63.1", "sha": "53e09ec0be6271e81a69f51ef93f37212c8834b0" + }, + "github/gh-aw-actions/setup@v0.64.2": { + "repo": "github/gh-aw-actions/setup", + "version": "v0.64.2", + "sha": "f22886a9607f5c27e79742a8bfc5faa34737138b" } } } diff --git a/.github/workflows/crossgen2-ci-triage.lock.yml b/.github/workflows/crossgen2-ci-triage.lock.yml new file mode 100644 index 00000000000000..7bf3bd0c517761 --- /dev/null +++ b/.github/workflows/crossgen2-ci-triage.lock.yml @@ -0,0 +1,1226 @@ +# ___ _ _ +# / _ \ | | (_) +# | |_| | __ _ ___ _ __ | |_ _ ___ +# | _ |/ _` |/ _ \ '_ \| __| |/ __| +# | | | | (_| | __/ | | | |_| | (__ +# \_| |_/\__, |\___|_| |_|\__|_|\___| +# __/ | +# _ _ |___/ +# | | | | / _| | +# | | | | ___ _ __ _ __| |_| | _____ ____ +# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| +# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ +# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ +# +# This file was automatically generated by gh-aw (v0.64.2). DO NOT EDIT. +# +# To update this file, edit the corresponding .md file and run: +# gh aw compile +# Not all edits will cause changes to this file. +# +# For more information: https://github.github.com/gh-aw/introduction/overview/ +# +# Daily triage of crossgen2 CI pipeline failures - analyzes builds, creates issues, and assigns Copilot to fix or disable failing tests +# +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"bc7ab7d15a655712927f8a98df48ffb24d1bfd5c771a0afe5013ab470dd750b1","compiler_version":"v0.64.2","strict":true,"agent_id":"copilot"} + +name: "Crossgen2 CI Failure Triage" +"on": + schedule: + - cron: "51 12 * * 1-5" + # Friendly format: daily on weekdays (scattered) + # steps: # Steps injected into pre-activation job + # - name: Checkout the select-copilot-pat action folder + # uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + # with: + # fetch-depth: 1 + # persist-credentials: false + # sparse-checkout: .github/actions/select-copilot-pat + # sparse-checkout-cone-mode: true + # - env: + # SECRET_0: ${{ secrets.COPILOT_PAT_0 }} + # SECRET_1: ${{ secrets.COPILOT_PAT_1 }} + # SECRET_2: ${{ secrets.COPILOT_PAT_2 }} + # SECRET_3: ${{ secrets.COPILOT_PAT_3 }} + # SECRET_4: ${{ secrets.COPILOT_PAT_4 }} + # SECRET_5: ${{ secrets.COPILOT_PAT_5 }} + # SECRET_6: ${{ secrets.COPILOT_PAT_6 }} + # SECRET_7: ${{ secrets.COPILOT_PAT_7 }} + # SECRET_8: ${{ secrets.COPILOT_PAT_8 }} + # SECRET_9: ${{ secrets.COPILOT_PAT_9 }} + # id: select-copilot-pat + # name: Select Copilot token from pool + # uses: ./.github/actions/select-copilot-pat + workflow_dispatch: + inputs: + aw_context: + default: "" + description: Agent caller context (used internally by Agentic Workflows). + required: false + type: string + +permissions: {} + +concurrency: + group: "gh-aw-${{ github.workflow }}" + +run-name: "Crossgen2 CI Failure Triage" + +jobs: + activation: + needs: pre_activation + if: needs.pre_activation.outputs.activated == 'true' + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + comment_id: "" + comment_repo: "" + lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} + model: ${{ steps.generate_aw_info.outputs.model }} + secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Generate agentic run info + id: generate_aw_info + env: + GH_AW_INFO_ENGINE_ID: "copilot" + GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" + GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'auto' }} + GH_AW_INFO_VERSION: "latest" + GH_AW_INFO_AGENT_VERSION: "latest" + GH_AW_INFO_CLI_VERSION: "v0.64.2" + GH_AW_INFO_WORKFLOW_NAME: "Crossgen2 CI Failure Triage" + GH_AW_INFO_EXPERIMENTAL: "false" + GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" + GH_AW_INFO_STAGED: "false" + GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","dev.azure.com","helix.dot.net","mihubot.xyz"]' + GH_AW_INFO_FIREWALL_ENABLED: "true" + GH_AW_INFO_AWF_VERSION: "v0.25.1" + GH_AW_INFO_AWMG_VERSION: "" + GH_AW_INFO_FIREWALL_TYPE: "squid" + GH_AW_COMPILED_STRICT: "true" + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); + await main(core, context); + - name: Validate COPILOT_GITHUB_TOKEN secret + id: validate-secret + run: ${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default + env: + COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_PAT_0, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_PAT_1, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_PAT_2, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_PAT_3, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_PAT_4, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_PAT_5, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_PAT_6, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_PAT_7, needs.pre_activation.outputs.copilot_pat_number == '8', secrets.COPILOT_PAT_8, needs.pre_activation.outputs.copilot_pat_number == '9', secrets.COPILOT_PAT_9, secrets.COPILOT_GITHUB_TOKEN) }} + - name: Checkout .github and .agents folders + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + sparse-checkout: | + .github + .agents + sparse-checkout-cone-mode: true + fetch-depth: 1 + - name: Check workflow file timestamps + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_WORKFLOW_FILE: "crossgen2-ci-triage.lock.yml" + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/check_workflow_timestamp_api.cjs'); + await main(); + - name: Create prompt with built-in context + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl + GH_AW_GITHUB_ACTOR: ${{ github.actor }} + GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} + GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} + GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} + GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + # poutine:ignore untrusted_checkout_exec + run: | + bash ${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh + { + cat << 'GH_AW_PROMPT_9da1e209676f482d_EOF' + + GH_AW_PROMPT_9da1e209676f482d_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/cache_memory_prompt.md" + cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" + cat << 'GH_AW_PROMPT_9da1e209676f482d_EOF' + + Tools: create_issue(max:10), missing_tool, missing_data, noop + + + The following GitHub context information is available for this workflow: + {{#if __GH_AW_GITHUB_ACTOR__ }} + - **actor**: __GH_AW_GITHUB_ACTOR__ + {{/if}} + {{#if __GH_AW_GITHUB_REPOSITORY__ }} + - **repository**: __GH_AW_GITHUB_REPOSITORY__ + {{/if}} + {{#if __GH_AW_GITHUB_WORKSPACE__ }} + - **workspace**: __GH_AW_GITHUB_WORKSPACE__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} + - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} + - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} + - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ + {{/if}} + {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} + - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ + {{/if}} + {{#if __GH_AW_GITHUB_RUN_ID__ }} + - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ + {{/if}} + + + GH_AW_PROMPT_9da1e209676f482d_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" + cat << 'GH_AW_PROMPT_9da1e209676f482d_EOF' + + GH_AW_PROMPT_9da1e209676f482d_EOF + cat << 'GH_AW_PROMPT_9da1e209676f482d_EOF' + {{#runtime-import .github/workflows/crossgen2-ci-triage.md}} + GH_AW_PROMPT_9da1e209676f482d_EOF + } > "$GH_AW_PROMPT" + - name: Interpolate variables and render templates + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/interpolate_prompt.cjs'); + await main(); + - name: Substitute placeholders + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_ALLOWED_EXTENSIONS: '' + GH_AW_CACHE_DESCRIPTION: '' + GH_AW_CACHE_DIR: '/tmp/gh-aw/cache-memory/' + GH_AW_GITHUB_ACTOR: ${{ github.actor }} + GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} + GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} + GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} + GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + + const substitutePlaceholders = require('${{ runner.temp }}/gh-aw/actions/substitute_placeholders.cjs'); + + // Call the substitution function + return await substitutePlaceholders({ + file: process.env.GH_AW_PROMPT, + substitutions: { + GH_AW_ALLOWED_EXTENSIONS: process.env.GH_AW_ALLOWED_EXTENSIONS, + GH_AW_CACHE_DESCRIPTION: process.env.GH_AW_CACHE_DESCRIPTION, + GH_AW_CACHE_DIR: process.env.GH_AW_CACHE_DIR, + GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, + GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, + GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, + GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, + GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, + GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, + GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, + GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE, + GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED + } + }); + - name: Validate prompt placeholders + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + # poutine:ignore untrusted_checkout_exec + run: bash ${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh + - name: Print prompt + env: + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + # poutine:ignore untrusted_checkout_exec + run: bash ${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh + - name: Upload activation artifact + if: success() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: activation + path: | + /tmp/gh-aw/aw_info.json + /tmp/gh-aw/aw-prompts/prompt.txt + retention-days: 1 + + agent: + needs: activation + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + issues: read + concurrency: + group: "gh-aw-copilot-${{ github.workflow }}" + env: + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + GH_AW_ASSETS_ALLOWED_EXTS: "" + GH_AW_ASSETS_BRANCH: "" + GH_AW_ASSETS_MAX_SIZE_KB: 0 + GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs + GH_AW_WORKFLOW_ID_SANITIZED: crossgen2citriage + outputs: + checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} + has_patch: ${{ steps.collect_output.outputs.has_patch }} + inference_access_error: ${{ steps.detect-inference-error.outputs.inference_access_error || 'false' }} + model: ${{ needs.activation.outputs.model }} + output: ${{ steps.collect_output.outputs.output }} + output_types: ${{ steps.collect_output.outputs.output_types }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Set runtime paths + id: set-runtime-paths + run: | + echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl" >> "$GITHUB_OUTPUT" + echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" >> "$GITHUB_OUTPUT" + echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json" >> "$GITHUB_OUTPUT" + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Create gh-aw temp directory + run: bash ${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh + - name: Configure gh CLI for GitHub Enterprise + run: bash ${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh + env: + GH_TOKEN: ${{ github.token }} + # Cache memory file share configuration from frontmatter processed below + - name: Create cache-memory directory + run: bash ${RUNNER_TEMP}/gh-aw/actions/create_cache_memory_dir.sh + - name: Restore cache-memory file share data + uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + key: memory-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} + path: /tmp/gh-aw/cache-memory + restore-keys: | + memory-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}- + - name: Configure Git credentials + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" + - name: Checkout PR branch + id: checkout-pr + if: | + github.event.pull_request || github.event.issue.pull_request + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + with: + github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs'); + await main(); + - name: Install GitHub Copilot CLI + run: ${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh latest + env: + GH_HOST: github.com + - name: Install AWF binary + run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.1 + - name: Determine automatic lockdown mode for GitHub MCP Server + id: determine-automatic-lockdown + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} + with: + script: | + const determineAutomaticLockdown = require('${{ runner.temp }}/gh-aw/actions/determine_automatic_lockdown.cjs'); + await determineAutomaticLockdown(github, context, core); + - name: Download container images + run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.1 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.1 ghcr.io/github/gh-aw-firewall/squid:0.25.1 ghcr.io/github/gh-aw-mcpg:v0.2.6 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine + - name: Write Safe Outputs Config + run: | + mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs + mkdir -p /tmp/gh-aw/safeoutputs + mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_ff440e9106c31114_EOF' + {"create_issue":{"assignees":["copilot"],"expires":720,"labels":["area-CodeGen-coreclr"],"max":10,"title_prefix":"[Crossgen2 CI] "},"mentions":{"enabled":false},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"}} + GH_AW_SAFE_OUTPUTS_CONFIG_ff440e9106c31114_EOF + - name: Write Safe Outputs Tools + run: | + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_4176a0d43c6caf3b_EOF' + { + "description_suffixes": { + "create_issue": " CONSTRAINTS: Maximum 10 issue(s) can be created. Title will be prefixed with \"[Crossgen2 CI] \". Labels [\"area-CodeGen-coreclr\"] will be automatically added. Assignees [\"copilot\"] will be automatically assigned." + }, + "repo_params": {}, + "dynamic_tools": [] + } + GH_AW_SAFE_OUTPUTS_TOOLS_META_4176a0d43c6caf3b_EOF + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_43914b81eb4dcd25_EOF' + { + "create_issue": { + "defaultMax": 1, + "fields": { + "body": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "labels": { + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 128 + }, + "parent": { + "issueOrPRNumber": true + }, + "repo": { + "type": "string", + "maxLength": 256 + }, + "temporary_id": { + "type": "string" + }, + "title": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 128 + } + } + }, + "missing_data": { + "defaultMax": 20, + "fields": { + "alternatives": { + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "context": { + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "data_type": { + "type": "string", + "sanitize": true, + "maxLength": 128 + }, + "reason": { + "type": "string", + "sanitize": true, + "maxLength": 256 + } + } + }, + "missing_tool": { + "defaultMax": 20, + "fields": { + "alternatives": { + "type": "string", + "sanitize": true, + "maxLength": 512 + }, + "reason": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "tool": { + "type": "string", + "sanitize": true, + "maxLength": 128 + } + } + }, + "noop": { + "defaultMax": 1, + "fields": { + "message": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + } + } + } + } + GH_AW_SAFE_OUTPUTS_VALIDATION_43914b81eb4dcd25_EOF + node ${RUNNER_TEMP}/gh-aw/actions/generate_safe_outputs_tools.cjs + - name: Generate Safe Outputs MCP Server Config + id: safe-outputs-config + run: | + # Generate a secure random API key (360 bits of entropy, 40+ chars) + # Mask immediately to prevent timing vulnerabilities + API_KEY=$(openssl rand -base64 45 | tr -d '/+=') + echo "::add-mask::${API_KEY}" + + PORT=3001 + + # Set outputs for next steps + { + echo "safe_outputs_api_key=${API_KEY}" + echo "safe_outputs_port=${PORT}" + } >> "$GITHUB_OUTPUT" + + echo "Safe Outputs MCP server will run on port ${PORT}" + + - name: Start Safe Outputs MCP HTTP Server + id: safe-outputs-start + env: + DEBUG: '*' + GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }} + GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }} + GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/tools.json + GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json + GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs + run: | + # Environment variables are set above to prevent template injection + export DEBUG + export GH_AW_SAFE_OUTPUTS_PORT + export GH_AW_SAFE_OUTPUTS_API_KEY + export GH_AW_SAFE_OUTPUTS_TOOLS_PATH + export GH_AW_SAFE_OUTPUTS_CONFIG_PATH + export GH_AW_MCP_LOG_DIR + + bash ${RUNNER_TEMP}/gh-aw/actions/start_safe_outputs_server.sh + + - name: Start MCP Gateway + id: start-mcp-gateway + env: + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} + GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} + GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }} + GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }} + GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + run: | + set -eo pipefail + mkdir -p /tmp/gh-aw/mcp-config + + # Export gateway environment variables for MCP config and gateway script + export MCP_GATEWAY_PORT="80" + export MCP_GATEWAY_DOMAIN="host.docker.internal" + MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') + echo "::add-mask::${MCP_GATEWAY_API_KEY}" + export MCP_GATEWAY_API_KEY + export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads" + mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}" + export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288" + export DEBUG="*" + + export GH_AW_ENGINE="copilot" + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.6' + + mkdir -p /home/runner/.copilot + cat << GH_AW_MCP_CONFIG_0749bad54f9020cf_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh + { + "mcpServers": { + "github": { + "type": "stdio", + "container": "ghcr.io/github/github-mcp-server:v0.32.0", + "env": { + "GITHUB_HOST": "\${GITHUB_SERVER_URL}", + "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", + "GITHUB_READ_ONLY": "1", + "GITHUB_TOOLSETS": "context,repos,issues,pull_requests,actions,search" + }, + "guard-policies": { + "allow-only": { + "min-integrity": "$GITHUB_MCP_GUARD_MIN_INTEGRITY", + "repos": "$GITHUB_MCP_GUARD_REPOS" + } + } + }, + "safeoutputs": { + "type": "http", + "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", + "headers": { + "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" + }, + "guard-policies": { + "write-sink": { + "accept": [ + "*" + ] + } + } + } + }, + "gateway": { + "port": $MCP_GATEWAY_PORT, + "domain": "${MCP_GATEWAY_DOMAIN}", + "apiKey": "${MCP_GATEWAY_API_KEY}", + "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" + } + } + GH_AW_MCP_CONFIG_0749bad54f9020cf_EOF + - name: Download activation artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: activation + path: /tmp/gh-aw + - name: Clean git credentials + continue-on-error: true + run: bash ${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh + - name: Execute GitHub Copilot CLI + id: agentic_execution + # Copilot CLI tool arguments (sorted): + timeout-minutes: 30 + run: | + set -o pipefail + touch /tmp/gh-aw/agent-step-summary.md + # shellcheck disable=SC1003 + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dev.azure.com,github.com,helix.dot.net,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,mihubot.xyz,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.1 --skip-pull --enable-api-proxy \ + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-all-tools --add-dir /tmp/gh-aw/cache-memory/ --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + env: + COPILOT_AGENT_RUNNER_TYPE: STANDALONE + COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_PAT_0, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_PAT_1, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_PAT_2, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_PAT_3, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_PAT_4, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_PAT_5, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_PAT_6, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_PAT_7, needs.pre_activation.outputs.copilot_pat_number == '8', secrets.COPILOT_PAT_8, needs.pre_activation.outputs.copilot_pat_number == '9', secrets.COPILOT_PAT_9, secrets.COPILOT_GITHUB_TOKEN) }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} + GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json + GH_AW_PHASE: agent + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + GH_AW_VERSION: v0.64.2 + GITHUB_API_URL: ${{ github.api_url }} + GITHUB_AW: true + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + GITHUB_REF_NAME: ${{ github.ref_name }} + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md + GITHUB_WORKSPACE: ${{ github.workspace }} + GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_AUTHOR_NAME: github-actions[bot] + GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_COMMITTER_NAME: github-actions[bot] + XDG_CONFIG_HOME: /home/runner + - name: Detect inference access error + id: detect-inference-error + if: always() + continue-on-error: true + run: bash ${RUNNER_TEMP}/gh-aw/actions/detect_inference_access_error.sh + - name: Configure Git credentials + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git config --global am.keepcr true + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" + - name: Copy Copilot session state files to logs + if: always() + continue-on-error: true + run: | + # Copy Copilot session state files to logs folder for artifact collection + # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them + SESSION_STATE_DIR="$HOME/.copilot/session-state" + LOGS_DIR="/tmp/gh-aw/sandbox/agent/logs" + + if [ -d "$SESSION_STATE_DIR" ]; then + echo "Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR" + mkdir -p "$LOGS_DIR" + cp -v "$SESSION_STATE_DIR"/*.jsonl "$LOGS_DIR/" 2>/dev/null || true + echo "Session state files copied successfully" + else + echo "No session-state directory found at $SESSION_STATE_DIR" + fi + - name: Stop MCP Gateway + if: always() + continue-on-error: true + env: + MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} + MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} + GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }} + run: | + bash ${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh "$GATEWAY_PID" + - name: Redact secrets in logs + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs'); + await main(); + env: + GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,COPILOT_PAT_0,COPILOT_PAT_1,COPILOT_PAT_2,COPILOT_PAT_3,COPILOT_PAT_4,COPILOT_PAT_5,COPILOT_PAT_6,COPILOT_PAT_7,COPILOT_PAT_8,COPILOT_PAT_9,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' + SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + SECRET_COPILOT_PAT_0: ${{ secrets.COPILOT_PAT_0 }} + SECRET_COPILOT_PAT_1: ${{ secrets.COPILOT_PAT_1 }} + SECRET_COPILOT_PAT_2: ${{ secrets.COPILOT_PAT_2 }} + SECRET_COPILOT_PAT_3: ${{ secrets.COPILOT_PAT_3 }} + SECRET_COPILOT_PAT_4: ${{ secrets.COPILOT_PAT_4 }} + SECRET_COPILOT_PAT_5: ${{ secrets.COPILOT_PAT_5 }} + SECRET_COPILOT_PAT_6: ${{ secrets.COPILOT_PAT_6 }} + SECRET_COPILOT_PAT_7: ${{ secrets.COPILOT_PAT_7 }} + SECRET_COPILOT_PAT_8: ${{ secrets.COPILOT_PAT_8 }} + SECRET_COPILOT_PAT_9: ${{ secrets.COPILOT_PAT_9 }} + SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} + SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} + SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Append agent step summary + if: always() + run: bash ${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh + - name: Copy Safe Outputs + if: always() + env: + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + run: | + mkdir -p /tmp/gh-aw + cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true + - name: Ingest agent output + id: collect_output + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} + GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dev.azure.com,github.com,helix.dot.net,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,mihubot.xyz,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GH_AW_ALLOWED_GITHUB_REFS: "" + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_API_URL: ${{ github.api_url }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/collect_ndjson_output.cjs'); + await main(); + - name: Parse agent logs for step summary + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_copilot_log.cjs'); + await main(); + - name: Parse MCP Gateway logs for step summary + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_mcp_gateway_log.cjs'); + await main(); + - name: Print firewall logs + if: always() + continue-on-error: true + env: + AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs + run: | + # Fix permissions on firewall logs so they can be uploaded as artifacts + # AWF runs with sudo, creating files owned by root + sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true + # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step) + if command -v awf &> /dev/null; then + awf logs summary | tee -a "$GITHUB_STEP_SUMMARY" + else + echo 'AWF binary not installed, skipping firewall log summary' + fi + - name: Write agent output placeholder if missing + if: always() + run: | + if [ ! -f /tmp/gh-aw/agent_output.json ]; then + echo '{"items":[]}' > /tmp/gh-aw/agent_output.json + fi + - name: Upload cache-memory data as artifact + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + if: always() + with: + name: cache-memory + path: /tmp/gh-aw/cache-memory + - name: Upload agent artifacts + if: always() + continue-on-error: true + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: agent + path: | + /tmp/gh-aw/aw-prompts/prompt.txt + /tmp/gh-aw/sandbox/agent/logs/ + /tmp/gh-aw/redacted-urls.log + /tmp/gh-aw/mcp-logs/ + /tmp/gh-aw/agent-stdio.log + /tmp/gh-aw/agent/ + /tmp/gh-aw/safeoutputs.jsonl + /tmp/gh-aw/agent_output.json + /tmp/gh-aw/aw-*.patch + if-no-files-found: ignore + - name: Upload firewall audit logs + if: always() + continue-on-error: true + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: firewall-audit-logs + path: | + /tmp/gh-aw/sandbox/firewall/logs/ + /tmp/gh-aw/sandbox/firewall/audit/ + if-no-files-found: ignore + + conclusion: + needs: + - activation + - agent + - detection + - safe_outputs + - update_cache_memory + if: always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true') + runs-on: ubuntu-slim + permissions: + contents: read + issues: write + concurrency: + group: "gh-aw-conclusion-crossgen2-ci-triage" + cancel-in-progress: false + outputs: + noop_message: ${{ steps.noop.outputs.noop_message }} + tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} + total_count: ${{ steps.missing_tool.outputs.total_count }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Download agent output artifact + id: download-agent-output + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Setup agent output environment variable + id: setup-agent-output-env + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + - name: Process No-Op Messages + id: noop + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_NOOP_MAX: "1" + GH_AW_WORKFLOW_NAME: "Crossgen2 CI Failure Triage" + GH_AW_TRACKER_ID: "crossgen2-ci-triage" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/noop.cjs'); + await main(); + - name: Record Missing Tool + id: missing_tool + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Crossgen2 CI Failure Triage" + GH_AW_TRACKER_ID: "crossgen2-ci-triage" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/missing_tool.cjs'); + await main(); + - name: Handle Agent Failure + id: handle_agent_failure + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Crossgen2 CI Failure Triage" + GH_AW_TRACKER_ID: "crossgen2-ci-triage" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} + GH_AW_WORKFLOW_ID: "crossgen2-ci-triage" + GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} + GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} + GH_AW_ASSIGN_COPILOT_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.assign_copilot_failure_count }} + GH_AW_ASSIGN_COPILOT_ERRORS: ${{ needs.safe_outputs.outputs.assign_copilot_errors }} + GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }} + GH_AW_GROUP_REPORTS: "false" + GH_AW_FAILURE_REPORT_AS_ISSUE: "true" + GH_AW_TIMEOUT_MINUTES: "30" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs'); + await main(); + - name: Handle No-Op Message + id: handle_noop_message + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Crossgen2 CI Failure Triage" + GH_AW_TRACKER_ID: "crossgen2-ci-triage" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} + GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }} + GH_AW_NOOP_REPORT_AS_ISSUE: "true" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_noop_message.cjs'); + await main(); + + detection: + needs: agent + if: always() && needs.agent.result != 'skipped' + runs-on: ubuntu-latest + outputs: + detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} + detection_success: ${{ steps.detection_conclusion.outputs.success }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Download agent output artifact + id: download-agent-output + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Setup agent output environment variable + id: setup-agent-output-env + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + # --- Threat Detection --- + - name: Download container images + run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.1 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.1 ghcr.io/github/gh-aw-firewall/squid:0.25.1 + - name: Check if detection needed + id: detection_guard + if: always() + env: + OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }} + HAS_PATCH: ${{ needs.agent.outputs.has_patch }} + run: | + if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then + echo "run_detection=true" >> "$GITHUB_OUTPUT" + echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH" + else + echo "run_detection=false" >> "$GITHUB_OUTPUT" + echo "Detection skipped: no agent outputs or patches to analyze" + fi + - name: Clear MCP configuration for detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + rm -f /tmp/gh-aw/mcp-config/mcp-servers.json + rm -f /home/runner/.copilot/mcp-config.json + rm -f "$GITHUB_WORKSPACE/.gemini/settings.json" + - name: Prepare threat detection files + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection/aw-prompts + cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true + cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true + for f in /tmp/gh-aw/aw-*.patch; do + [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true + done + echo "Prepared threat detection files:" + ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true + - name: Setup threat detection + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + WORKFLOW_NAME: "Crossgen2 CI Failure Triage" + WORKFLOW_DESCRIPTION: "Daily triage of crossgen2 CI pipeline failures - analyzes builds, creates issues, and assigns Copilot to fix or disable failing tests" + HAS_PATCH: ${{ needs.agent.outputs.has_patch }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/setup_threat_detection.cjs'); + await main(); + - name: Ensure threat-detection directory and log + if: always() && steps.detection_guard.outputs.run_detection == 'true' + run: | + mkdir -p /tmp/gh-aw/threat-detection + touch /tmp/gh-aw/threat-detection/detection.log + - name: Install GitHub Copilot CLI + run: ${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh latest + env: + GH_HOST: github.com + - name: Install AWF binary + run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.1 + - name: Execute GitHub Copilot CLI + if: always() && steps.detection_guard.outputs.run_detection == 'true' + id: detection_agentic_execution + # Copilot CLI tool arguments (sorted): + timeout-minutes: 20 + run: | + set -o pipefail + touch /tmp/gh-aw/agent-step-summary.md + # shellcheck disable=SC1003 + sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,telemetry.enterprise.githubcopilot.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.1 --skip-pull --enable-api-proxy \ + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + env: + COPILOT_AGENT_RUNNER_TYPE: STANDALONE + COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_PAT_0, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_PAT_1, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_PAT_2, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_PAT_3, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_PAT_4, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_PAT_5, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_PAT_6, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_PAT_7, needs.pre_activation.outputs.copilot_pat_number == '8', secrets.COPILOT_PAT_8, needs.pre_activation.outputs.copilot_pat_number == '9', secrets.COPILOT_PAT_9, secrets.COPILOT_GITHUB_TOKEN) }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} + GH_AW_PHASE: detection + GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_VERSION: v0.64.2 + GITHUB_API_URL: ${{ github.api_url }} + GITHUB_AW: true + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_REF_NAME: ${{ github.ref_name }} + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md + GITHUB_WORKSPACE: ${{ github.workspace }} + GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_AUTHOR_NAME: github-actions[bot] + GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com + GIT_COMMITTER_NAME: github-actions[bot] + XDG_CONFIG_HOME: /home/runner + - name: Upload threat detection log + if: always() && steps.detection_guard.outputs.run_detection == 'true' + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: detection + path: /tmp/gh-aw/threat-detection/detection.log + if-no-files-found: ignore + - name: Parse and conclude threat detection + id: detection_conclusion + if: always() + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} + with: + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs'); + await main(); + + pre_activation: + runs-on: ubuntu-slim + outputs: + activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }} + copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }} + matched_command: '' + select-copilot-pat_result: ${{ steps.select-copilot-pat.outcome }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Check team membership for workflow + id: check_membership + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_REQUIRED_ROLES: "admin,maintainer,write" + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/check_membership.cjs'); + await main(); + - name: Checkout the select-copilot-pat action folder + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 1 + persist-credentials: false + sparse-checkout: .github/actions/select-copilot-pat + sparse-checkout-cone-mode: true + - name: Select Copilot token from pool + id: select-copilot-pat + uses: ./.github/actions/select-copilot-pat + env: + SECRET_0: ${{ secrets.COPILOT_PAT_0 }} + SECRET_1: ${{ secrets.COPILOT_PAT_1 }} + SECRET_2: ${{ secrets.COPILOT_PAT_2 }} + SECRET_3: ${{ secrets.COPILOT_PAT_3 }} + SECRET_4: ${{ secrets.COPILOT_PAT_4 }} + SECRET_5: ${{ secrets.COPILOT_PAT_5 }} + SECRET_6: ${{ secrets.COPILOT_PAT_6 }} + SECRET_7: ${{ secrets.COPILOT_PAT_7 }} + SECRET_8: ${{ secrets.COPILOT_PAT_8 }} + SECRET_9: ${{ secrets.COPILOT_PAT_9 }} + + safe_outputs: + needs: + - agent + - detection + if: (!cancelled()) && needs.agent.result != 'skipped' && needs.detection.result == 'success' + runs-on: ubuntu-slim + permissions: + contents: read + issues: write + timeout-minutes: 15 + env: + GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/crossgen2-ci-triage" + GH_AW_ENGINE_ID: "copilot" + GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }} + GH_AW_TRACKER_ID: "crossgen2-ci-triage" + GH_AW_WORKFLOW_ID: "crossgen2-ci-triage" + GH_AW_WORKFLOW_NAME: "Crossgen2 CI Failure Triage" + outputs: + assign_copilot_errors: ${{ steps.assign_copilot_to_created_issues.outputs.assign_copilot_errors }} + assign_copilot_failure_count: ${{ steps.assign_copilot_to_created_issues.outputs.assign_copilot_failure_count }} + code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} + code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} + create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }} + create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} + created_issue_number: ${{ steps.process_safe_outputs.outputs.created_issue_number }} + created_issue_url: ${{ steps.process_safe_outputs.outputs.created_issue_url }} + process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} + process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Download agent output artifact + id: download-agent-output + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: agent + path: /tmp/gh-aw/ + - name: Setup agent output environment variable + id: setup-agent-output-env + if: steps.download-agent-output.outcome == 'success' + run: | + mkdir -p /tmp/gh-aw/ + find "/tmp/gh-aw/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" + - name: Configure GH_HOST for enterprise compatibility + id: ghes-host-config + shell: bash + run: | + # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct + # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op. + GH_HOST="${GITHUB_SERVER_URL#https://}" + GH_HOST="${GH_HOST#http://}" + echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" + - name: Process Safe Outputs + id: process_safe_outputs + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} + GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dev.azure.com,github.com,helix.dot.net,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,mihubot.xyz,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_API_URL: ${{ github.api_url }} + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"assignees\":[\"copilot\"],\"expires\":720,\"labels\":[\"area-CodeGen-coreclr\"],\"max\":10,\"title_prefix\":\"[Crossgen2 CI] \"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"}}" + GH_AW_ASSIGN_COPILOT: "true" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs'); + await main(); + - name: Assign Copilot to created issues + id: assign_copilot_to_created_issues + if: steps.process_safe_outputs.outputs.issues_to_assign_copilot != '' + continue-on-error: true + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_ISSUES_TO_ASSIGN_COPILOT: ${{ steps.process_safe_outputs.outputs.issues_to_assign_copilot }} + with: + github-token: ${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('${{ runner.temp }}/gh-aw/actions/assign_copilot_to_created_issues.cjs'); + await main(); + - name: Upload Safe Output Items + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 + with: + name: safe-output-items + path: /tmp/gh-aw/safe-output-items.jsonl + if-no-files-found: ignore + + update_cache_memory: + needs: + - agent + - detection + if: always() && needs.detection.result == 'success' + runs-on: ubuntu-latest + permissions: {} + env: + GH_AW_WORKFLOW_ID_SANITIZED: crossgen2citriage + steps: + - name: Setup Scripts + uses: github/gh-aw-actions/setup@f22886a9607f5c27e79742a8bfc5faa34737138b # v0.64.2 + with: + destination: ${{ runner.temp }}/gh-aw/actions + - name: Download cache-memory artifact (default) + id: download_cache_default + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + continue-on-error: true + with: + name: cache-memory + path: /tmp/gh-aw/cache-memory + - name: Check if cache-memory folder has content (default) + id: check_cache_default + shell: bash + run: | + if [ -d "/tmp/gh-aw/cache-memory" ] && [ "$(ls -A /tmp/gh-aw/cache-memory 2>/dev/null)" ]; then + echo "has_content=true" >> "$GITHUB_OUTPUT" + else + echo "has_content=false" >> "$GITHUB_OUTPUT" + fi + - name: Save cache-memory to cache (default) + if: steps.check_cache_default.outputs.has_content == 'true' + uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + key: memory-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} + path: /tmp/gh-aw/cache-memory + diff --git a/.github/workflows/crossgen2-ci-triage.md b/.github/workflows/crossgen2-ci-triage.md new file mode 100644 index 00000000000000..590b432c663311 --- /dev/null +++ b/.github/workflows/crossgen2-ci-triage.md @@ -0,0 +1,257 @@ +--- +description: "Daily triage of crossgen2 CI pipeline failures - analyzes builds, creates issues, and assigns Copilot to fix or disable failing tests" + +on: + schedule: daily on weekdays + workflow_dispatch: + + # ############################################################### + # Override the COPILOT_GITHUB_TOKEN secret usage for the workflow + # with a randomly-selected token from a pool of secrets. + # + # As soon as organization-level billing is offered for Agentic + # Workflows, this stop-gap approach will be removed. + # + # See: /.github/actions/select-copilot-pat/README.md + # ############################################################### + + # Add the pre-activation step of selecting a random PAT from the supplied secrets + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + name: Checkout the select-copilot-pat action folder + with: + persist-credentials: false + sparse-checkout: .github/actions/select-copilot-pat + sparse-checkout-cone-mode: true + fetch-depth: 1 + + - id: select-copilot-pat + name: Select Copilot token from pool + uses: ./.github/actions/select-copilot-pat + env: + SECRET_0: ${{ secrets.COPILOT_PAT_0 }} + SECRET_1: ${{ secrets.COPILOT_PAT_1 }} + SECRET_2: ${{ secrets.COPILOT_PAT_2 }} + SECRET_3: ${{ secrets.COPILOT_PAT_3 }} + SECRET_4: ${{ secrets.COPILOT_PAT_4 }} + SECRET_5: ${{ secrets.COPILOT_PAT_5 }} + SECRET_6: ${{ secrets.COPILOT_PAT_6 }} + SECRET_7: ${{ secrets.COPILOT_PAT_7 }} + SECRET_8: ${{ secrets.COPILOT_PAT_8 }} + SECRET_9: ${{ secrets.COPILOT_PAT_9 }} + +# Add the pre-activation output of the randomly selected PAT +jobs: + pre-activation: + outputs: + copilot_pat_number: ${{ steps.select-copilot-pat.outputs.copilot_pat_number }} + +# Override the COPILOT_GITHUB_TOKEN expression used in the activation job +# Consume the PAT number from the pre-activation step and select the corresponding secret +engine: + id: copilot + env: + # We cannot use line breaks in this expression as it leads to a syntax error in the compiled workflow + # If none of the `COPILOT_PAT_#` secrets were selected, then the default COPILOT_GITHUB_TOKEN is used + COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_PAT_0, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_PAT_1, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_PAT_2, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_PAT_3, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_PAT_4, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_PAT_5, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_PAT_6, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_PAT_7, needs.pre_activation.outputs.copilot_pat_number == '8', secrets.COPILOT_PAT_8, needs.pre_activation.outputs.copilot_pat_number == '9', secrets.COPILOT_PAT_9, secrets.COPILOT_GITHUB_TOKEN) }} + +timeout-minutes: 30 + +permissions: + contents: read + issues: read + actions: read + +tools: + github: + toolsets: [default, actions, search] + web-fetch: + cache-memory: true + +network: + allowed: + - defaults + - dev.azure.com + - helix.dot.net + - mihubot.xyz + +safe-outputs: + mentions: false + allowed-github-references: [] + create-issue: + max: 10 + assignees: [copilot] + labels: [area-CodeGen-coreclr] + title-prefix: "[Crossgen2 CI] " + expires: 30 + noop: + +tracker-id: crossgen2-ci-triage +--- + +# Crossgen2 CI Failure Triage + +You are an automated CI triage agent for the dotnet/runtime repository. Your job is to analyze recent failures in crossgen2-related CI pipelines, identify new unknown test failures, and create actionable GitHub issues assigned to Copilot Coding Agent. + +## Target Pipelines + +Analyze failures from these Azure DevOps pipelines (org: `dnceng-public`, project: `public`): + +1. `runtime-coreclr crossgen2` +2. `runtime-coreclr crossgen2-composite` +3. `runtime-coreclr crossgen2 outerloop` +4. `runtime-coreclr crossgen2-composite gcstress` + +## Step 1: Discover Failed Builds + +Query Azure DevOps for builds completed in the last 48 hours (to cover weekends on Monday) that have failures. + +For each target pipeline: + +1. **Look up the pipeline definition ID**: + ``` + curl -s "https://dev.azure.com/dnceng-public/public/_apis/build/definitions?name=&api-version=7.0" + ``` + Extract the `id` field from the response. + +2. **Query failed builds** using the definition ID: + ``` + curl -s "https://dev.azure.com/dnceng-public/public/_apis/build/builds?definitions=&minTime=&resultFilter=failed&statusFilter=completed&branchName=refs/heads/main&api-version=7.0" + ``` + Use the current UTC time minus 48 hours for `minTime` in ISO 8601 format. + +3. **Collect build IDs** for all failed builds across all four pipelines. + +If no failed builds are found across any pipeline, call the `noop` safe output with a message explaining that no crossgen2 pipeline failures were found in the last 48 hours. + +## Step 2: Analyze Each Failed Build + +For each failed build, use the CI Analysis skill script: + +```bash +pwsh .github/skills/ci-analysis/scripts/Get-CIStatus.ps1 -BuildId -ShowLogs -SearchMihuBot -ContinueOnError +``` + +From the output, extract: +- **Failed job names** and their error categories +- **Failed test names** and error messages +- **Helix work item details** (test names, error snippets, console logs) +- **Known issue matches** from Build Analysis +- **The `[CI_ANALYSIS_SUMMARY]` JSON block** for structured analysis + +### Filtering Known Issues + +Skip failures that are already matched to known issues by Build Analysis. Focus only on **unknown/untracked failures** — these are the ones that need new issues. + +### Check Cache Memory + +Read from `cache-memory` a file named `triaged-builds.json` (if it exists). This contains build IDs and failure signatures that have already been triaged. Skip any failures that match entries in this file. + +## Step 3: Search for Existing Issues + +For each unknown failure, search GitHub for existing issues that might already track it: + +1. **Search by test name**: Use GitHub search to find open issues mentioning the failing test name in `dotnet/runtime`: + - Search with the test class name and method name + - Check issues with labels `area-CodeGen-coreclr` or `Known Build Error` + +2. **Search by error signature**: If the test name search yields no results, search for distinctive parts of the error message. + +3. **Check MihuBot results**: The CI analysis script with `-SearchMihuBot` may have already found related issues — use those results. + +If an existing open issue already tracks the failure, skip creating a new one. Note the existing issue number in your analysis. + +## Step 4: Create Issues for New Failures + +For each genuinely new, untracked failure, create a GitHub issue using the `create-issue` safe output. + +### Assess Fix Complexity + +Before creating the issue, assess whether the failure looks **simply solvable**: + +**Simply solvable** (instruct Copilot to fix the root cause): +- An assertion message clearly indicates what value was expected vs actual +- A null reference exception with an obvious missing null check +- A simple type mismatch or casting error +- A race condition with an obvious synchronization fix +- The error message directly points to the fix + +**Not simply solvable** (instruct Copilot to disable the test): +- Complex logic failures requiring deep domain knowledge +- Intermittent/flaky failures without clear reproduction pattern +- Failures related to infrastructure or environment issues +- Crashes or timeouts without clear root cause +- Failures that require understanding complex crossgen2 internals + +### Issue Format + +Create issues with the following structure: + +**Title**: A concise description of the failing test (the `[Crossgen2 CI]` prefix is added automatically) + +**Body**: + +```markdown +### Failure Details + +- **Pipeline**: +- **Build**: [](https://dev.azure.com/dnceng-public/public/_build/results?buildId=) +- **Test**: `` +- **Configuration**: +- **Error Category**: + +### Error Output + +
+Error details + +\`\`\` + +\`\`\` + +
+ +### Helix Details + +- **Job**: +- **Work Item**: +- **Console Log**: + +### Recommended Action + + + +**Option A (simple fix):** +The failure appears to be straightforward to fix. Please investigate and fix the root cause: +- +- + +**Option B (disable test):** +This failure requires deeper investigation. Please disable the failing test by adding an `[ActiveIssue]` attribute referencing this issue: +- Locate the test method or test class +- Add `[ActiveIssue("https://github.com/dotnet/runtime/issues/ISSUE_NUMBER")]` attribute +- If the test is in a `.csproj` with crossgen2-specific conditions, the disable may need to target specific configurations +``` + +For Option B (disabling tests), provide specific guidance: +- If you can identify the test source file path, mention it +- Suggest the correct `[ActiveIssue]` attribute syntax +- Note which configurations to disable for (e.g., only crossgen2, only specific OS) + +## Step 5: Update Cache Memory + +After processing all builds, write the updated `triaged-builds.json` to `cache-memory` with: +- Build IDs that were analyzed +- Failure signatures (test name + error category) that were triaged +- Timestamp of this triage run + +Use filesystem-safe timestamp format `YYYY-MM-DD-HH-MM-SS` (no colons). + +## Important Guidelines + +- **Do not create duplicate issues.** Always search thoroughly before creating. +- **Do not create issues for known/tracked failures.** If Build Analysis has already matched a failure to a known issue, skip it. +- **Be conservative with "simple fix" assessments.** When in doubt, instruct Copilot to disable the test rather than attempt a fix. +- **Include enough context in issues** for Copilot Coding Agent to act without further investigation. +- **Group related failures.** If the same test fails across multiple pipelines or configurations, create a single issue covering all occurrences. +- If there are no new unknown failures to report, call the `noop` safe output explaining what you analyzed and that all failures are either known or already tracked. From 5441c9c3cc5a633c4af177511e64c5fe9073f67e Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 26 Mar 2026 19:41:20 -0700 Subject: [PATCH 2/3] Use Opus --- .../workflows/crossgen2-ci-triage.lock.yml | 42 +++++++++---------- .github/workflows/crossgen2-ci-triage.md | 1 + 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/.github/workflows/crossgen2-ci-triage.lock.yml b/.github/workflows/crossgen2-ci-triage.lock.yml index 7bf3bd0c517761..86527134d96882 100644 --- a/.github/workflows/crossgen2-ci-triage.lock.yml +++ b/.github/workflows/crossgen2-ci-triage.lock.yml @@ -22,7 +22,7 @@ # # Daily triage of crossgen2 CI pipeline failures - analyzes builds, creates issues, and assigns Copilot to fix or disable failing tests # -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"bc7ab7d15a655712927f8a98df48ffb24d1bfd5c771a0afe5013ab470dd750b1","compiler_version":"v0.64.2","strict":true,"agent_id":"copilot"} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"d5063c47392525950416b9d1f3a7c25be9e52de2e0fa7d3555921fa969d07b5b","compiler_version":"v0.64.2","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.6"} name: "Crossgen2 CI Failure Triage" "on": @@ -89,7 +89,7 @@ jobs: env: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" - GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'auto' }} + GH_AW_INFO_MODEL: "claude-opus-4.6" GH_AW_INFO_VERSION: "latest" GH_AW_INFO_AGENT_VERSION: "latest" GH_AW_INFO_CLI_VERSION: "v0.64.2" @@ -150,15 +150,15 @@ jobs: run: | bash ${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh { - cat << 'GH_AW_PROMPT_9da1e209676f482d_EOF' + cat << 'GH_AW_PROMPT_8b5caa7cf197bc86_EOF' - GH_AW_PROMPT_9da1e209676f482d_EOF + GH_AW_PROMPT_8b5caa7cf197bc86_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/cache_memory_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_9da1e209676f482d_EOF' + cat << 'GH_AW_PROMPT_8b5caa7cf197bc86_EOF' Tools: create_issue(max:10), missing_tool, missing_data, noop @@ -190,14 +190,14 @@ jobs: {{/if}} - GH_AW_PROMPT_9da1e209676f482d_EOF + GH_AW_PROMPT_8b5caa7cf197bc86_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_9da1e209676f482d_EOF' + cat << 'GH_AW_PROMPT_8b5caa7cf197bc86_EOF' - GH_AW_PROMPT_9da1e209676f482d_EOF - cat << 'GH_AW_PROMPT_9da1e209676f482d_EOF' + GH_AW_PROMPT_8b5caa7cf197bc86_EOF + cat << 'GH_AW_PROMPT_8b5caa7cf197bc86_EOF' {{#runtime-import .github/workflows/crossgen2-ci-triage.md}} - GH_AW_PROMPT_9da1e209676f482d_EOF + GH_AW_PROMPT_8b5caa7cf197bc86_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 @@ -373,12 +373,12 @@ jobs: mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_ff440e9106c31114_EOF' + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_00522bd93e262eb1_EOF' {"create_issue":{"assignees":["copilot"],"expires":720,"labels":["area-CodeGen-coreclr"],"max":10,"title_prefix":"[Crossgen2 CI] "},"mentions":{"enabled":false},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"}} - GH_AW_SAFE_OUTPUTS_CONFIG_ff440e9106c31114_EOF + GH_AW_SAFE_OUTPUTS_CONFIG_00522bd93e262eb1_EOF - name: Write Safe Outputs Tools run: | - cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_4176a0d43c6caf3b_EOF' + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_04f171aca78a4b9b_EOF' { "description_suffixes": { "create_issue": " CONSTRAINTS: Maximum 10 issue(s) can be created. Title will be prefixed with \"[Crossgen2 CI] \". Labels [\"area-CodeGen-coreclr\"] will be automatically added. Assignees [\"copilot\"] will be automatically assigned." @@ -386,8 +386,8 @@ jobs: "repo_params": {}, "dynamic_tools": [] } - GH_AW_SAFE_OUTPUTS_TOOLS_META_4176a0d43c6caf3b_EOF - cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_43914b81eb4dcd25_EOF' + GH_AW_SAFE_OUTPUTS_TOOLS_META_04f171aca78a4b9b_EOF + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_3bfef588d8637126_EOF' { "create_issue": { "defaultMax": 1, @@ -480,7 +480,7 @@ jobs: } } } - GH_AW_SAFE_OUTPUTS_VALIDATION_43914b81eb4dcd25_EOF + GH_AW_SAFE_OUTPUTS_VALIDATION_3bfef588d8637126_EOF node ${RUNNER_TEMP}/gh-aw/actions/generate_safe_outputs_tools.cjs - name: Generate Safe Outputs MCP Server Config id: safe-outputs-config @@ -548,7 +548,7 @@ jobs: export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.6' mkdir -p /home/runner/.copilot - cat << GH_AW_MCP_CONFIG_0749bad54f9020cf_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh + cat << GH_AW_MCP_CONFIG_6cb382831404933d_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh { "mcpServers": { "github": { @@ -589,7 +589,7 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_0749bad54f9020cf_EOF + GH_AW_MCP_CONFIG_6cb382831404933d_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -611,7 +611,7 @@ jobs: env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_PAT_0, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_PAT_1, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_PAT_2, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_PAT_3, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_PAT_4, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_PAT_5, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_PAT_6, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_PAT_7, needs.pre_activation.outputs.copilot_pat_number == '8', secrets.COPILOT_PAT_8, needs.pre_activation.outputs.copilot_pat_number == '9', secrets.COPILOT_PAT_9, secrets.COPILOT_GITHUB_TOKEN) }} - COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} + COPILOT_MODEL: claude-opus-4.6 GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt @@ -1010,7 +1010,7 @@ jobs: env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_PAT_0, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_PAT_1, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_PAT_2, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_PAT_3, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_PAT_4, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_PAT_5, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_PAT_6, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_PAT_7, needs.pre_activation.outputs.copilot_pat_number == '8', secrets.COPILOT_PAT_8, needs.pre_activation.outputs.copilot_pat_number == '9', secrets.COPILOT_PAT_9, secrets.COPILOT_GITHUB_TOKEN) }} - COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} + COPILOT_MODEL: claude-opus-4.6 GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_VERSION: v0.64.2 @@ -1105,7 +1105,7 @@ jobs: env: GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/crossgen2-ci-triage" GH_AW_ENGINE_ID: "copilot" - GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }} + GH_AW_ENGINE_MODEL: "claude-opus-4.6" GH_AW_TRACKER_ID: "crossgen2-ci-triage" GH_AW_WORKFLOW_ID: "crossgen2-ci-triage" GH_AW_WORKFLOW_NAME: "Crossgen2 CI Failure Triage" diff --git a/.github/workflows/crossgen2-ci-triage.md b/.github/workflows/crossgen2-ci-triage.md index 590b432c663311..f7d2b07273df24 100644 --- a/.github/workflows/crossgen2-ci-triage.md +++ b/.github/workflows/crossgen2-ci-triage.md @@ -50,6 +50,7 @@ jobs: # Consume the PAT number from the pre-activation step and select the corresponding secret engine: id: copilot + model: claude-opus-4.6 env: # We cannot use line breaks in this expression as it leads to a syntax error in the compiled workflow # If none of the `COPILOT_PAT_#` secrets were selected, then the default COPILOT_GITHUB_TOKEN is used From 0c1a22455697d8365c0d81e393f8249e3973e25b Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 30 Mar 2026 16:40:05 -0700 Subject: [PATCH 3/3] Fix DIFC integrity filtering and improve issue quality in crossgen2 CI triage - Add min-integrity: none to tools.github so the agent can read all dotnet/runtime issues regardless of author association (fixes false positive 'new' issues when existing issues were invisible) - Require specific fully qualified test names and verbatim error output in created issues instead of summaries - Add pull-requests: read permission to fix compilation warning - Recompile lock.yml Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/aw/actions-lock.json | 20 +++++++ .../workflows/crossgen2-ci-triage.lock.yml | 59 +++++++++---------- .github/workflows/crossgen2-ci-triage.md | 37 ++++++++++-- 3 files changed, 81 insertions(+), 35 deletions(-) diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index c19b6911647a53..1cd3695af0529a 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -1,10 +1,30 @@ { "entries": { + "actions/cache/restore@v5.0.4": { + "repo": "actions/cache/restore", + "version": "v5.0.4", + "sha": "668228422ae6a00e4ad889ee87cd7109ec5666a7" + }, + "actions/cache/save@v5.0.4": { + "repo": "actions/cache/save", + "version": "v5.0.4", + "sha": "668228422ae6a00e4ad889ee87cd7109ec5666a7" + }, + "actions/download-artifact@v8.0.1": { + "repo": "actions/download-artifact", + "version": "v8.0.1", + "sha": "3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c" + }, "actions/github-script@v8": { "repo": "actions/github-script", "version": "v8", "sha": "ed597411d8f924073f98dfc5c65a23a2325f34cd" }, + "actions/upload-artifact@v7": { + "repo": "actions/upload-artifact", + "version": "v7", + "sha": "bbbca2ddaa5d8feaa63e36b76fdaad77386f024f" + }, "github/gh-aw-actions/setup@v0.63.0": { "repo": "github/gh-aw-actions/setup", "version": "v0.63.0", diff --git a/.github/workflows/crossgen2-ci-triage.lock.yml b/.github/workflows/crossgen2-ci-triage.lock.yml index 86527134d96882..db03d9c5f946f0 100644 --- a/.github/workflows/crossgen2-ci-triage.lock.yml +++ b/.github/workflows/crossgen2-ci-triage.lock.yml @@ -22,7 +22,7 @@ # # Daily triage of crossgen2 CI pipeline failures - analyzes builds, creates issues, and assigns Copilot to fix or disable failing tests # -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"d5063c47392525950416b9d1f3a7c25be9e52de2e0fa7d3555921fa969d07b5b","compiler_version":"v0.64.2","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.6"} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"d44a5e48fa6b2fc3f700bf3858f0bf05e8b9ca09bbdc310eb664b57cfc672c5e","compiler_version":"v0.64.2","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.6"} name: "Crossgen2 CI Failure Triage" "on": @@ -150,15 +150,15 @@ jobs: run: | bash ${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh { - cat << 'GH_AW_PROMPT_8b5caa7cf197bc86_EOF' + cat << 'GH_AW_PROMPT_cbb12d0a2eefb802_EOF' - GH_AW_PROMPT_8b5caa7cf197bc86_EOF + GH_AW_PROMPT_cbb12d0a2eefb802_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/cache_memory_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_8b5caa7cf197bc86_EOF' + cat << 'GH_AW_PROMPT_cbb12d0a2eefb802_EOF' Tools: create_issue(max:10), missing_tool, missing_data, noop @@ -190,14 +190,14 @@ jobs: {{/if}} - GH_AW_PROMPT_8b5caa7cf197bc86_EOF + GH_AW_PROMPT_cbb12d0a2eefb802_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_8b5caa7cf197bc86_EOF' + cat << 'GH_AW_PROMPT_cbb12d0a2eefb802_EOF' - GH_AW_PROMPT_8b5caa7cf197bc86_EOF - cat << 'GH_AW_PROMPT_8b5caa7cf197bc86_EOF' + GH_AW_PROMPT_cbb12d0a2eefb802_EOF + cat << 'GH_AW_PROMPT_cbb12d0a2eefb802_EOF' {{#runtime-import .github/workflows/crossgen2-ci-triage.md}} - GH_AW_PROMPT_8b5caa7cf197bc86_EOF + GH_AW_PROMPT_cbb12d0a2eefb802_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 @@ -277,6 +277,7 @@ jobs: actions: read contents: read issues: read + pull-requests: read concurrency: group: "gh-aw-copilot-${{ github.workflow }}" env: @@ -356,16 +357,12 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.25.1 - - name: Determine automatic lockdown mode for GitHub MCP Server - id: determine-automatic-lockdown - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + - name: Parse integrity filter lists + id: parse-guard-vars env: - GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} - GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} - with: - script: | - const determineAutomaticLockdown = require('${{ runner.temp }}/gh-aw/actions/determine_automatic_lockdown.cjs'); - await determineAutomaticLockdown(github, context, core); + GH_AW_BLOCKED_USERS_VAR: ${{ vars.GH_AW_GITHUB_BLOCKED_USERS || '' }} + GH_AW_APPROVAL_LABELS_VAR: ${{ vars.GH_AW_GITHUB_APPROVAL_LABELS || '' }} + run: bash ${RUNNER_TEMP}/gh-aw/actions/parse_guard_list.sh - name: Download container images run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.25.1 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.1 ghcr.io/github/gh-aw-firewall/squid:0.25.1 ghcr.io/github/gh-aw-mcpg:v0.2.6 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine - name: Write Safe Outputs Config @@ -373,12 +370,12 @@ jobs: mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_00522bd93e262eb1_EOF' + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_4a4a87ef2c599b25_EOF' {"create_issue":{"assignees":["copilot"],"expires":720,"labels":["area-CodeGen-coreclr"],"max":10,"title_prefix":"[Crossgen2 CI] "},"mentions":{"enabled":false},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"}} - GH_AW_SAFE_OUTPUTS_CONFIG_00522bd93e262eb1_EOF + GH_AW_SAFE_OUTPUTS_CONFIG_4a4a87ef2c599b25_EOF - name: Write Safe Outputs Tools run: | - cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_04f171aca78a4b9b_EOF' + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_33af0b75731912b2_EOF' { "description_suffixes": { "create_issue": " CONSTRAINTS: Maximum 10 issue(s) can be created. Title will be prefixed with \"[Crossgen2 CI] \". Labels [\"area-CodeGen-coreclr\"] will be automatically added. Assignees [\"copilot\"] will be automatically assigned." @@ -386,8 +383,8 @@ jobs: "repo_params": {}, "dynamic_tools": [] } - GH_AW_SAFE_OUTPUTS_TOOLS_META_04f171aca78a4b9b_EOF - cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_3bfef588d8637126_EOF' + GH_AW_SAFE_OUTPUTS_TOOLS_META_33af0b75731912b2_EOF + cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_e5513dbdb514de38_EOF' { "create_issue": { "defaultMax": 1, @@ -480,7 +477,7 @@ jobs: } } } - GH_AW_SAFE_OUTPUTS_VALIDATION_3bfef588d8637126_EOF + GH_AW_SAFE_OUTPUTS_VALIDATION_e5513dbdb514de38_EOF node ${RUNNER_TEMP}/gh-aw/actions/generate_safe_outputs_tools.cjs - name: Generate Safe Outputs MCP Server Config id: safe-outputs-config @@ -526,8 +523,6 @@ jobs: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} - GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }} - GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }} GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} run: | set -eo pipefail @@ -548,7 +543,7 @@ jobs: export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.6' mkdir -p /home/runner/.copilot - cat << GH_AW_MCP_CONFIG_6cb382831404933d_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh + cat << GH_AW_MCP_CONFIG_4fe7628130205168_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh { "mcpServers": { "github": { @@ -562,8 +557,10 @@ jobs: }, "guard-policies": { "allow-only": { - "min-integrity": "$GITHUB_MCP_GUARD_MIN_INTEGRITY", - "repos": "$GITHUB_MCP_GUARD_REPOS" + "approval-labels": ${{ steps.parse-guard-vars.outputs.approval_labels }}, + "blocked-users": ${{ steps.parse-guard-vars.outputs.blocked_users }}, + "min-integrity": "none", + "repos": "all" } } }, @@ -589,7 +586,7 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_6cb382831404933d_EOF + GH_AW_MCP_CONFIG_4fe7628130205168_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -782,6 +779,8 @@ jobs: /tmp/gh-aw/sandbox/agent/logs/ /tmp/gh-aw/redacted-urls.log /tmp/gh-aw/mcp-logs/ + /tmp/gh-aw/proxy-logs/ + !/tmp/gh-aw/proxy-logs/proxy-tls/ /tmp/gh-aw/agent-stdio.log /tmp/gh-aw/agent/ /tmp/gh-aw/safeoutputs.jsonl diff --git a/.github/workflows/crossgen2-ci-triage.md b/.github/workflows/crossgen2-ci-triage.md index f7d2b07273df24..203153c7f2ba22 100644 --- a/.github/workflows/crossgen2-ci-triage.md +++ b/.github/workflows/crossgen2-ci-triage.md @@ -62,10 +62,12 @@ permissions: contents: read issues: read actions: read + pull-requests: read tools: github: toolsets: [default, actions, search] + min-integrity: none web-fetch: cache-memory: true @@ -133,13 +135,16 @@ For each failed build, use the CI Analysis skill script: pwsh .github/skills/ci-analysis/scripts/Get-CIStatus.ps1 -BuildId -ShowLogs -SearchMihuBot -ContinueOnError ``` -From the output, extract: +From the output, extract and preserve: - **Failed job names** and their error categories -- **Failed test names** and error messages -- **Helix work item details** (test names, error snippets, console logs) +- **Specific test names**: Fully qualified test class and method names (e.g., `System.Net.Security.Tests.SslStreamTest.ConnectAsync_InvalidCertificate_Throws`) +- **Error messages and stack traces**: Copy exact error text from the CI output — these go directly into issue bodies +- **Helix work item details**: Work item names, error snippets, and console log URLs - **Known issue matches** from Build Analysis - **The `[CI_ANALYSIS_SUMMARY]` JSON block** for structured analysis +**IMPORTANT**: Do not summarize or paraphrase error output. Copy the actual error messages, assertion failures, and stack traces verbatim from the CI analysis output. Issues must contain enough concrete detail for someone to understand the failure without re-running CI analysis. + ### Filtering Known Issues Skip failures that are already matched to known issues by Build Analysis. Focus only on **unknown/untracked failures** — these are the ones that need new issues. @@ -197,17 +202,35 @@ Create issues with the following structure: - **Pipeline**: - **Build**: [](https://dev.azure.com/dnceng-public/public/_build/results?buildId=) -- **Test**: `` +- **Failed Tests**: List each failing test with its fully qualified name - **Configuration**: - **Error Category**: +### Failing Tests + +List each failing test individually with its fully qualified name: + +| Test Name | Platform | Error Type | +|-----------|----------|------------| +| `Namespace.Class.Method` | linux-x64 | AssertionError / Timeout / Crash / etc. | + ### Error Output +Include the **actual error messages and stack traces** from the CI analysis output. +Do NOT write "Helix console logs are not accessible" — instead include whatever error +text the CI analysis script DID return (assertion messages, exit codes, error lines). +
Error details \`\`\` - + \`\`\`
@@ -253,6 +276,10 @@ Use filesystem-safe timestamp format `YYYY-MM-DD-HH-MM-SS` (no colons). - **Do not create duplicate issues.** Always search thoroughly before creating. - **Do not create issues for known/tracked failures.** If Build Analysis has already matched a failure to a known issue, skip it. - **Be conservative with "simple fix" assessments.** When in doubt, instruct Copilot to disable the test rather than attempt a fix. +- **Include specific test names and real error output in every issue.** Each issue MUST contain: + - Fully qualified test names (not just work item names like "GC" — drill into the specific test methods) + - Actual error messages, assertion text, or stack traces copied from the CI analysis output + - Do NOT say "Helix console logs are not accessible without authentication" as a substitute for error details. The CI analysis script already extracts error information — use it. - **Include enough context in issues** for Copilot Coding Agent to act without further investigation. - **Group related failures.** If the same test fails across multiple pipelines or configurations, create a single issue covering all occurrences. - If there are no new unknown failures to report, call the `noop` safe output explaining what you analyzed and that all failures are either known or already tracked.