From 430713e9c67a468cc7d9d526fbe8fdedb7d99877 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 11 Jun 2026 11:28:05 +0000
Subject: [PATCH] Remove all GitHub Agentic Workflow files
---
.github/aw/actions-lock.json | 14 -
.github/workflows/auto-merge.yaml | 100 --
.github/workflows/ci-doctor.lock.yml | 1477 ------------------
.github/workflows/ci-doctor.md | 161 --
.github/workflows/code-review.lock.yml | 1360 ----------------
.github/workflows/code-review.md | 131 --
.github/workflows/compile-workflows.yaml | 46 -
.github/workflows/dependency-update.lock.yml | 1308 ----------------
.github/workflows/dependency-update.md | 131 --
.github/workflows/pr-fix.lock.yml | 1342 ----------------
10 files changed, 6070 deletions(-)
delete mode 100644 .github/aw/actions-lock.json
delete mode 100644 .github/workflows/auto-merge.yaml
delete mode 100644 .github/workflows/ci-doctor.lock.yml
delete mode 100644 .github/workflows/ci-doctor.md
delete mode 100644 .github/workflows/code-review.lock.yml
delete mode 100644 .github/workflows/code-review.md
delete mode 100644 .github/workflows/compile-workflows.yaml
delete mode 100644 .github/workflows/dependency-update.lock.yml
delete mode 100644 .github/workflows/dependency-update.md
delete mode 100644 .github/workflows/pr-fix.lock.yml
diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json
deleted file mode 100644
index 6007057..0000000
--- a/.github/aw/actions-lock.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "entries": {
- "actions/github-script@v8": {
- "repo": "actions/github-script",
- "version": "v8",
- "sha": "ed597411d8f924073f98dfc5c65a23a2325f34cd"
- },
- "github/gh-aw/actions/setup@v0.50.7": {
- "repo": "github/gh-aw/actions/setup",
- "version": "v0.50.7",
- "sha": "9cbca3cd9be433a23a38e4da332635097fd40251"
- }
- }
-}
diff --git a/.github/workflows/auto-merge.yaml b/.github/workflows/auto-merge.yaml
deleted file mode 100644
index a6b9fa6..0000000
--- a/.github/workflows/auto-merge.yaml
+++ /dev/null
@@ -1,100 +0,0 @@
-name: Auto-merge automation PRs
-
-on:
- # Trigger when CI checks complete on PRs
- pull_request:
- types: [opened, synchronize, labeled]
- # Also trigger when check suites complete
- check_suite:
- types: [completed]
-
-permissions:
- contents: write
- pull-requests: write
-
-jobs:
- auto-merge:
- name: Auto-merge
- runs-on: ubuntu-latest
- # Only run for PRs created by agentic workflows (labeled "automation")
- if: >-
- (github.event_name == 'pull_request' &&
- contains(github.event.pull_request.labels.*.name, 'automation')) ||
- github.event_name == 'check_suite'
-
- steps:
- - name: Enable auto-merge for automation PRs
- uses: actions/github-script@v7
- with:
- script: |
- // Find the PR number depending on the trigger event
- let prNumber;
- if (context.eventName === 'pull_request') {
- prNumber = context.payload.pull_request.number;
- } else if (context.eventName === 'check_suite') {
- // Find PRs associated with this check suite
- const prs = context.payload.check_suite.pull_requests;
- if (!prs || prs.length === 0) {
- console.log('No PRs associated with this check suite');
- return;
- }
- prNumber = prs[0].number;
- }
-
- if (!prNumber) {
- console.log('No PR number found');
- return;
- }
-
- // Get the PR details
- const { data: pr } = await github.rest.pulls.get({
- owner: context.repo.owner,
- repo: context.repo.repo,
- pull_number: prNumber,
- });
-
- // Only auto-merge PRs with the "automation" label
- const hasAutomationLabel = pr.labels.some(l => l.name === 'automation');
- if (!hasAutomationLabel) {
- console.log(`PR #${prNumber} does not have the "automation" label, skipping`);
- return;
- }
-
- // Check if all CI checks have passed
- const { data: checks } = await github.rest.checks.listForRef({
- owner: context.repo.owner,
- repo: context.repo.repo,
- ref: pr.head.sha,
- });
-
- const pending = checks.check_runs.filter(c =>
- c.name !== 'Auto-merge' && c.status !== 'completed'
- );
- const failed = checks.check_runs.filter(c =>
- c.name !== 'Auto-merge' && c.status === 'completed' && c.conclusion !== 'success' && c.conclusion !== 'skipped'
- );
-
- if (pending.length > 0) {
- console.log(`PR #${prNumber} has ${pending.length} pending checks, will retry when they complete`);
- return;
- }
-
- if (failed.length > 0) {
- console.log(`PR #${prNumber} has ${failed.length} failed checks, not merging:`);
- failed.forEach(c => console.log(` - ${c.name}: ${c.conclusion}`));
- return;
- }
-
- // All checks passed — merge the PR
- console.log(`All checks passed for PR #${prNumber}, merging...`);
- try {
- await github.rest.pulls.merge({
- owner: context.repo.owner,
- repo: context.repo.repo,
- pull_number: prNumber,
- merge_method: 'merge',
- });
- console.log(`PR #${prNumber} merged successfully`);
- } catch (error) {
- console.log(`Failed to merge PR #${prNumber}: ${error.message}`);
- }
diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml
deleted file mode 100644
index d9f07c9..0000000
--- a/.github/workflows/ci-doctor.lock.yml
+++ /dev/null
@@ -1,1477 +0,0 @@
-#
-# ___ _ _
-# / _ \ | | (_)
-# | |_| | __ _ ___ _ __ | |_ _ ___
-# | _ |/ _` |/ _ \ '_ \| __| |/ __|
-# | | | | (_| | __/ | | | |_| | (__
-# \_| |_/\__, |\___|_| |_|\__|_|\___|
-# __/ |
-# _ _ |___/
-# | | | | / _| |
-# | | | | ___ _ __ _ __| |_| | _____ ____
-# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___|
-# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
-# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
-#
-# This file was automatically generated by gh-aw (v0.50.7). 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/
-#
-# Monitors the CI workflow and automatically investigates failures. Analyzes
-# logs to identify root causes, checks for patterns in past failures, and
-# either creates a fix PR directly or opens an issue with detailed diagnosis.
-# Assigns the maintainer only when manual intervention is truly needed.
-#
-# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"1302df0c6620280a3d77f0b7b2090bfbc431028291954806b5294bc7df869a85","compiler_version":"v0.50.7"}
-
-name: "CI Failure Doctor"
-"on":
- workflow_run:
- # zizmor: ignore[dangerous-triggers] - workflow_run trigger is secured with role and fork validation
- branches:
- - main
- types:
- - completed
- workflows:
- - CI
-
-permissions: {}
-
-concurrency:
- group: "gh-aw-${{ github.workflow }}"
-
-run-name: "CI Failure Doctor"
-
-jobs:
- activation:
- needs: pre_activation
- # zizmor: ignore[dangerous-triggers] - workflow_run trigger is secured with role and fork validation
- if: >
- ((needs.pre_activation.outputs.activated == 'true') && (github.event.workflow_run.conclusion == 'failure')) &&
- ((github.event_name != 'workflow_run') || ((github.event.workflow_run.repository.id == github.repository_id) &&
- (!(github.event.workflow_run.repository.fork))))
- runs-on: ubuntu-slim
- permissions:
- contents: read
- outputs:
- comment_id: ""
- comment_repo: ""
- secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
- steps:
- - name: Setup Scripts
- uses: github/gh-aw/actions/setup@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Validate ANTHROPIC_API_KEY secret
- id: validate-secret
- run: /opt/gh-aw/actions/validate_multi_secret.sh ANTHROPIC_API_KEY 'Claude Code' https://github.github.com/gh-aw/reference/engines/#anthropic-claude-code
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- - name: Validate context variables
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/validate_context_variables.cjs');
- await main();
- - name: Checkout .github and .agents folders
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- sparse-checkout: |
- .github
- .agents
- fetch-depth: 1
- persist-credentials: false
- - name: Check workflow file timestamps
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_WORKFLOW_FILE: "ci-doctor.lock.yml"
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: ${{ env.GH_AW_SAFE_OUTPUTS }}
- 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_EVENT_WORKFLOW_RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HTML_URL: ${{ github.event.workflow_run.html_url }}
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_RUN_NUMBER: ${{ github.event.workflow_run.run_number }}
- GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
- GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
- GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
- run: |
- bash /opt/gh-aw/actions/create_prompt_first.sh
- {
- cat << 'GH_AW_PROMPT_EOF'
-
- GH_AW_PROMPT_EOF
- cat "/opt/gh-aw/prompts/xpia.md"
- cat "/opt/gh-aw/prompts/temp_folder_prompt.md"
- cat "/opt/gh-aw/prompts/markdown.md"
- cat "/opt/gh-aw/prompts/cache_memory_prompt.md"
- cat "/opt/gh-aw/prompts/safe_outputs_prompt.md"
- cat << 'GH_AW_PROMPT_EOF'
-
- Tools: add_comment, create_issue, create_pull_request, push_to_pull_request_branch, missing_tool, missing_data, noop
- GH_AW_PROMPT_EOF
- cat "/opt/gh-aw/prompts/safe_outputs_create_pull_request.md"
- cat "/opt/gh-aw/prompts/safe_outputs_push_to_pr_branch.md"
- cat << 'GH_AW_PROMPT_EOF'
-
-
- 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_EOF
- cat << 'GH_AW_PROMPT_EOF'
-
- GH_AW_PROMPT_EOF
- cat << 'GH_AW_PROMPT_EOF'
- {{#runtime-import .github/workflows/ci-doctor.md}}
- GH_AW_PROMPT_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
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HTML_URL: ${{ github.event.workflow_run.html_url }}
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_RUN_NUMBER: ${{ github.event.workflow_run.run_number }}
- GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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_EVENT_WORKFLOW_RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HTML_URL: ${{ github.event.workflow_run.html_url }}
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_RUN_NUMBER: ${{ github.event.workflow_run.run_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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
-
- const substitutePlaceholders = require('/opt/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_EVENT_WORKFLOW_RUN_CONCLUSION: process.env.GH_AW_GITHUB_EVENT_WORKFLOW_RUN_CONCLUSION,
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HEAD_SHA: process.env.GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HEAD_SHA,
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HTML_URL: process.env.GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HTML_URL,
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_ID: process.env.GH_AW_GITHUB_EVENT_WORKFLOW_RUN_ID,
- GH_AW_GITHUB_EVENT_WORKFLOW_RUN_RUN_NUMBER: process.env.GH_AW_GITHUB_EVENT_WORKFLOW_RUN_RUN_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
- run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh
- - name: Print prompt
- env:
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- run: bash /opt/gh-aw/actions/print_prompt_summary.sh
- - name: Upload prompt artifact
- if: success()
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: prompt
- path: /tmp/gh-aw/aw-prompts/prompt.txt
- retention-days: 1
-
- agent:
- needs: activation
- runs-on: ubuntu-latest
- permissions: read-all
- concurrency:
- group: "gh-aw-claude-${{ 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_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl
- GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json
- GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json
- GH_AW_WORKFLOW_ID_SANITIZED: cidoctor
- outputs:
- checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
- detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}
- detection_success: ${{ steps.detection_conclusion.outputs.success }}
- has_patch: ${{ steps.collect_output.outputs.has_patch }}
- model: ${{ steps.generate_aw_info.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@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Checkout repository
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- persist-credentials: false
- - name: Create gh-aw temp directory
- run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.sh
- # Cache memory file share configuration from frontmatter processed below
- - name: Create cache-memory directory
- run: bash /opt/gh-aw/actions/create_cache_memory_dir.sh
- - name: Restore cache-memory file share data
- uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
- 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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs');
- await main();
- - name: Generate agentic run info
- id: generate_aw_info
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const fs = require('fs');
-
- const awInfo = {
- engine_id: "claude",
- engine_name: "Claude Code",
- model: process.env.GH_AW_MODEL_AGENT_CLAUDE || "",
- version: "",
- agent_version: "2.1.62",
- cli_version: "v0.50.7",
- workflow_name: "CI Failure Doctor",
- experimental: false,
- supports_tools_allowlist: true,
- run_id: context.runId,
- run_number: context.runNumber,
- run_attempt: process.env.GITHUB_RUN_ATTEMPT,
- repository: context.repo.owner + '/' + context.repo.repo,
- ref: context.ref,
- sha: context.sha,
- actor: context.actor,
- event_name: context.eventName,
- staged: false,
- allowed_domains: ["defaults"],
- firewall_enabled: true,
- awf_version: "v0.23.0",
- awmg_version: "v0.1.6",
- steps: {
- firewall: "squid"
- },
- created_at: new Date().toISOString()
- };
-
- // Write to /tmp/gh-aw directory to avoid inclusion in PR
- const tmpPath = '/tmp/gh-aw/aw_info.json';
- fs.writeFileSync(tmpPath, JSON.stringify(awInfo, null, 2));
- console.log('Generated aw_info.json at:', tmpPath);
- console.log(JSON.stringify(awInfo, null, 2));
-
- // Set model as output for reuse in other steps/jobs
- core.setOutput('model', awInfo.model);
- - name: Setup Node.js
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
- with:
- node-version: '24'
- package-manager-cache: false
- - name: Install awf binary
- run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0
- - name: Install Claude Code CLI
- run: npm install -g --silent @anthropic-ai/claude-code@2.1.62
- - 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('/opt/gh-aw/actions/determine_automatic_lockdown.cjs');
- await determineAutomaticLockdown(github, context, core);
- - name: Download container images
- run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.6 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine
- - name: Write Safe Outputs Config
- run: |
- mkdir -p /opt/gh-aw/safeoutputs
- mkdir -p /tmp/gh-aw/safeoutputs
- mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
- cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF'
- {"add_comment":{"max":1},"create_issue":{"max":1},"create_pull_request":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1},"push_to_pull_request_branch":{"max":0}}
- GH_AW_SAFE_OUTPUTS_CONFIG_EOF
- cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF'
- [
- {
- "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[CI Fix] \". Labels [automation ci-failure] will be automatically added. Assignees [imjasonh] will be automatically assigned.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "body": {
- "description": "Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.",
- "type": "string"
- },
- "labels": {
- "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "parent": {
- "description": "Parent issue number for creating sub-issues. This is the numeric ID from the GitHub URL (e.g., 42 in github.com/owner/repo/issues/42). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from a previously created issue in the same workflow run.",
- "type": [
- "number",
- "string"
- ]
- },
- "temporary_id": {
- "description": "Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 3 to 8 alphanumeric characters (e.g., 'aw_abc1', 'aw_Test123'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.",
- "pattern": "^aw_[A-Za-z0-9]{3,8}$",
- "type": "string"
- },
- "title": {
- "description": "Concise issue title summarizing the bug, feature, or task. The title appears as the main heading, so keep it brief and descriptive.",
- "type": "string"
- }
- },
- "required": [
- "title",
- "body"
- ],
- "type": "object"
- },
- "name": "create_issue"
- },
- {
- "description": "Add a comment to an existing GitHub issue, pull request, or discussion. Use this to provide feedback, answer questions, or add information to an existing conversation. For creating new items, use create_issue, create_discussion, or create_pull_request instead. IMPORTANT: Comments are subject to validation constraints enforced by the MCP server - maximum 65536 characters for the complete comment (including footer which is added automatically), 10 mentions (@username), and 50 links. Exceeding these limits will result in an immediate error with specific guidance. NOTE: By default, this tool requires discussions:write permission. If your GitHub App lacks Discussions permission, set 'discussions: false' in the workflow's safe-outputs.add-comment configuration to exclude this permission. CONSTRAINTS: Maximum 1 comment(s) can be added.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "body": {
- "description": "The comment text in Markdown format. This is the 'body' field - do not use 'comment_body' or other variations. Provide helpful, relevant information that adds value to the conversation. CONSTRAINTS: The complete comment (your body text + automatically added footer) must not exceed 65536 characters total. Maximum 10 mentions (@username), maximum 50 links (http/https URLs). A footer (~200-500 characters) is automatically appended with workflow attribution, so leave adequate space. If these limits are exceeded, the tool call will fail with a detailed error message indicating which constraint was violated.",
- "type": "string"
- },
- "item_number": {
- "description": "The issue, pull request, or discussion number to comment on. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123). If omitted, the tool auto-targets the issue, PR, or discussion that triggered this workflow. Auto-targeting only works for issue, pull_request, discussion, and comment event triggers — it does NOT work for schedule, workflow_dispatch, push, or workflow_run triggers. For those trigger types, always provide item_number explicitly, or the comment will be silently discarded.",
- "type": "number"
- }
- },
- "required": [
- "body"
- ],
- "type": "object"
- },
- "name": "add_comment"
- },
- {
- "description": "Create a new GitHub pull request to propose code changes. Use this after making file edits to submit them for review and merging. The PR will be created from the current branch with your committed changes. For code review comments on an existing PR, use create_pull_request_review_comment instead. CONSTRAINTS: Maximum 1 pull request(s) can be created. Title will be prefixed with \"[CI Fix] \". Labels [automation ci-failure] will be automatically added.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "body": {
- "description": "Detailed PR description in Markdown. Include what changes were made, why, testing notes, and any breaking changes. Do NOT repeat the title as a heading.",
- "type": "string"
- },
- "branch": {
- "description": "Source branch name containing the changes. If omitted, uses the current working branch.",
- "type": "string"
- },
- "draft": {
- "description": "Whether to create the PR as a draft. Draft PRs cannot be merged until marked as ready for review. Use mark_pull_request_as_ready_for_review to convert a draft PR. Default: true.",
- "type": "boolean"
- },
- "labels": {
- "description": "Labels to categorize the PR (e.g., 'enhancement', 'bugfix'). Labels must exist in the repository.",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "title": {
- "description": "Concise PR title describing the changes. Follow repository conventions (e.g., conventional commits). The title appears as the main heading.",
- "type": "string"
- }
- },
- "required": [
- "title",
- "body"
- ],
- "type": "object"
- },
- "name": "create_pull_request"
- },
- {
- "description": "Push committed changes to a pull request's branch. Use this to add follow-up commits to an existing PR, such as addressing review feedback or fixing issues. Changes must be committed locally before calling this tool.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "branch": {
- "description": "Branch name to push changes from. If omitted, uses the current working branch. Only specify if you need to push from a different branch.",
- "type": "string"
- },
- "message": {
- "description": "Commit message describing the changes. Follow repository commit message conventions (e.g., conventional commits).",
- "type": "string"
- },
- "pull_request_number": {
- "description": "Pull request number to push changes to. This is the numeric ID from the GitHub URL (e.g., 654 in github.com/owner/repo/pull/654). Required when the workflow target is '*' (any PR).",
- "type": [
- "number",
- "string"
- ]
- }
- },
- "required": [
- "message"
- ],
- "type": "object"
- },
- "name": "push_to_pull_request_branch"
- },
- {
- "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "alternatives": {
- "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
- "type": "string"
- },
- "reason": {
- "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).",
- "type": "string"
- },
- "tool": {
- "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.",
- "type": "string"
- }
- },
- "required": [
- "reason"
- ],
- "type": "object"
- },
- "name": "missing_tool"
- },
- {
- "description": "Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "message": {
- "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').",
- "type": "string"
- }
- },
- "required": [
- "message"
- ],
- "type": "object"
- },
- "name": "noop"
- },
- {
- "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "alternatives": {
- "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
- "type": "string"
- },
- "context": {
- "description": "Additional context about the missing data or where it should come from (max 256 characters).",
- "type": "string"
- },
- "data_type": {
- "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.",
- "type": "string"
- },
- "reason": {
- "description": "Explanation of why this data is needed to complete the task (max 256 characters).",
- "type": "string"
- }
- },
- "required": [],
- "type": "object"
- },
- "name": "missing_data"
- }
- ]
- GH_AW_SAFE_OUTPUTS_TOOLS_EOF
- cat > /opt/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF'
- {
- "add_comment": {
- "defaultMax": 1,
- "fields": {
- "body": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "item_number": {
- "issueOrPRNumber": true
- },
- "repo": {
- "type": "string",
- "maxLength": 256
- }
- }
- },
- "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
- }
- }
- },
- "create_pull_request": {
- "defaultMax": 1,
- "fields": {
- "body": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "branch": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 256
- },
- "draft": {
- "type": "boolean"
- },
- "labels": {
- "type": "array",
- "itemType": "string",
- "itemSanitize": true,
- "itemMaxLength": 128
- },
- "repo": {
- "type": "string",
- "maxLength": 256
- },
- "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
- }
- }
- },
- "push_to_pull_request_branch": {
- "defaultMax": 1,
- "fields": {
- "branch": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 256
- },
- "message": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "pull_request_number": {
- "issueOrPRNumber": true
- }
- }
- }
- }
- GH_AW_SAFE_OUTPUTS_VALIDATION_EOF
- - 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: /opt/gh-aw/safeoutputs/tools.json
- GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/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 /opt/gh-aw/actions/start_safe_outputs_server.sh
-
- - name: Start MCP Gateway
- id: start-mcp-gateway
- env:
- GH_AW_SAFE_OUTPUTS: ${{ env.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_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }}
- 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 DEBUG="*"
-
- export GH_AW_ENGINE="claude"
- 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 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_LOCKDOWN -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.1.6'
-
- cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh
- {
- "mcpServers": {
- "github": {
- "container": "ghcr.io/github/github-mcp-server:v0.31.0",
- "env": {
- "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN",
- "GITHUB_PERSONAL_ACCESS_TOKEN": "$GITHUB_MCP_SERVER_TOKEN",
- "GITHUB_READ_ONLY": "1",
- "GITHUB_TOOLSETS": "pull_requests,repos,issues"
- }
- },
- "safeoutputs": {
- "type": "http",
- "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT",
- "headers": {
- "Authorization": "$GH_AW_SAFE_OUTPUTS_API_KEY"
- }
- }
- },
- "gateway": {
- "port": $MCP_GATEWAY_PORT,
- "domain": "${MCP_GATEWAY_DOMAIN}",
- "apiKey": "${MCP_GATEWAY_API_KEY}",
- "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
- }
- }
- GH_AW_MCP_CONFIG_EOF
- - name: Generate workflow overview
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { generateWorkflowOverview } = require('/opt/gh-aw/actions/generate_workflow_overview.cjs');
- await generateWorkflowOverview(core);
- - name: Download prompt artifact
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: prompt
- path: /tmp/gh-aw/aw-prompts
- - name: Clean git credentials
- run: bash /opt/gh-aw/actions/clean_git_credentials.sh
- - name: Execute Claude Code CLI
- id: agentic_execution
- # Allowed tools (sorted):
- # - Bash
- # - BashOutput
- # - Edit
- # - Edit(/tmp/gh-aw/cache-memory/*)
- # - ExitPlanMode
- # - Glob
- # - Grep
- # - KillBash
- # - LS
- # - MultiEdit
- # - MultiEdit(/tmp/gh-aw/cache-memory/*)
- # - NotebookEdit
- # - NotebookRead
- # - Read
- # - Read(/tmp/gh-aw/cache-memory/*)
- # - Task
- # - TodoWrite
- # - WebFetch
- # - Write
- # - Write(/tmp/gh-aw/cache-memory/*)
- # - mcp__github__download_workflow_run_artifact
- # - mcp__github__get_code_scanning_alert
- # - mcp__github__get_commit
- # - mcp__github__get_dependabot_alert
- # - mcp__github__get_discussion
- # - mcp__github__get_discussion_comments
- # - mcp__github__get_file_contents
- # - mcp__github__get_job_logs
- # - mcp__github__get_label
- # - mcp__github__get_latest_release
- # - mcp__github__get_me
- # - mcp__github__get_notification_details
- # - mcp__github__get_pull_request
- # - mcp__github__get_pull_request_comments
- # - mcp__github__get_pull_request_diff
- # - mcp__github__get_pull_request_files
- # - mcp__github__get_pull_request_review_comments
- # - mcp__github__get_pull_request_reviews
- # - mcp__github__get_pull_request_status
- # - mcp__github__get_release_by_tag
- # - mcp__github__get_secret_scanning_alert
- # - mcp__github__get_tag
- # - mcp__github__get_workflow_run
- # - mcp__github__get_workflow_run_logs
- # - mcp__github__get_workflow_run_usage
- # - mcp__github__issue_read
- # - mcp__github__list_branches
- # - mcp__github__list_code_scanning_alerts
- # - mcp__github__list_commits
- # - mcp__github__list_dependabot_alerts
- # - mcp__github__list_discussion_categories
- # - mcp__github__list_discussions
- # - mcp__github__list_issue_types
- # - mcp__github__list_issues
- # - mcp__github__list_label
- # - mcp__github__list_notifications
- # - mcp__github__list_pull_requests
- # - mcp__github__list_releases
- # - mcp__github__list_secret_scanning_alerts
- # - mcp__github__list_starred_repositories
- # - mcp__github__list_tags
- # - mcp__github__list_workflow_jobs
- # - mcp__github__list_workflow_run_artifacts
- # - mcp__github__list_workflow_runs
- # - mcp__github__list_workflows
- # - mcp__github__pull_request_read
- # - mcp__github__search_code
- # - mcp__github__search_issues
- # - mcp__github__search_orgs
- # - mcp__github__search_pull_requests
- # - mcp__github__search_repositories
- # - mcp__github__search_users
- timeout-minutes: 20
- run: |
- set -o pipefail
- # shellcheck disable=SC1003
- sudo -E awf --tty --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && claude --print --disable-slash-commands --no-chrome --mcp-config /tmp/gh-aw/mcp-config/mcp-servers.json --allowed-tools '\''Bash,BashOutput,Edit,Edit(/tmp/gh-aw/cache-memory/*),ExitPlanMode,Glob,Grep,KillBash,LS,MultiEdit,MultiEdit(/tmp/gh-aw/cache-memory/*),NotebookEdit,NotebookRead,Read,Read(/tmp/gh-aw/cache-memory/*),Task,TodoWrite,WebFetch,Write,Write(/tmp/gh-aw/cache-memory/*),mcp__github__download_workflow_run_artifact,mcp__github__get_code_scanning_alert,mcp__github__get_commit,mcp__github__get_dependabot_alert,mcp__github__get_discussion,mcp__github__get_discussion_comments,mcp__github__get_file_contents,mcp__github__get_job_logs,mcp__github__get_label,mcp__github__get_latest_release,mcp__github__get_me,mcp__github__get_notification_details,mcp__github__get_pull_request,mcp__github__get_pull_request_comments,mcp__github__get_pull_request_diff,mcp__github__get_pull_request_files,mcp__github__get_pull_request_review_comments,mcp__github__get_pull_request_reviews,mcp__github__get_pull_request_status,mcp__github__get_release_by_tag,mcp__github__get_secret_scanning_alert,mcp__github__get_tag,mcp__github__get_workflow_run,mcp__github__get_workflow_run_logs,mcp__github__get_workflow_run_usage,mcp__github__issue_read,mcp__github__list_branches,mcp__github__list_code_scanning_alerts,mcp__github__list_commits,mcp__github__list_dependabot_alerts,mcp__github__list_discussion_categories,mcp__github__list_discussions,mcp__github__list_issue_types,mcp__github__list_issues,mcp__github__list_label,mcp__github__list_notifications,mcp__github__list_pull_requests,mcp__github__list_releases,mcp__github__list_secret_scanning_alerts,mcp__github__list_starred_repositories,mcp__github__list_tags,mcp__github__list_workflow_jobs,mcp__github__list_workflow_run_artifacts,mcp__github__list_workflow_runs,mcp__github__list_workflows,mcp__github__pull_request_read,mcp__github__search_code,mcp__github__search_issues,mcp__github__search_orgs,mcp__github__search_pull_requests,mcp__github__search_repositories,mcp__github__search_users'\'' --debug-file /tmp/gh-aw/agent-stdio.log --verbose --permission-mode bypassPermissions --output-format stream-json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_CLAUDE:+ --model "$GH_AW_MODEL_AGENT_CLAUDE"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- BASH_DEFAULT_TIMEOUT_MS: 60000
- BASH_MAX_TIMEOUT_MS: 60000
- DISABLE_BUG_COMMAND: 1
- DISABLE_ERROR_REPORTING: 1
- DISABLE_TELEMETRY: 1
- GH_AW_MCP_CONFIG: /tmp/gh-aw/mcp-config/mcp-servers.json
- GH_AW_MODEL_AGENT_CLAUDE: ${{ vars.GH_AW_MODEL_AGENT_CLAUDE || '' }}
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
- GITHUB_WORKSPACE: ${{ github.workspace }}
- MCP_TIMEOUT: 120000
- MCP_TOOL_TIMEOUT: 60000
- - 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: 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 /opt/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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs');
- await main();
- env:
- GH_AW_SECRET_NAMES: 'ANTHROPIC_API_KEY,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
- SECRET_ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
- SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
- SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: Upload Safe Outputs
- if: always()
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: safe-output
- path: ${{ env.GH_AW_SAFE_OUTPUTS }}
- if-no-files-found: warn
- - name: Ingest agent output
- id: collect_output
- if: always()
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
- GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com"
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_API_URL: ${{ github.api_url }}
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs');
- await main();
- - name: Upload sanitized agent output
- if: always() && env.GH_AW_AGENT_OUTPUT
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: agent-output
- path: ${{ env.GH_AW_AGENT_OUTPUT }}
- if-no-files-found: warn
- - name: Parse agent logs for step summary
- if: always()
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: /tmp/gh-aw/agent-stdio.log
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/parse_claude_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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: Upload cache-memory data as artifact
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- 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@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: agent-artifacts
- path: |
- /tmp/gh-aw/aw-prompts/prompt.txt
- /tmp/gh-aw/aw_info.json
- /tmp/gh-aw/mcp-logs/
- /tmp/gh-aw/sandbox/firewall/logs/
- /tmp/gh-aw/agent-stdio.log
- /tmp/gh-aw/agent/
- /tmp/gh-aw/aw-*.patch
- if-no-files-found: ignore
- # --- Threat Detection (inline) ---
- - name: Check if detection needed
- id: detection_guard
- if: always()
- env:
- OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }}
- HAS_PATCH: ${{ steps.collect_output.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: "CI Failure Doctor"
- WORKFLOW_DESCRIPTION: "Monitors the CI workflow and automatically investigates failures. Analyzes\nlogs to identify root causes, checks for patterns in past failures, and\neither creates a fix PR directly or opens an issue with detailed diagnosis.\nAssigns the maintainer only when manual intervention is truly needed."
- HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: Execute Claude Code CLI
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- id: detection_agentic_execution
- # Allowed tools (sorted):
- # - Bash(cat)
- # - Bash(grep)
- # - Bash(head)
- # - Bash(jq)
- # - Bash(ls)
- # - Bash(tail)
- # - Bash(wc)
- # - BashOutput
- # - ExitPlanMode
- # - Glob
- # - Grep
- # - KillBash
- # - LS
- # - NotebookRead
- # - Read
- # - Task
- # - TodoWrite
- timeout-minutes: 20
- run: |
- set -o pipefail
- # shellcheck disable=SC1003
- sudo -E awf --tty --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && claude --print --disable-slash-commands --no-chrome --allowed-tools '\''Bash(cat),Bash(grep),Bash(head),Bash(jq),Bash(ls),Bash(tail),Bash(wc),BashOutput,ExitPlanMode,Glob,Grep,KillBash,LS,NotebookRead,Read,Task,TodoWrite'\'' --debug-file /tmp/gh-aw/threat-detection/detection.log --verbose --permission-mode bypassPermissions --output-format stream-json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_DETECTION_CLAUDE:+ --model "$GH_AW_MODEL_DETECTION_CLAUDE"}' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- BASH_DEFAULT_TIMEOUT_MS: 60000
- BASH_MAX_TIMEOUT_MS: 60000
- DISABLE_BUG_COMMAND: 1
- DISABLE_ERROR_REPORTING: 1
- DISABLE_TELEMETRY: 1
- GH_AW_MODEL_DETECTION_CLAUDE: ${{ vars.GH_AW_MODEL_DETECTION_CLAUDE || '' }}
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GITHUB_WORKSPACE: ${{ github.workspace }}
- MCP_TIMEOUT: 120000
- MCP_TOOL_TIMEOUT: 60000
- - name: Parse threat detection results
- id: parse_detection_results
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs');
- await main();
- - name: Upload threat detection log
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: threat-detection.log
- path: /tmp/gh-aw/threat-detection/detection.log
- if-no-files-found: ignore
- - name: Set detection conclusion
- id: detection_conclusion
- if: always()
- env:
- RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}
- DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }}
- run: |
- if [[ "$RUN_DETECTION" != "true" ]]; then
- echo "conclusion=skipped" >> "$GITHUB_OUTPUT"
- echo "success=true" >> "$GITHUB_OUTPUT"
- echo "Detection was not needed, marking as skipped"
- elif [[ "$DETECTION_SUCCESS" == "true" ]]; then
- echo "conclusion=success" >> "$GITHUB_OUTPUT"
- echo "success=true" >> "$GITHUB_OUTPUT"
- echo "Detection passed successfully"
- else
- echo "conclusion=failure" >> "$GITHUB_OUTPUT"
- echo "success=false" >> "$GITHUB_OUTPUT"
- echo "Detection found issues"
- fi
-
- conclusion:
- needs:
- - activation
- - agent
- - safe_outputs
- - update_cache_memory
- if: (always()) && (needs.agent.result != 'skipped')
- runs-on: ubuntu-slim
- permissions:
- contents: write
- discussions: write
- issues: write
- pull-requests: write
- 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@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Download agent output artifact
- continue-on-error: true
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: agent-output
- path: /tmp/gh-aw/safeoutputs/
- - name: Setup agent output environment variable
- run: |
- mkdir -p /tmp/gh-aw/safeoutputs/
- find "/tmp/gh-aw/safeoutputs/" -type f -print
- echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
- - name: Process No-Op Messages
- id: noop
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_NOOP_MAX: "1"
- GH_AW_WORKFLOW_NAME: "CI Failure Doctor"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "CI Failure Doctor"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/missing_tool.cjs');
- await main();
- - name: Handle Agent Failure
- id: handle_agent_failure
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "CI Failure Doctor"
- 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: "ci-doctor"
- GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }}
- GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
- GH_AW_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }}
- GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }}
- GH_AW_GROUP_REPORTS: "false"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "CI Failure Doctor"
- 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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/handle_noop_message.cjs');
- await main();
- - name: Handle Create Pull Request Error
- id: handle_create_pr_error
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "CI Failure Doctor"
- GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/handle_create_pr_error.cjs');
- await main();
-
- pre_activation:
- if: ${{ github.event.workflow_run.conclusion == 'failure' }}
- runs-on: ubuntu-slim
- outputs:
- activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }}
- matched_command: ''
- steps:
- - name: Setup Scripts
- uses: github/gh-aw/actions/setup@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/check_membership.cjs');
- await main();
-
- safe_outputs:
- needs:
- - activation
- - agent
- if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_success == 'true')
- runs-on: ubuntu-slim
- permissions:
- contents: write
- discussions: write
- issues: write
- pull-requests: write
- timeout-minutes: 15
- env:
- GH_AW_ENGINE_ID: "claude"
- GH_AW_WORKFLOW_ID: "ci-doctor"
- GH_AW_WORKFLOW_NAME: "CI Failure Doctor"
- outputs:
- 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 }}
- 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@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Download agent output artifact
- continue-on-error: true
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: agent-output
- path: /tmp/gh-aw/safeoutputs/
- - name: Setup agent output environment variable
- run: |
- mkdir -p /tmp/gh-aw/safeoutputs/
- find "/tmp/gh-aw/safeoutputs/" -type f -print
- echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
- - name: Download patch artifact
- continue-on-error: true
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: agent-artifacts
- path: /tmp/gh-aw/
- - name: Checkout repository
- if: (((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request'))) || (((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')))
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- ref: ${{ github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }}
- token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- persist-credentials: false
- fetch-depth: 1
- - name: Configure Git credentials
- if: (((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request'))) || (((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')))
- env:
- REPO_NAME: ${{ github.repository }}
- SERVER_URL: ${{ github.server_url }}
- GIT_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- 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:${GIT_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
- echo "Git configured with standard GitHub Actions identity"
- - name: Process Safe Outputs
- id: process_safe_outputs
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com"
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_API_URL: ${{ github.api_url }}
- GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_issue\":{\"assignees\":[\"imjasonh\"],\"labels\":[\"automation\",\"ci-failure\"],\"max\":1,\"title_prefix\":\"[CI Fix] \"},\"create_pull_request\":{\"draft\":false,\"labels\":[\"automation\",\"ci-failure\"],\"max\":1,\"max_patch_size\":1024,\"title_prefix\":\"[CI Fix] \"},\"missing_data\":{},\"missing_tool\":{},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"max_patch_size\":1024}}"
- GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }}
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs');
- await main();
- - name: Upload safe output items manifest
- if: always()
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: safe-output-items
- path: /tmp/safe-output-items.jsonl
- if-no-files-found: warn
-
- update_cache_memory:
- needs: agent
- if: always() && needs.agent.outputs.detection_success == 'true'
- runs-on: ubuntu-latest
- permissions: {}
- env:
- GH_AW_WORKFLOW_ID_SANITIZED: cidoctor
- steps:
- - name: Setup Scripts
- uses: github/gh-aw/actions/setup@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Download cache-memory artifact (default)
- id: download_cache_default
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- 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@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
- with:
- key: memory-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }}
- path: /tmp/gh-aw/cache-memory
-
diff --git a/.github/workflows/ci-doctor.md b/.github/workflows/ci-doctor.md
deleted file mode 100644
index 03909bd..0000000
--- a/.github/workflows/ci-doctor.md
+++ /dev/null
@@ -1,161 +0,0 @@
----
-description: |
- Monitors the CI workflow and automatically investigates failures. Analyzes
- logs to identify root causes, checks for patterns in past failures, and
- either creates a fix PR directly or opens an issue with detailed diagnosis.
- Assigns the maintainer only when manual intervention is truly needed.
-
-on:
- workflow_run:
- workflows: ["CI"]
- types:
- - completed
- branches:
- - main
-
-if: ${{ github.event.workflow_run.conclusion == 'failure' }}
-
-permissions: read-all
-
-network: defaults
-
-safe-outputs:
- create-issue:
- title-prefix: "[CI Fix] "
- labels: [automation, ci-failure]
- assignees: [imjasonh]
- create-pull-request:
- title-prefix: "[CI Fix] "
- labels: [automation, ci-failure]
- draft: false
- add-comment:
- push-to-pull-request-branch:
-
-tools:
- cache-memory: true
- bash: true
- web-fetch:
- github:
- toolsets: [pull_requests, repos, issues]
-
-engine: claude
-
-timeout-minutes: 20
----
-
-# CI Failure Doctor
-
-You are the CI Failure Doctor for the **git-k8s** project. When CI fails, you investigate the root cause and fix it — or clearly explain what needs human attention.
-
-## Project Context
-
-- **Language**: Go 1.24.7, module `github.com/imjasonh/git-k8s`
-- **CI workflow**: Two jobs — `Build` (compile, test, vet) and `e2e` (KinD cluster + Gitea + controller deployment + integration tests)
-- **Controllers**: push-controller, sync-controller, resolver-controller, repo-watcher-controller
-- **Key dependencies**: `go-git/v5`, `k8s.io/client-go`, `knative.dev/pkg`
-
-## Context
-
-- **Repository**: ${{ github.repository }}
-- **Failed Run**: ${{ github.event.workflow_run.id }}
-- **Conclusion**: ${{ github.event.workflow_run.conclusion }}
-- **Run URL**: ${{ github.event.workflow_run.html_url }}
-- **Head SHA**: ${{ github.event.workflow_run.head_sha }}
-
-## Investigation Protocol
-
-**Only proceed if the conclusion is `failure` or `cancelled`.** Exit immediately if successful.
-
-### Phase 1: Identify Failures
-
-1. Use `get_workflow_run` to get full details of the failed run
-2. Use `list_workflow_jobs` to identify which jobs failed
-3. Determine if this is the Build job, e2e job, or both
-
-### Phase 2: Analyze Logs
-
-1. Use `get_job_logs` with `failed_only=true` to retrieve logs from failed jobs
-2. Look for:
- - **Compilation errors**: missing imports, type mismatches, undefined references
- - **Test failures**: specific test names, assertion messages, panic traces
- - **Vet failures**: shadowed variables, unreachable code, printf format mismatches
- - **go mod tidy drift**: `go.sum` or `go.mod` changes needed
- - **E2E failures**: controller crash loops, timeout waiting for deployments, Gitea setup failures, test assertions on CRD status
- - **Infrastructure issues**: KinD cluster creation failures, image pull errors, port-forward failures
-
-### Phase 3: Check History
-
-1. Search cached investigation files in `/tmp/memory/investigations/` for similar failures
-2. Search existing GitHub issues for related problems
-3. If this is a known recurring pattern, reference previous findings
-
-### Phase 4: Fix or Escalate
-
-Based on your analysis, take **one** of the following paths:
-
-#### Path A: Auto-fix (for clear, mechanical failures)
-
-These are safe to fix automatically:
-- `go mod tidy` drift
-- `go fmt` issues
-- Missing or extra imports
-- Simple compilation errors with obvious fixes
-- Test expectation mismatches due to intentional behavior changes
-
-Steps:
-1. Create a new branch from `main`
-2. Check out the code and apply the fix
-3. Run `go build ./cmd/push-controller/ && go build ./cmd/sync-controller/ && go build ./cmd/resolver-controller/ && go build ./cmd/repo-watcher-controller/` to verify compilation
-4. Run `go test ./...` to verify tests pass
-5. Run `go vet ./...` to verify linting
-6. Create a pull request with the fix, referencing the failed run
-
-#### Path B: Detailed diagnosis (for complex failures)
-
-For failures that require human judgment:
-1. Create a GitHub issue with the investigation report (template below)
-2. Assign to @imjasonh with specific questions about the fix approach
-
-### Phase 5: Store Findings
-
-Save investigation data to `/tmp/memory/investigations/${{ github.event.workflow_run.id }}.json` with:
-- Failure type and category
-- Root cause analysis
-- Error messages and file paths
-- Whether an auto-fix was attempted
-- Resolution status
-
-## Issue Template
-
-```markdown
-## CI Failure Investigation — Run #${{ github.event.workflow_run.run_number }}
-
-**Run**: [${{ github.event.workflow_run.id }}](${{ github.event.workflow_run.html_url }})
-**Commit**: ${{ github.event.workflow_run.head_sha }}
-**Failed jobs**: [list]
-
-### Root Cause
-
-[Detailed explanation of what went wrong]
-
-### Error Details
-
-[Key error messages with file paths and line numbers]
-
-### Recommended Fix
-
-[Specific steps or code changes needed]
-
-### Questions for @imjasonh
-
-- [Specific question 1]
-- [Specific question 2]
-```
-
-## Guidelines
-
-- **Fix what you can** — don't create an issue for something you can auto-fix
-- **Be specific** — include exact error messages, file paths, and line numbers
-- **Don't guess** — if the root cause is unclear, say so and ask specific questions
-- **Check for flakes** — if the same test fails intermittently, note it as a flaky test
-- **Respect the architecture** — don't change fundamental patterns (reconciler structure, client design) without escalating
diff --git a/.github/workflows/code-review.lock.yml b/.github/workflows/code-review.lock.yml
deleted file mode 100644
index b0ee446..0000000
--- a/.github/workflows/code-review.lock.yml
+++ /dev/null
@@ -1,1360 +0,0 @@
-#
-# ___ _ _
-# / _ \ | | (_)
-# | |_| | __ _ ___ _ __ | |_ _ ___
-# | _ |/ _` |/ _ \ '_ \| __| |/ __|
-# | | | | (_| | __/ | | | |_| | (__
-# \_| |_/\__, |\___|_| |_|\__|_|\___|
-# __/ |
-# _ _ |___/
-# | | | | / _| |
-# | | | | ___ _ __ _ __| |_| | _____ ____
-# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___|
-# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
-# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
-#
-# This file was automatically generated by gh-aw (v0.50.7). 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/
-#
-# Automated code reviewer for pull requests. Analyzes code changes for bugs,
-# security issues, performance problems, Go best practices, and Kubernetes
-# controller patterns. Creates review comments with specific feedback and
-# pushes minor fixes (formatting, linting) directly. Assigns the maintainer
-# only when human judgment is genuinely needed.
-#
-# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"dfa45fdc312db55a0f80440c4033526192f20ea76482ba2b11c9740be8651fdf","compiler_version":"v0.50.7"}
-
-name: "Automated Code Reviewer"
-"on":
- pull_request:
- types:
- - opened
- - synchronize
-
-permissions: {}
-
-concurrency:
- group: "gh-aw-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}"
- cancel-in-progress: true
-
-run-name: "Automated Code Reviewer"
-
-jobs:
- activation:
- needs: pre_activation
- if: >
- (needs.pre_activation.outputs.activated == 'true') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.id == github.repository_id))
- runs-on: ubuntu-slim
- permissions:
- contents: read
- outputs:
- body: ${{ steps.sanitized.outputs.body }}
- comment_id: ""
- comment_repo: ""
- secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
- text: ${{ steps.sanitized.outputs.text }}
- title: ${{ steps.sanitized.outputs.title }}
- steps:
- - name: Setup Scripts
- uses: github/gh-aw/actions/setup@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Validate ANTHROPIC_API_KEY secret
- id: validate-secret
- run: /opt/gh-aw/actions/validate_multi_secret.sh ANTHROPIC_API_KEY 'Claude Code' https://github.github.com/gh-aw/reference/engines/#anthropic-claude-code
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- - name: Validate context variables
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/validate_context_variables.cjs');
- await main();
- - name: Checkout .github and .agents folders
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- sparse-checkout: |
- .github
- .agents
- fetch-depth: 1
- persist-credentials: false
- - name: Check workflow file timestamps
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_WORKFLOW_FILE: "code-review.lock.yml"
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs');
- await main();
- - name: Compute current body text
- id: sanitized
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/compute_text.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: ${{ env.GH_AW_SAFE_OUTPUTS }}
- 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 }}
- run: |
- bash /opt/gh-aw/actions/create_prompt_first.sh
- {
- cat << 'GH_AW_PROMPT_EOF'
-
- GH_AW_PROMPT_EOF
- cat "/opt/gh-aw/prompts/xpia.md"
- cat "/opt/gh-aw/prompts/temp_folder_prompt.md"
- cat "/opt/gh-aw/prompts/markdown.md"
- cat "/opt/gh-aw/prompts/safe_outputs_prompt.md"
- cat << 'GH_AW_PROMPT_EOF'
-
- Tools: add_comment, create_pull_request_review_comment, submit_pull_request_review, push_to_pull_request_branch, missing_tool, missing_data, noop
- GH_AW_PROMPT_EOF
- cat "/opt/gh-aw/prompts/safe_outputs_push_to_pr_branch.md"
- cat << 'GH_AW_PROMPT_EOF'
-
-
- 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_EOF
- cat << 'GH_AW_PROMPT_EOF'
-
- GH_AW_PROMPT_EOF
- cat << 'GH_AW_PROMPT_EOF'
- {{#runtime-import .github/workflows/code-review.md}}
- GH_AW_PROMPT_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
- GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
- GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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_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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
-
- const substitutePlaceholders = require('/opt/gh-aw/actions/substitute_placeholders.cjs');
-
- // Call the substitution function
- return await substitutePlaceholders({
- file: process.env.GH_AW_PROMPT,
- substitutions: {
- 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
- run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh
- - name: Print prompt
- env:
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- run: bash /opt/gh-aw/actions/print_prompt_summary.sh
- - name: Upload prompt artifact
- if: success()
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: prompt
- path: /tmp/gh-aw/aw-prompts/prompt.txt
- retention-days: 1
-
- agent:
- needs: activation
- runs-on: ubuntu-latest
- permissions: read-all
- 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_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl
- GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json
- GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json
- GH_AW_WORKFLOW_ID_SANITIZED: codereview
- outputs:
- checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
- detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}
- detection_success: ${{ steps.detection_conclusion.outputs.success }}
- has_patch: ${{ steps.collect_output.outputs.has_patch }}
- model: ${{ steps.generate_aw_info.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@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Checkout repository
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- persist-credentials: false
- - name: Create gh-aw temp directory
- run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.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: 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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs');
- await main();
- - name: Generate agentic run info
- id: generate_aw_info
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const fs = require('fs');
-
- const awInfo = {
- engine_id: "claude",
- engine_name: "Claude Code",
- model: process.env.GH_AW_MODEL_AGENT_CLAUDE || "",
- version: "",
- agent_version: "2.1.62",
- cli_version: "v0.50.7",
- workflow_name: "Automated Code Reviewer",
- experimental: false,
- supports_tools_allowlist: true,
- run_id: context.runId,
- run_number: context.runNumber,
- run_attempt: process.env.GITHUB_RUN_ATTEMPT,
- repository: context.repo.owner + '/' + context.repo.repo,
- ref: context.ref,
- sha: context.sha,
- actor: context.actor,
- event_name: context.eventName,
- staged: false,
- allowed_domains: ["defaults"],
- firewall_enabled: true,
- awf_version: "v0.23.0",
- awmg_version: "v0.1.6",
- steps: {
- firewall: "squid"
- },
- created_at: new Date().toISOString()
- };
-
- // Write to /tmp/gh-aw directory to avoid inclusion in PR
- const tmpPath = '/tmp/gh-aw/aw_info.json';
- fs.writeFileSync(tmpPath, JSON.stringify(awInfo, null, 2));
- console.log('Generated aw_info.json at:', tmpPath);
- console.log(JSON.stringify(awInfo, null, 2));
-
- // Set model as output for reuse in other steps/jobs
- core.setOutput('model', awInfo.model);
- - name: Setup Node.js
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
- with:
- node-version: '24'
- package-manager-cache: false
- - name: Install awf binary
- run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0
- - name: Install Claude Code CLI
- run: npm install -g --silent @anthropic-ai/claude-code@2.1.62
- - 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('/opt/gh-aw/actions/determine_automatic_lockdown.cjs');
- await determineAutomaticLockdown(github, context, core);
- - name: Download container images
- run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.6 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine
- - name: Write Safe Outputs Config
- run: |
- mkdir -p /opt/gh-aw/safeoutputs
- mkdir -p /tmp/gh-aw/safeoutputs
- mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
- cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF'
- {"add_comment":{"max":1},"create_pull_request_review_comment":{"max":10},"missing_data":{},"missing_tool":{},"noop":{"max":1},"push_to_pull_request_branch":{"max":0},"submit_pull_request_review":{"max":1}}
- GH_AW_SAFE_OUTPUTS_CONFIG_EOF
- cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF'
- [
- {
- "description": "Add a comment to an existing GitHub issue, pull request, or discussion. Use this to provide feedback, answer questions, or add information to an existing conversation. For creating new items, use create_issue, create_discussion, or create_pull_request instead. IMPORTANT: Comments are subject to validation constraints enforced by the MCP server - maximum 65536 characters for the complete comment (including footer which is added automatically), 10 mentions (@username), and 50 links. Exceeding these limits will result in an immediate error with specific guidance. NOTE: By default, this tool requires discussions:write permission. If your GitHub App lacks Discussions permission, set 'discussions: false' in the workflow's safe-outputs.add-comment configuration to exclude this permission. CONSTRAINTS: Maximum 1 comment(s) can be added.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "body": {
- "description": "The comment text in Markdown format. This is the 'body' field - do not use 'comment_body' or other variations. Provide helpful, relevant information that adds value to the conversation. CONSTRAINTS: The complete comment (your body text + automatically added footer) must not exceed 65536 characters total. Maximum 10 mentions (@username), maximum 50 links (http/https URLs). A footer (~200-500 characters) is automatically appended with workflow attribution, so leave adequate space. If these limits are exceeded, the tool call will fail with a detailed error message indicating which constraint was violated.",
- "type": "string"
- },
- "item_number": {
- "description": "The issue, pull request, or discussion number to comment on. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123). If omitted, the tool auto-targets the issue, PR, or discussion that triggered this workflow. Auto-targeting only works for issue, pull_request, discussion, and comment event triggers — it does NOT work for schedule, workflow_dispatch, push, or workflow_run triggers. For those trigger types, always provide item_number explicitly, or the comment will be silently discarded.",
- "type": "number"
- }
- },
- "required": [
- "body"
- ],
- "type": "object"
- },
- "name": "add_comment"
- },
- {
- "description": "Create a review comment on a specific line of code in a pull request. Use this for inline code review feedback, suggestions, or questions about specific code changes. For general PR comments not tied to specific lines, use add_comment instead. CONSTRAINTS: Maximum 10 review comment(s) can be created. Comments will be on the RIGHT side of the diff.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "body": {
- "description": "Review comment content in Markdown. Provide specific, actionable feedback about the code at this location.",
- "type": "string"
- },
- "line": {
- "description": "Line number for the comment. For single-line comments, this is the target line. For multi-line comments, this is the ending line.",
- "type": [
- "number",
- "string"
- ]
- },
- "path": {
- "description": "File path relative to the repository root (e.g., 'src/auth/login.js'). Must be a file that was changed in the PR.",
- "type": "string"
- },
- "side": {
- "description": "Side of the diff to comment on: RIGHT for the new version (additions), LEFT for the old version (deletions). Defaults to RIGHT.",
- "enum": [
- "LEFT",
- "RIGHT"
- ],
- "type": "string"
- },
- "start_line": {
- "description": "Starting line number for multi-line comments. When set, the comment spans from start_line to line. Omit for single-line comments.",
- "type": [
- "number",
- "string"
- ]
- }
- },
- "required": [
- "path",
- "line",
- "body"
- ],
- "type": "object"
- },
- "name": "create_pull_request_review_comment"
- },
- {
- "description": "Submit a pull request review with a status decision. All create_pull_request_review_comment outputs are automatically collected and included as inline comments in this review. Use APPROVE to approve the PR, REQUEST_CHANGES to request changes, or COMMENT for general feedback without a decision. If you don't call this tool, review comments are still submitted as a COMMENT review. CONSTRAINTS: Maximum 1 review(s) can be submitted.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "body": {
- "description": "Overall review summary in Markdown. Provide a high-level assessment of the changes. Required for REQUEST_CHANGES; optional for APPROVE and COMMENT.",
- "type": "string"
- },
- "event": {
- "description": "Review decision: APPROVE to approve the pull request, REQUEST_CHANGES to formally request changes before merging, or COMMENT for general feedback without a formal decision. Defaults to COMMENT when omitted.",
- "enum": [
- "APPROVE",
- "REQUEST_CHANGES",
- "COMMENT"
- ],
- "type": "string"
- }
- },
- "type": "object"
- },
- "name": "submit_pull_request_review"
- },
- {
- "description": "Push committed changes to a pull request's branch. Use this to add follow-up commits to an existing PR, such as addressing review feedback or fixing issues. Changes must be committed locally before calling this tool.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "branch": {
- "description": "Branch name to push changes from. If omitted, uses the current working branch. Only specify if you need to push from a different branch.",
- "type": "string"
- },
- "message": {
- "description": "Commit message describing the changes. Follow repository commit message conventions (e.g., conventional commits).",
- "type": "string"
- },
- "pull_request_number": {
- "description": "Pull request number to push changes to. This is the numeric ID from the GitHub URL (e.g., 654 in github.com/owner/repo/pull/654). Required when the workflow target is '*' (any PR).",
- "type": [
- "number",
- "string"
- ]
- }
- },
- "required": [
- "message"
- ],
- "type": "object"
- },
- "name": "push_to_pull_request_branch"
- },
- {
- "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "alternatives": {
- "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
- "type": "string"
- },
- "reason": {
- "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).",
- "type": "string"
- },
- "tool": {
- "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.",
- "type": "string"
- }
- },
- "required": [
- "reason"
- ],
- "type": "object"
- },
- "name": "missing_tool"
- },
- {
- "description": "Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "message": {
- "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').",
- "type": "string"
- }
- },
- "required": [
- "message"
- ],
- "type": "object"
- },
- "name": "noop"
- },
- {
- "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "alternatives": {
- "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
- "type": "string"
- },
- "context": {
- "description": "Additional context about the missing data or where it should come from (max 256 characters).",
- "type": "string"
- },
- "data_type": {
- "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.",
- "type": "string"
- },
- "reason": {
- "description": "Explanation of why this data is needed to complete the task (max 256 characters).",
- "type": "string"
- }
- },
- "required": [],
- "type": "object"
- },
- "name": "missing_data"
- }
- ]
- GH_AW_SAFE_OUTPUTS_TOOLS_EOF
- cat > /opt/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF'
- {
- "add_comment": {
- "defaultMax": 1,
- "fields": {
- "body": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "item_number": {
- "issueOrPRNumber": true
- },
- "repo": {
- "type": "string",
- "maxLength": 256
- }
- }
- },
- "create_pull_request_review_comment": {
- "defaultMax": 1,
- "fields": {
- "body": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "line": {
- "required": true,
- "positiveInteger": true
- },
- "path": {
- "required": true,
- "type": "string"
- },
- "repo": {
- "type": "string",
- "maxLength": 256
- },
- "side": {
- "type": "string",
- "enum": [
- "LEFT",
- "RIGHT"
- ]
- },
- "start_line": {
- "optionalPositiveInteger": true
- }
- },
- "customValidation": "startLineLessOrEqualLine"
- },
- "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
- }
- }
- },
- "push_to_pull_request_branch": {
- "defaultMax": 1,
- "fields": {
- "branch": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 256
- },
- "message": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "pull_request_number": {
- "issueOrPRNumber": true
- }
- }
- },
- "submit_pull_request_review": {
- "defaultMax": 1,
- "fields": {
- "body": {
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "event": {
- "type": "string",
- "enum": [
- "APPROVE",
- "REQUEST_CHANGES",
- "COMMENT"
- ]
- }
- }
- }
- }
- GH_AW_SAFE_OUTPUTS_VALIDATION_EOF
- - 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: /opt/gh-aw/safeoutputs/tools.json
- GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/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 /opt/gh-aw/actions/start_safe_outputs_server.sh
-
- - name: Start MCP Gateway
- id: start-mcp-gateway
- env:
- GH_AW_SAFE_OUTPUTS: ${{ env.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_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }}
- 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 DEBUG="*"
-
- export GH_AW_ENGINE="claude"
- 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 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_LOCKDOWN -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.1.6'
-
- cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh
- {
- "mcpServers": {
- "github": {
- "container": "ghcr.io/github/github-mcp-server:v0.31.0",
- "env": {
- "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN",
- "GITHUB_PERSONAL_ACCESS_TOKEN": "$GITHUB_MCP_SERVER_TOKEN",
- "GITHUB_READ_ONLY": "1",
- "GITHUB_TOOLSETS": "pull_requests,repos"
- }
- },
- "safeoutputs": {
- "type": "http",
- "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT",
- "headers": {
- "Authorization": "$GH_AW_SAFE_OUTPUTS_API_KEY"
- }
- }
- },
- "gateway": {
- "port": $MCP_GATEWAY_PORT,
- "domain": "${MCP_GATEWAY_DOMAIN}",
- "apiKey": "${MCP_GATEWAY_API_KEY}",
- "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
- }
- }
- GH_AW_MCP_CONFIG_EOF
- - name: Generate workflow overview
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { generateWorkflowOverview } = require('/opt/gh-aw/actions/generate_workflow_overview.cjs');
- await generateWorkflowOverview(core);
- - name: Download prompt artifact
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: prompt
- path: /tmp/gh-aw/aw-prompts
- - name: Clean git credentials
- run: bash /opt/gh-aw/actions/clean_git_credentials.sh
- - name: Execute Claude Code CLI
- id: agentic_execution
- # Allowed tools (sorted):
- # - Bash
- # - BashOutput
- # - Edit
- # - ExitPlanMode
- # - Glob
- # - Grep
- # - KillBash
- # - LS
- # - MultiEdit
- # - NotebookEdit
- # - NotebookRead
- # - Read
- # - Task
- # - TodoWrite
- # - WebFetch
- # - Write
- # - mcp__github__download_workflow_run_artifact
- # - mcp__github__get_code_scanning_alert
- # - mcp__github__get_commit
- # - mcp__github__get_dependabot_alert
- # - mcp__github__get_discussion
- # - mcp__github__get_discussion_comments
- # - mcp__github__get_file_contents
- # - mcp__github__get_job_logs
- # - mcp__github__get_label
- # - mcp__github__get_latest_release
- # - mcp__github__get_me
- # - mcp__github__get_notification_details
- # - mcp__github__get_pull_request
- # - mcp__github__get_pull_request_comments
- # - mcp__github__get_pull_request_diff
- # - mcp__github__get_pull_request_files
- # - mcp__github__get_pull_request_review_comments
- # - mcp__github__get_pull_request_reviews
- # - mcp__github__get_pull_request_status
- # - mcp__github__get_release_by_tag
- # - mcp__github__get_secret_scanning_alert
- # - mcp__github__get_tag
- # - mcp__github__get_workflow_run
- # - mcp__github__get_workflow_run_logs
- # - mcp__github__get_workflow_run_usage
- # - mcp__github__issue_read
- # - mcp__github__list_branches
- # - mcp__github__list_code_scanning_alerts
- # - mcp__github__list_commits
- # - mcp__github__list_dependabot_alerts
- # - mcp__github__list_discussion_categories
- # - mcp__github__list_discussions
- # - mcp__github__list_issue_types
- # - mcp__github__list_issues
- # - mcp__github__list_label
- # - mcp__github__list_notifications
- # - mcp__github__list_pull_requests
- # - mcp__github__list_releases
- # - mcp__github__list_secret_scanning_alerts
- # - mcp__github__list_starred_repositories
- # - mcp__github__list_tags
- # - mcp__github__list_workflow_jobs
- # - mcp__github__list_workflow_run_artifacts
- # - mcp__github__list_workflow_runs
- # - mcp__github__list_workflows
- # - mcp__github__pull_request_read
- # - mcp__github__search_code
- # - mcp__github__search_issues
- # - mcp__github__search_orgs
- # - mcp__github__search_pull_requests
- # - mcp__github__search_repositories
- # - mcp__github__search_users
- timeout-minutes: 15
- run: |
- set -o pipefail
- # shellcheck disable=SC1003
- sudo -E awf --tty --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && claude --print --disable-slash-commands --no-chrome --mcp-config /tmp/gh-aw/mcp-config/mcp-servers.json --allowed-tools Bash,BashOutput,Edit,ExitPlanMode,Glob,Grep,KillBash,LS,MultiEdit,NotebookEdit,NotebookRead,Read,Task,TodoWrite,WebFetch,Write,mcp__github__download_workflow_run_artifact,mcp__github__get_code_scanning_alert,mcp__github__get_commit,mcp__github__get_dependabot_alert,mcp__github__get_discussion,mcp__github__get_discussion_comments,mcp__github__get_file_contents,mcp__github__get_job_logs,mcp__github__get_label,mcp__github__get_latest_release,mcp__github__get_me,mcp__github__get_notification_details,mcp__github__get_pull_request,mcp__github__get_pull_request_comments,mcp__github__get_pull_request_diff,mcp__github__get_pull_request_files,mcp__github__get_pull_request_review_comments,mcp__github__get_pull_request_reviews,mcp__github__get_pull_request_status,mcp__github__get_release_by_tag,mcp__github__get_secret_scanning_alert,mcp__github__get_tag,mcp__github__get_workflow_run,mcp__github__get_workflow_run_logs,mcp__github__get_workflow_run_usage,mcp__github__issue_read,mcp__github__list_branches,mcp__github__list_code_scanning_alerts,mcp__github__list_commits,mcp__github__list_dependabot_alerts,mcp__github__list_discussion_categories,mcp__github__list_discussions,mcp__github__list_issue_types,mcp__github__list_issues,mcp__github__list_label,mcp__github__list_notifications,mcp__github__list_pull_requests,mcp__github__list_releases,mcp__github__list_secret_scanning_alerts,mcp__github__list_starred_repositories,mcp__github__list_tags,mcp__github__list_workflow_jobs,mcp__github__list_workflow_run_artifacts,mcp__github__list_workflow_runs,mcp__github__list_workflows,mcp__github__pull_request_read,mcp__github__search_code,mcp__github__search_issues,mcp__github__search_orgs,mcp__github__search_pull_requests,mcp__github__search_repositories,mcp__github__search_users --debug-file /tmp/gh-aw/agent-stdio.log --verbose --permission-mode bypassPermissions --output-format stream-json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_CLAUDE:+ --model "$GH_AW_MODEL_AGENT_CLAUDE"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- BASH_DEFAULT_TIMEOUT_MS: 60000
- BASH_MAX_TIMEOUT_MS: 60000
- DISABLE_BUG_COMMAND: 1
- DISABLE_ERROR_REPORTING: 1
- DISABLE_TELEMETRY: 1
- GH_AW_MCP_CONFIG: /tmp/gh-aw/mcp-config/mcp-servers.json
- GH_AW_MODEL_AGENT_CLAUDE: ${{ vars.GH_AW_MODEL_AGENT_CLAUDE || '' }}
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
- GITHUB_WORKSPACE: ${{ github.workspace }}
- MCP_TIMEOUT: 120000
- MCP_TOOL_TIMEOUT: 60000
- - 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: 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 /opt/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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs');
- await main();
- env:
- GH_AW_SECRET_NAMES: 'ANTHROPIC_API_KEY,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
- SECRET_ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
- SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
- SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: Upload Safe Outputs
- if: always()
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: safe-output
- path: ${{ env.GH_AW_SAFE_OUTPUTS }}
- if-no-files-found: warn
- - name: Ingest agent output
- id: collect_output
- if: always()
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
- GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com"
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_API_URL: ${{ github.api_url }}
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs');
- await main();
- - name: Upload sanitized agent output
- if: always() && env.GH_AW_AGENT_OUTPUT
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: agent-output
- path: ${{ env.GH_AW_AGENT_OUTPUT }}
- if-no-files-found: warn
- - name: Parse agent logs for step summary
- if: always()
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: /tmp/gh-aw/agent-stdio.log
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/parse_claude_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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: Upload agent artifacts
- if: always()
- continue-on-error: true
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: agent-artifacts
- path: |
- /tmp/gh-aw/aw-prompts/prompt.txt
- /tmp/gh-aw/aw_info.json
- /tmp/gh-aw/mcp-logs/
- /tmp/gh-aw/sandbox/firewall/logs/
- /tmp/gh-aw/agent-stdio.log
- /tmp/gh-aw/agent/
- /tmp/gh-aw/aw-*.patch
- if-no-files-found: ignore
- # --- Threat Detection (inline) ---
- - name: Check if detection needed
- id: detection_guard
- if: always()
- env:
- OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }}
- HAS_PATCH: ${{ steps.collect_output.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: "Automated Code Reviewer"
- WORKFLOW_DESCRIPTION: "Automated code reviewer for pull requests. Analyzes code changes for bugs,\nsecurity issues, performance problems, Go best practices, and Kubernetes\ncontroller patterns. Creates review comments with specific feedback and\npushes minor fixes (formatting, linting) directly. Assigns the maintainer\nonly when human judgment is genuinely needed."
- HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: Execute Claude Code CLI
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- id: detection_agentic_execution
- # Allowed tools (sorted):
- # - Bash(cat)
- # - Bash(grep)
- # - Bash(head)
- # - Bash(jq)
- # - Bash(ls)
- # - Bash(tail)
- # - Bash(wc)
- # - BashOutput
- # - ExitPlanMode
- # - Glob
- # - Grep
- # - KillBash
- # - LS
- # - NotebookRead
- # - Read
- # - Task
- # - TodoWrite
- timeout-minutes: 20
- run: |
- set -o pipefail
- # shellcheck disable=SC1003
- sudo -E awf --tty --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && claude --print --disable-slash-commands --no-chrome --allowed-tools '\''Bash(cat),Bash(grep),Bash(head),Bash(jq),Bash(ls),Bash(tail),Bash(wc),BashOutput,ExitPlanMode,Glob,Grep,KillBash,LS,NotebookRead,Read,Task,TodoWrite'\'' --debug-file /tmp/gh-aw/threat-detection/detection.log --verbose --permission-mode bypassPermissions --output-format stream-json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_DETECTION_CLAUDE:+ --model "$GH_AW_MODEL_DETECTION_CLAUDE"}' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- BASH_DEFAULT_TIMEOUT_MS: 60000
- BASH_MAX_TIMEOUT_MS: 60000
- DISABLE_BUG_COMMAND: 1
- DISABLE_ERROR_REPORTING: 1
- DISABLE_TELEMETRY: 1
- GH_AW_MODEL_DETECTION_CLAUDE: ${{ vars.GH_AW_MODEL_DETECTION_CLAUDE || '' }}
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GITHUB_WORKSPACE: ${{ github.workspace }}
- MCP_TIMEOUT: 120000
- MCP_TOOL_TIMEOUT: 60000
- - name: Parse threat detection results
- id: parse_detection_results
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs');
- await main();
- - name: Upload threat detection log
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: threat-detection.log
- path: /tmp/gh-aw/threat-detection/detection.log
- if-no-files-found: ignore
- - name: Set detection conclusion
- id: detection_conclusion
- if: always()
- env:
- RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}
- DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }}
- run: |
- if [[ "$RUN_DETECTION" != "true" ]]; then
- echo "conclusion=skipped" >> "$GITHUB_OUTPUT"
- echo "success=true" >> "$GITHUB_OUTPUT"
- echo "Detection was not needed, marking as skipped"
- elif [[ "$DETECTION_SUCCESS" == "true" ]]; then
- echo "conclusion=success" >> "$GITHUB_OUTPUT"
- echo "success=true" >> "$GITHUB_OUTPUT"
- echo "Detection passed successfully"
- else
- echo "conclusion=failure" >> "$GITHUB_OUTPUT"
- echo "success=false" >> "$GITHUB_OUTPUT"
- echo "Detection found issues"
- fi
-
- conclusion:
- needs:
- - activation
- - agent
- - safe_outputs
- if: (always()) && (needs.agent.result != 'skipped')
- runs-on: ubuntu-slim
- permissions:
- contents: write
- discussions: write
- issues: write
- pull-requests: write
- 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@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Download agent output artifact
- continue-on-error: true
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: agent-output
- path: /tmp/gh-aw/safeoutputs/
- - name: Setup agent output environment variable
- run: |
- mkdir -p /tmp/gh-aw/safeoutputs/
- find "/tmp/gh-aw/safeoutputs/" -type f -print
- echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
- - name: Process No-Op Messages
- id: noop
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_NOOP_MAX: "1"
- GH_AW_WORKFLOW_NAME: "Automated Code Reviewer"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Automated Code Reviewer"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/missing_tool.cjs');
- await main();
- - name: Handle Agent Failure
- id: handle_agent_failure
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Automated Code Reviewer"
- 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: "code-review"
- GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }}
- GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
- GH_AW_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }}
- GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }}
- GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e Reviewed by [{workflow_name}]({run_url})\",\"runStarted\":\"[{workflow_name}]({run_url}) is reviewing this pull request...\",\"runSuccess\":\"[{workflow_name}]({run_url}) has completed the review.\",\"runFailure\":\"[{workflow_name}]({run_url}) encountered an error ({status}).\"}"
- GH_AW_GROUP_REPORTS: "false"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Automated Code Reviewer"
- 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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/handle_noop_message.cjs');
- await main();
-
- pre_activation:
- if: (github.event_name != 'pull_request') || (github.event.pull_request.head.repo.id == github.repository_id)
- runs-on: ubuntu-slim
- outputs:
- activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }}
- matched_command: ''
- steps:
- - name: Setup Scripts
- uses: github/gh-aw/actions/setup@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/check_membership.cjs');
- await main();
-
- safe_outputs:
- needs:
- - activation
- - agent
- if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_success == 'true')
- runs-on: ubuntu-slim
- permissions:
- contents: write
- discussions: write
- issues: write
- pull-requests: write
- timeout-minutes: 15
- env:
- GH_AW_ENGINE_ID: "claude"
- GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e Reviewed by [{workflow_name}]({run_url})\",\"runStarted\":\"[{workflow_name}]({run_url}) is reviewing this pull request...\",\"runSuccess\":\"[{workflow_name}]({run_url}) has completed the review.\",\"runFailure\":\"[{workflow_name}]({run_url}) encountered an error ({status}).\"}"
- GH_AW_WORKFLOW_ID: "code-review"
- GH_AW_WORKFLOW_NAME: "Automated Code Reviewer"
- outputs:
- 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 }}
- 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@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Download agent output artifact
- continue-on-error: true
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: agent-output
- path: /tmp/gh-aw/safeoutputs/
- - name: Setup agent output environment variable
- run: |
- mkdir -p /tmp/gh-aw/safeoutputs/
- find "/tmp/gh-aw/safeoutputs/" -type f -print
- echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
- - name: Download patch artifact
- continue-on-error: true
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: agent-artifacts
- path: /tmp/gh-aw/
- - name: Checkout repository
- if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch'))
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- ref: ${{ github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }}
- token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- persist-credentials: false
- fetch-depth: 1
- - name: Configure Git credentials
- if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch'))
- env:
- REPO_NAME: ${{ github.repository }}
- SERVER_URL: ${{ github.server_url }}
- GIT_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- 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:${GIT_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
- echo "Git configured with standard GitHub Actions identity"
- - name: Process Safe Outputs
- id: process_safe_outputs
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com"
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_API_URL: ${{ github.api_url }}
- GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request_review_comment\":{\"max\":10,\"side\":\"RIGHT\"},\"missing_data\":{},\"missing_tool\":{},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"max_patch_size\":1024},\"submit_pull_request_review\":{\"max\":1}}"
- GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }}
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs');
- await main();
- - name: Upload safe output items manifest
- if: always()
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: safe-output-items
- path: /tmp/safe-output-items.jsonl
- if-no-files-found: warn
-
diff --git a/.github/workflows/code-review.md b/.github/workflows/code-review.md
deleted file mode 100644
index aaf9026..0000000
--- a/.github/workflows/code-review.md
+++ /dev/null
@@ -1,131 +0,0 @@
----
-description: |
- Automated code reviewer for pull requests. Analyzes code changes for bugs,
- security issues, performance problems, Go best practices, and Kubernetes
- controller patterns. Creates review comments with specific feedback and
- pushes minor fixes (formatting, linting) directly. Assigns the maintainer
- only when human judgment is genuinely needed.
-
-on:
- pull_request:
- types: [opened, synchronize]
-
-permissions: read-all
-
-network: defaults
-
-safe-outputs:
- create-pull-request-review-comment:
- max: 10
- side: "RIGHT"
- submit-pull-request-review:
- max: 1
- push-to-pull-request-branch:
- add-comment:
- messages:
- footer: "> Reviewed by [{workflow_name}]({run_url})"
- run-started: "[{workflow_name}]({run_url}) is reviewing this pull request..."
- run-success: "[{workflow_name}]({run_url}) has completed the review."
- run-failure: "[{workflow_name}]({run_url}) encountered an error ({status})."
-
-tools:
- github:
- lockdown: true
- toolsets: [pull_requests, repos]
- bash: true
- web-fetch:
-
-engine: claude
-
-timeout-minutes: 15
----
-
-# Automated Code Reviewer
-
-You are an expert Go and Kubernetes developer reviewing pull requests for the **git-k8s** project — a Kubernetes-native controller system for managing Git repositories and automated Git operations.
-
-## Project Context
-
-- **Language**: Go 1.24.7
-- **Module**: `github.com/imjasonh/git-k8s`
-- **Key dependencies**: `go-git/v5`, `k8s.io/client-go`, `knative.dev/pkg`
-- **Pattern**: Knative-style `KindReconciler[T]` with hand-written typed client over dynamic client
-- **API group**: `git-k8s.imjasonh.com/v1alpha1`
-- **Controllers**: push, sync, resolver, repo-watcher (each a separate binary)
-- **Git operations**: All in-memory via `go-git` with `memory.NewStorage()`
-
-## Review Protocol
-
-### Step 1: Understand the Change
-
-1. Get the pull request details for PR #${{ github.event.pull_request.number }} in `${{ github.repository }}`
-2. Fetch the list of changed files and review the diff for each file
-3. Understand the intent of the change from the PR title, description, and commit messages
-
-### Step 2: Analyze the Code
-
-Review the changes against these criteria, ordered by priority:
-
-#### Critical (must block merge)
-- **Security vulnerabilities**: command injection, credential leaks, unsafe deserialization
-- **Data loss risks**: incorrect owner references, missing CAS (compare-and-swap) on push transactions
-- **Concurrency bugs**: race conditions in reconcilers, unsafe shared state
-- **API contract violations**: breaking changes to CRD types, incorrect status phase transitions
-
-#### Important (should fix before merge)
-- **Bug risks**: nil pointer dereferences, unhandled error returns, incorrect error wrapping
-- **Kubernetes anti-patterns**: missing RBAC for new resources, incorrect label selectors, missing owner references
-- **Go anti-patterns**: goroutine leaks, deferred calls in loops, shadowed variables
-- **Controller correctness**: reconciler not idempotent, missing requeue on transient errors, status not updated on all code paths
-- **Test gaps**: untested error paths in new reconciler logic
-
-#### Minor (nice to fix)
-- **Style**: non-idiomatic Go, unnecessary complexity, unclear naming
-- **Performance**: unnecessary allocations in hot paths, redundant API calls
-
-### Step 3: Apply Automated Fixes
-
-If you find issues that are unambiguously fixable (formatting, linting, `go mod tidy`), apply them:
-
-1. Check out the PR branch
-2. Run `go fmt ./...` and `go vet ./...`
-3. Run `go mod tidy` if dependencies changed
-4. If any files changed, commit and push to the PR branch with a clear message
-5. Comment on the PR noting what was auto-fixed
-
-### Step 4: Write Review Comments
-
-For each issue found:
-- Create a review comment on the specific file and line
-- Explain **what** is wrong and **why** it matters
-- Suggest a fix when possible
-- Be concise and direct — no filler
-
-### Step 5: Submit the Review
-
-Submit a pull request review with your verdict:
-- **APPROVE** if no critical or important issues remain (after auto-fixes)
-- **REQUEST_CHANGES** if there are critical or important issues the author must address
-- **COMMENT** if there are only minor suggestions
-
-### Step 6: Escalation
-
-If the change involves any of the following, add a comment tagging @imjasonh and assign the PR to them:
-- CRD schema changes (anything in `pkg/apis/`)
-- New controller or major architectural changes
-- Changes to the CI pipeline itself
-- Security-sensitive changes (auth, credentials, RBAC)
-- Changes you are uncertain about
-
-Use this format for escalation:
-```
-@imjasonh — This PR needs your review because: [specific reason and question]
-```
-
-## Important Guidelines
-
-- Focus **only** on changed lines — do not review the entire codebase
-- Prioritize critical and important issues over minor style nits
-- When in doubt about intent, leave a question rather than requesting changes
-- Never approve a PR that introduces security vulnerabilities or data loss risks
-- Be direct and specific — every comment should be actionable
diff --git a/.github/workflows/compile-workflows.yaml b/.github/workflows/compile-workflows.yaml
deleted file mode 100644
index 8575589..0000000
--- a/.github/workflows/compile-workflows.yaml
+++ /dev/null
@@ -1,46 +0,0 @@
-name: Compile Agentic Workflows
-
-on:
- pull_request:
- branches: ["main"]
- paths:
- - ".github/workflows/*.md"
-
-jobs:
- compile:
- name: Compile
- runs-on: ubuntu-latest
- # Skip fork PRs: secrets are unavailable, and we should not compile
- # untrusted .md content from a fork and push it back.
- if: github.event.pull_request.head.repo.fork == false
- permissions:
- contents: read # checkout; push uses GH_PAT explicitly
-
- steps:
- - name: Checkout
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- with:
- ref: ${{ github.head_ref }}
- token: ${{ secrets.GH_PAT }}
-
- - name: Install gh-aw extension
- run: gh extension install github/gh-aw --version v0.50.7
- env:
- GH_TOKEN: ${{ secrets.GH_PAT }}
-
- - name: Compile all agentic workflows
- run: gh aw compile .github/workflows/*.md
- env:
- GH_TOKEN: ${{ secrets.GH_PAT }}
-
- - name: Commit and push lock files if changed
- run: |
- git add .github/workflows/*.lock.yml || true
- if git diff --cached --quiet; then
- echo "Lock files are up to date."
- else
- git config user.name "github-actions[bot]"
- git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- git commit -m "Recompile agentic workflow lock files"
- git push
- fi
diff --git a/.github/workflows/dependency-update.lock.yml b/.github/workflows/dependency-update.lock.yml
deleted file mode 100644
index 20fc98d..0000000
--- a/.github/workflows/dependency-update.lock.yml
+++ /dev/null
@@ -1,1308 +0,0 @@
-#
-# ___ _ _
-# / _ \ | | (_)
-# | |_| | __ _ ___ _ __ | |_ _ ___
-# | _ |/ _` |/ _ \ '_ \| __| |/ __|
-# | | | | (_| | __/ | | | |_| | (__
-# \_| |_/\__, |\___|_| |_|\__|_|\___|
-# __/ |
-# _ _ |___/
-# | | | | / _| |
-# | | | | ___ _ __ _ __| |_| | _____ ____
-# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___|
-# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
-# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
-#
-# This file was automatically generated by gh-aw (v0.50.7). 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/
-#
-# Scheduled workflow that checks for Go module dependency updates, applies
-# them, fixes any breaking changes, verifies the build and tests pass, and
-# creates a pull request. Handles major version bumps by updating import
-# paths. Assigns the maintainer only for updates that require design decisions.
-#
-# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"384bff9199673e9f0f6bcc34191f192217a12ef0ba1720d4afb1667426d0893b","compiler_version":"v0.50.7"}
-
-name: "Dependency Updater"
-"on":
- schedule:
- - cron: "12 1 * * 4"
- # Friendly format: weekly (scattered)
- workflow_dispatch:
-
-permissions: {}
-
-concurrency:
- group: "gh-aw-${{ github.workflow }}"
-
-run-name: "Dependency Updater"
-
-jobs:
- activation:
- runs-on: ubuntu-slim
- permissions:
- contents: read
- outputs:
- comment_id: ""
- comment_repo: ""
- secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
- steps:
- - name: Setup Scripts
- uses: github/gh-aw/actions/setup@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Validate ANTHROPIC_API_KEY secret
- id: validate-secret
- run: /opt/gh-aw/actions/validate_multi_secret.sh ANTHROPIC_API_KEY 'Claude Code' https://github.github.com/gh-aw/reference/engines/#anthropic-claude-code
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- - name: Validate context variables
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/validate_context_variables.cjs');
- await main();
- - name: Checkout .github and .agents folders
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- sparse-checkout: |
- .github
- .agents
- fetch-depth: 1
- persist-credentials: false
- - name: Check workflow file timestamps
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_WORKFLOW_FILE: "dependency-update.lock.yml"
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: ${{ env.GH_AW_SAFE_OUTPUTS }}
- 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 }}
- run: |
- bash /opt/gh-aw/actions/create_prompt_first.sh
- {
- cat << 'GH_AW_PROMPT_EOF'
-
- GH_AW_PROMPT_EOF
- cat "/opt/gh-aw/prompts/xpia.md"
- cat "/opt/gh-aw/prompts/temp_folder_prompt.md"
- cat "/opt/gh-aw/prompts/markdown.md"
- cat "/opt/gh-aw/prompts/safe_outputs_prompt.md"
- cat << 'GH_AW_PROMPT_EOF'
-
- Tools: add_comment, create_issue, create_pull_request, missing_tool, missing_data, noop
- GH_AW_PROMPT_EOF
- cat "/opt/gh-aw/prompts/safe_outputs_create_pull_request.md"
- cat << 'GH_AW_PROMPT_EOF'
-
-
- 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_EOF
- cat << 'GH_AW_PROMPT_EOF'
-
- GH_AW_PROMPT_EOF
- cat << 'GH_AW_PROMPT_EOF'
- {{#runtime-import .github/workflows/dependency-update.md}}
- GH_AW_PROMPT_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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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_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 }}
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
-
- const substitutePlaceholders = require('/opt/gh-aw/actions/substitute_placeholders.cjs');
-
- // Call the substitution function
- return await substitutePlaceholders({
- file: process.env.GH_AW_PROMPT,
- substitutions: {
- 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
- }
- });
- - name: Validate prompt placeholders
- env:
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh
- - name: Print prompt
- env:
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- run: bash /opt/gh-aw/actions/print_prompt_summary.sh
- - name: Upload prompt artifact
- if: success()
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: prompt
- path: /tmp/gh-aw/aw-prompts/prompt.txt
- retention-days: 1
-
- agent:
- needs: activation
- runs-on: ubuntu-latest
- permissions: read-all
- concurrency:
- group: "gh-aw-claude-${{ 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_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl
- GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json
- GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json
- GH_AW_WORKFLOW_ID_SANITIZED: dependencyupdate
- outputs:
- checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
- detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}
- detection_success: ${{ steps.detection_conclusion.outputs.success }}
- has_patch: ${{ steps.collect_output.outputs.has_patch }}
- model: ${{ steps.generate_aw_info.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@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Checkout repository
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- persist-credentials: false
- - name: Create gh-aw temp directory
- run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.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: 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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs');
- await main();
- - name: Generate agentic run info
- id: generate_aw_info
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const fs = require('fs');
-
- const awInfo = {
- engine_id: "claude",
- engine_name: "Claude Code",
- model: process.env.GH_AW_MODEL_AGENT_CLAUDE || "",
- version: "",
- agent_version: "2.1.62",
- cli_version: "v0.50.7",
- workflow_name: "Dependency Updater",
- experimental: false,
- supports_tools_allowlist: true,
- run_id: context.runId,
- run_number: context.runNumber,
- run_attempt: process.env.GITHUB_RUN_ATTEMPT,
- repository: context.repo.owner + '/' + context.repo.repo,
- ref: context.ref,
- sha: context.sha,
- actor: context.actor,
- event_name: context.eventName,
- staged: false,
- allowed_domains: ["go"],
- firewall_enabled: true,
- awf_version: "v0.23.0",
- awmg_version: "v0.1.6",
- steps: {
- firewall: "squid"
- },
- created_at: new Date().toISOString()
- };
-
- // Write to /tmp/gh-aw directory to avoid inclusion in PR
- const tmpPath = '/tmp/gh-aw/aw_info.json';
- fs.writeFileSync(tmpPath, JSON.stringify(awInfo, null, 2));
- console.log('Generated aw_info.json at:', tmpPath);
- console.log(JSON.stringify(awInfo, null, 2));
-
- // Set model as output for reuse in other steps/jobs
- core.setOutput('model', awInfo.model);
- - name: Setup Node.js
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
- with:
- node-version: '24'
- package-manager-cache: false
- - name: Install awf binary
- run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0
- - name: Install Claude Code CLI
- run: npm install -g --silent @anthropic-ai/claude-code@2.1.62
- - 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('/opt/gh-aw/actions/determine_automatic_lockdown.cjs');
- await determineAutomaticLockdown(github, context, core);
- - name: Download container images
- run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.6 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine
- - name: Write Safe Outputs Config
- run: |
- mkdir -p /opt/gh-aw/safeoutputs
- mkdir -p /tmp/gh-aw/safeoutputs
- mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
- cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF'
- {"add_comment":{"max":1},"create_issue":{"max":1},"create_pull_request":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}}
- GH_AW_SAFE_OUTPUTS_CONFIG_EOF
- cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF'
- [
- {
- "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[Deps] \". Labels [automation dependencies] will be automatically added. Assignees [imjasonh] will be automatically assigned.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "body": {
- "description": "Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.",
- "type": "string"
- },
- "labels": {
- "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "parent": {
- "description": "Parent issue number for creating sub-issues. This is the numeric ID from the GitHub URL (e.g., 42 in github.com/owner/repo/issues/42). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from a previously created issue in the same workflow run.",
- "type": [
- "number",
- "string"
- ]
- },
- "temporary_id": {
- "description": "Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 3 to 8 alphanumeric characters (e.g., 'aw_abc1', 'aw_Test123'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.",
- "pattern": "^aw_[A-Za-z0-9]{3,8}$",
- "type": "string"
- },
- "title": {
- "description": "Concise issue title summarizing the bug, feature, or task. The title appears as the main heading, so keep it brief and descriptive.",
- "type": "string"
- }
- },
- "required": [
- "title",
- "body"
- ],
- "type": "object"
- },
- "name": "create_issue"
- },
- {
- "description": "Add a comment to an existing GitHub issue, pull request, or discussion. Use this to provide feedback, answer questions, or add information to an existing conversation. For creating new items, use create_issue, create_discussion, or create_pull_request instead. IMPORTANT: Comments are subject to validation constraints enforced by the MCP server - maximum 65536 characters for the complete comment (including footer which is added automatically), 10 mentions (@username), and 50 links. Exceeding these limits will result in an immediate error with specific guidance. NOTE: By default, this tool requires discussions:write permission. If your GitHub App lacks Discussions permission, set 'discussions: false' in the workflow's safe-outputs.add-comment configuration to exclude this permission. CONSTRAINTS: Maximum 1 comment(s) can be added.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "body": {
- "description": "The comment text in Markdown format. This is the 'body' field - do not use 'comment_body' or other variations. Provide helpful, relevant information that adds value to the conversation. CONSTRAINTS: The complete comment (your body text + automatically added footer) must not exceed 65536 characters total. Maximum 10 mentions (@username), maximum 50 links (http/https URLs). A footer (~200-500 characters) is automatically appended with workflow attribution, so leave adequate space. If these limits are exceeded, the tool call will fail with a detailed error message indicating which constraint was violated.",
- "type": "string"
- },
- "item_number": {
- "description": "The issue, pull request, or discussion number to comment on. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123). If omitted, the tool auto-targets the issue, PR, or discussion that triggered this workflow. Auto-targeting only works for issue, pull_request, discussion, and comment event triggers — it does NOT work for schedule, workflow_dispatch, push, or workflow_run triggers. For those trigger types, always provide item_number explicitly, or the comment will be silently discarded.",
- "type": "number"
- }
- },
- "required": [
- "body"
- ],
- "type": "object"
- },
- "name": "add_comment"
- },
- {
- "description": "Create a new GitHub pull request to propose code changes. Use this after making file edits to submit them for review and merging. The PR will be created from the current branch with your committed changes. For code review comments on an existing PR, use create_pull_request_review_comment instead. CONSTRAINTS: Maximum 1 pull request(s) can be created. Title will be prefixed with \"[Deps] \". Labels [automation dependencies] will be automatically added.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "body": {
- "description": "Detailed PR description in Markdown. Include what changes were made, why, testing notes, and any breaking changes. Do NOT repeat the title as a heading.",
- "type": "string"
- },
- "branch": {
- "description": "Source branch name containing the changes. If omitted, uses the current working branch.",
- "type": "string"
- },
- "draft": {
- "description": "Whether to create the PR as a draft. Draft PRs cannot be merged until marked as ready for review. Use mark_pull_request_as_ready_for_review to convert a draft PR. Default: true.",
- "type": "boolean"
- },
- "labels": {
- "description": "Labels to categorize the PR (e.g., 'enhancement', 'bugfix'). Labels must exist in the repository.",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "title": {
- "description": "Concise PR title describing the changes. Follow repository conventions (e.g., conventional commits). The title appears as the main heading.",
- "type": "string"
- }
- },
- "required": [
- "title",
- "body"
- ],
- "type": "object"
- },
- "name": "create_pull_request"
- },
- {
- "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "alternatives": {
- "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
- "type": "string"
- },
- "reason": {
- "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).",
- "type": "string"
- },
- "tool": {
- "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.",
- "type": "string"
- }
- },
- "required": [
- "reason"
- ],
- "type": "object"
- },
- "name": "missing_tool"
- },
- {
- "description": "Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "message": {
- "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').",
- "type": "string"
- }
- },
- "required": [
- "message"
- ],
- "type": "object"
- },
- "name": "noop"
- },
- {
- "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "alternatives": {
- "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
- "type": "string"
- },
- "context": {
- "description": "Additional context about the missing data or where it should come from (max 256 characters).",
- "type": "string"
- },
- "data_type": {
- "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.",
- "type": "string"
- },
- "reason": {
- "description": "Explanation of why this data is needed to complete the task (max 256 characters).",
- "type": "string"
- }
- },
- "required": [],
- "type": "object"
- },
- "name": "missing_data"
- }
- ]
- GH_AW_SAFE_OUTPUTS_TOOLS_EOF
- cat > /opt/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF'
- {
- "add_comment": {
- "defaultMax": 1,
- "fields": {
- "body": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "item_number": {
- "issueOrPRNumber": true
- },
- "repo": {
- "type": "string",
- "maxLength": 256
- }
- }
- },
- "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
- }
- }
- },
- "create_pull_request": {
- "defaultMax": 1,
- "fields": {
- "body": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "branch": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 256
- },
- "draft": {
- "type": "boolean"
- },
- "labels": {
- "type": "array",
- "itemType": "string",
- "itemSanitize": true,
- "itemMaxLength": 128
- },
- "repo": {
- "type": "string",
- "maxLength": 256
- },
- "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_EOF
- - 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: /opt/gh-aw/safeoutputs/tools.json
- GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/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 /opt/gh-aw/actions/start_safe_outputs_server.sh
-
- - name: Start MCP Gateway
- id: start-mcp-gateway
- env:
- GH_AW_SAFE_OUTPUTS: ${{ env.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_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }}
- 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 DEBUG="*"
-
- export GH_AW_ENGINE="claude"
- 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 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_LOCKDOWN -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.1.6'
-
- cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh
- {
- "mcpServers": {
- "github": {
- "container": "ghcr.io/github/github-mcp-server:v0.31.0",
- "env": {
- "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN",
- "GITHUB_PERSONAL_ACCESS_TOKEN": "$GITHUB_MCP_SERVER_TOKEN",
- "GITHUB_READ_ONLY": "1",
- "GITHUB_TOOLSETS": "pull_requests,repos,issues"
- }
- },
- "safeoutputs": {
- "type": "http",
- "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT",
- "headers": {
- "Authorization": "$GH_AW_SAFE_OUTPUTS_API_KEY"
- }
- }
- },
- "gateway": {
- "port": $MCP_GATEWAY_PORT,
- "domain": "${MCP_GATEWAY_DOMAIN}",
- "apiKey": "${MCP_GATEWAY_API_KEY}",
- "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
- }
- }
- GH_AW_MCP_CONFIG_EOF
- - name: Generate workflow overview
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { generateWorkflowOverview } = require('/opt/gh-aw/actions/generate_workflow_overview.cjs');
- await generateWorkflowOverview(core);
- - name: Download prompt artifact
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: prompt
- path: /tmp/gh-aw/aw-prompts
- - name: Clean git credentials
- run: bash /opt/gh-aw/actions/clean_git_credentials.sh
- - name: Execute Claude Code CLI
- id: agentic_execution
- # Allowed tools (sorted):
- # - Bash
- # - BashOutput
- # - Edit
- # - ExitPlanMode
- # - Glob
- # - Grep
- # - KillBash
- # - LS
- # - MultiEdit
- # - NotebookEdit
- # - NotebookRead
- # - Read
- # - Task
- # - TodoWrite
- # - WebFetch
- # - Write
- # - mcp__github__download_workflow_run_artifact
- # - mcp__github__get_code_scanning_alert
- # - mcp__github__get_commit
- # - mcp__github__get_dependabot_alert
- # - mcp__github__get_discussion
- # - mcp__github__get_discussion_comments
- # - mcp__github__get_file_contents
- # - mcp__github__get_job_logs
- # - mcp__github__get_label
- # - mcp__github__get_latest_release
- # - mcp__github__get_me
- # - mcp__github__get_notification_details
- # - mcp__github__get_pull_request
- # - mcp__github__get_pull_request_comments
- # - mcp__github__get_pull_request_diff
- # - mcp__github__get_pull_request_files
- # - mcp__github__get_pull_request_review_comments
- # - mcp__github__get_pull_request_reviews
- # - mcp__github__get_pull_request_status
- # - mcp__github__get_release_by_tag
- # - mcp__github__get_secret_scanning_alert
- # - mcp__github__get_tag
- # - mcp__github__get_workflow_run
- # - mcp__github__get_workflow_run_logs
- # - mcp__github__get_workflow_run_usage
- # - mcp__github__issue_read
- # - mcp__github__list_branches
- # - mcp__github__list_code_scanning_alerts
- # - mcp__github__list_commits
- # - mcp__github__list_dependabot_alerts
- # - mcp__github__list_discussion_categories
- # - mcp__github__list_discussions
- # - mcp__github__list_issue_types
- # - mcp__github__list_issues
- # - mcp__github__list_label
- # - mcp__github__list_notifications
- # - mcp__github__list_pull_requests
- # - mcp__github__list_releases
- # - mcp__github__list_secret_scanning_alerts
- # - mcp__github__list_starred_repositories
- # - mcp__github__list_tags
- # - mcp__github__list_workflow_jobs
- # - mcp__github__list_workflow_run_artifacts
- # - mcp__github__list_workflow_runs
- # - mcp__github__list_workflows
- # - mcp__github__pull_request_read
- # - mcp__github__search_code
- # - mcp__github__search_issues
- # - mcp__github__search_orgs
- # - mcp__github__search_pull_requests
- # - mcp__github__search_repositories
- # - mcp__github__search_users
- timeout-minutes: 30
- run: |
- set -o pipefail
- # shellcheck disable=SC1003
- sudo -E awf --tty --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,go.dev,golang.org,goproxy.io,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkg.go.dev,playwright.download.prss.microsoft.com,ppa.launchpad.net,proxy.golang.org,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,storage.googleapis.com,sum.golang.org,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && claude --print --disable-slash-commands --no-chrome --mcp-config /tmp/gh-aw/mcp-config/mcp-servers.json --allowed-tools Bash,BashOutput,Edit,ExitPlanMode,Glob,Grep,KillBash,LS,MultiEdit,NotebookEdit,NotebookRead,Read,Task,TodoWrite,WebFetch,Write,mcp__github__download_workflow_run_artifact,mcp__github__get_code_scanning_alert,mcp__github__get_commit,mcp__github__get_dependabot_alert,mcp__github__get_discussion,mcp__github__get_discussion_comments,mcp__github__get_file_contents,mcp__github__get_job_logs,mcp__github__get_label,mcp__github__get_latest_release,mcp__github__get_me,mcp__github__get_notification_details,mcp__github__get_pull_request,mcp__github__get_pull_request_comments,mcp__github__get_pull_request_diff,mcp__github__get_pull_request_files,mcp__github__get_pull_request_review_comments,mcp__github__get_pull_request_reviews,mcp__github__get_pull_request_status,mcp__github__get_release_by_tag,mcp__github__get_secret_scanning_alert,mcp__github__get_tag,mcp__github__get_workflow_run,mcp__github__get_workflow_run_logs,mcp__github__get_workflow_run_usage,mcp__github__issue_read,mcp__github__list_branches,mcp__github__list_code_scanning_alerts,mcp__github__list_commits,mcp__github__list_dependabot_alerts,mcp__github__list_discussion_categories,mcp__github__list_discussions,mcp__github__list_issue_types,mcp__github__list_issues,mcp__github__list_label,mcp__github__list_notifications,mcp__github__list_pull_requests,mcp__github__list_releases,mcp__github__list_secret_scanning_alerts,mcp__github__list_starred_repositories,mcp__github__list_tags,mcp__github__list_workflow_jobs,mcp__github__list_workflow_run_artifacts,mcp__github__list_workflow_runs,mcp__github__list_workflows,mcp__github__pull_request_read,mcp__github__search_code,mcp__github__search_issues,mcp__github__search_orgs,mcp__github__search_pull_requests,mcp__github__search_repositories,mcp__github__search_users --debug-file /tmp/gh-aw/agent-stdio.log --verbose --permission-mode bypassPermissions --output-format stream-json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_CLAUDE:+ --model "$GH_AW_MODEL_AGENT_CLAUDE"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- BASH_DEFAULT_TIMEOUT_MS: 60000
- BASH_MAX_TIMEOUT_MS: 60000
- DISABLE_BUG_COMMAND: 1
- DISABLE_ERROR_REPORTING: 1
- DISABLE_TELEMETRY: 1
- GH_AW_MCP_CONFIG: /tmp/gh-aw/mcp-config/mcp-servers.json
- GH_AW_MODEL_AGENT_CLAUDE: ${{ vars.GH_AW_MODEL_AGENT_CLAUDE || '' }}
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
- GITHUB_WORKSPACE: ${{ github.workspace }}
- MCP_TIMEOUT: 120000
- MCP_TOOL_TIMEOUT: 60000
- - 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: 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 /opt/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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs');
- await main();
- env:
- GH_AW_SECRET_NAMES: 'ANTHROPIC_API_KEY,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
- SECRET_ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
- SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
- SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: Upload Safe Outputs
- if: always()
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: safe-output
- path: ${{ env.GH_AW_SAFE_OUTPUTS }}
- if-no-files-found: warn
- - name: Ingest agent output
- id: collect_output
- if: always()
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
- GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,go.dev,golang.org,goproxy.io,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkg.go.dev,playwright.download.prss.microsoft.com,ppa.launchpad.net,proxy.golang.org,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,storage.googleapis.com,sum.golang.org,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com"
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_API_URL: ${{ github.api_url }}
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs');
- await main();
- - name: Upload sanitized agent output
- if: always() && env.GH_AW_AGENT_OUTPUT
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: agent-output
- path: ${{ env.GH_AW_AGENT_OUTPUT }}
- if-no-files-found: warn
- - name: Parse agent logs for step summary
- if: always()
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: /tmp/gh-aw/agent-stdio.log
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/parse_claude_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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: Upload agent artifacts
- if: always()
- continue-on-error: true
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: agent-artifacts
- path: |
- /tmp/gh-aw/aw-prompts/prompt.txt
- /tmp/gh-aw/aw_info.json
- /tmp/gh-aw/mcp-logs/
- /tmp/gh-aw/sandbox/firewall/logs/
- /tmp/gh-aw/agent-stdio.log
- /tmp/gh-aw/agent/
- /tmp/gh-aw/aw-*.patch
- if-no-files-found: ignore
- # --- Threat Detection (inline) ---
- - name: Check if detection needed
- id: detection_guard
- if: always()
- env:
- OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }}
- HAS_PATCH: ${{ steps.collect_output.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: "Dependency Updater"
- WORKFLOW_DESCRIPTION: "Scheduled workflow that checks for Go module dependency updates, applies\nthem, fixes any breaking changes, verifies the build and tests pass, and\ncreates a pull request. Handles major version bumps by updating import\npaths. Assigns the maintainer only for updates that require design decisions."
- HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: Execute Claude Code CLI
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- id: detection_agentic_execution
- # Allowed tools (sorted):
- # - Bash(cat)
- # - Bash(grep)
- # - Bash(head)
- # - Bash(jq)
- # - Bash(ls)
- # - Bash(tail)
- # - Bash(wc)
- # - BashOutput
- # - ExitPlanMode
- # - Glob
- # - Grep
- # - KillBash
- # - LS
- # - NotebookRead
- # - Read
- # - Task
- # - TodoWrite
- timeout-minutes: 20
- run: |
- set -o pipefail
- # shellcheck disable=SC1003
- sudo -E awf --tty --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && claude --print --disable-slash-commands --no-chrome --allowed-tools '\''Bash(cat),Bash(grep),Bash(head),Bash(jq),Bash(ls),Bash(tail),Bash(wc),BashOutput,ExitPlanMode,Glob,Grep,KillBash,LS,NotebookRead,Read,Task,TodoWrite'\'' --debug-file /tmp/gh-aw/threat-detection/detection.log --verbose --permission-mode bypassPermissions --output-format stream-json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_DETECTION_CLAUDE:+ --model "$GH_AW_MODEL_DETECTION_CLAUDE"}' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- BASH_DEFAULT_TIMEOUT_MS: 60000
- BASH_MAX_TIMEOUT_MS: 60000
- DISABLE_BUG_COMMAND: 1
- DISABLE_ERROR_REPORTING: 1
- DISABLE_TELEMETRY: 1
- GH_AW_MODEL_DETECTION_CLAUDE: ${{ vars.GH_AW_MODEL_DETECTION_CLAUDE || '' }}
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GITHUB_WORKSPACE: ${{ github.workspace }}
- MCP_TIMEOUT: 120000
- MCP_TOOL_TIMEOUT: 60000
- - name: Parse threat detection results
- id: parse_detection_results
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs');
- await main();
- - name: Upload threat detection log
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: threat-detection.log
- path: /tmp/gh-aw/threat-detection/detection.log
- if-no-files-found: ignore
- - name: Set detection conclusion
- id: detection_conclusion
- if: always()
- env:
- RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}
- DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }}
- run: |
- if [[ "$RUN_DETECTION" != "true" ]]; then
- echo "conclusion=skipped" >> "$GITHUB_OUTPUT"
- echo "success=true" >> "$GITHUB_OUTPUT"
- echo "Detection was not needed, marking as skipped"
- elif [[ "$DETECTION_SUCCESS" == "true" ]]; then
- echo "conclusion=success" >> "$GITHUB_OUTPUT"
- echo "success=true" >> "$GITHUB_OUTPUT"
- echo "Detection passed successfully"
- else
- echo "conclusion=failure" >> "$GITHUB_OUTPUT"
- echo "success=false" >> "$GITHUB_OUTPUT"
- echo "Detection found issues"
- fi
-
- conclusion:
- needs:
- - activation
- - agent
- - safe_outputs
- if: (always()) && (needs.agent.result != 'skipped')
- runs-on: ubuntu-slim
- permissions:
- contents: write
- discussions: write
- issues: write
- pull-requests: write
- 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@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Download agent output artifact
- continue-on-error: true
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: agent-output
- path: /tmp/gh-aw/safeoutputs/
- - name: Setup agent output environment variable
- run: |
- mkdir -p /tmp/gh-aw/safeoutputs/
- find "/tmp/gh-aw/safeoutputs/" -type f -print
- echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
- - name: Process No-Op Messages
- id: noop
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_NOOP_MAX: "1"
- GH_AW_WORKFLOW_NAME: "Dependency Updater"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Dependency Updater"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/missing_tool.cjs');
- await main();
- - name: Handle Agent Failure
- id: handle_agent_failure
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Dependency Updater"
- 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: "dependency-update"
- GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }}
- GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
- GH_AW_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }}
- GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }}
- GH_AW_GROUP_REPORTS: "false"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Dependency Updater"
- 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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/handle_noop_message.cjs');
- await main();
- - name: Handle Create Pull Request Error
- id: handle_create_pr_error
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Dependency Updater"
- GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/handle_create_pr_error.cjs');
- await main();
-
- safe_outputs:
- needs:
- - activation
- - agent
- if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_success == 'true')
- runs-on: ubuntu-slim
- permissions:
- contents: write
- discussions: write
- issues: write
- pull-requests: write
- timeout-minutes: 15
- env:
- GH_AW_ENGINE_ID: "claude"
- GH_AW_WORKFLOW_ID: "dependency-update"
- GH_AW_WORKFLOW_NAME: "Dependency Updater"
- outputs:
- 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 }}
- 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@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Download agent output artifact
- continue-on-error: true
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: agent-output
- path: /tmp/gh-aw/safeoutputs/
- - name: Setup agent output environment variable
- run: |
- mkdir -p /tmp/gh-aw/safeoutputs/
- find "/tmp/gh-aw/safeoutputs/" -type f -print
- echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
- - name: Download patch artifact
- continue-on-error: true
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: agent-artifacts
- path: /tmp/gh-aw/
- - name: Checkout repository
- if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request'))
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- ref: ${{ github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }}
- token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- persist-credentials: false
- fetch-depth: 1
- - name: Configure Git credentials
- if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request'))
- env:
- REPO_NAME: ${{ github.repository }}
- SERVER_URL: ${{ github.server_url }}
- GIT_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- 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:${GIT_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
- echo "Git configured with standard GitHub Actions identity"
- - name: Process Safe Outputs
- id: process_safe_outputs
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,go.dev,golang.org,goproxy.io,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkg.go.dev,playwright.download.prss.microsoft.com,ppa.launchpad.net,proxy.golang.org,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,storage.googleapis.com,sum.golang.org,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com"
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_API_URL: ${{ github.api_url }}
- GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_issue\":{\"assignees\":[\"imjasonh\"],\"labels\":[\"automation\",\"dependencies\"],\"max\":1,\"title_prefix\":\"[Deps] \"},\"create_pull_request\":{\"draft\":false,\"labels\":[\"automation\",\"dependencies\"],\"max\":1,\"max_patch_size\":1024,\"title_prefix\":\"[Deps] \"},\"missing_data\":{},\"missing_tool\":{}}"
- GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }}
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs');
- await main();
- - name: Upload safe output items manifest
- if: always()
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: safe-output-items
- path: /tmp/safe-output-items.jsonl
- if-no-files-found: warn
-
diff --git a/.github/workflows/dependency-update.md b/.github/workflows/dependency-update.md
deleted file mode 100644
index 7c202a9..0000000
--- a/.github/workflows/dependency-update.md
+++ /dev/null
@@ -1,131 +0,0 @@
----
-description: |
- Scheduled workflow that checks for Go module dependency updates, applies
- them, fixes any breaking changes, verifies the build and tests pass, and
- creates a pull request. Handles major version bumps by updating import
- paths. Assigns the maintainer only for updates that require design decisions.
-
-on:
- schedule: weekly
- workflow_dispatch:
-
-permissions: read-all
-
-network:
- allowed:
- - go
- blocked: []
-
-safe-outputs:
- create-pull-request:
- title-prefix: "[Deps] "
- labels: [automation, dependencies]
- draft: false
- create-issue:
- title-prefix: "[Deps] "
- labels: [automation, dependencies]
- assignees: [imjasonh]
- add-comment:
-
-tools:
- bash: true
- web-fetch:
- github:
- toolsets: [pull_requests, repos, issues]
-
-engine: claude
-
-timeout-minutes: 30
----
-
-# Dependency Updater
-
-You are a dependency maintenance agent for the **git-k8s** project. Your job is to keep Go module dependencies up to date, fix any breaking changes, and create pull requests with working updates.
-
-## Project Context
-
-- **Language**: Go 1.24.7, module `github.com/imjasonh/git-k8s`
-- **Key direct dependencies**:
- - `github.com/go-git/go-git/v5` — all Git operations (clone, push, diff, merge)
- - `k8s.io/api`, `k8s.io/apimachinery`, `k8s.io/client-go` — Kubernetes API and client
- - `knative.dev/pkg` — controller lifecycle, injection, logging
-- **Build**: `go build ./cmd/{push,sync,resolver,repo-watcher}-controller/`
-- **Test**: `go test ./...`
-- **Lint**: `go vet ./...`
-
-## Update Protocol
-
-### Step 1: Check for Updates
-
-1. Create a fresh branch from `main`
-2. Run `go list -m -u all` to check for available updates
-3. Categorize updates:
- - **Security patches**: any update flagged by `govulncheck` or known CVEs
- - **Direct dependency updates**: updates to the 5 direct dependencies listed above
- - **Indirect dependency updates**: transitive dependency updates
- - **Go toolchain**: check if a newer Go patch version is available
-
-### Step 2: Prioritize and Group
-
-Group updates into logical batches for separate PRs:
-
-1. **Security fixes** — highest priority, always process first
-2. **Kubernetes ecosystem** (`k8s.io/*`) — update together since they share versions
-3. **Knative** (`knative.dev/pkg`) — update separately, may have breaking changes
-4. **go-git** (`go-git/v5`) — update separately, core to the project
-5. **Everything else** — bundle remaining indirect updates
-
-### Step 3: Apply Updates (per batch)
-
-For each batch:
-
-1. Run `go get @latest` for each module in the batch
-2. Run `go mod tidy`
-3. Attempt to build: `go build ./cmd/push-controller/ && go build ./cmd/sync-controller/ && go build ./cmd/resolver-controller/ && go build ./cmd/repo-watcher-controller/`
-
-If the build fails:
-4. Analyze compilation errors
-5. Fix breaking API changes:
- - Renamed functions/types: update all call sites
- - Changed signatures: adapt to new parameter/return types
- - Removed APIs: find replacement APIs in the new version's docs (use web-fetch)
- - Import path changes (major version bumps): update all import statements
-6. Rebuild and iterate until compilation succeeds
-
-7. Run `go test ./...` and fix any test failures
-8. Run `go vet ./...` and fix any linting issues
-
-### Step 4: Create Pull Request
-
-For each successful batch, create a PR with:
-- Title summarizing which dependencies were updated
-- Body listing each dependency, old version, new version
-- Description of any breaking changes fixed
-- Confirmation that build, tests, and vet pass
-
-### Step 5: Handle Failures
-
-If you cannot resolve breaking changes for a dependency update:
-1. Do **not** create a PR with broken code
-2. Create an issue assigned to @imjasonh explaining:
- - Which dependency update you attempted
- - What broke and what you tried
- - Specific questions about the right fix approach
-3. Move on to the next batch
-
-### Step 6: Go Toolchain
-
-If a newer Go patch version is available (e.g., 1.24.8):
-1. Update `go.mod` directive
-2. Update `.github/workflows/ci.yaml` `go-version-file` (already uses `go.mod`, but verify)
-3. Build and test
-4. Create a separate PR for the Go version bump
-
-## Guidelines
-
-- **One logical change per PR** — don't mix Kubernetes updates with go-git updates
-- **Always verify** — never create a PR without confirming build + test + vet pass
-- **Fix breaking changes** — don't just bump versions; make the code work with new APIs
-- **Document what changed** — the PR description should explain what was updated and why
-- **Security first** — process security-related updates before feature updates
-- **Skip if current** — if all dependencies are already at their latest versions, exit cleanly without creating issues or PRs
diff --git a/.github/workflows/pr-fix.lock.yml b/.github/workflows/pr-fix.lock.yml
deleted file mode 100644
index 7d0fc39..0000000
--- a/.github/workflows/pr-fix.lock.yml
+++ /dev/null
@@ -1,1342 +0,0 @@
-#
-# ___ _ _
-# / _ \ | | (_)
-# | |_| | __ _ ___ _ __ | |_ _ ___
-# | _ |/ _` |/ _ \ '_ \| __| |/ __|
-# | | | | (_| | __/ | | | |_| | (__
-# \_| |_/\__, |\___|_| |_|\__|_|\___|
-# __/ |
-# _ _ |___/
-# | | | | / _| |
-# | | | | ___ _ __ _ __| |_| | _____ ____
-# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___|
-# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
-# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
-#
-# This file was automatically generated by gh-aw (v0.50.7). 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/
-#
-# On-demand PR fixer triggered by the /pr-fix command. Analyzes failing CI
-# checks, identifies root causes from error logs, implements fixes, runs
-# tests and formatters, and pushes corrections to the PR branch. Provides
-# detailed comments explaining changes made.
-#
-# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"5d6c037e259559e077aea1b007a9253451aae79ad1065dc0d45de6d77a7b6ee4","compiler_version":"v0.50.7"}
-
-name: "PR Fix"
-"on":
- discussion:
- types:
- - created
- - edited
- discussion_comment:
- types:
- - created
- - edited
- issue_comment:
- types:
- - created
- - edited
- issues:
- types:
- - opened
- - edited
- - reopened
- pull_request:
- types:
- - opened
- - edited
- - reopened
- pull_request_review_comment:
- types:
- - created
- - edited
-
-permissions: {}
-
-concurrency:
- group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number }}"
-
-run-name: "PR Fix"
-
-jobs:
- activation:
- needs: pre_activation
- if: >
- (needs.pre_activation.outputs.activated == 'true') && ((github.event_name == 'issues') && ((startsWith(github.event.issue.body, '/pr-fix ')) ||
- (github.event.issue.body == '/pr-fix')) || (github.event_name == 'issue_comment') && (((startsWith(github.event.comment.body, '/pr-fix ')) ||
- (github.event.comment.body == '/pr-fix')) && (github.event.issue.pull_request == null)) || (github.event_name == 'issue_comment') &&
- (((startsWith(github.event.comment.body, '/pr-fix ')) || (github.event.comment.body == '/pr-fix')) &&
- (github.event.issue.pull_request != null)) || (github.event_name == 'pull_request_review_comment') &&
- ((startsWith(github.event.comment.body, '/pr-fix ')) || (github.event.comment.body == '/pr-fix')) ||
- (github.event_name == 'pull_request') &&
- ((startsWith(github.event.pull_request.body, '/pr-fix ')) || (github.event.pull_request.body == '/pr-fix')) ||
- (github.event_name == 'discussion') && ((startsWith(github.event.discussion.body, '/pr-fix ')) || (github.event.discussion.body == '/pr-fix')) ||
- (github.event_name == 'discussion_comment') && ((startsWith(github.event.comment.body, '/pr-fix ')) ||
- (github.event.comment.body == '/pr-fix')))
- runs-on: ubuntu-slim
- permissions:
- contents: read
- discussions: write
- issues: write
- pull-requests: write
- outputs:
- body: ${{ steps.sanitized.outputs.body }}
- comment_id: ""
- comment_repo: ""
- secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
- slash_command: ${{ needs.pre_activation.outputs.matched_command }}
- text: ${{ steps.sanitized.outputs.text }}
- title: ${{ steps.sanitized.outputs.title }}
- steps:
- - name: Setup Scripts
- uses: github/gh-aw/actions/setup@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Validate ANTHROPIC_API_KEY secret
- id: validate-secret
- run: /opt/gh-aw/actions/validate_multi_secret.sh ANTHROPIC_API_KEY 'Anthropic Claude' https://github.github.com/gh-aw/reference/engines/#anthropic-claude
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- - name: Validate context variables
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/validate_context_variables.cjs');
- await main();
- - name: Checkout .github and .agents folders
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- sparse-checkout: |
- .github
- .agents
- fetch-depth: 1
- persist-credentials: false
- - name: Check workflow file timestamps
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_WORKFLOW_FILE: "pr-fix.lock.yml"
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs');
- await main();
- - name: Compute current body text
- id: sanitized
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/compute_text.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: ${{ env.GH_AW_SAFE_OUTPUTS }}
- 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_IS_PR_COMMENT: ${{ github.event.issue.pull_request && 'true' || '' }}
- GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
- run: |
- bash /opt/gh-aw/actions/create_prompt_first.sh
- {
- cat << 'GH_AW_PROMPT_EOF'
-
- GH_AW_PROMPT_EOF
- cat "/opt/gh-aw/prompts/xpia.md"
- cat "/opt/gh-aw/prompts/temp_folder_prompt.md"
- cat "/opt/gh-aw/prompts/markdown.md"
- cat "/opt/gh-aw/prompts/safe_outputs_prompt.md"
- cat << 'GH_AW_PROMPT_EOF'
-
- Tools: add_comment, create_issue, push_to_pull_request_branch, missing_tool, missing_data, noop
- GH_AW_PROMPT_EOF
- cat "/opt/gh-aw/prompts/safe_outputs_push_to_pr_branch.md"
- cat << 'GH_AW_PROMPT_EOF'
-
-
- 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_EOF
- if [ "$GITHUB_EVENT_NAME" = "issue_comment" ] && [ -n "$GH_AW_IS_PR_COMMENT" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review_comment" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review" ]; then
- cat "/opt/gh-aw/prompts/pr_context_prompt.md"
- fi
- cat << 'GH_AW_PROMPT_EOF'
-
- GH_AW_PROMPT_EOF
- cat << 'GH_AW_PROMPT_EOF'
- {{#runtime-import .github/workflows/pr-fix.md}}
- GH_AW_PROMPT_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
- GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
- GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
- GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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_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_IS_PR_COMMENT: ${{ github.event.issue.pull_request && 'true' || '' }}
- GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }}
- GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: ${{ needs.pre_activation.outputs.matched_command }}
- GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
-
- const substitutePlaceholders = require('/opt/gh-aw/actions/substitute_placeholders.cjs');
-
- // Call the substitution function
- return await substitutePlaceholders({
- file: process.env.GH_AW_PROMPT,
- substitutions: {
- 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_IS_PR_COMMENT: process.env.GH_AW_IS_PR_COMMENT,
- GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED,
- GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND,
- GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: process.env.GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT
- }
- });
- - name: Validate prompt placeholders
- env:
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh
- - name: Print prompt
- env:
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- run: bash /opt/gh-aw/actions/print_prompt_summary.sh
- - name: Upload prompt artifact
- if: success()
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: prompt
- path: /tmp/gh-aw/aw-prompts/prompt.txt
- retention-days: 1
-
- agent:
- needs: activation
- runs-on: ubuntu-latest
- permissions: read-all
- 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_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl
- GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json
- GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json
- GH_AW_WORKFLOW_ID_SANITIZED: prfix
- outputs:
- checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
- detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}
- detection_success: ${{ steps.detection_conclusion.outputs.success }}
- has_patch: ${{ steps.collect_output.outputs.has_patch }}
- model: ${{ steps.generate_aw_info.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@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Checkout repository
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- persist-credentials: false
- - name: Create gh-aw temp directory
- run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.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: 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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs');
- await main();
- - name: Generate agentic run info
- id: generate_aw_info
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const fs = require('fs');
-
- const awInfo = {
- engine_id: "copilot",
- engine_name: "GitHub Copilot CLI",
- model: process.env.GH_AW_MODEL_AGENT_COPILOT || "",
- version: "",
- agent_version: "0.0.419",
- cli_version: "v0.50.7",
- workflow_name: "PR Fix",
- experimental: false,
- supports_tools_allowlist: true,
- run_id: context.runId,
- run_number: context.runNumber,
- run_attempt: process.env.GITHUB_RUN_ATTEMPT,
- repository: context.repo.owner + '/' + context.repo.repo,
- ref: context.ref,
- sha: context.sha,
- actor: context.actor,
- event_name: context.eventName,
- staged: false,
- allowed_domains: ["defaults"],
- firewall_enabled: true,
- awf_version: "v0.23.0",
- awmg_version: "v0.1.6",
- steps: {
- firewall: "squid"
- },
- created_at: new Date().toISOString()
- };
-
- // Write to /tmp/gh-aw directory to avoid inclusion in PR
- const tmpPath = '/tmp/gh-aw/aw_info.json';
- fs.writeFileSync(tmpPath, JSON.stringify(awInfo, null, 2));
- console.log('Generated aw_info.json at:', tmpPath);
- console.log(JSON.stringify(awInfo, null, 2));
-
- // Set model as output for reuse in other steps/jobs
- core.setOutput('model', awInfo.model);
- - name: Install GitHub Copilot CLI
- run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.419
- - name: Install awf binary
- run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0
- - 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('/opt/gh-aw/actions/determine_automatic_lockdown.cjs');
- await determineAutomaticLockdown(github, context, core);
- - name: Download container images
- run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.6 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine
- - name: Write Safe Outputs Config
- run: |
- mkdir -p /opt/gh-aw/safeoutputs
- mkdir -p /tmp/gh-aw/safeoutputs
- mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
- cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF'
- {"add_comment":{"max":1},"create_issue":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1},"push_to_pull_request_branch":{"max":0}}
- GH_AW_SAFE_OUTPUTS_CONFIG_EOF
- cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF'
- [
- {
- "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[PR Fix] \". Labels [automation pr-fix] will be automatically added. Assignees [imjasonh] will be automatically assigned.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "body": {
- "description": "Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.",
- "type": "string"
- },
- "labels": {
- "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "parent": {
- "description": "Parent issue number for creating sub-issues. This is the numeric ID from the GitHub URL (e.g., 42 in github.com/owner/repo/issues/42). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from a previously created issue in the same workflow run.",
- "type": [
- "number",
- "string"
- ]
- },
- "temporary_id": {
- "description": "Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 3 to 8 alphanumeric characters (e.g., 'aw_abc1', 'aw_Test123'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.",
- "pattern": "^aw_[A-Za-z0-9]{3,8}$",
- "type": "string"
- },
- "title": {
- "description": "Concise issue title summarizing the bug, feature, or task. The title appears as the main heading, so keep it brief and descriptive.",
- "type": "string"
- }
- },
- "required": [
- "title",
- "body"
- ],
- "type": "object"
- },
- "name": "create_issue"
- },
- {
- "description": "Add a comment to an existing GitHub issue, pull request, or discussion. Use this to provide feedback, answer questions, or add information to an existing conversation. For creating new items, use create_issue, create_discussion, or create_pull_request instead. IMPORTANT: Comments are subject to validation constraints enforced by the MCP server - maximum 65536 characters for the complete comment (including footer which is added automatically), 10 mentions (@username), and 50 links. Exceeding these limits will result in an immediate error with specific guidance. NOTE: By default, this tool requires discussions:write permission. If your GitHub App lacks Discussions permission, set 'discussions: false' in the workflow's safe-outputs.add-comment configuration to exclude this permission. CONSTRAINTS: Maximum 1 comment(s) can be added.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "body": {
- "description": "The comment text in Markdown format. This is the 'body' field - do not use 'comment_body' or other variations. Provide helpful, relevant information that adds value to the conversation. CONSTRAINTS: The complete comment (your body text + automatically added footer) must not exceed 65536 characters total. Maximum 10 mentions (@username), maximum 50 links (http/https URLs). A footer (~200-500 characters) is automatically appended with workflow attribution, so leave adequate space. If these limits are exceeded, the tool call will fail with a detailed error message indicating which constraint was violated.",
- "type": "string"
- },
- "item_number": {
- "description": "The issue, pull request, or discussion number to comment on. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123). If omitted, the tool auto-targets the issue, PR, or discussion that triggered this workflow. Auto-targeting only works for issue, pull_request, discussion, and comment event triggers — it does NOT work for schedule, workflow_dispatch, push, or workflow_run triggers. For those trigger types, always provide item_number explicitly, or the comment will be silently discarded.",
- "type": "number"
- }
- },
- "required": [
- "body"
- ],
- "type": "object"
- },
- "name": "add_comment"
- },
- {
- "description": "Push committed changes to a pull request's branch. Use this to add follow-up commits to an existing PR, such as addressing review feedback or fixing issues. Changes must be committed locally before calling this tool.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "branch": {
- "description": "Branch name to push changes from. If omitted, uses the current working branch. Only specify if you need to push from a different branch.",
- "type": "string"
- },
- "message": {
- "description": "Commit message describing the changes. Follow repository commit message conventions (e.g., conventional commits).",
- "type": "string"
- },
- "pull_request_number": {
- "description": "Pull request number to push changes to. This is the numeric ID from the GitHub URL (e.g., 654 in github.com/owner/repo/pull/654). Required when the workflow target is '*' (any PR).",
- "type": [
- "number",
- "string"
- ]
- }
- },
- "required": [
- "message"
- ],
- "type": "object"
- },
- "name": "push_to_pull_request_branch"
- },
- {
- "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "alternatives": {
- "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
- "type": "string"
- },
- "reason": {
- "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).",
- "type": "string"
- },
- "tool": {
- "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.",
- "type": "string"
- }
- },
- "required": [
- "reason"
- ],
- "type": "object"
- },
- "name": "missing_tool"
- },
- {
- "description": "Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "message": {
- "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').",
- "type": "string"
- }
- },
- "required": [
- "message"
- ],
- "type": "object"
- },
- "name": "noop"
- },
- {
- "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.",
- "inputSchema": {
- "additionalProperties": false,
- "properties": {
- "alternatives": {
- "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
- "type": "string"
- },
- "context": {
- "description": "Additional context about the missing data or where it should come from (max 256 characters).",
- "type": "string"
- },
- "data_type": {
- "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.",
- "type": "string"
- },
- "reason": {
- "description": "Explanation of why this data is needed to complete the task (max 256 characters).",
- "type": "string"
- }
- },
- "required": [],
- "type": "object"
- },
- "name": "missing_data"
- }
- ]
- GH_AW_SAFE_OUTPUTS_TOOLS_EOF
- cat > /opt/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF'
- {
- "add_comment": {
- "defaultMax": 1,
- "fields": {
- "body": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "item_number": {
- "issueOrPRNumber": true
- },
- "repo": {
- "type": "string",
- "maxLength": 256
- }
- }
- },
- "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
- }
- }
- },
- "push_to_pull_request_branch": {
- "defaultMax": 1,
- "fields": {
- "branch": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 256
- },
- "message": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "pull_request_number": {
- "issueOrPRNumber": true
- }
- }
- }
- }
- GH_AW_SAFE_OUTPUTS_VALIDATION_EOF
- - 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: /opt/gh-aw/safeoutputs/tools.json
- GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/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 /opt/gh-aw/actions/start_safe_outputs_server.sh
-
- - name: Start MCP Gateway
- id: start-mcp-gateway
- env:
- GH_AW_SAFE_OUTPUTS: ${{ env.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_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }}
- 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 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 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_LOCKDOWN -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.1.6'
-
- mkdir -p /home/runner/.copilot
- cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh
- {
- "mcpServers": {
- "github": {
- "type": "stdio",
- "container": "ghcr.io/github/github-mcp-server:v0.31.0",
- "env": {
- "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN",
- "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
- "GITHUB_READ_ONLY": "1",
- "GITHUB_TOOLSETS": "pull_requests,repos"
- }
- },
- "safeoutputs": {
- "type": "http",
- "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT",
- "headers": {
- "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}"
- }
- }
- },
- "gateway": {
- "port": $MCP_GATEWAY_PORT,
- "domain": "${MCP_GATEWAY_DOMAIN}",
- "apiKey": "${MCP_GATEWAY_API_KEY}",
- "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
- }
- }
- GH_AW_MCP_CONFIG_EOF
- - name: Generate workflow overview
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { generateWorkflowOverview } = require('/opt/gh-aw/actions/generate_workflow_overview.cjs');
- await generateWorkflowOverview(core);
- - name: Download prompt artifact
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: prompt
- path: /tmp/gh-aw/aw-prompts
- - name: Clean git credentials
- run: bash /opt/gh-aw/actions/clean_git_credentials.sh
- - name: Execute GitHub Copilot CLI
- id: agentic_execution
- # Copilot CLI tool arguments (sorted):
- timeout-minutes: 20
- run: |
- set -o pipefail
- # shellcheck disable=SC1003
- sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --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,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,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" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --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/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
- env:
- COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
- GH_AW_MODEL_AGENT_COPILOT: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }}
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
- GITHUB_API_URL: ${{ github.api_url }}
- 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: ${{ env.GITHUB_STEP_SUMMARY }}
- GITHUB_WORKSPACE: ${{ github.workspace }}
- XDG_CONFIG_HOME: /home/runner
- - 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 /opt/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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs');
- await main();
- env:
- GH_AW_SECRET_NAMES: 'ANTHROPIC_API_KEY,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
- SECRET_ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
- SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
- SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: Upload Safe Outputs
- if: always()
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: safe-output
- path: ${{ env.GH_AW_SAFE_OUTPUTS }}
- if-no-files-found: warn
- - name: Ingest agent output
- id: collect_output
- if: always()
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_SAFE_OUTPUTS: ${{ env.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,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,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"
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_API_URL: ${{ github.api_url }}
- GH_AW_COMMAND: pr-fix
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs');
- await main();
- - name: Upload sanitized agent output
- if: always() && env.GH_AW_AGENT_OUTPUT
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: agent-output
- path: ${{ env.GH_AW_AGENT_OUTPUT }}
- if-no-files-found: warn
- - name: Upload engine output files
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: agent_outputs
- path: |
- /tmp/gh-aw/sandbox/agent/logs/
- /tmp/gh-aw/redacted-urls.log
- if-no-files-found: ignore
- - 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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: Upload agent artifacts
- if: always()
- continue-on-error: true
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: agent-artifacts
- path: |
- /tmp/gh-aw/aw-prompts/prompt.txt
- /tmp/gh-aw/aw_info.json
- /tmp/gh-aw/mcp-logs/
- /tmp/gh-aw/sandbox/firewall/logs/
- /tmp/gh-aw/agent-stdio.log
- /tmp/gh-aw/agent/
- /tmp/gh-aw/aw-*.patch
- if-no-files-found: ignore
- # --- Threat Detection (inline) ---
- - name: Check if detection needed
- id: detection_guard
- if: always()
- env:
- OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }}
- HAS_PATCH: ${{ steps.collect_output.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: "PR Fix"
- WORKFLOW_DESCRIPTION: "On-demand PR fixer triggered by the /pr-fix command. Analyzes failing CI\nchecks, identifies root causes from error logs, implements fixes, runs\ntests and formatters, and pushes corrections to the PR branch. Provides\ndetailed comments explaining changes made."
- HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: Execute GitHub Copilot CLI
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- id: detection_agentic_execution
- # Copilot CLI tool arguments (sorted):
- # --allow-tool shell(cat)
- # --allow-tool shell(grep)
- # --allow-tool shell(head)
- # --allow-tool shell(jq)
- # --allow-tool shell(ls)
- # --allow-tool shell(tail)
- # --allow-tool shell(wc)
- timeout-minutes: 20
- run: |
- set -o pipefail
- # shellcheck disable=SC1003
- sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --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,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --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/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_DETECTION_COPILOT:+ --model "$GH_AW_MODEL_DETECTION_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
- env:
- COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- GH_AW_MODEL_DETECTION_COPILOT: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }}
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GITHUB_API_URL: ${{ github.api_url }}
- GITHUB_HEAD_REF: ${{ github.head_ref }}
- GITHUB_REF_NAME: ${{ github.ref_name }}
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }}
- GITHUB_WORKSPACE: ${{ github.workspace }}
- XDG_CONFIG_HOME: /home/runner
- - name: Parse threat detection results
- id: parse_detection_results
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs');
- await main();
- - name: Upload threat detection log
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: threat-detection.log
- path: /tmp/gh-aw/threat-detection/detection.log
- if-no-files-found: ignore
- - name: Set detection conclusion
- id: detection_conclusion
- if: always()
- env:
- RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}
- DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }}
- run: |
- if [[ "$RUN_DETECTION" != "true" ]]; then
- echo "conclusion=skipped" >> "$GITHUB_OUTPUT"
- echo "success=true" >> "$GITHUB_OUTPUT"
- echo "Detection was not needed, marking as skipped"
- elif [[ "$DETECTION_SUCCESS" == "true" ]]; then
- echo "conclusion=success" >> "$GITHUB_OUTPUT"
- echo "success=true" >> "$GITHUB_OUTPUT"
- echo "Detection passed successfully"
- else
- echo "conclusion=failure" >> "$GITHUB_OUTPUT"
- echo "success=false" >> "$GITHUB_OUTPUT"
- echo "Detection found issues"
- fi
-
- conclusion:
- needs:
- - activation
- - agent
- - safe_outputs
- if: (always()) && (needs.agent.result != 'skipped')
- runs-on: ubuntu-slim
- permissions:
- contents: write
- discussions: write
- issues: write
- pull-requests: write
- 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@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Download agent output artifact
- continue-on-error: true
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: agent-output
- path: /tmp/gh-aw/safeoutputs/
- - name: Setup agent output environment variable
- run: |
- mkdir -p /tmp/gh-aw/safeoutputs/
- find "/tmp/gh-aw/safeoutputs/" -type f -print
- echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
- - name: Process No-Op Messages
- id: noop
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_NOOP_MAX: "1"
- GH_AW_WORKFLOW_NAME: "PR Fix"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "PR Fix"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/missing_tool.cjs');
- await main();
- - name: Handle Agent Failure
- id: handle_agent_failure
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "PR Fix"
- 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: "pr-fix"
- GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }}
- GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
- GH_AW_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }}
- GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }}
- GH_AW_GROUP_REPORTS: "false"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/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: ${{ env.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "PR Fix"
- 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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/handle_noop_message.cjs');
- await main();
-
- pre_activation:
- if: >
- (github.event_name == 'issues') && ((startsWith(github.event.issue.body, '/pr-fix ')) || (github.event.issue.body == '/pr-fix')) ||
- (github.event_name == 'issue_comment') && (((startsWith(github.event.comment.body, '/pr-fix ')) || (github.event.comment.body == '/pr-fix')) &&
- (github.event.issue.pull_request == null)) || (github.event_name == 'issue_comment') && (((startsWith(github.event.comment.body, '/pr-fix ')) ||
- (github.event.comment.body == '/pr-fix')) && (github.event.issue.pull_request != null)) || (github.event_name == 'pull_request_review_comment') &&
- ((startsWith(github.event.comment.body, '/pr-fix ')) || (github.event.comment.body == '/pr-fix')) ||
- (github.event_name == 'pull_request') &&
- ((startsWith(github.event.pull_request.body, '/pr-fix ')) || (github.event.pull_request.body == '/pr-fix')) ||
- (github.event_name == 'discussion') && ((startsWith(github.event.discussion.body, '/pr-fix ')) || (github.event.discussion.body == '/pr-fix')) ||
- (github.event_name == 'discussion_comment') && ((startsWith(github.event.comment.body, '/pr-fix ')) ||
- (github.event.comment.body == '/pr-fix'))
- runs-on: ubuntu-slim
- permissions:
- discussions: write
- issues: write
- pull-requests: write
- outputs:
- activated: ${{ (steps.check_membership.outputs.is_team_member == 'true') && (steps.check_command_position.outputs.command_position_ok == 'true') }}
- matched_command: ${{ steps.check_command_position.outputs.matched_command }}
- steps:
- - name: Setup Scripts
- uses: github/gh-aw/actions/setup@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Add eyes reaction for immediate feedback
- id: react
- if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id)
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_REACTION: "eyes"
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/add_reaction.cjs');
- await main();
- - name: Check team membership for command 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('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/check_membership.cjs');
- await main();
- - name: Check command position
- id: check_command_position
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_COMMANDS: "[\"pr-fix\"]"
- with:
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/check_command_position.cjs');
- await main();
-
- safe_outputs:
- needs:
- - activation
- - agent
- if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_success == 'true')
- runs-on: ubuntu-slim
- permissions:
- contents: write
- discussions: write
- issues: write
- pull-requests: write
- timeout-minutes: 15
- env:
- GH_AW_ENGINE_ID: "copilot"
- GH_AW_WORKFLOW_ID: "pr-fix"
- GH_AW_WORKFLOW_NAME: "PR Fix"
- outputs:
- 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 }}
- 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@9cbca3cd9be433a23a38e4da332635097fd40251 # v0.50.7
- with:
- destination: /opt/gh-aw/actions
- - name: Download agent output artifact
- continue-on-error: true
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: agent-output
- path: /tmp/gh-aw/safeoutputs/
- - name: Setup agent output environment variable
- run: |
- mkdir -p /tmp/gh-aw/safeoutputs/
- find "/tmp/gh-aw/safeoutputs/" -type f -print
- echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
- - name: Download patch artifact
- continue-on-error: true
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
- with:
- name: agent-artifacts
- path: /tmp/gh-aw/
- - name: Checkout repository
- if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch'))
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- ref: ${{ github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }}
- token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- persist-credentials: false
- fetch-depth: 1
- - name: Configure Git credentials
- if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch'))
- env:
- REPO_NAME: ${{ github.repository }}
- SERVER_URL: ${{ github.server_url }}
- GIT_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- 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:${GIT_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
- echo "Git configured with standard GitHub Actions identity"
- - name: Process Safe Outputs
- id: process_safe_outputs
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
- env:
- GH_AW_AGENT_OUTPUT: ${{ env.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,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,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"
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_API_URL: ${{ github.api_url }}
- GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_issue\":{\"assignees\":[\"imjasonh\"],\"labels\":[\"automation\",\"pr-fix\"],\"max\":1,\"title_prefix\":\"[PR Fix] \"},\"missing_data\":{},\"missing_tool\":{},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"max_patch_size\":1024}}"
- GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }}
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io);
- const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs');
- await main();
- - name: Upload safe output items manifest
- if: always()
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
- with:
- name: safe-output-items
- path: /tmp/safe-output-items.jsonl
- if-no-files-found: warn
-