microsoft/gctoolkit

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
enable-agentic-workflows

Branches

Tags

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

Clone

HTTPS

Download ZIP

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

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