From 214af0e297b05a2436ee2a0560ba70d984064fef Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Fri, 9 Oct 2026 00:35:17 +0000
Subject: [PATCH] chore: publish from main
---
.github/review-routing.yml | 6 +
.github/risk-tiers.yml | 6 +
.github/workflows/codeowner-update.lock.yml | 1965 ------------------
.github/workflows/codeowner-update.md | 94 -
.github/workflows/label-pr-intent-writer.yml | 1 +
.github/workflows/label-pr-intent.yml | 8 +
.github/workflows/setup-labels.yml | 4 +
CODEOWNERS | 62 +-
docs/maintainers/review-routing.md | 6 +-
eng/review-routing.mjs | 1 +
eng/review-routing.test.mjs | 6 +-
eng/submission-gate.test.mjs | 14 +-
12 files changed, 53 insertions(+), 2120 deletions(-)
delete mode 100644 .github/workflows/codeowner-update.lock.yml
delete mode 100644 .github/workflows/codeowner-update.md
diff --git a/.github/review-routing.yml b/.github/review-routing.yml
index 06a9fa9f9..46657b77b 100644
--- a/.github/review-routing.yml
+++ b/.github/review-routing.yml
@@ -52,10 +52,16 @@ pools:
team: github/awesome-copilot-content-reviewers
reviewers: [] # TODO: add at least three reviewers for skills, agents, and instructions.
backup: [] # TODO: add backup content reviewers.
+ workshops:
+ team: github/awesome-copilot-workshop-reviewers
+ reviewers: [] # TODO: add at least three workshop reviewers.
+ backup: [] # TODO: add backup workshop reviewers.
# Intent labels (applied by .github/workflows/label-pr-intent*.yml) mapped to
# pools. Order is priority: the first route whose label is on the PR wins.
routes:
+ - label: workshops
+ pool: workshops
- label: canvas-extension
pool: canvas
- label: external-plugin
diff --git a/.github/risk-tiers.yml b/.github/risk-tiers.yml
index 6517fb1dd..6de076219 100644
--- a/.github/risk-tiers.yml
+++ b/.github/risk-tiers.yml
@@ -143,6 +143,12 @@ domains:
content:
paths: ["agents/**", "instructions/**", "skills/**", "workflows/**", "hooks/**"]
pools: ["content"]
+ workshops:
+ paths:
+ - "website/**/cli-for-beginners/**"
+ - "website/**/app-for-beginners/**"
+ - "website/**/copilot-workshops/**"
+ pools: ["workshops"]
# Files outside every domain (repository automation such as `.github/workflows/**`,
# `eng/**`, review policy, and docs) are owned by the core pools.
diff --git a/.github/workflows/codeowner-update.lock.yml b/.github/workflows/codeowner-update.lock.yml
deleted file mode 100644
index c59d1fbd1..000000000
--- a/.github/workflows/codeowner-update.lock.yml
+++ /dev/null
@@ -1,1965 +0,0 @@
-# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"eee5557beebca58fbbe2106fb8577c61ac5c2c645edcd5e7c8aaa8b14d01e766","body_hash":"408df128d7b2623572ab8c06638b472d7e270daff1eb81c82ca24bf609125c25","compiler_version":"v0.89.21","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.87"}}
-# gh-aw-manifest: {"version":1,"secrets":["GH_AW_CI_TRIGGER_TOKEN","GH_AW_DEFAULT_OTLP_ENDPOINT","GH_AW_DEFAULT_OTLP_HEADERS","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"924af5fdc64061cfbf66fb584c8b07e2ac230c60","version":"v0.89.21"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.28.23","digest":"sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.28.23@sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.23","digest":"sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.23@sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.28.23","digest":"sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.28.23@sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.25","digest":"sha256:9be0a86220e807a0ecc89e53d7453468f7a53fbc6b3d1efd2299025ffe01d086","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.25@sha256:9be0a86220e807a0ecc89e53d7453468f7a53fbc6b3d1efd2299025ffe01d086"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.12.2","digest":"sha256:508a0857ec762b1ab1cece29193345b501fab1dd9d1228a7b617062954cecac6","pinned_image":"ghcr.io/github/github-mcp-server:v1.12.2@sha256:508a0857ec762b1ab1cece29193345b501fab1dd9d1228a7b617062954cecac6"}],"mcp_servers":[{"name":"github","tools":["get_commit","get_file_contents","get_latest_release","get_me","get_pull_request","get_pull_request_comments","get_pull_request_diff","get_pull_request_files","get_pull_request_review_comments","get_pull_request_reviews","get_pull_request_status","get_release_by_tag","get_tag","issue_read","list_branches","list_commits","list_issue_types","list_issues","list_pull_requests","list_releases","list_starred_repositories","list_tags","pull_request_read","search_code","search_issues","search_pull_requests","search_repositories"]},{"name":"safeoutputs","tools":["add_comment","create_pull_request","missing_data","missing_tool","noop"]}]}
-# This file was automatically generated by gh-aw (v0.89.21). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md
-#
-# ___ _ _
-# / _ \ | | (_)
-# | |_| | __ _ ___ _ __ | |_ _ ___
-# | _ |/ _` |/ _ \ '_ \| __| |/ __|
-# | | | | (_| | __/ | | | |_| | (__
-# \_| |_/\__, |\___|_| |_|\__|_|\___|
-# __/ |
-# _ _ |___/
-# | | | | / _| |
-# | | | | ___ _ __ _ __| |_| | _____ ____
-# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___|
-# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
-# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
-#
-#
-# 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/
-#
-# Updates the CODEOWNERS file when a maintainer comments #codeowner on a pull request
-#
-# Secrets used:
-# - GH_AW_CI_TRIGGER_TOKEN
-# - GH_AW_DEFAULT_OTLP_ENDPOINT
-# - GH_AW_DEFAULT_OTLP_HEADERS
-# - GH_AW_GITHUB_MCP_SERVER_TOKEN
-# - GH_AW_GITHUB_TOKEN
-# - GITHUB_TOKEN
-#
-# Custom actions used:
-# - actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
-# - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
-# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
-# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
-# - actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
-# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
-# - github/gh-aw-actions/setup@924af5fdc64061cfbf66fb584c8b07e2ac230c60 # v0.89.21
-#
-# Container images used:
-# - ghcr.io/github/gh-aw-firewall/agent:0.28.23@sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2
-# - ghcr.io/github/gh-aw-firewall/api-proxy:0.28.23@sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64
-# - ghcr.io/github/gh-aw-firewall/squid:0.28.23@sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0
-# - ghcr.io/github/gh-aw-mcpg:v0.4.25@sha256:9be0a86220e807a0ecc89e53d7453468f7a53fbc6b3d1efd2299025ffe01d086
-# - ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196
-# - ghcr.io/github/github-mcp-server:v1.12.2@sha256:508a0857ec762b1ab1cece29193345b501fab1dd9d1228a7b617062954cecac6
-
-name: "Codeowner Update Agent"
-on:
- issue_comment:
- types:
- - created
-
-permissions: {}
-
-concurrency:
- group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number || github.run_id }}"
- queue: max
-
-run-name: "Codeowner Update Agent"
-
-env:
- OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.GH_AW_DEFAULT_OTLP_ENDPOINT || vars.GH_AW_DEFAULT_OTLP_ENDPOINT }}
- OTEL_SERVICE_NAME: gh-aw.codeowner-update
- OTEL_RESOURCE_ATTRIBUTES: 'gh-aw.workflow.name=Codeowner%20Update%20Agent,gh-aw.repository=${{ github.repository }},gh-aw.run.id=${{ github.run_id }},github.run_id=${{ github.run_id }},gh-aw.engine.id=copilot'
- OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }}
- GH_AW_OTLP_ENDPOINTS: '[{"url":"${{ secrets.GH_AW_DEFAULT_OTLP_ENDPOINT || vars.GH_AW_DEFAULT_OTLP_ENDPOINT }}","headers":"${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }}"}]'
- GH_AW_OTLP_IF_MISSING: ignore
-
-jobs:
- activation:
- needs: pre_activation
- if: >
- needs.pre_activation.outputs.activated == 'true' && (contains(github.event.comment.body, '#codeowner') &&
- github.event.issue.pull_request)
- runs-on: ubuntu-slim
- permissions:
- actions: read
- contents: read
- issues: write
- env:
- GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }}
- GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
- outputs:
- body: ${{ steps.sanitized.outputs.body }}
- comment_id: ""
- comment_repo: ""
- daily_ai_credits_exceeded: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }}
- daily_ai_credits_guardrail_error: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_guardrail_error || '' }}
- daily_ai_credits_guardrail_status: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_guardrail_status || '' }}
- daily_ai_credits_threshold: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }}
- daily_ai_credits_total: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_total || '' }}
- engine_id: ${{ steps.generate_aw_info.outputs.engine_id }}
- lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }}
- model: ${{ steps.generate_aw_info.outputs.model }}
- oauth_token_check_failed: ${{ steps.check-oauth-tokens.outputs.oauth_token_check_failed == 'true' }}
- setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
- setup-span-id: ${{ steps.setup.outputs.span-id }}
- setup-trace-id: ${{ steps.setup.outputs.trace-id }}
- stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }}
- text: ${{ steps.sanitized.outputs.text }}
- title: ${{ steps.sanitized.outputs.title }}
- steps:
- - name: Setup Scripts
- id: setup
- uses: github/gh-aw-actions/setup@924af5fdc64061cfbf66fb584c8b07e2ac230c60 # v0.89.21
- with:
- destination: ${{ runner.temp }}/gh-aw/actions
- job-name: ${{ github.job }}
- trace-id: ${{ needs.pre_activation.outputs.setup-trace-id }}
- parent-span-id: ${{ needs.pre_activation.outputs.setup-parent-span-id || needs.pre_activation.outputs.setup-span-id }}
- safe-output-artifact-client: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
- env:
- GH_AW_SETUP_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/codeowner-update.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.87"
- GH_AW_INFO_AWF_VERSION: "v0.28.23"
- GH_AW_INFO_ENGINE_ID: "copilot"
- - name: Mask OTLP telemetry headers
- run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh"
- - name: Generate agentic run info
- id: generate_aw_info
- env:
- GH_AW_INFO_ENGINE_ID: "copilot"
- GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
- GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'auto' }}
- GH_AW_INFO_VERSION: "1.0.87"
- GH_AW_INFO_AGENT_VERSION: "1.0.87"
- GH_AW_INFO_CLI_VERSION: "v0.89.21"
- GH_AW_INFO_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_INFO_EXPERIMENTAL: "false"
- GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
- GH_AW_INFO_STAGED: "false"
- GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]'
- GH_AW_INFO_FIREWALL_ENABLED: "true"
- GH_AW_INFO_AWF_VERSION: "v0.28.23"
- GH_AW_INFO_AWMG_VERSION: ""
- GH_AW_INFO_FIREWALL_TYPE: "squid"
- GH_AW_INFO_AGENT_RUNTIME: ""
- GH_AW_COMPILED_STRICT: "true"
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'generate_aw_info.cjs'));
- await main(core, context);
- - name: Restore daily AIC scan observations
- id: restore-daily-aic-cache-fallback
- if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_HAS_SLASH_COMMAND: "false"
- GH_AW_HAS_LABEL_COMMAND: "false"
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'restore_aic_scan_cache.cjs'));
- await main();
- - name: Check daily workflow token guardrail
- id: daily-ai-credits-workflow-guardrail
- if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_WORKFLOW_ID: "codeowner-update"
- GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- GH_AW_WORKFLOW_DISPATCH_AW_CONTEXT: ${{ github.event.inputs.aw_context || '' }}
- GH_AW_HAS_SLASH_COMMAND: "false"
- GH_AW_HAS_LABEL_COMMAND: "false"
- GH_AW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }}
- GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'check_daily_aic_workflow_guardrail.cjs'));
- await main();
- - name: Publish daily AIC scan observations
- if: always() && env.GH_AW_MAX_DAILY_AI_CREDITS != ''
- continue-on-error: true
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
- with:
- name: aic-usage-scan-v2
- path: /tmp/gh-aw/agentic-workflow-usage-scan-v2.jsonl
- overwrite: true
- if-no-files-found: ignore
- retention-days: 3
- - name: Check for OAuth tokens
- id: check-oauth-tokens
- run: bash "${RUNNER_TEMP}/gh-aw/actions/check_oauth_tokens.sh"
- env:
- GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
- GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
- - name: Checkout .github and .agents folders
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- with:
- persist-credentials: false
- sparse-checkout: |
- .github
- .agents
- .claude
- .codex
- .gemini
- .pi
- sparse-checkout-cone-mode: true
- fetch-depth: 1
- - name: Save agent config folders for base branch restoration
- env:
- GH_AW_AGENT_FOLDERS: ".agents .github"
- GH_AW_AGENT_FILES: "AGENTS.md"
- run: |
- bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
- - name: Check workflow lock file
- id: check-lock-file
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_WORKFLOW_FILE: "codeowner-update.lock.yml"
- GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}"
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'check_workflow_timestamp_api.cjs'));
- await main();
- - name: Check compile-agentic version
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_COMPILED_VERSION: "v0.89.21"
- GH_AW_BLOCKED_VERSION_REPORT_AS_ISSUE: "true"
- GH_AW_WORKFLOW_NAME: "Codeowner Update Agent"
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'check_version_updates.cjs'));
- await main();
- - name: Compute current body text
- id: sanitized
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_ALLOWED_DOMAINS: "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,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,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'compute_text.cjs'));
- await main();
- - name: Log runtime features
- if: ${{ contains(toJSON(vars), '"GH_AW_RUNTIME_FEATURES":') }}
- run: bash "${RUNNER_TEMP}/gh-aw/actions/log_runtime_features_summary.sh"
- - name: Create prompt with built-in context
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_ACTIONS_DIR: ${{ runner.temp }}/gh-aw/actions
- GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
- GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl
- GH_AW_PROMPT_CONFIG: "{\"items\":[{\"content_env\":\"GH_AW_PROMPT_CONTENT_0000\"},{\"file\":\"xpia.md\"},{\"file\":\"temp_folder_prompt.md\"},{\"file\":\"markdown.md\"},{\"file\":\"safe_outputs_prompt.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0001\"},{\"file\":\"safe_outputs_create_pull_request.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0002\"},{\"file\":\"mcp_cli_tools_with_safeoutputs_prompt.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0003\"},{\"file\":\"github_mcp_tools_with_safeoutputs_prompt.md\"},{\"file\":\"pr_context_prompt.md\",\"condition_env\":\"GH_AW_INCLUDE_PR_CONTEXT\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0004\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0005\"}]}"
- GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }}
- GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }}
- GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }}
- GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }}
- GH_AW_GITHUB_ACTOR: ${{ github.actor }}
- GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
- GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
- GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
- GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
- GH_AW_INCLUDE_PR_CONTEXT: ${{ (github.event_name == 'issue_comment' && github.event.issue.pull_request != null) || github.event_name == 'pull_request_review_comment' || github.event_name == 'pull_request_review' }}
- GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
- GH_AW_PROMPT_CONTENT_0000: "\n"
- GH_AW_PROMPT_CONTENT_0001: "\nTools: add_comment, create_pull_request, missing_tool, missing_data, noop\n"
- GH_AW_PROMPT_CONTENT_0002: "\n"
- GH_AW_PROMPT_CONTENT_0003: "\nThe following GitHub context information is available for this workflow:\n{{#if github.actor}}\n- **actor**: __GH_AW_GITHUB_ACTOR__\n{{/if}}\n{{#if github.repository}}\n- **repository**: __GH_AW_GITHUB_REPOSITORY__\n{{/if}}\n{{#if github.workspace}}\n- **workspace**: __GH_AW_GITHUB_WORKSPACE__\n{{/if}}\n{{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}}\n- **issue-number**: #__GH_AW_EXPR_802A9F6A__\n{{/if}}\n{{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}}\n- **discussion-number**: #__GH_AW_EXPR_1A3A194A__\n{{/if}}\n{{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}}\n- **pull-request-number**: #__GH_AW_EXPR_463A214A__\n{{/if}}\n{{#if github.event.comment.id || github.aw.context.comment_id}}\n- **comment-id**: __GH_AW_EXPR_FF1D34CE__\n{{/if}}\n{{#if github.run_id}}\n- **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__\n{{/if}}\n\n\n"
- GH_AW_PROMPT_CONTENT_0004: "\n"
- GH_AW_PROMPT_CONTENT_0005: "{{#runtime-import .github/workflows/codeowner-update.md}}\n"
- with:
- script: |
- const { setupGlobals } = require(process.env.GH_AW_ACTIONS_DIR + '/setup_globals.cjs');
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(process.env.GH_AW_ACTIONS_DIR + '/create_prompt.cjs');
- await main(core);
- - name: Interpolate variables and render templates
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
- GH_AW_ENGINE_ID: "copilot"
- GH_AW_GITHUB_ACTOR: ${{ github.actor }}
- 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 path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'interpolate_prompt.cjs'));
- await main();
- - name: Substitute placeholders
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
- GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }}
- GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }}
- GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }}
- GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }}
- GH_AW_GITHUB_ACTOR: ${{ github.actor }}
- GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
- GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
- GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
- GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
- GH_AW_INCLUDE_PR_CONTEXT: ${{ (github.event_name == 'issue_comment' && github.event.issue.pull_request != null) || github.event_name == 'pull_request_review_comment' || github.event_name == 'pull_request_review' }}
- GH_AW_MCP_CLI_SERVERS_LIST: "- `github` — run `github --help` to see available tools\n- `safeoutputs` — run `safeoutputs --help` to see available tools"
- GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }}
- GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
-
- const substitutePlaceholders = require(path.join(actionsDir, 'substitute_placeholders.cjs'));
-
- // Call the substitution function
- return await substitutePlaceholders({
- file: process.env.GH_AW_PROMPT,
- substitutions: {
- GH_AW_EXPR_1A3A194A: process.env.GH_AW_EXPR_1A3A194A,
- GH_AW_EXPR_463A214A: process.env.GH_AW_EXPR_463A214A,
- GH_AW_EXPR_802A9F6A: process.env.GH_AW_EXPR_802A9F6A,
- GH_AW_EXPR_FF1D34CE: process.env.GH_AW_EXPR_FF1D34CE,
- GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,
- GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_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_INCLUDE_PR_CONTEXT: process.env.GH_AW_INCLUDE_PR_CONTEXT,
- GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST,
- GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED,
- GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: process.env.GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT
- }
- });
- - name: Validate prompt placeholders
- env:
- GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
- run: |
- bash "${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh"
- - name: Print prompt
- env:
- GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
- run: |
- bash "${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh"
- - name: Upload info artifact
- if: success() || failure()
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
- with:
- name: info
- path: /tmp/gh-aw/aw_info.json
- if-no-files-found: ignore
- - name: Stage prompt files for artifact upload
- run: |
- mkdir -p /tmp/gh-aw/aw-prompts
- cp -a "${RUNNER_TEMP}/gh-aw/aw-prompts/." /tmp/gh-aw/aw-prompts/
- - name: Upload activation artifact
- if: success() || failure()
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
- with:
- name: activation
- include-hidden-files: true
- path: |
- /tmp/gh-aw/aw_info.json
- /tmp/gh-aw/models.json
- /tmp/gh-aw/aw-prompts/prompt.txt
- /tmp/gh-aw/aw-prompts/prompt-template.txt
- /tmp/gh-aw/aw-prompts/prompt-import-tree.json
- /tmp/gh-aw/github_rate_limits.jsonl
- /tmp/gh-aw/base
- /tmp/gh-aw/.github/agents
- /tmp/gh-aw/.github/skills
- if-no-files-found: ignore
- retention-days: 1
-
- agent:
- needs: activation
- if: needs.activation.outputs.daily_ai_credits_exceeded != 'true'
- runs-on: ubuntu-latest
- permissions:
- contents: read
- copilot-requests: write
- issues: read
- pull-requests: read
- timeout-minutes: 60
- 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_PR_HEAD_BASE_BRANCH: ""
- GH_AW_PR_HEAD_BASE_PR_NUMBER: ""
- GH_AW_PR_HEAD_BASE_REF: ""
- GH_AW_PR_HEAD_BASE_REPO: ""
- GH_AW_PR_HEAD_BASE_SHA: ""
- GH_AW_PR_HEAD_REPO: ""
- GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
- GH_AW_WORKFLOW_ID_SANITIZED: codeownerupdate
- outputs:
- agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
- ai_credits_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.ai_credits_rate_limit_error || 'false' }}
- aic: ${{ steps.parse-token-usage.outputs.aic }}
- ambient_context: ${{ steps.parse-token-usage.outputs.ambient_context }}
- checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
- has_patch: ${{ steps.collect_output.outputs.has_patch }}
- http_400_response_error: ${{ steps.detect-agent-errors.outputs.http_400_response_error || 'false' }}
- inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
- invocation_cap_exceeded: ${{ steps.detect-agent-errors.outputs.invocation_cap_exceeded || 'false' }}
- max_cache_misses_exceeded: ${{ steps.detect-agent-errors.outputs.max_cache_misses_exceeded || 'false' }}
- mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
- missing_model_pricing_error: ${{ steps.detect-agent-errors.outputs.missing_model_pricing_error || 'false' }}
- missing_model_pricing_model_name: ${{ steps.detect-agent-errors.outputs.missing_model_pricing_model_name || '' }}
- model: ${{ needs.activation.outputs.model }}
- model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
- output: ${{ steps.collect_output.outputs.output }}
- output_types: ${{ steps.collect_output.outputs.output_types }}
- setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
- setup-span-id: ${{ steps.setup.outputs.span-id }}
- setup-trace-id: ${{ steps.setup.outputs.trace-id }}
- shell_expansion_guard_rejected: ${{ steps.detect-agent-errors.outputs.shell_expansion_guard_rejected || 'false' }}
- unknown_model_ai_credits: ${{ steps.parse-mcp-gateway.outputs.unknown_model_ai_credits || 'false' }}
- steps:
- - name: Setup Scripts
- id: setup
- uses: github/gh-aw-actions/setup@924af5fdc64061cfbf66fb584c8b07e2ac230c60 # v0.89.21
- with:
- destination: ${{ runner.temp }}/gh-aw/actions
- job-name: ${{ github.job }}
- trace-id: ${{ needs.activation.outputs.setup-trace-id }}
- parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
- env:
- GH_AW_SETUP_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/codeowner-update.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.87"
- GH_AW_INFO_AWF_VERSION: "v0.28.23"
- GH_AW_INFO_ENGINE_ID: "copilot"
- - name: Set runtime paths
- id: set-runtime-paths
- env:
- GH_AW_RUNNER_TOOL_CACHE: ${{ runner.tool_cache }}
- run: | # zizmor: ignore[github-env] - runner.tool_cache is set by GitHub Actions, not user input.
- if [ -z "${RUNNER_TOOL_CACHE:-}" ]; then
- echo "RUNNER_TOOL_CACHE=${GH_AW_RUNNER_TOOL_CACHE}" >> "$GITHUB_ENV"
- fi
- {
- echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl"
- echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json"
- echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json"
- } >> "$GITHUB_OUTPUT"
- - name: Mask OTLP telemetry headers
- run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh"
- - name: Check OTLP telemetry configuration
- run: bash "${RUNNER_TEMP}/gh-aw/actions/check_otlp_default_credentials.sh"
- - name: Checkout repository
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- with:
- persist-credentials: false
- - name: Initialize agent execution evidence
- run: |
- mkdir -p "/tmp/gh-aw"
- evidence_tmp="/tmp/gh-aw/agent_execution.json.tmp"
- printf '{"version":1,"component":"agent","run_id":%s,"run_attempt":%s,"state":"not_started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp"
- mv "$evidence_tmp" "/tmp/gh-aw/agent_execution.json"
- - name: Create gh-aw temp directory
- run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh"
- - name: Configure gh CLI for GitHub Enterprise
- run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh"
- env:
- GH_TOKEN: ${{ github.token }}
- - name: Download activation artifact
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- with:
- name: activation
- path: /tmp/gh-aw
- - name: Configure Git credentials
- env:
- GITHUB_REPOSITORY: ${{ github.repository }}
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_TOKEN: ${{ github.token }}
- run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_git_credentials.sh"
- - name: Checkout PR branch
- id: checkout-pr
- if: |
- github.event.pull_request || github.event.issue.pull_request || github.event_name == 'workflow_dispatch' && fromJSON(github.event.inputs.aw_context || '{}').item_type == 'pull_request'
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- 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 path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'checkout_pr_branch.cjs'));
- await main();
- - name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh"
- env:
- GH_HOST: github.com
- GH_AW_COMPILED_VERSION: v0.89.21
- - name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.28.23 --rootless
- - name: Determine automatic lockdown mode for GitHub MCP Server
- id: determine-automatic-lockdown
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
- env:
- GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
- GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const determineAutomaticLockdown = require(path.join(actionsDir, 'determine_automatic_lockdown.cjs'));
- await determineAutomaticLockdown(github, context, core);
- - name: Restore agent config folders from base branch
- if: steps.checkout-pr.outcome == 'success'
- env:
- GH_AW_AGENT_FOLDERS: ".agents .github"
- GH_AW_AGENT_FILES: "AGENTS.md"
- run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
- - name: Restore inline sub-agents from activation artifact
- env:
- GH_AW_SUB_AGENT_DIR: ".github/agents"
- GH_AW_SUB_AGENT_EXT: ".agent.md"
- run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
- - name: Restore inline skills from activation artifact
- env:
- GH_AW_SKILL_DIR: ".github/skills"
- run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
- - name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.28.23@sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2 ghcr.io/github/gh-aw-firewall/api-proxy:0.28.23@sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64 ghcr.io/github/gh-aw-firewall/squid:0.28.23@sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0 ghcr.io/github/gh-aw-mcpg:v0.4.25@sha256:9be0a86220e807a0ecc89e53d7453468f7a53fbc6b3d1efd2299025ffe01d086 ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196 ghcr.io/github/github-mcp-server:v1.12.2@sha256:508a0857ec762b1ab1cece29193345b501fab1dd9d1228a7b617062954cecac6
- - name: Prepare Safe Outputs Directories
- run: |
- mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
- mkdir -p /tmp/gh-aw/safeoutputs
- mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
- - name: Generate Safe Outputs Config
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_FILE_ROOT: "${{ runner.temp }}/gh-aw"
- GH_AW_FILE_CONFIG: "{\"files\":[{\"path\":\"safeoutputs/config.json\",\"content_env\":\"GH_AW_SAFE_OUTPUTS_CONFIG\"}]}"
- GH_AW_SAFE_OUTPUTS_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"base_branch\":\"main\",\"draft\":false,\"max\":1,\"max_patch_files\":100,\"max_patch_size\":4096,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\"],\"protected_files_policy\":\"request-review\",\"title_prefix\":\"[codeowner] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}"
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'create_files.cjs'));
- await main();
- - name: Generate Safe Outputs Tools
- env:
- GH_AW_TOOLS_META_JSON: |
- {
- "description_suffixes": {
- "add_comment": " CONSTRAINTS: Maximum 1 comment(s) can be added. Supports reply_to_id for discussion threading.",
- "create_pull_request": " CONSTRAINTS: Maximum 1 pull request(s) can be created. Title will be prefixed with \"[codeowner] \"."
- },
- "repo_params": {},
- "dynamic_tools": []
- }
- GH_AW_VALIDATION_JSON: |
- {
- "add_comment": {
- "defaultMax": 1,
- "fields": {
- "body": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "comment_id": {
- "optionalPositiveInteger": true
- },
- "item_number": {
- "issueOrPRNumber": true
- },
- "pr": {
- "issueOrPRNumber": true
- },
- "pr_number": {
- "issueOrPRNumber": true
- },
- "reply_to_id": {
- "type": "string",
- "maxLength": 256
- },
- "repo": {
- "type": "string",
- "maxLength": 256
- },
- "target": {
- "type": "string",
- "enum": [
- "status"
- ]
- },
- "temporary_id": {
- "type": "string",
- "pattern": "^#?aw_[A-Za-z0-9_]{3,12}$"
- }
- }
- },
- "create_pull_request": {
- "defaultMax": 1,
- "fields": {
- "base": {
- "type": "string",
- "sanitize": true,
- "maxLength": 128
- },
- "body": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "branch": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 256
- },
- "dependencies": {
- "type": "array",
- "itemType": "string",
- "itemSanitize": true,
- "itemMaxLength": 256
- },
- "draft": {
- "type": "boolean"
- },
- "labels": {
- "type": "array",
- "itemType": "string",
- "itemSanitize": true,
- "itemMaxLength": 128
- },
- "repo": {
- "type": "string",
- "maxLength": 256
- },
- "stack_position": {
- "optionalPositiveInteger": true
- },
- "stack_root": {
- "type": "string",
- "sanitize": true,
- "maxLength": 256
- },
- "temporary_id": {
- "type": "string",
- "pattern": "^#?aw_[A-Za-z0-9_]{3,12}$"
- },
- "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
- }
- }
- },
- "report_incomplete": {
- "defaultMax": 5,
- "fields": {
- "details": {
- "type": "string",
- "sanitize": true,
- "maxLength": 65000
- },
- "reason": {
- "required": true,
- "type": "string",
- "sanitize": true,
- "maxLength": 1024
- }
- }
- }
- }
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'generate_safe_outputs_tools.cjs'));
- await main();
- - name: Start MCP Gateway
- id: start-mcp-gateway
- env:
- GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST: ${{ vars.GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST || 'true' }}
- GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_CONFIG_PATH }}
- GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_TOOLS_PATH }}
- GH_AW_SINK_VISIBILITY: ${{ steps.determine-automatic-lockdown.outputs.visibility }}
- GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }}
- GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }}
- GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: |
- set -eo pipefail
- mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-config"
- if [ -n "${GITHUB_EVENT_PATH:-}" ] && [ -r "${GITHUB_EVENT_PATH}" ]; then
- GH_AW_SAFEOUTPUTS_EVENT_PATH="${RUNNER_TEMP}/gh-aw/safeoutputs/github_event.json"
- cp "${GITHUB_EVENT_PATH}" "${GH_AW_SAFEOUTPUTS_EVENT_PATH}"
- export GITHUB_EVENT_PATH="${GH_AW_SAFEOUTPUTS_EVENT_PATH}"
- fi
-
- # Export gateway environment variables for MCP config and gateway script
- export MCP_GATEWAY_PORT="8080"
- export MCP_GATEWAY_DOMAIN="awmg-mcpg"
- export MCP_GATEWAY_HOST_DOMAIN="localhost"
- MCP_GATEWAY_AGENT_ID=$(openssl rand -base64 45 | tr -d '/+=')
- echo "::add-mask::${MCP_GATEWAY_AGENT_ID}"
- export MCP_GATEWAY_AGENT_ID
- export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads"
- mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}"
- export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288"
- export MCP_GATEWAY_ALLOWED_MOUNT_ROOTS="${GITHUB_WORKSPACE}:rw,${RUNNER_TEMP}/gh-aw:ro,${RUNNER_TEMP}/gh-aw/safeoutputs:rw,/opt:ro,/tmp:rw,/usr/bin/gh:ro"
- export GH_AW_PR_HEAD_BASE_BRANCH="${GH_AW_PR_HEAD_BASE_BRANCH:-}"
- export GH_AW_PR_HEAD_BASE_SHA="${GH_AW_PR_HEAD_BASE_SHA:-}"
- export GH_AW_PR_HEAD_BASE_REPO="${GH_AW_PR_HEAD_BASE_REPO:-}"
- export GH_AW_PR_HEAD_BASE_PR_NUMBER="${GH_AW_PR_HEAD_BASE_PR_NUMBER:-}"
- export GH_AW_PR_HEAD_BASE_REF="${GH_AW_PR_HEAD_BASE_REF:-}"
- export GH_AW_PR_HEAD_REPO="${GH_AW_PR_HEAD_REPO:-}"
- export DEBUG="*"
-
- export GH_AW_ENGINE="copilot"
- MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0')
- MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0')
- source "${RUNNER_TEMP}/gh-aw/actions/resolve_docker_socket_gid.sh"
- export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network bridge -p 127.0.0.1:'"${MCP_GATEWAY_PORT}"':'"${MCP_GATEWAY_PORT}"' --name awmg-mcpg --add-host host.docker.internal:host-gateway --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_AGENT_ID -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -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_PR_HEAD_BASE_BRANCH -e GH_AW_PR_HEAD_BASE_SHA -e GH_AW_PR_HEAD_BASE_REPO -e GH_AW_PR_HEAD_BASE_PR_NUMBER -e GH_AW_PR_HEAD_BASE_REF -e GH_AW_PR_HEAD_REPO -e GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GH_AW_SINK_VISIBILITY -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 RUNNER_TEMP -e RUNNER_TOOL_CACHE -e MCP_GATEWAY_ALLOWED_MOUNT_ROOTS -e GITHUB_AW_OTEL_TRACE_ID -e GITHUB_AW_OTEL_PARENT_SPAN_ID -e OTEL_EXPORTER_OTLP_HEADERS -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 -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:v0.4.25'
-
- mkdir -p "$HOME/.copilot"
- GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
- cat << GH_AW_MCP_CONFIG_6e47705499a41fbb_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs"
- {
- "mcpServers": {
- "github": {
- "type": "stdio",
- "container": "ghcr.io/github/github-mcp-server:v1.12.2",
- "env": {
- "GITHUB_FEATURES": "fields_param",
- "GITHUB_HOST": "${GITHUB_SERVER_URL}",
- "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_MCP_SERVER_TOKEN}",
- "GITHUB_READ_ONLY": "1",
- "GITHUB_TOOLSETS": "context,repos,issues,pull_requests"
- },
- "guard-policies": {
- "allow-only": {
- "min-integrity": "$GITHUB_MCP_GUARD_MIN_INTEGRITY",
- "repos": "$GITHUB_MCP_GUARD_REPOS"
- }
- }
- },
- "safeoutputs": {
- "type": "stdio",
- "container": "ghcr.io/github/gh-aw-node",
- "mounts": ["\${GITHUB_WORKSPACE}:\${GITHUB_WORKSPACE}:rw", "${RUNNER_TEMP}/gh-aw/safeoutputs:${RUNNER_TEMP}/gh-aw/safeoutputs:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"],
- "args": ["-w", "\${GITHUB_WORKSPACE}"],
- "entrypoint": "sh",
- "entrypointArgs": ["-c", "sh ${RUNNER_TEMP}/gh-aw/safeoutputs/start_safe_outputs_mcp.sh"],
- "env": {
- "DEBUG": "*",
- "DEFAULT_BRANCH": "\${DEFAULT_BRANCH}",
- "GH_AW_ASSETS_ALLOWED_EXTS": "\${GH_AW_ASSETS_ALLOWED_EXTS}",
- "GH_AW_ASSETS_BRANCH": "\${GH_AW_ASSETS_BRANCH}",
- "GH_AW_ASSETS_MAX_SIZE_KB": "\${GH_AW_ASSETS_MAX_SIZE_KB}",
- "GH_AW_MCP_LOG_DIR": "\${GH_AW_MCP_LOG_DIR}",
- "GH_AW_SAFE_OUTPUTS": "\${GH_AW_SAFE_OUTPUTS}",
- "GH_AW_SAFE_OUTPUTS_CONFIG_PATH": "\${GH_AW_SAFE_OUTPUTS_CONFIG_PATH}",
- "GH_AW_SAFE_OUTPUTS_TOOLS_PATH": "\${GH_AW_SAFE_OUTPUTS_TOOLS_PATH}",
- "GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST": "\${GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST}",
- "GH_AW_PR_HEAD_BASE_BRANCH": "\${GH_AW_PR_HEAD_BASE_BRANCH}",
- "GH_AW_PR_HEAD_BASE_SHA": "\${GH_AW_PR_HEAD_BASE_SHA}",
- "GH_AW_PR_HEAD_BASE_REPO": "\${GH_AW_PR_HEAD_BASE_REPO}",
- "GH_AW_PR_HEAD_BASE_PR_NUMBER": "\${GH_AW_PR_HEAD_BASE_PR_NUMBER}",
- "GH_AW_PR_HEAD_BASE_REF": "\${GH_AW_PR_HEAD_BASE_REF}",
- "GH_AW_PR_HEAD_REPO": "\${GH_AW_PR_HEAD_REPO}",
- "GITHUB_EVENT_NAME": "\${GITHUB_EVENT_NAME}",
- "GITHUB_EVENT_PATH": "\${GITHUB_EVENT_PATH}",
- "GITHUB_REPOSITORY": "\${GITHUB_REPOSITORY}",
- "GITHUB_SHA": "\${GITHUB_SHA}",
- "GITHUB_TOKEN": "\${GITHUB_TOKEN}",
- "GITHUB_WORKSPACE": "\${GITHUB_WORKSPACE}",
- "RUNNER_TEMP": "\${RUNNER_TEMP}"
- },
- "guard-policies": {
- "write-sink": {
- "accept": [
- "*"
- ],
- "sink-visibility": "${GH_AW_SINK_VISIBILITY}"
- }
- }
- }
- },
- "gateway": {
- "port": $MCP_GATEWAY_PORT,
- "domain": "${MCP_GATEWAY_DOMAIN}",
- "agentId": "${MCP_GATEWAY_AGENT_ID}",
- "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}",
- "startupTimeout": 120,
- "opentelemetry": {
- "endpoint": "${OTEL_EXPORTER_OTLP_ENDPOINT}",
- "traceId": "${GITHUB_AW_OTEL_TRACE_ID}",
- "spanId": "${GITHUB_AW_OTEL_PARENT_SPAN_ID}"
- }
- }
- }
- GH_AW_MCP_CONFIG_6e47705499a41fbb_EOF
- - name: Mount MCP servers as CLIs
- id: mount-mcp-clis
- continue-on-error: true
- env:
- MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }}
- MCP_GATEWAY_DOMAIN: ${{ steps.start-mcp-gateway.outputs.gateway-domain }}
- MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io);
- const { main } = require(path.join(actionsDir, 'mount_mcp_as_cli.cjs'));
- await main();
- - name: Clean credentials
- continue-on-error: true
- run: bash "${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh"
- - name: Audit pre-agent workspace
- id: pre_agent_audit
- continue-on-error: true
- run: bash "${RUNNER_TEMP}/gh-aw/actions/audit_pre_agent_workspace.sh"
- - name: Execute GitHub Copilot CLI
- id: agentic_execution
- # Copilot CLI tool arguments (sorted):
- timeout-minutes: ${{ fromJSON(vars.GH_AW_DEFAULT_TIMEOUT_MINUTES || '20') }}
- run: |
- set -o pipefail
- printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt
- trap 'gh_aw_exit_code=$?; mkdir -p /tmp/gh-aw >/dev/null 2>&1 || true; printf "%s" "$gh_aw_exit_code" > /tmp/gh-aw/agent_execution_exit_code.txt || true; rm -f "$HOME/.copilot/settings.json"; if [ "$gh_aw_exit_code" -ne 0 ]; then echo "::error::Agent execution exited with code $gh_aw_exit_code"; fi' EXIT
- mkdir -p "$HOME/.copilot"
- printf '%s' '{"builtInAgents":{"rubberDuck":false}}' > "$HOME/.copilot/settings.json"
- export XDG_CONFIG_HOME="$HOME"
- export GH_AW_MCP_CONFIG="$HOME/.copilot/mcp-config.json"
- GH_AW_COPILOT_SRC="$(command -v copilot 2>/dev/null || true)"
- if [ -z "$GH_AW_COPILOT_SRC" ] || [ ! -x "$GH_AW_COPILOT_SRC" ]; then
- echo "GitHub Copilot CLI executable not found on PATH after installation" >&2
- exit 127
- fi
- GH_AW_COPILOT_BIN="${RUNNER_TEMP}/gh-aw/bin/copilot"
- mkdir -p "${RUNNER_TEMP}/gh-aw/bin"
- if [ "$GH_AW_COPILOT_SRC" != "$GH_AW_COPILOT_BIN" ]; then
- cp "$GH_AW_COPILOT_SRC" "$GH_AW_COPILOT_BIN"
- fi
- chmod 755 "$GH_AW_COPILOT_BIN"
-
- touch /tmp/gh-aw/agent-step-summary.md
- GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
- export GH_AW_NODE_BIN
- export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
- (umask 177 && touch /tmp/gh-aw/agent-stdio.log)
- GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-1000}"
- if [[ ! "$GH_AW_MAX_AI_CREDITS" =~ ^[0-9]+$ ]]; then
- GH_AW_MAX_AI_CREDITS="1000"
- fi
- printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.28.23/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"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\",\"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\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\"],\"isolation\":true,\"topologyAttach\":[\"awmg-mcpg\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-6\",\"gpt-5.4\",\"gpt-5.5\",\"gpt-5.6\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"auto\":[\"copilot/auto\",\"large\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"detection\":[\"small\"],\"evals\":[\"small\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-3.6-flash\":[\"copilot/gemini-3.6*flash*\",\"google/gemini-3.6*flash*\",\"gemini/gemini-3.6*flash*\"],\"gemini-3.7-flash\":[\"copilot/gemini-3.7*flash*\",\"google/gemini-3.7*flash*\",\"gemini/gemini-3.7*flash*\"],\"gemini-3.8-flash\":[\"copilot/gemini-3.8*flash*\",\"google/gemini-3.8*flash*\",\"gemini/gemini-3.8*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"gpt-6\":[\"copilot/gpt-6*\",\"openai/gpt-6*\"],\"grok\":[\"copilot/*grok*\",\"openai/*grok*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"sonnet\",\"gpt-6\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mai-code-1-flash-picker\":[\"copilot/MAI-Code-1-Flash-picker*\",\"copilot/mai-code-1-flash-picker*\",\"openai/MAI-Code-1-Flash-picker*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"raptor-mini\":[\"copilot/raptor*\",\"openai/raptor*\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-5*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\",\"anthropic/*sonnet-5*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.28.23,squid=sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0,agent=sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2,api-proxy=sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64,cli-proxy=sha256:9e31a6e518eba44652b9ae94ce55c3b6958e06290c3b81b08de4174751bb439a\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json"
- cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
- export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json"
- GH_AW_DOCKER_HOST=""
- if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
- GH_AW_DOCKER_HOST="${DOCKER_HOST}"
- fi
- if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
- GH_AW_CHROOT_BINARIES_SOURCE_PATH="${RUNNER_TEMP}/gh-aw" GH_AW_CHROOT_IDENTITY_HOME="${RUNNER_TEMP}/gh-aw/home" node "${RUNNER_TEMP}/gh-aw/actions/patch_awf_chroot_config.cjs"
- fi
- GH_AW_TOOL_CACHE_MOUNT=""
- GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"
- if [ -d "$GH_AW_TOOL_CACHE" ]; then
- if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
- GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
- fi
- fi
- # shellcheck disable=SC1003,SC2016,SC2086
- mkdir -p "/tmp/gh-aw"
- evidence_tmp="/tmp/gh-aw/agent_execution.json.tmp"
- printf '{"version":1,"component":"agent","run_id":%s,"run_attempt":%s,"state":"started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp"
- mv "$evidence_tmp" "/tmp/gh-aw/agent_execution.json"
- export GH_AW_AWF_EXECUTION_COMPONENT="agent"
- export GH_AW_AWF_EXECUTION_EVIDENCE_FILE="/tmp/gh-aw/agent_execution.json"
- GH_AW_AWF_ENGINE_NAME=copilot \
- GH_AW_AWF_HARNESS_MARKER='[copilot-harness]' \
- GH_AW_AWF_LOG_FILE=/tmp/gh-aw/agent-stdio.log \
- GH_AW_AWF_ATTEMPT_LOG_NAME=copilot \
- bash "${RUNNER_TEMP}/gh-aw/actions/run_awf_with_startup_retries.sh" -- \
- awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --env-all --exclude-env ACTIONS_ID_TOKEN_REQUEST_TOKEN --exclude-env ACTIONS_ID_TOKEN_REQUEST_URL --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_AGENT_ID --mount /tmp/gh-aw:/tmp/gh-aw:rw --log-level info --skip-pull \
- -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; GH_AW_TOOL_BINS="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')"; GH_AW_TOOL_BINS="${GH_AW_TOOL_BINS%:}"; export PATH="$PATH${GH_AW_TOOL_BINS:+:}$GH_AW_TOOL_BINS"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" "${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs" "${RUNNER_TEMP}/gh-aw/bin/copilot" --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt'
- env:
- AWF_REFLECT_ENABLED: 1
- COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
- COPILOT_GITHUB_TOKEN: ${{ github.token }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'auto' }}
- GH_AW_LLM_PROVIDER: github
- GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
- GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }}
- GH_AW_PHASE: agent
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_TIMEOUT_MINUTES: ${{ fromJSON(vars.GH_AW_DEFAULT_TIMEOUT_MINUTES || '20') }}
- GH_AW_VERSION: v0.89.21
- GITHUB_API_URL: ${{ github.api_url }}
- GITHUB_AW: true
- GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
- GITHUB_HEAD_REF: ${{ github.head_ref }}
- GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- GITHUB_REF_NAME: ${{ github.ref_name }}
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
- GITHUB_WORKSPACE: ${{ github.workspace }}
- GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
- GIT_AUTHOR_NAME: github-actions[bot]
- GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
- GIT_COMMITTER_NAME: github-actions[bot]
- RUNNER_TEMP: ${{ runner.temp }}
- S2STOKENS: true
- TRACEPARENT: ${{ env.GITHUB_AW_OTEL_TRACE_ID != '' && env.GITHUB_AW_OTEL_PARENT_SPAN_ID != '' && format('00-{0}-{1}-01', env.GITHUB_AW_OTEL_TRACE_ID, env.GITHUB_AW_OTEL_PARENT_SPAN_ID) || '' }}
- - name: Detect agent errors
- if: always()
- id: detect-agent-errors
- continue-on-error: true
- env:
- GH_AW_AGENTIC_EXECUTION_OUTCOME: ${{ steps.agentic_execution.outcome }}
- GH_AW_ENGINE_STEP_TIMEOUT_MINUTES: ${{ fromJSON(vars.GH_AW_DEFAULT_TIMEOUT_MINUTES || '20') }}
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'detect_agent_errors.cjs'));
- await main();
- - name: Configure Git credentials
- env:
- GITHUB_REPOSITORY: ${{ github.repository }}
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_TOKEN: ${{ github.token }}
- run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_git_credentials.sh"
- - name: Copy Copilot session state files to logs
- if: always()
- continue-on-error: true
- run: bash "${RUNNER_TEMP}/gh-aw/actions/copy_copilot_session_state.sh"
- - name: Stop MCP Gateway
- if: always()
- continue-on-error: true
- env:
- MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
- MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }}
- GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}
- run: |
- bash "${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh" "$GATEWAY_PID"
- - name: Redact secrets in logs
- if: always()
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'redact_secrets.cjs'));
- await main();
- env:
- GH_AW_SECRET_NAMES: 'GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
- SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
- SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
- SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: Append agent step summary
- if: always()
- run: bash "${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh"
- - name: Copy Safe Outputs
- if: always()
- env:
- GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- run: |
- mkdir -p /tmp/gh-aw
- cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true
- - name: Ingest agent output
- id: collect_output
- if: always()
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_ALLOWED_DOMAINS: "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,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,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_API_URL: ${{ github.api_url }}
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'collect_ndjson_output.cjs'));
- await main();
- - name: Parse agent logs for step summary
- if: always()
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/
- GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'parse_copilot_log.cjs'));
- await main();
- - name: Parse MCP Gateway logs for step summary
- if: always()
- id: parse-mcp-gateway
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, '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: bash "${RUNNER_TEMP}/gh-aw/actions/print_firewall_logs.sh" --rootless
- - name: Parse token usage for step summary
- if: always()
- id: parse-token-usage
- continue-on-error: true
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'parse_token_usage.cjs'));
- await main();
- - name: Print AWF reflect summary
- if: always()
- continue-on-error: true
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'awf_reflect_summary.cjs'));
- await main();
- - name: Generate observability summary
- if: always()
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'generate_observability_summary.cjs'));
- await main(core);
- - name: Write agent output placeholder if missing
- if: always()
- run: |
- if [ ! -f /tmp/gh-aw/agent_output.json ]; then
- echo '{"items":[]}' > /tmp/gh-aw/agent_output.json
- fi
- # Small dedicated copy of the agent output so safe-output processing
- # survives a failed or timed-out upload of the larger agent artifact
- - name: Upload agent output fallback artifact
- if: always()
- continue-on-error: true
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
- with:
- name: agent-output-fallback
- path: |
- /tmp/gh-aw/agent_output.json
- /tmp/gh-aw/safeoutputs.jsonl
- /tmp/gh-aw/agent_execution.json
- /tmp/gh-aw/agent_usage.jsonl
- /tmp/gh-aw/agent_usage.json
- /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl
- /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl
- /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl
- if-no-files-found: ignore
- - name: Upload agent artifacts
- if: always()
- continue-on-error: true
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
- with:
- name: agent
- path: |
- /tmp/gh-aw/aw-prompts/prompt.txt
- /tmp/gh-aw/agent_execution.json
- /tmp/gh-aw/sandbox/agent/logs/
- /tmp/gh-aw/redacted-urls.log
- /tmp/gh-aw/mcp-logs/
- /tmp/gh-aw/agent_usage.json
- /tmp/gh-aw/agent_usage.jsonl
- /tmp/gh-aw/agent-stdio.log
- /tmp/gh-aw/pre-agent-audit.txt
- /tmp/gh-aw/github_rate_limits.jsonl
- /tmp/gh-aw/otel.jsonl
- /tmp/gh-aw/otlp-export-errors.jsonl
- /tmp/gh-aw/safeoutputs.jsonl
- /tmp/gh-aw/agent_output.json
- /tmp/gh-aw/aw-*.patch
- /tmp/gh-aw/aw-*.bundle
- /tmp/gh-aw/awf-config.json
- /tmp/gh-aw/sandbox/firewall/logs/
- /tmp/gh-aw/sandbox/firewall/audit/
- /tmp/gh-aw/sandbox/firewall/awf-reflect.json
- if-no-files-found: ignore
-
- conclusion:
- needs:
- - activation
- - agent
- - detection
- - safe_outputs
- if: >
- always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' ||
- needs.activation.outputs.oauth_token_check_failed == 'true' || needs.activation.outputs.stale_lock_file_failed == 'true' ||
- needs.activation.outputs.daily_ai_credits_exceeded == 'true' || needs.activation.outputs.daily_ai_credits_guardrail_status == 'structural_error' ||
- needs.activation.outputs.daily_ai_credits_guardrail_status == 'transient_error')
- runs-on: ubuntu-slim
- permissions:
- actions: read
- contents: write
- issues: write
- pull-requests: write
- concurrency:
- group: "gh-aw-conclusion-codeowner-update"
- cancel-in-progress: false
- queue: max
- env:
- GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
- outputs:
- incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }}
- 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
- id: setup
- uses: github/gh-aw-actions/setup@924af5fdc64061cfbf66fb584c8b07e2ac230c60 # v0.89.21
- with:
- destination: ${{ runner.temp }}/gh-aw/actions
- job-name: ${{ github.job }}
- trace-id: ${{ needs.activation.outputs.setup-trace-id }}
- parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
- env:
- GH_AW_SETUP_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/codeowner-update.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.87"
- GH_AW_INFO_AWF_VERSION: "v0.28.23"
- GH_AW_INFO_ENGINE_ID: "copilot"
- - name: Download agent output artifact
- id: download-agent-output
- continue-on-error: true
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- with:
- pattern: "{agent,agent-output-fallback}"
- merge-multiple: true
- path: /tmp/gh-aw/
- - name: Setup agent output environment variable
- id: setup-agent-output-env
- if: steps.download-agent-output.outcome == 'success'
- run: |
- mkdir -p /tmp/gh-aw/
- find "/tmp/gh-aw/" -type f -print
- if [ -f "/tmp/gh-aw/agent_output.json" ]; then
- echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
- fi
- - name: Download detection artifact
- id: download-detection-artifact
- continue-on-error: true
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- with:
- name: detection
- path: /tmp/gh-aw/threat-detection/
- - name: Download Safe Outputs Items Manifest
- id: download-safe-outputs-manifest
- if: always()
- continue-on-error: true
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- with:
- pattern: safe-outputs-items
- merge-multiple: true
- path: /tmp/gh-aw/
- - name: Collect usage artifact files
- if: always()
- continue-on-error: true
- run: bash "${RUNNER_TEMP}/gh-aw/actions/collect_usage_artifact_files.sh"
- - name: Upload usage artifact
- id: upload-usage-artifact
- if: always()
- continue-on-error: true
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
- with:
- name: usage
- path: |
- /tmp/gh-aw/usage/aw_info.json
- /tmp/gh-aw/usage/aw-info.jsonl
- /tmp/gh-aw/usage/agent_usage.json
- /tmp/gh-aw/usage/agent_usage.jsonl
- /tmp/gh-aw/usage/detection_usage.jsonl
- /tmp/gh-aw/usage/evals.jsonl
- /tmp/gh-aw/usage/graders/grader_manifest.json
- /tmp/gh-aw/usage/graders/grader_results.json
- /tmp/gh-aw/usage/github_rate_limits.jsonl
- /tmp/gh-aw/usage/agent/token_usage.jsonl
- /tmp/gh-aw/usage/agent/execution.json
- /tmp/gh-aw/usage/detection/token_usage.jsonl
- /tmp/gh-aw/usage/detection/execution.json
- /tmp/gh-aw/usage/evals/token_usage.jsonl
- /tmp/gh-aw/usage/evals/execution.json
- /tmp/gh-aw/usage/activity/summary.json
- if-no-files-found: ignore
- - name: Wait before retrying usage artifact upload
- if: always() && steps.upload-usage-artifact.outcome == 'failure'
- run: sleep 10
- - name: Retry upload usage artifact
- id: upload-usage-artifact-retry
- if: always() && steps.upload-usage-artifact.outcome == 'failure'
- continue-on-error: true
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
- with:
- name: usage
- path: |
- /tmp/gh-aw/usage/aw_info.json
- /tmp/gh-aw/usage/aw-info.jsonl
- /tmp/gh-aw/usage/agent_usage.json
- /tmp/gh-aw/usage/agent_usage.jsonl
- /tmp/gh-aw/usage/detection_usage.jsonl
- /tmp/gh-aw/usage/evals.jsonl
- /tmp/gh-aw/usage/graders/grader_manifest.json
- /tmp/gh-aw/usage/graders/grader_results.json
- /tmp/gh-aw/usage/github_rate_limits.jsonl
- /tmp/gh-aw/usage/agent/token_usage.jsonl
- /tmp/gh-aw/usage/agent/execution.json
- /tmp/gh-aw/usage/detection/token_usage.jsonl
- /tmp/gh-aw/usage/detection/execution.json
- /tmp/gh-aw/usage/evals/token_usage.jsonl
- /tmp/gh-aw/usage/evals/execution.json
- /tmp/gh-aw/usage/activity/summary.json
- if-no-files-found: ignore
- overwrite: true
- - name: Process no-op messages
- id: noop
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
- GH_AW_NOOP_MAX: "1"
- GH_AW_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codeowner-update.md"
- GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
- GH_AW_NOOP_REPORT_AS_ISSUE: "true"
- GH_AW_AIC: ${{ needs.agent.outputs.aic }}
- GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }}
- GH_AW_AMBIENT_CONTEXT: ${{ needs.agent.outputs.ambient_context }}
- GH_AW_WORKFLOW_ID: "codeowner-update"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'handle_noop_message.cjs'));
- await main();
- - name: Log detection run
- id: detection_runs
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codeowner-update.md"
- GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
- GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'handle_detection_runs.cjs'));
- await main();
- - name: Record missing tool
- id: missing_tool
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
- GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
- GH_AW_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codeowner-update.md"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'missing_tool.cjs'));
- await main();
- - name: Record incomplete
- id: report_incomplete
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
- GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
- GH_AW_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codeowner-update.md"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'report_incomplete_handler.cjs'));
- await main();
- - name: Handle agent failure
- id: handle_agent_failure
- if: always()
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codeowner-update.md"
- 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: "codeowner-update"
- GH_AW_ACTION_FAILURE_ISSUE_EXPIRES_HOURS: "168"
- GH_AW_ENGINE_ID: "copilot"
- GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
- GH_AW_AI_CREDITS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.ai_credits_rate_limit_error || 'false' }}
- GH_AW_UNKNOWN_MODEL_AI_CREDITS: ${{ needs.agent.outputs.unknown_model_ai_credits || 'false' }}
- GH_AW_AIC: ${{ needs.agent.outputs.aic }}
- GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }}
- GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
- GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }}
- GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }}
- GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }}
- GH_AW_MODEL_NOT_SUPPORTED_ERROR: ${{ needs.agent.outputs.model_not_supported_error }}
- GH_AW_HTTP_400_RESPONSE_ERROR: ${{ needs.agent.outputs.http_400_response_error }}
- GH_AW_MAX_CACHE_MISSES_EXCEEDED: ${{ needs.agent.outputs.max_cache_misses_exceeded }}
- GH_AW_MISSING_MODEL_PRICING_ERROR: ${{ needs.agent.outputs.missing_model_pricing_error }}
- GH_AW_MISSING_MODEL_PRICING_MODEL_NAME: ${{ needs.agent.outputs.missing_model_pricing_model_name }}
- GH_AW_SHELL_EXPANSION_GUARD_REJECTED: ${{ needs.agent.outputs.shell_expansion_guard_rejected }}
- GH_AW_ENGINE_API_HOSTS: "api.enterprise.githubcopilot.com,api.githubcopilot.com,api.business.githubcopilot.com,api.individual.githubcopilot.com"
- 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_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }}
- GH_AW_OAUTH_TOKEN_CHECK_FAILED: ${{ needs.activation.outputs.oauth_token_check_failed }}
- GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }}
- GH_AW_DAILY_AI_CREDITS_EXCEEDED: ${{ needs.activation.outputs.daily_ai_credits_exceeded }}
- GH_AW_DAILY_AI_CREDITS_GUARDRAIL_STATUS: ${{ needs.activation.outputs.daily_ai_credits_guardrail_status }}
- GH_AW_DAILY_AI_CREDITS_GUARDRAIL_ERROR: ${{ needs.activation.outputs.daily_ai_credits_guardrail_error }}
- GH_AW_DAILY_AI_CREDITS_TOTAL: ${{ needs.activation.outputs.daily_ai_credits_total }}
- GH_AW_DAILY_AI_CREDITS_THRESHOLD: ${{ needs.activation.outputs.daily_ai_credits_threshold }}
- GH_AW_DAILY_AI_CREDITS_CONTINUE_ON_ERROR: "false"
- GH_AW_GROUP_REPORTS: "false"
- GH_AW_FAILURE_REPORT_AS_ISSUE: "true"
- GH_AW_MISSING_TOOL_REPORT_AS_FAILURE: "true"
- GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true"
- GH_AW_TIMEOUT_MINUTES: "${{ fromJSON(vars.GH_AW_DEFAULT_TIMEOUT_MINUTES || '20') }}"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'handle_agent_failure.cjs'));
- await main();
- - name: Report failed jobs
- id: report_failed_jobs
- if: always()
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
- GH_AW_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codeowner-update.md"
- GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- GH_AW_REPORT_FAILED_JOBS: "true"
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'report_failed_jobs.cjs'));
- await main();
-
- detection:
- needs:
- - activation
- - agent
- if: always() && needs.agent.result != 'skipped'
- runs-on: ubuntu-latest
- permissions:
- contents: read
- copilot-requests: write
- timeout-minutes: 10
- env:
- GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
- outputs:
- aic: ${{ steps.parse_detection_token_usage.outputs.aic }}
- detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}
- detection_reason: ${{ steps.detection_conclusion.outputs.reason }}
- detection_success: ${{ steps.detection_conclusion.outputs.success }}
- steps:
- - name: Setup Scripts
- id: setup
- uses: github/gh-aw-actions/setup@924af5fdc64061cfbf66fb584c8b07e2ac230c60 # v0.89.21
- with:
- destination: ${{ runner.temp }}/gh-aw/actions
- job-name: ${{ github.job }}
- trace-id: ${{ needs.activation.outputs.setup-trace-id }}
- parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
- env:
- GH_AW_SETUP_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/codeowner-update.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.87"
- GH_AW_INFO_AWF_VERSION: "v0.28.23"
- GH_AW_INFO_ENGINE_ID: "copilot"
- - name: Download activation artifact
- continue-on-error: true
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- with:
- name: activation
- path: /tmp/gh-aw
- - name: Download agent output artifact
- id: download-agent-output
- continue-on-error: true
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- with:
- pattern: "{agent,agent-output-fallback}"
- merge-multiple: true
- path: /tmp/gh-aw/
- - name: Setup agent output environment variable
- id: setup-agent-output-env
- if: steps.download-agent-output.outcome == 'success'
- run: |
- mkdir -p /tmp/gh-aw/
- find "/tmp/gh-aw/" -type f -print
- if [ -f "/tmp/gh-aw/agent_output.json" ]; then
- echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
- fi
- - name: Checkout repository for patch context
- if: needs.agent.outputs.has_patch == 'true'
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- with:
- persist-credentials: false
- # --- Threat Detection ---
- - name: Initialize detection execution evidence
- run: |
- mkdir -p "/tmp/gh-aw/threat-detection"
- evidence_tmp="/tmp/gh-aw/threat-detection/execution.json.tmp"
- printf '{"version":1,"component":"detection","run_id":%s,"run_attempt":%s,"state":"not_started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp"
- mv "$evidence_tmp" "/tmp/gh-aw/threat-detection/execution.json"
- - name: Clear inherited Copilot session state
- run: rm -rf /tmp/gh-aw/sandbox/agent/logs/copilot-session-state
- - name: Clean stale firewall files from agent artifact
- run: |
- rm -rf /tmp/gh-aw/sandbox/firewall/logs
- rm -rf /tmp/gh-aw/sandbox/firewall/audit
- - name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.28.23@sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2 ghcr.io/github/gh-aw-firewall/api-proxy:0.28.23@sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64 ghcr.io/github/gh-aw-firewall/squid:0.28.23@sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0
- - name: Check if detection needed
- id: detection_guard
- if: always()
- env:
- OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }}
- HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
- run: |
- if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then
- echo "run_detection=true" >> "$GITHUB_OUTPUT"
- echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH"
- else
- echo "run_detection=false" >> "$GITHUB_OUTPUT"
- echo "Detection skipped: no agent outputs or patches to analyze"
- fi
- - name: Clear MCP Config for detection
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- run: |
- rm -f "${RUNNER_TEMP}/gh-aw/mcp-config/mcp-servers.json"
- rm -f "$HOME/.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: |
- bash "${RUNNER_TEMP}/gh-aw/actions/prepare_threat_detection_files.sh"
- - name: Setup threat detection
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- WORKFLOW_NAME: "Codeowner Update Agent"
- WORKFLOW_DESCRIPTION: "Updates the CODEOWNERS file when a maintainer comments #codeowner on a pull request"
- HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
- GH_AW_DETECTION_CONTINUE_ON_ERROR: "true"
- GH_AW_DETECTION_SKIP_PROMPT_SUMMARY: "true"
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'setup_threat_detection.cjs'));
- await main();
- - name: Ensure threat-detection directory and log
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- run: |
- mkdir -p /tmp/gh-aw/threat-detection
- touch /tmp/gh-aw/threat-detection/detection.log
- - name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.28.23 --rootless
- - name: Setup Node.js
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
- with:
- node-version: '24'
- package-manager-cache: false
- - name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh"
- env:
- GH_HOST: github.com
- GH_AW_COMPILED_VERSION: v0.89.21
- - name: Install threat-detect binary
- id: threat_detect_install
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- continue-on-error: true
- run: |
- bash "${RUNNER_TEMP}/gh-aw/actions/install_threat_detect_binary.sh" v0.5.2 --artifact-base-url https://github.com/github/gh-aw-threat-detection/releases/download --sha256-amd64 b4ecda6a8f1ee09913c40b58e5e9d3337d2173618d41b1bfdef9207e4e7959b9 --sha256-arm64 f6260a0f9ad72bcb67c7af19c4ce262ca34e2c3d5ccbf912832a8bd277200904
- - name: Execute threat detection with AWF
- id: detection_agentic_execution
- if: always() && steps.detection_guard.outputs.run_detection == 'true' && steps.threat_detect_install.outcome == 'success'
- continue-on-error: true
- timeout-minutes: 10
- env:
- AWF_REFLECT_ENABLED: 1
- COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
- COPILOT_GITHUB_TOKEN: ${{ github.token }}
- COPILOT_MODEL: detection
- GH_AW_HARNESS_MAX_RETRIES: 0
- GH_AW_LLM_PROVIDER: github
- GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_DETECTION_MAX_AI_CREDITS || '400' }}
- GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }}
- GH_AW_PHASE: detection
- GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_TIMEOUT_MINUTES: 10
- GH_AW_VERSION: v0.89.21
- GITHUB_API_URL: ${{ github.api_url }}
- GITHUB_AW: true
- GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
- GITHUB_HEAD_REF: ${{ github.head_ref }}
- GITHUB_REF_NAME: ${{ github.ref_name }}
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
- GITHUB_WORKSPACE: ${{ github.workspace }}
- GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
- GIT_AUTHOR_NAME: github-actions[bot]
- GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
- GIT_COMMITTER_NAME: github-actions[bot]
- RUNNER_TEMP: ${{ runner.temp }}
- S2STOKENS: true
- TRACEPARENT: ${{ env.GITHUB_AW_OTEL_TRACE_ID != '' && env.GITHUB_AW_OTEL_PARENT_SPAN_ID != '' && format('00-{0}-{1}-01', env.GITHUB_AW_OTEL_TRACE_ID, env.GITHUB_AW_OTEL_PARENT_SPAN_ID) || '' }}
- WORKFLOW_NAME: "Codeowner Update Agent"
- WORKFLOW_DESCRIPTION: "Updates the CODEOWNERS file when a maintainer comments #codeowner on a pull request"
- HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
- GH_AW_DETECTION_CONTINUE_ON_ERROR: "true"
- run: |
- mkdir -p "/tmp/gh-aw/threat-detection"
- evidence_tmp="/tmp/gh-aw/threat-detection/execution.json.tmp"
- printf '{"version":1,"component":"detection","run_id":%s,"run_attempt":%s,"state":"started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp"
- mv "$evidence_tmp" "/tmp/gh-aw/threat-detection/execution.json"
- export GH_AW_AWF_EXECUTION_COMPONENT="detection"
- export GH_AW_AWF_EXECUTION_EVIDENCE_FILE="/tmp/gh-aw/threat-detection/execution.json"
- set -o pipefail
- printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt
- GH_AW_COPILOT_SRC="$(command -v copilot 2>/dev/null || true)"
- if [ -z "$GH_AW_COPILOT_SRC" ] || [ ! -x "$GH_AW_COPILOT_SRC" ]; then
- echo "GitHub Copilot CLI executable not found on PATH after installation" >&2
- exit 127
- fi
- GH_AW_COPILOT_BIN="${RUNNER_TEMP}/gh-aw/bin/copilot"
- mkdir -p "${RUNNER_TEMP}/gh-aw/bin"
- if [ "$GH_AW_COPILOT_SRC" != "$GH_AW_COPILOT_BIN" ]; then
- cp "$GH_AW_COPILOT_SRC" "$GH_AW_COPILOT_BIN"
- fi
- chmod 755 "$GH_AW_COPILOT_BIN"
-
- (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
- GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-400}"
- if [[ ! "$GH_AW_MAX_AI_CREDITS" =~ ^[0-9]+$ ]]; then
- GH_AW_MAX_AI_CREDITS="400"
- fi
- printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.28.23/awf-config.schema.json\",\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-6\",\"gpt-5.4\",\"gpt-5.5\",\"gpt-5.6\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"auto\":[\"copilot/auto\",\"large\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"detection\":[\"small\"],\"evals\":[\"small\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-3.6-flash\":[\"copilot/gemini-3.6*flash*\",\"google/gemini-3.6*flash*\",\"gemini/gemini-3.6*flash*\"],\"gemini-3.7-flash\":[\"copilot/gemini-3.7*flash*\",\"google/gemini-3.7*flash*\",\"gemini/gemini-3.7*flash*\"],\"gemini-3.8-flash\":[\"copilot/gemini-3.8*flash*\",\"google/gemini-3.8*flash*\",\"gemini/gemini-3.8*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"gpt-6\":[\"copilot/gpt-6*\",\"openai/gpt-6*\"],\"grok\":[\"copilot/*grok*\",\"openai/*grok*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"sonnet\",\"gpt-6\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mai-code-1-flash-picker\":[\"copilot/MAI-Code-1-Flash-picker*\",\"copilot/mai-code-1-flash-picker*\",\"openai/MAI-Code-1-Flash-picker*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"raptor-mini\":[\"copilot/raptor*\",\"openai/raptor*\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-5*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\",\"anthropic/*sonnet-5*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.28.23,squid=sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0,agent=sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2,api-proxy=sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64,cli-proxy=sha256:9e31a6e518eba44652b9ae94ce55c3b6958e06290c3b81b08de4174751bb439a\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json"
- cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
- export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json"
- GH_AW_DOCKER_HOST=""
- if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
- GH_AW_DOCKER_HOST="${DOCKER_HOST}"
- fi
- if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
- _GH_AW_CHROOT_JSON=$(jq -c --arg src "${RUNNER_TEMP}/gh-aw" --arg user "$(id -un)" --argjson uid "$(id -u)" --argjson gid "$(id -g)" --arg home "${RUNNER_TEMP}/gh-aw/home" '.chroot={"binariesSourcePath":$src,"identity":{"user":$user,"uid":$uid,"gid":$gid,"home":$home}}' "${RUNNER_TEMP}/gh-aw/awf-config.json") || { echo "chroot config patch failed" >&2; exit 1; }
- printf '%s\n' "$_GH_AW_CHROOT_JSON" > "${RUNNER_TEMP}/gh-aw/awf-config.json"
- fi
- GH_AW_TOOL_CACHE_MOUNT=""
- GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"
- if [ -d "$GH_AW_TOOL_CACHE" ]; then
- if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
- GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
- fi
- fi
- # shellcheck disable=SC1003,SC2016,SC2086
- awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --env-all --exclude-env ACTIONS_ID_TOKEN_REQUEST_TOKEN --exclude-env ACTIONS_ID_TOKEN_REQUEST_URL --exclude-env COPILOT_GITHUB_TOKEN --mount /tmp/gh-aw:/tmp/gh-aw:rw --mount /tmp/gh-aw/threat-detection:/tmp/gh-aw/threat-detection:rw --log-level info --skip-pull \
- -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; GH_AW_TOOL_BINS="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')"; GH_AW_TOOL_BINS="${GH_AW_TOOL_BINS%:}"; export PATH="$PATH${GH_AW_TOOL_BINS:+:}$GH_AW_TOOL_BINS"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && threat-detect --engine copilot --output /tmp/gh-aw/threat-detection/detection_result.json /tmp/gh-aw/threat-detection' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
- - name: Render detection log
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- continue-on-error: true
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'render_detection_log.cjs'));
- await main();
- - name: Copy detection firewall logs
- if: always() && steps.detection_guard.outputs.run_detection == 'true'
- continue-on-error: true
- run: |
- mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall
- if [ -d /tmp/gh-aw/sandbox/firewall/logs ]; then mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall/logs && cp -r /tmp/gh-aw/sandbox/firewall/logs/. /tmp/gh-aw/threat-detection/sandbox/firewall/logs/; fi
- if [ -d /tmp/gh-aw/sandbox/firewall/audit ]; then mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall/audit && cp -r /tmp/gh-aw/sandbox/firewall/audit/. /tmp/gh-aw/threat-detection/sandbox/firewall/audit/; fi
- - name: Parse threat detection token usage for step summary
- id: parse_detection_token_usage
- if: always()
- continue-on-error: true
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_TOKEN_USAGE_SUMMARY_TITLE: Threat Detection Token Usage
- GH_AW_AGENT_USAGE_PATH: /tmp/gh-aw/threat-detection/detection_usage.json
- GH_AW_AGENT_USAGE_JSONL_PATH: /tmp/gh-aw/threat-detection/detection_usage.jsonl
- GH_AW_WRITE_EMPTY_USAGE: "true"
- with:
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'parse_token_usage.cjs'));
- await main();
- - name: Upload threat detection artifact
- if: always()
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
- with:
- name: detection
- path: |
- /tmp/gh-aw/threat-detection/detection_result.json
- /tmp/gh-aw/threat-detection/execution.json
- /tmp/gh-aw/threat-detection/detection_usage.json
- /tmp/gh-aw/threat-detection/detection_usage.jsonl
- /tmp/gh-aw/threat-detection/sandbox/firewall/logs/
- /tmp/gh-aw/threat-detection/sandbox/firewall/audit/
- if-no-files-found: ignore
- - name: Conclude threat detection
- id: detection_conclusion
- if: always()
- continue-on-error: true
- env:
- RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}
- DETECTION_AGENTIC_EXECUTION_OUTCOME: ${{ steps.detection_agentic_execution.outcome }}
- THREAT_DETECT_INSTALL_OUTCOME: ${{ steps.threat_detect_install.outcome }}
- GH_AW_DETECTION_CONTINUE_ON_ERROR: "true"
- run: |
- bash "${RUNNER_TEMP}/gh-aw/actions/conclude_threat_detection.sh" /tmp/gh-aw/threat-detection/detection_result.json
-
- pre_activation:
- if: >
- (github.event_name != 'issue_comment' || contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) &&
- (contains(github.event.comment.body, '#codeowner') && github.event.issue.pull_request)
- runs-on: ubuntu-slim
- env:
- GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
- outputs:
- activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }}
- matched_command: ''
- setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
- setup-span-id: ${{ steps.setup.outputs.span-id }}
- setup-trace-id: ${{ steps.setup.outputs.trace-id }}
- steps:
- - name: Setup Scripts
- id: setup
- uses: github/gh-aw-actions/setup@924af5fdc64061cfbf66fb584c8b07e2ac230c60 # v0.89.21
- with:
- destination: ${{ runner.temp }}/gh-aw/actions
- job-name: ${{ github.job }}
- env:
- GH_AW_SETUP_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/codeowner-update.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.87"
- GH_AW_INFO_AWF_VERSION: "v0.28.23"
- GH_AW_INFO_ENGINE_ID: "copilot"
- - name: Check team membership for workflow
- id: check_membership
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_REQUIRED_ROLES: "admin,maintainer,write"
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'check_membership.cjs'));
- await main();
-
- safe_outputs:
- needs:
- - activation
- - agent
- - detection
- if: (!cancelled()) && needs.agent.result != 'skipped' && needs.detection.result == 'success'
- runs-on: ubuntu-slim
- permissions:
- contents: write
- issues: write
- pull-requests: write
- timeout-minutes: 45
- env:
- GH_AW_AGENT_AIC: ${{ needs.agent.outputs.aic }}
- GH_AW_AIC: ${{ needs.agent.outputs.aic }}
- GH_AW_AMBIENT_CONTEXT: ${{ needs.agent.outputs.ambient_context }}
- GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/codeowner-update"
- GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
- GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
- GH_AW_ENGINE_ID: "copilot"
- GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
- GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
- GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }}
- GH_AW_WORKFLOW_ID: "codeowner-update"
- GH_AW_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codeowner-update.md"
- 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 }}
- comment_id: ${{ steps.process_safe_outputs.outputs.comment_id }}
- comment_url: ${{ steps.process_safe_outputs.outputs.comment_url }}
- create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}
- create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}
- created_pr_number: ${{ steps.process_safe_outputs.outputs.created_pr_number }}
- created_pr_url: ${{ steps.process_safe_outputs.outputs.created_pr_url }}
- process_safe_outputs_items_applied: ${{ steps.process_safe_outputs.outputs.items_applied }}
- process_safe_outputs_items_cancelled: ${{ steps.process_safe_outputs.outputs.items_cancelled }}
- process_safe_outputs_items_deferred: ${{ steps.process_safe_outputs.outputs.items_deferred }}
- process_safe_outputs_items_failed: ${{ steps.process_safe_outputs.outputs.items_failed }}
- process_safe_outputs_items_skipped: ${{ steps.process_safe_outputs.outputs.items_skipped }}
- process_safe_outputs_items_succeeded: ${{ steps.process_safe_outputs.outputs.items_succeeded }}
- process_safe_outputs_items_warnings: ${{ steps.process_safe_outputs.outputs.items_warnings }}
- process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}
- process_safe_outputs_status: ${{ steps.process_safe_outputs.outputs.status }}
- steps:
- - name: Setup Scripts
- id: setup
- uses: github/gh-aw-actions/setup@924af5fdc64061cfbf66fb584c8b07e2ac230c60 # v0.89.21
- with:
- destination: ${{ runner.temp }}/gh-aw/actions
- job-name: ${{ github.job }}
- trace-id: ${{ needs.activation.outputs.setup-trace-id }}
- parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
- env:
- GH_AW_SETUP_WORKFLOW_NAME: "Codeowner Update Agent"
- GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/codeowner-update.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.87"
- GH_AW_INFO_AWF_VERSION: "v0.28.23"
- GH_AW_INFO_ENGINE_ID: "copilot"
- - name: Mask OTLP telemetry headers
- run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh"
- - name: Download agent output artifact
- id: download-agent-output
- continue-on-error: true
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- with:
- pattern: "{agent,agent-output-fallback}"
- merge-multiple: true
- path: /tmp/gh-aw/
- - name: Setup agent output environment variable
- id: setup-agent-output-env
- if: steps.download-agent-output.outcome == 'success'
- run: |
- mkdir -p /tmp/gh-aw/
- find "/tmp/gh-aw/" -type f -print
- if [ -f "/tmp/gh-aw/agent_output.json" ]; then
- echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
- fi
- - name: Download patch artifact
- continue-on-error: true
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- with:
- name: agent
- 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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- with:
- persist-credentials: true
- token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- - name: Configure Git credentials
- if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request')
- env:
- GITHUB_REPOSITORY: ${{ github.repository }}
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GIT_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_git_credentials.sh"
- - name: Configure GH_HOST for enterprise compatibility
- id: ghes-host-config
- shell: bash
- run: | # zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input.
- # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
- # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
- GH_HOST="${GITHUB_SERVER_URL#https://}"
- GH_HOST="${GH_HOST#http://}"
- echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
- - name: Process Safe Outputs
- id: process_safe_outputs
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
- GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
- GH_AW_ALLOWED_DOMAINS: "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,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,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
- GITHUB_SERVER_URL: ${{ github.server_url }}
- GITHUB_API_URL: ${{ github.api_url }}
- GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request\":{\"base_branch\":\"main\",\"draft\":false,\"max\":1,\"max_patch_files\":100,\"max_patch_size\":4096,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\"],\"protected_files_policy\":\"request-review\",\"title_prefix\":\"[codeowner] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}"
- GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }}
- with:
- github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
- script: |
- const path = require('path');
- const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
- const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
- setupGlobals(core, github, context, exec, io, getOctokit);
- const { main } = require(path.join(actionsDir, 'process_safe_outputs.cjs'));
- await main();
- - name: Upload Safe Outputs Items
- if: always()
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
- with:
- name: safe-outputs-items
- path: |
- /tmp/gh-aw/safe-output-items.jsonl
- /tmp/gh-aw/temporary-id-map.json
- /tmp/gh-aw/safe-output-errors.json
- if-no-files-found: ignore
diff --git a/.github/workflows/codeowner-update.md b/.github/workflows/codeowner-update.md
deleted file mode 100644
index 9f11ff4e4..000000000
--- a/.github/workflows/codeowner-update.md
+++ /dev/null
@@ -1,94 +0,0 @@
----
-description: "Updates the CODEOWNERS file when a maintainer comments #codeowner on a pull request"
-on:
- issue_comment:
- types: [created]
-if: ${{ contains(github.event.comment.body, '#codeowner') && github.event.issue.pull_request }}
-permissions:
- contents: read
- pull-requests: read
- issues: read
- copilot-requests: write
-tools:
- github:
- toolsets: [default]
-safe-outputs:
- create-pull-request:
- base-branch: main
- title-prefix: "[codeowner] "
- draft: false
- add-comment:
- max: 1
- noop:
----
-
-# Codeowner Update Agent
-
-You are a CODEOWNERS file updater for the **${{ github.repository }}** repository. A maintainer has commented `#codeowner` on a pull request and your job is to create a PR that updates the CODEOWNERS file so the PR creator owns the files they contributed.
-
-## Context
-
-- **Triggering PR:** #${{ github.event.issue.number }}
-- **Comment author:** @${{ github.actor }}
-- **Comment body:** "${{ steps.sanitized.outputs.text }}"
-
-## Instructions
-
-### 1. Validate the Trigger
-
-- Confirm the comment body contains `#codeowner`.
-- If the check fails, exit with a `noop`.
-
-### 2. Gather PR Information
-
-- Use the GitHub tools to get details for pull request #${{ github.event.issue.number }}.
-- Record the **PR creator's username** (the user who opened the PR — `user.login` from the PR object).
-- Retrieve the full list of files changed in the PR.
-
-### 3. Filter Relevant Files
-
-Only include files whose paths start with one of these directories:
-
-- `agents/`
-- `skills/`
-- `instructions/`
-- `workflows/`
-- `hooks/`
-- `plugins/`
-
-If **no files** match these directories, exit with a `noop` message: "No files in agents/, skills/, instructions/, workflows/, hooks/, or plugins/ directories were found in this PR."
-
-### 4. Read the Current CODEOWNERS File
-
-Read the `CODEOWNERS` file from the root of the repository on the `main` branch. Parse its existing entries so you can avoid creating duplicates.
-
-### 5. Build the Updated CODEOWNERS File
-
-For each matched file path from the PR:
-
-- Construct a CODEOWNERS entry: `/ @`
-- For files inside `skills/`, `hooks/`, or `plugins/` (which are directory-based resources), use the **directory pattern** instead of individual file paths. For example, if the PR touches `skills/my-skill/SKILL.md` and `skills/my-skill/template.txt`, add a single entry: `/skills/my-skill/ @`
-- If an entry for that exact path already exists in CODEOWNERS, **replace** the owner with the PR creator rather than adding a duplicate line.
-
-Insert the new entries in the CODEOWNERS file grouped under a comment block:
-
-```
-# Added via #codeowner from PR #
-/ @
-```
-
-Place this block at the end of the file, before any trailing newline.
-
-### 6. Create the Pull Request
-
-Use `create-pull-request` to open a PR with the updated `CODEOWNERS` file. The PR should:
-
-- **Title:** `Update CODEOWNERS for PR #${{ github.event.issue.number }}`
-- **Body:** A summary listing every new or updated CODEOWNERS entry and the PR creator who was assigned ownership.
-- **Only modify the `CODEOWNERS` file** — do not touch any other files.
-
-### 7. Post a Confirmation Comment
-
-After successfully creating the PR, use `add-comment` on the triggering PR to let the team know. Include a link to the newly created CODEOWNERS PR.
-
-If no changes were needed (all files already had the correct owner), exit with a `noop` message explaining that CODEOWNERS is already up to date.
diff --git a/.github/workflows/label-pr-intent-writer.yml b/.github/workflows/label-pr-intent-writer.yml
index f4c77341e..3bcde18fd 100644
--- a/.github/workflows/label-pr-intent-writer.yml
+++ b/.github/workflows/label-pr-intent-writer.yml
@@ -46,6 +46,7 @@ jobs:
'agent',
'instructions',
'new-submission',
+ 'workshops',
'website-update',
'external-plugin',
'hooks',
diff --git a/.github/workflows/label-pr-intent.yml b/.github/workflows/label-pr-intent.yml
index 1fe88f466..dfb53320d 100644
--- a/.github/workflows/label-pr-intent.yml
+++ b/.github/workflows/label-pr-intent.yml
@@ -27,6 +27,7 @@ jobs:
'agent': true,
'instructions': true,
'new-submission': true,
+ 'workshops': true,
'website-update': true,
'external-plugin': true,
'hooks': true,
@@ -78,6 +79,9 @@ jobs:
websiteUpdate: [
/^website\//
],
+ workshops: [
+ /^website\/(?:.*\/)?(?:cli-for-beginners|app-for-beginners|copilot-workshops)\//
+ ],
externalPlugin: [
/^plugins\/external\.json$/
],
@@ -130,6 +134,10 @@ jobs:
desiredLabels.add('instructions');
}
+ if (filenames.some((filename) => matchesAny(filename, patterns.workshops))) {
+ desiredLabels.add('workshops');
+ }
+
if (filenames.some((filename) => matchesAny(filename, patterns.websiteUpdate))) {
desiredLabels.add('website-update');
}
diff --git a/.github/workflows/setup-labels.yml b/.github/workflows/setup-labels.yml
index 56fcffdee..803165f48 100644
--- a/.github/workflows/setup-labels.yml
+++ b/.github/workflows/setup-labels.yml
@@ -36,6 +36,10 @@ jobs:
color: '006B75',
description: 'PR adds at least one new contribution'
},
+ 'workshops': {
+ color: '7057FF',
+ description: 'PR touches Copilot workshop content'
+ },
'website-update': {
color: '0052CC',
description: 'PR touches website content or code'
diff --git a/CODEOWNERS b/CODEOWNERS
index 49d52d850..9c58a6af4 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -2,9 +2,7 @@
#
# - Teams own paths; no individual is the default owner. Do not add individual
# users to the `*` rule or to the team block below.
-# - The last matching rule wins, so per-resource owners appended at the end of
-# this file (for example by the `#codeowner` automation) override the team
-# defaults for their specific paths.
+# - The last matching rule wins.
# - Reviewer pools used for automatic review requests live in
# .github/review-routing.yml.
@@ -22,57 +20,7 @@
/.github/ @github/awesome-copilot-core-maintainers
/eng/ @github/awesome-copilot-core-maintainers
-# Adding Dan Wahlin as the owner for the CLI for Beginners content and images
-/website/src/content/docs/learning-hub/cli-for-beginners/ @DanWahlin
-/website/src/images/cli-for-beginners/ @DanWahlin
-
-# Copilot app for Beginners course and public images
-/website/src/content/docs/learning-hub/app-for-beginners/ @DanWahlin
-/website/public/images/learning-hub/copilot-app-for-beginners/ @DanWahlin
-
-# Agentic Workflows
-/workflows/ @brunoborges
-/.github/workflows/validate-agentic-workflows-pr.yml @brunoborges
-
-# Copilot review policy
-/.github/skills/code-review/ @aaronpowell
-/.github/copilot-instructions.md @aaronpowell
-
-# Added via #codeowner from PR #930
-/plugins/automate-this/ @dvelton
-/skills/automate-this/ @dvelton
-
-# Added via #codeowner from PR #915
-/skills/cli-mastery/ @DUBSOpenHub
-
-# Added via #codeowner from PR #929
-/plugins/napkin/ @dvelton
-/skills/napkin/ @dvelton
-
-# Added via #codeowner from PR #888
-/skills/github-issues/ @labudis
-
-# Added via #codeowner from PR #884
-/skills/github-issues/ @labudis
-
-# Added via #codeowner from PR #889
-/skills/copilot-spaces/ @labudis
-
-# Added via #codeowner from PR #978
-/agents/doublecheck.agent.md @dvelton
-/plugins/doublecheck/ @dvelton
-/skills/doublecheck/ @dvelton
-
-# Added via #codeowner from PR #990
-/skills/issue-fields-migration/ @labudis
-
-# Added via #codeowner from PR #1009
-/skills/publish-to-pages/ @AndreaGriffiths11
-
-# Added via #codeowner from PR #1049
-/skills/codeql/ @VeVarunSharma
-/skills/dependabot/ @VeVarunSharma
-/skills/secret-scanning/ @VeVarunSharma
-
-# Added via #codeowner from PR #1118
-/agents/github-actions-node-upgrade.agent.md @joshjohanning
+# Copilot workshops
+/website/**/cli-for-beginners/ @github/awesome-copilot-workshop-reviewers
+/website/**/app-for-beginners/ @github/awesome-copilot-workshop-reviewers
+/website/**/copilot-workshops/ @github/awesome-copilot-workshop-reviewers
diff --git a/docs/maintainers/review-routing.md b/docs/maintainers/review-routing.md
index 7003bf251..f4ee50fca 100644
--- a/docs/maintainers/review-routing.md
+++ b/docs/maintainers/review-routing.md
@@ -13,12 +13,13 @@ The root [`CODEOWNERS`](../../CODEOWNERS) file assigns every path to a team, not
| `/plugins/` | `@github/awesome-copilot-plugin-reviewers` |
| `/agents/`, `/instructions/`, `/skills/`, `/hooks/`, `/workflows/` | `@github/awesome-copilot-content-reviewers` |
| `/.github/` (including GitHub Actions workflows), `/eng/` | `@github/awesome-copilot-core-maintainers` |
+| Copilot workshop content under `/website/` | `@github/awesome-copilot-workshop-reviewers` |
-GitHub applies the **last** matching rule, so the per-resource entries at the bottom of the file override the team defaults for their paths. Those entries are added through the `#codeowner` command (`.github/workflows/codeowner-update.md`), which only appends a block at the end of the file. The existing per-resource entries are kept as they are for now; removing them is planned as a separate cleanup. When you edit `CODEOWNERS` by hand:
+GitHub applies the **last** matching rule, so the workshop entries at the bottom of the file override the default team for their paths. When you edit `CODEOWNERS` by hand:
- Keep the `*` rule and the domain team block at the top of the file.
- Never add an individual user to the `*` rule.
-- Append new per-resource owners at the end of the file.
+- Add more-specific path owners after the broader rules they override.
## Reviewer pools (`.github/review-routing.yml`)
@@ -44,6 +45,7 @@ Current routes, in priority order:
| Intent label | Pool |
|---|---|
+| `workshops` | `workshops` |
| `canvas-extension` | `canvas` |
| `external-plugin`, `plugin` | `plugin` |
| `skills`, `agent`, `instructions`, `workflow`, `hooks` | `content` |
diff --git a/eng/review-routing.mjs b/eng/review-routing.mjs
index 6bdd8633a..417b79c66 100644
--- a/eng/review-routing.mjs
+++ b/eng/review-routing.mjs
@@ -23,6 +23,7 @@ export const INTENT_LABELS = Object.freeze([
"new-submission",
"plugin",
"skills",
+ "workshops",
"website-update",
"workflow",
]);
diff --git a/eng/review-routing.test.mjs b/eng/review-routing.test.mjs
index 65a723a08..7566205d5 100644
--- a/eng/review-routing.test.mjs
+++ b/eng/review-routing.test.mjs
@@ -46,9 +46,11 @@ function rawConfig(overrides = {}) {
canvas: { team: "github/canvas", reviewers: ["canvas1", "canvas2", "canvas3"], backup: ["canvasBackup"] },
plugin: { team: "github/plugin", reviewers: ["plugin1"], backup: [] },
content: { team: "github/content", reviewers: [], backup: [] },
+ workshops: { team: "github/workshops", reviewers: ["workshop1"], backup: [] },
automation: { team: "github/automation", reviewers: ["auto1"], backup: ["autoBackup"] },
},
routes: [
+ { label: "workshops", pool: "workshops" },
{ label: "workflow", pool: "automation" },
{ label: "hooks", pool: "automation" },
{ label: "canvas-extension", pool: "canvas" },
@@ -97,6 +99,7 @@ describe("configuration", () => {
assert.deepEqual(
loaded.routes.map((route) => [route.label, route.pool]),
[
+ ["workshops", "workshops"],
["canvas-extension", "canvas"],
["external-plugin", "plugin"],
["plugin", "plugin"],
@@ -108,7 +111,7 @@ describe("configuration", () => {
["website-update", "core-maintainers"],
]
);
- assert.deepEqual(Object.keys(loaded.pools).sort(), ["canvas", "content", "core-maintainers", "plugin"]);
+ assert.deepEqual(Object.keys(loaded.pools).sort(), ["canvas", "content", "core-maintainers", "plugin", "workshops"]);
assert.equal(loaded.defaultPool, "core-maintainers");
assert.equal(loaded.escalationPool, "core-maintainers");
});
@@ -165,6 +168,7 @@ describe("reviewer selection", () => {
assert.equal(selectPool(["skills", "plugin"], cfg), "plugin");
assert.equal(selectPool(["plugin", "canvas-extension"], cfg), "canvas");
assert.equal(selectPool(["canvas-extension", "workflow"], cfg), "automation");
+ assert.equal(selectPool(["website-update", "workshops"], cfg), "workshops");
assert.equal(selectPool(["website-update"], cfg), "core-maintainers");
});
diff --git a/eng/submission-gate.test.mjs b/eng/submission-gate.test.mjs
index 0b25c3918..58073622f 100644
--- a/eng/submission-gate.test.mjs
+++ b/eng/submission-gate.test.mjs
@@ -214,6 +214,7 @@ const routing = {
canvas: { team: "github/canvas", reviewers: ["canvasa"], backup: [] },
plugin: { team: "github/plugin", reviewers: [], backup: [] },
content: { reviewers: [] },
+ workshops: { team: "github/workshops", reviewers: ["workshopa"], backup: [] },
},
};
@@ -255,7 +256,11 @@ test("latest review state wins and changes requested blocks", () => {
});
test("medium tier requires a domain reviewer when the pool is staffed", () => {
- const permissions = new Map([["alice", "write"], ["canvasa", "write"]]);
+ const permissions = new Map([
+ ["alice", "write"],
+ ["canvasa", "write"],
+ ["workshopa", "write"],
+ ]);
const files = [file("extensions/x/extension.mjs", { status: "added" })];
const base = { tier: "medium", tiers, author: "author", permissions, routing, files };
assert.equal(evaluateApprovals({ ...base, reviews: [review("alice", "APPROVED")] }).satisfied, false);
@@ -270,6 +275,13 @@ test("medium tier requires a domain reviewer when the pool is staffed", () => {
assert.equal(unstaffed.satisfied, true, "falls back to any writer when the domain pool is empty");
assert.ok(unstaffed.notes.length > 0);
+ const workshop = evaluateApprovals({
+ ...base,
+ files: [file("website/src/content/docs/learning-hub/copilot-workshops/lesson.md", { status: "added" })],
+ reviews: [review("workshopa", "APPROVED")],
+ });
+ assert.equal(workshop.satisfied, true);
+
const noRouting = evaluateApprovals({ ...base, routing: null, reviews: [review("alice", "APPROVED")] });
assert.equal(noRouting.satisfied, true);
});