microsoft/gctoolkit

Public

mirrored fromhttps://github.com/microsoft/gctoolkitAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
restrict-relevance-check-roles

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

.github/workflows/relevance-check.lock.yml

1187lines · modecode

1#
2# ___ _ _
3# / _ \ | | (_)
4# | |_| | __ _ ___ _ __ | |_ _ ___
5# | _ |/ _` |/ _ \ '_ \| __| |/ __|
6# | | | | (_| | __/ | | | |_| | (__
7# \_| |_/\__, |\___|_| |_|\__|_|\___|
8# __/ |
9# _ _ |___/
10# | | | | / _| |
11# | | | | ___ _ __ _ __| |_| | _____ ____
12# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___|
13# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
14# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
15#
16# This file was automatically generated by gh-aw (v0.50.4). DO NOT EDIT.
17#
18# To update this file, edit the corresponding .md file and run:
19# gh aw compile
20# Not all edits will cause changes to this file.
21#
22# For more information: https://github.github.com/gh-aw/introduction/overview/
23#
24# Slash command to evaluate whether an issue or pull request is still relevant to the project
25#
26# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"b521aea4f3e295ac50ea3ceb02279672256fa9cb308d9b1846130e3464d97214","compiler_version":"v0.50.4"}
27
28name: "Relevance Check Agent"
29"on":
30 discussion:
31 types:
32 - created
33 - edited
34 discussion_comment:
35 types:
36 - created
37 - edited
38 issue_comment:
39 types:
40 - created
41 - edited
42 issues:
43 types:
44 - opened
45 - edited
46 - reopened
47 pull_request:
48 types:
49 - opened
50 - edited
51 - reopened
52 pull_request_review_comment:
53 types:
54 - created
55 - edited
56 # roles: # Roles processed as role check in pre-activation job
57 # - admin # Roles processed as role check in pre-activation job
58 # - maintainer # Roles processed as role check in pre-activation job
59 # - write # Roles processed as role check in pre-activation job
60
61permissions: {}
62
63concurrency:
64 group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number }}"
65
66run-name: "Relevance Check Agent"
67
68jobs:
69 activation:
70 needs: pre_activation
71 if: >
72 (needs.pre_activation.outputs.activated == 'true') && (((github.event_name == 'issues' || github.event_name == 'issue_comment' ||
73 github.event_name == 'pull_request' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' ||
74 github.event_name == 'discussion_comment') && ((github.event_name == 'issues') && ((startsWith(github.event.issue.body, '/relevance-check ')) ||
75 (github.event.issue.body == '/relevance-check')) || (github.event_name == 'issue_comment') && (((startsWith(github.event.comment.body, '/relevance-check ')) ||
76 (github.event.comment.body == '/relevance-check')) && (github.event.issue.pull_request == null)) || (github.event_name == 'issue_comment') &&
77 (((startsWith(github.event.comment.body, '/relevance-check ')) || (github.event.comment.body == '/relevance-check')) &&
78 (github.event.issue.pull_request != null)) || (github.event_name == 'pull_request_review_comment') &&
79 ((startsWith(github.event.comment.body, '/relevance-check ')) || (github.event.comment.body == '/relevance-check')) ||
80 (github.event_name == 'pull_request') && ((startsWith(github.event.pull_request.body, '/relevance-check ')) ||
81 (github.event.pull_request.body == '/relevance-check')) || (github.event_name == 'discussion') && ((startsWith(github.event.discussion.body, '/relevance-check ')) ||
82 (github.event.discussion.body == '/relevance-check')) || (github.event_name == 'discussion_comment') &&
83 ((startsWith(github.event.comment.body, '/relevance-check ')) || (github.event.comment.body == '/relevance-check')))) ||
84 (!(github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request' ||
85 github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment')))
86 runs-on: ubuntu-slim
87 permissions:
88 contents: read
89 discussions: write
90 issues: write
91 pull-requests: write
92 outputs:
93 body: ${{ steps.sanitized.outputs.body }}
94 comment_id: ""
95 comment_repo: ""
96 slash_command: ${{ needs.pre_activation.outputs.matched_command }}
97 text: ${{ steps.sanitized.outputs.text }}
98 title: ${{ steps.sanitized.outputs.title }}
99 steps:
100 - name: Setup Scripts
101 uses: github/gh-aw/actions/setup@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4
102 with:
103 destination: /opt/gh-aw/actions
104 - name: Validate context variables
105 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
106 with:
107 script: |
108 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
109 setupGlobals(core, github, context, exec, io);
110 const { main } = require('/opt/gh-aw/actions/validate_context_variables.cjs');
111 await main();
112 - name: Checkout .github and .agents folders
113 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
114 with:
115 sparse-checkout: |
116 .github
117 .agents
118 fetch-depth: 1
119 persist-credentials: false
120 - name: Check workflow file timestamps
121 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
122 env:
123 GH_AW_WORKFLOW_FILE: "relevance-check.lock.yml"
124 with:
125 script: |
126 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
127 setupGlobals(core, github, context, exec, io);
128 const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs');
129 await main();
130 - name: Compute current body text
131 id: sanitized
132 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
133 with:
134 script: |
135 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
136 setupGlobals(core, github, context, exec, io);
137 const { main } = require('/opt/gh-aw/actions/compute_text.cjs');
138 await main();
139 - name: Create prompt with built-in context
140 env:
141 GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
142 GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
143 GH_AW_GITHUB_ACTOR: ${{ github.actor }}
144 GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
145 GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
146 GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
147 GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
148 GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
149 GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
150 GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
151 GH_AW_IS_PR_COMMENT: ${{ github.event.issue.pull_request && 'true' || '' }}
152 GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
153 run: |
154 bash /opt/gh-aw/actions/create_prompt_first.sh
155 {
156 cat << 'GH_AW_PROMPT_EOF'
157 <system>
158 GH_AW_PROMPT_EOF
159 cat "/opt/gh-aw/prompts/xpia.md"
160 cat "/opt/gh-aw/prompts/temp_folder_prompt.md"
161 cat "/opt/gh-aw/prompts/markdown.md"
162 cat "/opt/gh-aw/prompts/safe_outputs_prompt.md"
163 cat << 'GH_AW_PROMPT_EOF'
164 <safe-output-tools>
165 Tools: add_comment, missing_tool, missing_data
166 </safe-output-tools>
167 <github-context>
168 The following GitHub context information is available for this workflow:
169 {{#if __GH_AW_GITHUB_ACTOR__ }}
170 - **actor**: __GH_AW_GITHUB_ACTOR__
171 {{/if}}
172 {{#if __GH_AW_GITHUB_REPOSITORY__ }}
173 - **repository**: __GH_AW_GITHUB_REPOSITORY__
174 {{/if}}
175 {{#if __GH_AW_GITHUB_WORKSPACE__ }}
176 - **workspace**: __GH_AW_GITHUB_WORKSPACE__
177 {{/if}}
178 {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }}
179 - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__
180 {{/if}}
181 {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }}
182 - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__
183 {{/if}}
184 {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }}
185 - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__
186 {{/if}}
187 {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }}
188 - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__
189 {{/if}}
190 {{#if __GH_AW_GITHUB_RUN_ID__ }}
191 - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__
192 {{/if}}
193 </github-context>
194
195 GH_AW_PROMPT_EOF
196 if [ "$GITHUB_EVENT_NAME" = "issue_comment" ] && [ -n "$GH_AW_IS_PR_COMMENT" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review_comment" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review" ]; then
197 cat "/opt/gh-aw/prompts/pr_context_prompt.md"
198 fi
199 cat << 'GH_AW_PROMPT_EOF'
200 </system>
201 GH_AW_PROMPT_EOF
202 cat << 'GH_AW_PROMPT_EOF'
203 {{#runtime-import .github/workflows/relevance-check.md}}
204 GH_AW_PROMPT_EOF
205 } > "$GH_AW_PROMPT"
206 - name: Interpolate variables and render templates
207 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
208 env:
209 GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
210 GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
211 GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
212 with:
213 script: |
214 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
215 setupGlobals(core, github, context, exec, io);
216 const { main } = require('/opt/gh-aw/actions/interpolate_prompt.cjs');
217 await main();
218 - name: Substitute placeholders
219 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
220 env:
221 GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
222 GH_AW_GITHUB_ACTOR: ${{ github.actor }}
223 GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
224 GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
225 GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
226 GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
227 GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
228 GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
229 GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
230 GH_AW_IS_PR_COMMENT: ${{ github.event.issue.pull_request && 'true' || '' }}
231 GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }}
232 GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: ${{ needs.pre_activation.outputs.matched_command }}
233 GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
234 with:
235 script: |
236 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
237 setupGlobals(core, github, context, exec, io);
238
239 const substitutePlaceholders = require('/opt/gh-aw/actions/substitute_placeholders.cjs');
240
241 // Call the substitution function
242 return await substitutePlaceholders({
243 file: process.env.GH_AW_PROMPT,
244 substitutions: {
245 GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,
246 GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID,
247 GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER,
248 GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER,
249 GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER,
250 GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,
251 GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,
252 GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,
253 GH_AW_IS_PR_COMMENT: process.env.GH_AW_IS_PR_COMMENT,
254 GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED,
255 GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND,
256 GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: process.env.GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT
257 }
258 });
259 - name: Validate prompt placeholders
260 env:
261 GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
262 run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh
263 - name: Print prompt
264 env:
265 GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
266 run: bash /opt/gh-aw/actions/print_prompt_summary.sh
267 - name: Upload prompt artifact
268 if: success()
269 uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
270 with:
271 name: prompt
272 path: /tmp/gh-aw/aw-prompts/prompt.txt
273 retention-days: 1
274
275 agent:
276 needs: activation
277 runs-on: ubuntu-latest
278 permissions:
279 contents: read
280 issues: read
281 pull-requests: read
282 env:
283 DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
284 GH_AW_ASSETS_ALLOWED_EXTS: ""
285 GH_AW_ASSETS_BRANCH: ""
286 GH_AW_ASSETS_MAX_SIZE_KB: 0
287 GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
288 GH_AW_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl
289 GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json
290 GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json
291 GH_AW_WORKFLOW_ID_SANITIZED: relevancecheck
292 outputs:
293 checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
294 detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}
295 detection_success: ${{ steps.detection_conclusion.outputs.success }}
296 has_patch: ${{ steps.collect_output.outputs.has_patch }}
297 model: ${{ steps.generate_aw_info.outputs.model }}
298 output: ${{ steps.collect_output.outputs.output }}
299 output_types: ${{ steps.collect_output.outputs.output_types }}
300 secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
301 steps:
302 - name: Setup Scripts
303 uses: github/gh-aw/actions/setup@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4
304 with:
305 destination: /opt/gh-aw/actions
306 - name: Checkout repository
307 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
308 with:
309 persist-credentials: false
310 - name: Create gh-aw temp directory
311 run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.sh
312 - name: Configure Git credentials
313 env:
314 REPO_NAME: ${{ github.repository }}
315 SERVER_URL: ${{ github.server_url }}
316 run: |
317 git config --global user.email "github-actions[bot]@users.noreply.github.com"
318 git config --global user.name "github-actions[bot]"
319 git config --global am.keepcr true
320 # Re-authenticate git with GitHub token
321 SERVER_URL_STRIPPED="${SERVER_URL#https://}"
322 git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
323 echo "Git configured with standard GitHub Actions identity"
324 - name: Checkout PR branch
325 id: checkout-pr
326 if: |
327 github.event.pull_request
328 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
329 env:
330 GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
331 with:
332 github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
333 script: |
334 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
335 setupGlobals(core, github, context, exec, io);
336 const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs');
337 await main();
338 - name: Generate agentic run info
339 id: generate_aw_info
340 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
341 with:
342 script: |
343 const fs = require('fs');
344
345 const awInfo = {
346 engine_id: "copilot",
347 engine_name: "GitHub Copilot CLI",
348 model: "claude-opus-4.6",
349 version: "",
350 agent_version: "0.0.417",
351 cli_version: "v0.50.4",
352 workflow_name: "Relevance Check Agent",
353 experimental: false,
354 supports_tools_allowlist: true,
355 run_id: context.runId,
356 run_number: context.runNumber,
357 run_attempt: process.env.GITHUB_RUN_ATTEMPT,
358 repository: context.repo.owner + '/' + context.repo.repo,
359 ref: context.ref,
360 sha: context.sha,
361 actor: context.actor,
362 event_name: context.eventName,
363 staged: false,
364 allowed_domains: ["defaults"],
365 firewall_enabled: true,
366 awf_version: "v0.23.0",
367 awmg_version: "v0.1.5",
368 steps: {
369 firewall: "squid"
370 },
371 created_at: new Date().toISOString()
372 };
373
374 // Write to /tmp/gh-aw directory to avoid inclusion in PR
375 const tmpPath = '/tmp/gh-aw/aw_info.json';
376 fs.writeFileSync(tmpPath, JSON.stringify(awInfo, null, 2));
377 console.log('Generated aw_info.json at:', tmpPath);
378 console.log(JSON.stringify(awInfo, null, 2));
379
380 // Set model as output for reuse in other steps/jobs
381 core.setOutput('model', awInfo.model);
382 - name: Validate COPILOT_GITHUB_TOKEN secret
383 id: validate-secret
384 run: /opt/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default
385 env:
386 COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
387 - name: Install GitHub Copilot CLI
388 run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.417
389 - name: Install awf binary
390 run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0
391 - name: Determine automatic lockdown mode for GitHub MCP Server
392 id: determine-automatic-lockdown
393 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
394 env:
395 GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
396 GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
397 with:
398 script: |
399 const determineAutomaticLockdown = require('/opt/gh-aw/actions/determine_automatic_lockdown.cjs');
400 await determineAutomaticLockdown(github, context, core);
401 - name: Download container images
402 run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.5 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine
403 - name: Write Safe Outputs Config
404 run: |
405 mkdir -p /opt/gh-aw/safeoutputs
406 mkdir -p /tmp/gh-aw/safeoutputs
407 mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
408 cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF'
409 {"add_comment":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}}
410 GH_AW_SAFE_OUTPUTS_CONFIG_EOF
411 cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF'
412 [
413 {
414 "description": "Add a comment to an existing GitHub issue, pull request, or discussion. Use this to provide feedback, answer questions, or add information to an existing conversation. For creating new items, use create_issue, create_discussion, or create_pull_request instead. IMPORTANT: Comments are subject to validation constraints enforced by the MCP server - maximum 65536 characters for the complete comment (including footer which is added automatically), 10 mentions (@username), and 50 links. Exceeding these limits will result in an immediate error with specific guidance. NOTE: By default, this tool requires discussions:write permission. If your GitHub App lacks Discussions permission, set 'discussions: false' in the workflow's safe-outputs.add-comment configuration to exclude this permission. CONSTRAINTS: Maximum 1 comment(s) can be added.",
415 "inputSchema": {
416 "additionalProperties": false,
417 "properties": {
418 "body": {
419 "description": "The comment text in Markdown format. This is the 'body' field - do not use 'comment_body' or other variations. Provide helpful, relevant information that adds value to the conversation. CONSTRAINTS: The complete comment (your body text + automatically added footer) must not exceed 65536 characters total. Maximum 10 mentions (@username), maximum 50 links (http/https URLs). A footer (~200-500 characters) is automatically appended with workflow attribution, so leave adequate space. If these limits are exceeded, the tool call will fail with a detailed error message indicating which constraint was violated.",
420 "type": "string"
421 },
422 "item_number": {
423 "description": "The issue, pull request, or discussion number to comment on. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123). If omitted, the tool auto-targets the issue, PR, or discussion that triggered this workflow. Auto-targeting only works for issue, pull_request, discussion, and comment event triggers — it does NOT work for schedule, workflow_dispatch, push, or workflow_run triggers. For those trigger types, always provide item_number explicitly, or the comment will be silently discarded.",
424 "type": "number"
425 }
426 },
427 "required": [
428 "body"
429 ],
430 "type": "object"
431 },
432 "name": "add_comment"
433 },
434 {
435 "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.",
436 "inputSchema": {
437 "additionalProperties": false,
438 "properties": {
439 "alternatives": {
440 "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
441 "type": "string"
442 },
443 "reason": {
444 "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).",
445 "type": "string"
446 },
447 "tool": {
448 "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.",
449 "type": "string"
450 }
451 },
452 "required": [
453 "reason"
454 ],
455 "type": "object"
456 },
457 "name": "missing_tool"
458 },
459 {
460 "description": "Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.",
461 "inputSchema": {
462 "additionalProperties": false,
463 "properties": {
464 "message": {
465 "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').",
466 "type": "string"
467 }
468 },
469 "required": [
470 "message"
471 ],
472 "type": "object"
473 },
474 "name": "noop"
475 },
476 {
477 "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.",
478 "inputSchema": {
479 "additionalProperties": false,
480 "properties": {
481 "alternatives": {
482 "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).",
483 "type": "string"
484 },
485 "context": {
486 "description": "Additional context about the missing data or where it should come from (max 256 characters).",
487 "type": "string"
488 },
489 "data_type": {
490 "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.",
491 "type": "string"
492 },
493 "reason": {
494 "description": "Explanation of why this data is needed to complete the task (max 256 characters).",
495 "type": "string"
496 }
497 },
498 "required": [],
499 "type": "object"
500 },
501 "name": "missing_data"
502 }
503 ]
504 GH_AW_SAFE_OUTPUTS_TOOLS_EOF
505 cat > /opt/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF'
506 {
507 "add_comment": {
508 "defaultMax": 1,
509 "fields": {
510 "body": {
511 "required": true,
512 "type": "string",
513 "sanitize": true,
514 "maxLength": 65000
515 },
516 "item_number": {
517 "issueOrPRNumber": true
518 },
519 "repo": {
520 "type": "string",
521 "maxLength": 256
522 }
523 }
524 },
525 "missing_data": {
526 "defaultMax": 20,
527 "fields": {
528 "alternatives": {
529 "type": "string",
530 "sanitize": true,
531 "maxLength": 256
532 },
533 "context": {
534 "type": "string",
535 "sanitize": true,
536 "maxLength": 256
537 },
538 "data_type": {
539 "type": "string",
540 "sanitize": true,
541 "maxLength": 128
542 },
543 "reason": {
544 "type": "string",
545 "sanitize": true,
546 "maxLength": 256
547 }
548 }
549 },
550 "missing_tool": {
551 "defaultMax": 20,
552 "fields": {
553 "alternatives": {
554 "type": "string",
555 "sanitize": true,
556 "maxLength": 512
557 },
558 "reason": {
559 "required": true,
560 "type": "string",
561 "sanitize": true,
562 "maxLength": 256
563 },
564 "tool": {
565 "type": "string",
566 "sanitize": true,
567 "maxLength": 128
568 }
569 }
570 },
571 "noop": {
572 "defaultMax": 1,
573 "fields": {
574 "message": {
575 "required": true,
576 "type": "string",
577 "sanitize": true,
578 "maxLength": 65000
579 }
580 }
581 }
582 }
583 GH_AW_SAFE_OUTPUTS_VALIDATION_EOF
584 - name: Generate Safe Outputs MCP Server Config
585 id: safe-outputs-config
586 run: |
587 # Generate a secure random API key (360 bits of entropy, 40+ chars)
588 # Mask immediately to prevent timing vulnerabilities
589 API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
590 echo "::add-mask::${API_KEY}"
591
592 PORT=3001
593
594 # Set outputs for next steps
595 {
596 echo "safe_outputs_api_key=${API_KEY}"
597 echo "safe_outputs_port=${PORT}"
598 } >> "$GITHUB_OUTPUT"
599
600 echo "Safe Outputs MCP server will run on port ${PORT}"
601
602 - name: Start Safe Outputs MCP HTTP Server
603 id: safe-outputs-start
604 env:
605 DEBUG: '*'
606 GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }}
607 GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }}
608 GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json
609 GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json
610 GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
611 run: |
612 # Environment variables are set above to prevent template injection
613 export DEBUG
614 export GH_AW_SAFE_OUTPUTS_PORT
615 export GH_AW_SAFE_OUTPUTS_API_KEY
616 export GH_AW_SAFE_OUTPUTS_TOOLS_PATH
617 export GH_AW_SAFE_OUTPUTS_CONFIG_PATH
618 export GH_AW_MCP_LOG_DIR
619
620 bash /opt/gh-aw/actions/start_safe_outputs_server.sh
621
622 - name: Start MCP Gateway
623 id: start-mcp-gateway
624 env:
625 GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
626 GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }}
627 GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }}
628 GITHUB_MCP_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }}
629 GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
630 run: |
631 set -eo pipefail
632 mkdir -p /tmp/gh-aw/mcp-config
633
634 # Export gateway environment variables for MCP config and gateway script
635 export MCP_GATEWAY_PORT="80"
636 export MCP_GATEWAY_DOMAIN="host.docker.internal"
637 MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
638 echo "::add-mask::${MCP_GATEWAY_API_KEY}"
639 export MCP_GATEWAY_API_KEY
640 export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads"
641 mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}"
642 export DEBUG="*"
643
644 export GH_AW_ENGINE="copilot"
645 export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.5'
646
647 mkdir -p /home/runner/.copilot
648 cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh
649 {
650 "mcpServers": {
651 "github": {
652 "type": "stdio",
653 "container": "ghcr.io/github/github-mcp-server:v0.31.0",
654 "env": {
655 "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN",
656 "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
657 "GITHUB_READ_ONLY": "1",
658 "GITHUB_TOOLSETS": "context,repos,issues,pull_requests"
659 }
660 },
661 "safeoutputs": {
662 "type": "http",
663 "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT",
664 "headers": {
665 "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}"
666 }
667 }
668 },
669 "gateway": {
670 "port": $MCP_GATEWAY_PORT,
671 "domain": "${MCP_GATEWAY_DOMAIN}",
672 "apiKey": "${MCP_GATEWAY_API_KEY}",
673 "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
674 }
675 }
676 GH_AW_MCP_CONFIG_EOF
677 - name: Generate workflow overview
678 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
679 with:
680 script: |
681 const { generateWorkflowOverview } = require('/opt/gh-aw/actions/generate_workflow_overview.cjs');
682 await generateWorkflowOverview(core);
683 - name: Download prompt artifact
684 uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
685 with:
686 name: prompt
687 path: /tmp/gh-aw/aw-prompts
688 - name: Clean git credentials
689 run: bash /opt/gh-aw/actions/clean_git_credentials.sh
690 - name: Execute GitHub Copilot CLI
691 id: agentic_execution
692 # Copilot CLI tool arguments (sorted):
693 timeout-minutes: 20
694 run: |
695 set -o pipefail
696 # shellcheck disable=SC1003
697 sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \
698 -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
699 env:
700 COPILOT_AGENT_RUNNER_TYPE: STANDALONE
701 COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
702 COPILOT_MODEL: claude-opus-4.6
703 GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
704 GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
705 GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
706 GITHUB_HEAD_REF: ${{ github.head_ref }}
707 GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
708 GITHUB_REF_NAME: ${{ github.ref_name }}
709 GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }}
710 GITHUB_WORKSPACE: ${{ github.workspace }}
711 XDG_CONFIG_HOME: /home/runner
712 - name: Configure Git credentials
713 env:
714 REPO_NAME: ${{ github.repository }}
715 SERVER_URL: ${{ github.server_url }}
716 run: |
717 git config --global user.email "github-actions[bot]@users.noreply.github.com"
718 git config --global user.name "github-actions[bot]"
719 git config --global am.keepcr true
720 # Re-authenticate git with GitHub token
721 SERVER_URL_STRIPPED="${SERVER_URL#https://}"
722 git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
723 echo "Git configured with standard GitHub Actions identity"
724 - name: Copy Copilot session state files to logs
725 if: always()
726 continue-on-error: true
727 run: |
728 # Copy Copilot session state files to logs folder for artifact collection
729 # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them
730 SESSION_STATE_DIR="$HOME/.copilot/session-state"
731 LOGS_DIR="/tmp/gh-aw/sandbox/agent/logs"
732
733 if [ -d "$SESSION_STATE_DIR" ]; then
734 echo "Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR"
735 mkdir -p "$LOGS_DIR"
736 cp -v "$SESSION_STATE_DIR"/*.jsonl "$LOGS_DIR/" 2>/dev/null || true
737 echo "Session state files copied successfully"
738 else
739 echo "No session-state directory found at $SESSION_STATE_DIR"
740 fi
741 - name: Stop MCP Gateway
742 if: always()
743 continue-on-error: true
744 env:
745 MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
746 MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }}
747 GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}
748 run: |
749 bash /opt/gh-aw/actions/stop_mcp_gateway.sh "$GATEWAY_PID"
750 - name: Redact secrets in logs
751 if: always()
752 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
753 with:
754 script: |
755 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
756 setupGlobals(core, github, context, exec, io);
757 const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs');
758 await main();
759 env:
760 GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
761 SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
762 SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
763 SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
764 SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
765 - name: Upload Safe Outputs
766 if: always()
767 uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
768 with:
769 name: safe-output
770 path: ${{ env.GH_AW_SAFE_OUTPUTS }}
771 if-no-files-found: warn
772 - name: Ingest agent output
773 id: collect_output
774 if: always()
775 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
776 env:
777 GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
778 GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com"
779 GITHUB_SERVER_URL: ${{ github.server_url }}
780 GITHUB_API_URL: ${{ github.api_url }}
781 GH_AW_COMMAND: relevance-check
782 with:
783 script: |
784 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
785 setupGlobals(core, github, context, exec, io);
786 const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs');
787 await main();
788 - name: Upload sanitized agent output
789 if: always() && env.GH_AW_AGENT_OUTPUT
790 uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
791 with:
792 name: agent-output
793 path: ${{ env.GH_AW_AGENT_OUTPUT }}
794 if-no-files-found: warn
795 - name: Upload engine output files
796 uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
797 with:
798 name: agent_outputs
799 path: |
800 /tmp/gh-aw/sandbox/agent/logs/
801 /tmp/gh-aw/redacted-urls.log
802 if-no-files-found: ignore
803 - name: Parse agent logs for step summary
804 if: always()
805 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
806 env:
807 GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/
808 with:
809 script: |
810 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
811 setupGlobals(core, github, context, exec, io);
812 const { main } = require('/opt/gh-aw/actions/parse_copilot_log.cjs');
813 await main();
814 - name: Parse MCP Gateway logs for step summary
815 if: always()
816 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
817 with:
818 script: |
819 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
820 setupGlobals(core, github, context, exec, io);
821 const { main } = require('/opt/gh-aw/actions/parse_mcp_gateway_log.cjs');
822 await main();
823 - name: Print firewall logs
824 if: always()
825 continue-on-error: true
826 env:
827 AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs
828 run: |
829 # Fix permissions on firewall logs so they can be uploaded as artifacts
830 # AWF runs with sudo, creating files owned by root
831 sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true
832 # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step)
833 if command -v awf &> /dev/null; then
834 awf logs summary | tee -a "$GITHUB_STEP_SUMMARY"
835 else
836 echo 'AWF binary not installed, skipping firewall log summary'
837 fi
838 - name: Upload agent artifacts
839 if: always()
840 continue-on-error: true
841 uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
842 with:
843 name: agent-artifacts
844 path: |
845 /tmp/gh-aw/aw-prompts/prompt.txt
846 /tmp/gh-aw/aw_info.json
847 /tmp/gh-aw/mcp-logs/
848 /tmp/gh-aw/sandbox/firewall/logs/
849 /tmp/gh-aw/agent-stdio.log
850 /tmp/gh-aw/agent/
851 if-no-files-found: ignore
852 # --- Threat Detection (inline) ---
853 - name: Check if detection needed
854 id: detection_guard
855 if: always()
856 env:
857 OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }}
858 HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}
859 run: |
860 if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then
861 echo "run_detection=true" >> "$GITHUB_OUTPUT"
862 echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH"
863 else
864 echo "run_detection=false" >> "$GITHUB_OUTPUT"
865 echo "Detection skipped: no agent outputs or patches to analyze"
866 fi
867 - name: Clear MCP configuration for detection
868 if: always() && steps.detection_guard.outputs.run_detection == 'true'
869 run: |
870 rm -f /tmp/gh-aw/mcp-config/mcp-servers.json
871 rm -f /home/runner/.copilot/mcp-config.json
872 rm -f "$GITHUB_WORKSPACE/.gemini/settings.json"
873 - name: Prepare threat detection files
874 if: always() && steps.detection_guard.outputs.run_detection == 'true'
875 run: |
876 mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
877 cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
878 cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
879 for f in /tmp/gh-aw/aw-*.patch; do
880 [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
881 done
882 echo "Prepared threat detection files:"
883 ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true
884 - name: Setup threat detection
885 if: always() && steps.detection_guard.outputs.run_detection == 'true'
886 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
887 env:
888 WORKFLOW_NAME: "Relevance Check Agent"
889 WORKFLOW_DESCRIPTION: "Slash command to evaluate whether an issue or pull request is still relevant to the project"
890 HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}
891 with:
892 script: |
893 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
894 setupGlobals(core, github, context, exec, io);
895 const { main } = require('/opt/gh-aw/actions/setup_threat_detection.cjs');
896 await main();
897 - name: Ensure threat-detection directory and log
898 if: always() && steps.detection_guard.outputs.run_detection == 'true'
899 run: |
900 mkdir -p /tmp/gh-aw/threat-detection
901 touch /tmp/gh-aw/threat-detection/detection.log
902 - name: Execute GitHub Copilot CLI
903 if: always() && steps.detection_guard.outputs.run_detection == 'true'
904 id: detection_agentic_execution
905 # Copilot CLI tool arguments (sorted):
906 # --allow-tool shell(cat)
907 # --allow-tool shell(grep)
908 # --allow-tool shell(head)
909 # --allow-tool shell(jq)
910 # --allow-tool shell(ls)
911 # --allow-tool shell(tail)
912 # --allow-tool shell(wc)
913 timeout-minutes: 20
914 run: |
915 set -o pipefail
916 # shellcheck disable=SC1003
917 sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \
918 -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
919 env:
920 COPILOT_AGENT_RUNNER_TYPE: STANDALONE
921 COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
922 COPILOT_MODEL: claude-opus-4.6
923 GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
924 GITHUB_HEAD_REF: ${{ github.head_ref }}
925 GITHUB_REF_NAME: ${{ github.ref_name }}
926 GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }}
927 GITHUB_WORKSPACE: ${{ github.workspace }}
928 XDG_CONFIG_HOME: /home/runner
929 - name: Parse threat detection results
930 id: parse_detection_results
931 if: always() && steps.detection_guard.outputs.run_detection == 'true'
932 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
933 with:
934 script: |
935 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
936 setupGlobals(core, github, context, exec, io);
937 const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs');
938 await main();
939 - name: Upload threat detection log
940 if: always() && steps.detection_guard.outputs.run_detection == 'true'
941 uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
942 with:
943 name: threat-detection.log
944 path: /tmp/gh-aw/threat-detection/detection.log
945 if-no-files-found: ignore
946 - name: Set detection conclusion
947 id: detection_conclusion
948 if: always()
949 env:
950 RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}
951 DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }}
952 run: |
953 if [[ "$RUN_DETECTION" != "true" ]]; then
954 echo "conclusion=skipped" >> "$GITHUB_OUTPUT"
955 echo "success=true" >> "$GITHUB_OUTPUT"
956 echo "Detection was not needed, marking as skipped"
957 elif [[ "$DETECTION_SUCCESS" == "true" ]]; then
958 echo "conclusion=success" >> "$GITHUB_OUTPUT"
959 echo "success=true" >> "$GITHUB_OUTPUT"
960 echo "Detection passed successfully"
961 else
962 echo "conclusion=failure" >> "$GITHUB_OUTPUT"
963 echo "success=false" >> "$GITHUB_OUTPUT"
964 echo "Detection found issues"
965 fi
966
967 conclusion:
968 needs:
969 - activation
970 - agent
971 - safe_outputs
972 if: (always()) && (needs.agent.result != 'skipped')
973 runs-on: ubuntu-slim
974 permissions:
975 contents: read
976 discussions: write
977 issues: write
978 pull-requests: write
979 outputs:
980 noop_message: ${{ steps.noop.outputs.noop_message }}
981 tools_reported: ${{ steps.missing_tool.outputs.tools_reported }}
982 total_count: ${{ steps.missing_tool.outputs.total_count }}
983 steps:
984 - name: Setup Scripts
985 uses: github/gh-aw/actions/setup@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4
986 with:
987 destination: /opt/gh-aw/actions
988 - name: Download agent output artifact
989 continue-on-error: true
990 uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
991 with:
992 name: agent-output
993 path: /tmp/gh-aw/safeoutputs/
994 - name: Setup agent output environment variable
995 run: |
996 mkdir -p /tmp/gh-aw/safeoutputs/
997 find "/tmp/gh-aw/safeoutputs/" -type f -print
998 echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
999 - name: Process No-Op Messages
1000 id: noop
1001 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
1002 env:
1003 GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
1004 GH_AW_NOOP_MAX: "1"
1005 GH_AW_WORKFLOW_NAME: "Relevance Check Agent"
1006 with:
1007 github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1008 script: |
1009 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
1010 setupGlobals(core, github, context, exec, io);
1011 const { main } = require('/opt/gh-aw/actions/noop.cjs');
1012 await main();
1013 - name: Record Missing Tool
1014 id: missing_tool
1015 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
1016 env:
1017 GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
1018 GH_AW_WORKFLOW_NAME: "Relevance Check Agent"
1019 with:
1020 github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1021 script: |
1022 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
1023 setupGlobals(core, github, context, exec, io);
1024 const { main } = require('/opt/gh-aw/actions/missing_tool.cjs');
1025 await main();
1026 - name: Handle Agent Failure
1027 id: handle_agent_failure
1028 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
1029 env:
1030 GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
1031 GH_AW_WORKFLOW_NAME: "Relevance Check Agent"
1032 GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
1033 GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
1034 GH_AW_WORKFLOW_ID: "relevance-check"
1035 GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.agent.outputs.secret_verification_result }}
1036 GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
1037 GH_AW_GROUP_REPORTS: "false"
1038 with:
1039 github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1040 script: |
1041 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
1042 setupGlobals(core, github, context, exec, io);
1043 const { main } = require('/opt/gh-aw/actions/handle_agent_failure.cjs');
1044 await main();
1045 - name: Handle No-Op Message
1046 id: handle_noop_message
1047 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
1048 env:
1049 GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
1050 GH_AW_WORKFLOW_NAME: "Relevance Check Agent"
1051 GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
1052 GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
1053 GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }}
1054 GH_AW_NOOP_REPORT_AS_ISSUE: "true"
1055 with:
1056 github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1057 script: |
1058 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
1059 setupGlobals(core, github, context, exec, io);
1060 const { main } = require('/opt/gh-aw/actions/handle_noop_message.cjs');
1061 await main();
1062
1063 pre_activation:
1064 if: >
1065 ((github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request' ||
1066 github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment') &&
1067 ((github.event_name == 'issues') && ((startsWith(github.event.issue.body, '/relevance-check ')) || (github.event.issue.body == '/relevance-check')) ||
1068 (github.event_name == 'issue_comment') && (((startsWith(github.event.comment.body, '/relevance-check ')) ||
1069 (github.event.comment.body == '/relevance-check')) && (github.event.issue.pull_request == null)) || (github.event_name == 'issue_comment') &&
1070 (((startsWith(github.event.comment.body, '/relevance-check ')) || (github.event.comment.body == '/relevance-check')) &&
1071 (github.event.issue.pull_request != null)) || (github.event_name == 'pull_request_review_comment') &&
1072 ((startsWith(github.event.comment.body, '/relevance-check ')) || (github.event.comment.body == '/relevance-check')) ||
1073 (github.event_name == 'pull_request') && ((startsWith(github.event.pull_request.body, '/relevance-check ')) ||
1074 (github.event.pull_request.body == '/relevance-check')) || (github.event_name == 'discussion') && ((startsWith(github.event.discussion.body, '/relevance-check ')) ||
1075 (github.event.discussion.body == '/relevance-check')) || (github.event_name == 'discussion_comment') &&
1076 ((startsWith(github.event.comment.body, '/relevance-check ')) || (github.event.comment.body == '/relevance-check')))) ||
1077 (!(github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request' ||
1078 github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment'))
1079 runs-on: ubuntu-slim
1080 permissions:
1081 discussions: write
1082 issues: write
1083 pull-requests: write
1084 outputs:
1085 activated: ${{ (steps.check_membership.outputs.is_team_member == 'true') && (steps.check_command_position.outputs.command_position_ok == 'true') }}
1086 matched_command: ${{ steps.check_command_position.outputs.matched_command }}
1087 steps:
1088 - name: Setup Scripts
1089 uses: github/gh-aw/actions/setup@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4
1090 with:
1091 destination: /opt/gh-aw/actions
1092 - name: Add eyes reaction for immediate feedback
1093 id: react
1094 if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id)
1095 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
1096 env:
1097 GH_AW_REACTION: "eyes"
1098 with:
1099 github-token: ${{ secrets.GITHUB_TOKEN }}
1100 script: |
1101 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
1102 setupGlobals(core, github, context, exec, io);
1103 const { main } = require('/opt/gh-aw/actions/add_reaction.cjs');
1104 await main();
1105 - name: Check team membership for command workflow
1106 id: check_membership
1107 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
1108 env:
1109 GH_AW_REQUIRED_ROLES: admin,maintainer,write
1110 with:
1111 github-token: ${{ secrets.GITHUB_TOKEN }}
1112 script: |
1113 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
1114 setupGlobals(core, github, context, exec, io);
1115 const { main } = require('/opt/gh-aw/actions/check_membership.cjs');
1116 await main();
1117 - name: Check command position
1118 id: check_command_position
1119 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
1120 env:
1121 GH_AW_COMMANDS: "[\"relevance-check\"]"
1122 with:
1123 script: |
1124 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
1125 setupGlobals(core, github, context, exec, io);
1126 const { main } = require('/opt/gh-aw/actions/check_command_position.cjs');
1127 await main();
1128
1129 safe_outputs:
1130 needs: agent
1131 if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_success == 'true')
1132 runs-on: ubuntu-slim
1133 permissions:
1134 contents: read
1135 discussions: write
1136 issues: write
1137 pull-requests: write
1138 timeout-minutes: 15
1139 env:
1140 GH_AW_ENGINE_ID: "copilot"
1141 GH_AW_ENGINE_MODEL: "claude-opus-4.6"
1142 GH_AW_WORKFLOW_ID: "relevance-check"
1143 GH_AW_WORKFLOW_NAME: "Relevance Check Agent"
1144 outputs:
1145 code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
1146 code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
1147 create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}
1148 create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}
1149 process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}
1150 process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }}
1151 steps:
1152 - name: Setup Scripts
1153 uses: github/gh-aw/actions/setup@90ebf8057e8e005103b8d123732d2c64c30e9b27 # v0.50.4
1154 with:
1155 destination: /opt/gh-aw/actions
1156 - name: Download agent output artifact
1157 continue-on-error: true
1158 uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
1159 with:
1160 name: agent-output
1161 path: /tmp/gh-aw/safeoutputs/
1162 - name: Setup agent output environment variable
1163 run: |
1164 mkdir -p /tmp/gh-aw/safeoutputs/
1165 find "/tmp/gh-aw/safeoutputs/" -type f -print
1166 echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV"
1167 - name: Process Safe Outputs
1168 id: process_safe_outputs
1169 uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
1170 env:
1171 GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
1172 GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"missing_data\":{},\"missing_tool\":{}}"
1173 with:
1174 github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1175 script: |
1176 const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
1177 setupGlobals(core, github, context, exec, io);
1178 const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs');
1179 await main();
1180 - name: Upload safe output items manifest
1181 if: always()
1182 uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
1183 with:
1184 name: safe-output-items
1185 path: /tmp/safe-output-items.jsonl
1186 if-no-files-found: warn
1187
1188