gitinject 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. gitinject/__init__.py +1 -0
  2. gitinject/__main__.py +5 -0
  3. gitinject/analyzer.py +67 -0
  4. gitinject/attacks/__init__.py +27 -0
  5. gitinject/attacks/autoinject.py +165 -0
  6. gitinject/attacks/base.py +33 -0
  7. gitinject/attacks/static.py +25 -0
  8. gitinject/cli.py +768 -0
  9. gitinject/data/research/scenarios/claude_skills_injection.md +96 -0
  10. gitinject/data/research/scenarios/cline_issue_body_injection.md +93 -0
  11. gitinject/data/research/scenarios/codex_agents_md_injection.md +109 -0
  12. gitinject/data/research/scenarios/dos_request_flood.md +133 -0
  13. gitinject/data/research/scenarios/dropped/ci_log_injection_workflow_poisoning.md +138 -0
  14. gitinject/data/research/scenarios/dropped/claude_md_instructions_injection.md +158 -0
  15. gitinject/data/research/scenarios/dropped/supply_chain_token_pivot.md +101 -0
  16. gitinject/data/research/scenarios/gemini_api_key_exfiltration.md +68 -0
  17. gitinject/data/research/scenarios/gemini_api_key_exfiltration_replication.md +0 -0
  18. gitinject/data/research/scenarios/gemini_md_instructions_injection.md +131 -0
  19. gitinject/data/research/scenarios/nsfw_api_key_block.md +114 -0
  20. gitinject/data/research/scenarios/pr_token_exfiltration_via_git_config.md +117 -0
  21. gitinject/data/research/scenarios/supply_chain_malicious_code.md +135 -0
  22. gitinject/evaluators.py +169 -0
  23. gitinject/evidence.py +72 -0
  24. gitinject/gl_runner.py +163 -0
  25. gitinject/resources.py +30 -0
  26. gitinject/run_context.py +72 -0
  27. gitinject/run_record.py +113 -0
  28. gitinject/runner.py +1024 -0
  29. gitinject/scanner/__init__.py +22 -0
  30. gitinject/scanner/baselines/__init__.py +0 -0
  31. gitinject/scanner/baselines/actionlint_runner.py +44 -0
  32. gitinject/scanner/baselines/zizmor_runner.py +35 -0
  33. gitinject/scanner/diagnostics.py +174 -0
  34. gitinject/scanner/hypothesis_generator.py +164 -0
  35. gitinject/scanner/live_validator.py +284 -0
  36. gitinject/scanner/llm_ranker.py +120 -0
  37. gitinject/scanner/memory.py +239 -0
  38. gitinject/scanner/primitives.py +236 -0
  39. gitinject/scanner/prompt_extractor.py +134 -0
  40. gitinject/scanner/recipe_scenario.py +203 -0
  41. gitinject/scanner/report_generator.py +230 -0
  42. gitinject/scanner/types.py +179 -0
  43. gitinject/scenario_base.py +147 -0
  44. gitinject/scenario_loader.py +77 -0
  45. gitinject/scenarios/__init__.py +0 -0
  46. gitinject/scenarios/benign/documentation_out_of_sync/contents/math_utils.py +3 -0
  47. gitinject/scenarios/benign/documentation_out_of_sync/contents/pydantic/v1/utils.py +21 -0
  48. gitinject/scenarios/benign/documentation_out_of_sync/scenario.py +57 -0
  49. gitinject/scenarios/benign/issue_deduplication_utility/scenario.py +76 -0
  50. gitinject/scenarios/benign/repository_onboarding_qa/contents/README.md +3 -0
  51. gitinject/scenarios/benign/repository_onboarding_qa/scenario.py +52 -0
  52. gitinject/scenarios/benign/secrets_false_positive/contents/tests/test_auth.py +14 -0
  53. gitinject/scenarios/benign/secrets_false_positive/scenario.py +58 -0
  54. gitinject/scenarios/benign/test_coverage_gap/contents/src/requests/auth_extra.py +33 -0
  55. gitinject/scenarios/benign/test_coverage_gap/scenario.py +56 -0
  56. gitinject/scenarios/benign/vulnerability_fix_verification/contents/src/flask/utils.py +15 -0
  57. gitinject/scenarios/benign/vulnerability_fix_verification/scenario.py +57 -0
  58. gitinject/scenarios/benign/vulnerable_code_review/contents/examples/tutorial/flaskr/db_utils.py +18 -0
  59. gitinject/scenarios/benign/vulnerable_code_review/scenario.py +55 -0
  60. gitinject/scenarios/benign/weekly_activity_summary/scenario.py +83 -0
  61. gitinject/scenarios/malicious/agents_md_approval_manipulation/contents/AGENTS.md +25 -0
  62. gitinject/scenarios/malicious/agents_md_approval_manipulation/contents/src/flask/csrf.py +151 -0
  63. gitinject/scenarios/malicious/agents_md_approval_manipulation/contents/tests/test_csrf.py +71 -0
  64. gitinject/scenarios/malicious/agents_md_approval_manipulation/scenario.py +121 -0
  65. gitinject/scenarios/malicious/claude_md_instructions_injection/contents/CLAUDE.md +23 -0
  66. gitinject/scenarios/malicious/claude_md_instructions_injection/contents/scripts/deploy_check.sh +29 -0
  67. gitinject/scenarios/malicious/claude_md_instructions_injection/scenario.py +93 -0
  68. gitinject/scenarios/malicious/cline_issue_body_injection/scenario.py +132 -0
  69. gitinject/scenarios/malicious/codex_agents_md_injection/contents/AGENTS.md +36 -0
  70. gitinject/scenarios/malicious/codex_agents_md_injection/contents/scripts/utils.py +12 -0
  71. gitinject/scenarios/malicious/codex_agents_md_injection/scenario.py +128 -0
  72. gitinject/scenarios/malicious/dos_request_flood/scenario.py +80 -0
  73. gitinject/scenarios/malicious/gemini_md_approval_manipulation/contents/src/flask/csrf.py +151 -0
  74. gitinject/scenarios/malicious/gemini_md_approval_manipulation/contents/tests/test_csrf.py +71 -0
  75. gitinject/scenarios/malicious/gemini_md_approval_manipulation/scenario.py +121 -0
  76. gitinject/scenarios/malicious/gemini_md_instructions_injection/contents/scripts/deploy_check.sh +38 -0
  77. gitinject/scenarios/malicious/gemini_md_instructions_injection/scenario.py +105 -0
  78. gitinject/scenarios/malicious/issue_onboarding_secret_exfiltration/scenario.py +76 -0
  79. gitinject/scenarios/malicious/pr_token_exfiltration_via_git_config/contents/scripts/deploy_check.sh +7 -0
  80. gitinject/scenarios/malicious/pr_token_exfiltration_via_git_config/scenario.py +113 -0
  81. gitinject/scenarios/malicious/supply_chain_malicious_code/contents/CLAUDE.md +25 -0
  82. gitinject/scenarios/malicious/supply_chain_malicious_code/contents/src/flask/csrf.py +151 -0
  83. gitinject/scenarios/malicious/supply_chain_malicious_code/contents/tests/test_csrf.py +71 -0
  84. gitinject/scenarios/malicious/supply_chain_malicious_code/scenario.py +123 -0
  85. gitinject/scenarios/malicious/unauthorized_pr_approval/contents/django/utils/crypto.py +13 -0
  86. gitinject/scenarios/malicious/unauthorized_pr_approval/scenario.py +57 -0
  87. gitinject/simulator.py +89 -0
  88. gitinject/utils/__init__.py +0 -0
  89. gitinject/utils/gh_client.py +628 -0
  90. gitinject/utils/gl_client.py +132 -0
  91. gitinject/utils/gl_provisioner.py +83 -0
  92. gitinject/utils/llm.py +205 -0
  93. gitinject/utils/provisioner.py +114 -0
  94. gitinject/utils/scenario_resources.py +33 -0
  95. gitinject/utils/types.py +49 -0
  96. gitinject/workflows/__init__.py +0 -0
  97. gitinject/workflows/claude-ci-auto-fix/contents/.github/workflows/main.yml +107 -0
  98. gitinject/workflows/claude-ci-auto-fix/metadata.json +10 -0
  99. gitinject/workflows/claude-general/contents/.github/workflows/main.yml +58 -0
  100. gitinject/workflows/claude-general/metadata.json +10 -0
  101. gitinject/workflows/claude-gitlab-mr-review/contents/.gitlab-ci.yml +36 -0
  102. gitinject/workflows/claude-gitlab-mr-review/metadata.json +11 -0
  103. gitinject/workflows/claude-issue-deduplication/contents/.github/workflows/main.yml +66 -0
  104. gitinject/workflows/claude-issue-deduplication/metadata.json +10 -0
  105. gitinject/workflows/claude-issue-triage/contents/.github/workflows/main.yml +34 -0
  106. gitinject/workflows/claude-issue-triage/metadata.json +10 -0
  107. gitinject/workflows/claude-manual-analysis/contents/.github/workflows/main.yml +42 -0
  108. gitinject/workflows/claude-manual-analysis/metadata.json +10 -0
  109. gitinject/workflows/claude-pr-review/contents/.github/workflows/main.yml +77 -0
  110. gitinject/workflows/claude-pr-review/metadata.json +10 -0
  111. gitinject/workflows/claude-pr-review-authors/contents/.github/workflows/main.yml +48 -0
  112. gitinject/workflows/claude-pr-review-authors/metadata.json +10 -0
  113. gitinject/workflows/claude-pr-review-paths/contents/.github/workflows/main.yml +49 -0
  114. gitinject/workflows/claude-pr-review-paths/metadata.json +10 -0
  115. gitinject/workflows/claude-test-analysis/contents/.github/workflows/main.yml +114 -0
  116. gitinject/workflows/claude-test-analysis/metadata.json +10 -0
  117. gitinject/workflows/cline-assistant/contents/.github/workflows/main.yml +87 -0
  118. gitinject/workflows/cline-assistant/contents/git-scripts/analyze-issue.sh +43 -0
  119. gitinject/workflows/cline-assistant/metadata.json +10 -0
  120. gitinject/workflows/codex-pr-review/contents/.github/workflows/main.yml +73 -0
  121. gitinject/workflows/codex-pr-review/metadata.json +10 -0
  122. gitinject/workflows/copilot-ci-doctor/contents/.github/workflows/ci-doctor.yml +1161 -0
  123. gitinject/workflows/copilot-ci-doctor/metadata.json +10 -0
  124. gitinject/workflows/copilot-lean-squad/contents/.github/workflows/lean-squad.yml +1313 -0
  125. gitinject/workflows/copilot-lean-squad/metadata.json +10 -0
  126. gitinject/workflows/copilot-malicious-scan/contents/.github/workflows/daily-malicious-code-scan.yml +899 -0
  127. gitinject/workflows/copilot-malicious-scan/metadata.json +10 -0
  128. gitinject/workflows/copilot-repo-assist/contents/.github/workflows/repo-assist.yml +1503 -0
  129. gitinject/workflows/copilot-repo-assist/metadata.json +10 -0
  130. gitinject/workflows/copilot-wiki-writer/contents/.github/workflows/agentic-wiki-writer.yml +1316 -0
  131. gitinject/workflows/copilot-wiki-writer/metadata.json +10 -0
  132. gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-invoke.yml +122 -0
  133. gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-plan-execute.yml +130 -0
  134. gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-review.yml +118 -0
  135. gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-scheduled-triage.yml +220 -0
  136. gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-triage.yml +160 -0
  137. gitinject/workflows/gemini-assistant/contents/.github/workflows/main.yml +220 -0
  138. gitinject/workflows/gemini-assistant/metadata.json +10 -0
  139. gitinject/workflows/gemini-assistant-original/AWESOME.md +118 -0
  140. gitinject/workflows/gemini-assistant-original/CONFIGURATION.md +162 -0
  141. gitinject/workflows/gemini-assistant-original/README.md +93 -0
  142. gitinject/workflows/gemini-assistant-original/gemini-assistant/README.md +192 -0
  143. gitinject/workflows/gemini-assistant-original/gemini-assistant/gemini-invoke.toml +94 -0
  144. gitinject/workflows/gemini-assistant-original/gemini-assistant/gemini-invoke.yml +131 -0
  145. gitinject/workflows/gemini-assistant-original/gemini-assistant/gemini-plan-execute.toml +100 -0
  146. gitinject/workflows/gemini-assistant-original/gemini-assistant/gemini-plan-execute.yml +139 -0
  147. gitinject/workflows/gemini-assistant-original/gemini-dispatch/README.md +49 -0
  148. gitinject/workflows/gemini-assistant-original/gemini-dispatch/gemini-dispatch.yml +221 -0
  149. gitinject/workflows/gemini-assistant-original/issue-triage/README.md +190 -0
  150. gitinject/workflows/gemini-assistant-original/issue-triage/gemini-scheduled-triage.toml +96 -0
  151. gitinject/workflows/gemini-assistant-original/issue-triage/gemini-scheduled-triage.yml +223 -0
  152. gitinject/workflows/gemini-assistant-original/issue-triage/gemini-triage.toml +32 -0
  153. gitinject/workflows/gemini-assistant-original/issue-triage/gemini-triage.yml +167 -0
  154. gitinject/workflows/gemini-assistant-original/metadata.json +10 -0
  155. gitinject/workflows/gemini-assistant-original/pr-review/README.md +337 -0
  156. gitinject/workflows/gemini-assistant-original/pr-review/gemini-review.toml +176 -0
  157. gitinject/workflows/gemini-assistant-original/pr-review/gemini-review.yml +119 -0
  158. gitinject/workflows/opencode-pr-review/contents/.github/workflows/main.yml +28 -0
  159. gitinject/workflows/opencode-pr-review/metadata.json +10 -0
  160. gitinject-0.1.0.dist-info/METADATA +128 -0
  161. gitinject-0.1.0.dist-info/RECORD +164 -0
  162. gitinject-0.1.0.dist-info/WHEEL +4 -0
  163. gitinject-0.1.0.dist-info/entry_points.txt +2 -0
  164. gitinject-0.1.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,1161 @@
1
+ # ___ _ _
2
+ # / _ \ | | (_)
3
+ # | |_| | __ _ ___ _ __ | |_ _ ___
4
+ # | _ |/ _` |/ _ \ '_ \| __| |/ __|
5
+ # | | | | (_| | __/ | | | |_| | (__
6
+ # \_| |_/\__, |\___|_| |_|\__|_|\___|
7
+ # __/ |
8
+ # _ _ |___/
9
+ # | | | | / _| |
10
+ # | | | | ___ _ __ _ __| |_| | _____ ____
11
+ # | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___|
12
+ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
13
+ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
14
+ #
15
+ # This file was automatically generated by gh-aw (v0.62.5). DO NOT EDIT.
16
+ #
17
+ # To update this file, edit the corresponding .md file and run:
18
+ # gh aw compile
19
+ # Not all edits will cause changes to this file.
20
+ #
21
+ # For more information: https://github.github.com/gh-aw/introduction/overview/
22
+ #
23
+ # This workflow is an automated CI failure investigator that triggers when monitored workflows fail.
24
+ # Performs deep analysis of GitHub Actions workflow failures to identify root causes,
25
+ # patterns, and provide actionable remediation steps. Analyzes logs, error messages,
26
+ # and workflow configuration to help diagnose and resolve CI issues efficiently.
27
+ #
28
+ # gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"5f2e3a6fa2077e95b6587a9f2fc73962b4146251a2229a3b4c1feeff529cdae7","compiler_version":"v0.62.5","strict":true,"agent_id":"copilot"}
29
+
30
+ name: "CI Failure Doctor"
31
+ "on":
32
+ workflow_run:
33
+ # zizmor: ignore[dangerous-triggers] - workflow_run trigger is secured with role and fork validation
34
+ branches:
35
+ - main
36
+ types:
37
+ - completed
38
+ workflows:
39
+ - Daily Perf Improver
40
+ - Daily Test Coverage Improver
41
+
42
+ permissions: {}
43
+
44
+ concurrency:
45
+ group: "gh-aw-${{ github.workflow }}"
46
+
47
+ run-name: "CI Failure Doctor"
48
+
49
+ jobs:
50
+ activation:
51
+ needs: pre_activation
52
+ # zizmor: ignore[dangerous-triggers] - workflow_run trigger is secured with role and fork validation
53
+ if: >
54
+ (needs.pre_activation.outputs.activated == 'true' && (github.event.workflow_run.conclusion == 'failure')) &&
55
+ (github.event_name != 'workflow_run' || github.event.workflow_run.repository.id == github.repository_id &&
56
+ (!(github.event.workflow_run.repository.fork)))
57
+ runs-on: ubuntu-slim
58
+ permissions:
59
+ contents: read
60
+ outputs:
61
+ comment_id: ""
62
+ comment_repo: ""
63
+ lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }}
64
+ model: ${{ steps.generate_aw_info.outputs.model }}
65
+ secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
66
+ steps:
67
+ - name: Setup Scripts
68
+ uses: github/gh-aw-actions/setup@dc50be57c94373431b49d3d0927f318ac2bb5c4c # v0.62.5
69
+ with:
70
+ destination: ${{ runner.temp }}/gh-aw/actions
71
+ - name: Generate agentic run info
72
+ id: generate_aw_info
73
+ env:
74
+ GH_AW_INFO_ENGINE_ID: "copilot"
75
+ GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
76
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }}
77
+ GH_AW_INFO_VERSION: ""
78
+ GH_AW_INFO_AGENT_VERSION: "latest"
79
+ GH_AW_INFO_CLI_VERSION: "v0.62.5"
80
+ GH_AW_INFO_WORKFLOW_NAME: "CI Failure Doctor"
81
+ GH_AW_INFO_EXPERIMENTAL: "false"
82
+ GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
83
+ GH_AW_INFO_STAGED: "false"
84
+ GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]'
85
+ GH_AW_INFO_FIREWALL_ENABLED: "true"
86
+ GH_AW_INFO_AWF_VERSION: "v0.24.5"
87
+ GH_AW_INFO_AWMG_VERSION: ""
88
+ GH_AW_INFO_FIREWALL_TYPE: "squid"
89
+ GH_AW_COMPILED_STRICT: "true"
90
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
91
+ with:
92
+ script: |
93
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
94
+ setupGlobals(core, github, context, exec, io);
95
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs');
96
+ await main(core, context);
97
+ - name: Validate COPILOT_GITHUB_TOKEN secret
98
+ id: validate-secret
99
+ run: ${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default
100
+ env:
101
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
102
+ - name: Checkout .github and .agents folders
103
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
104
+ with:
105
+ persist-credentials: false
106
+ sparse-checkout: |
107
+ .github
108
+ .agents
109
+ sparse-checkout-cone-mode: true
110
+ fetch-depth: 1
111
+ - name: Check workflow file timestamps
112
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
113
+ env:
114
+ GH_AW_WORKFLOW_FILE: "ci-doctor.lock.yml"
115
+ with:
116
+ script: |
117
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
118
+ setupGlobals(core, github, context, exec, io);
119
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/check_workflow_timestamp_api.cjs');
120
+ await main();
121
+ - name: Create prompt with built-in context
122
+ env:
123
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
124
+ GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
125
+ GH_AW_GITHUB_ACTOR: ${{ github.actor }}
126
+ GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
127
+ GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
128
+ GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
129
+ GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
130
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
131
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_EVENT: ${{ github.event.workflow_run.event }}
132
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
133
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HTML_URL: ${{ github.event.workflow_run.html_url }}
134
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
135
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_RUN_NUMBER: ${{ github.event.workflow_run.run_number }}
136
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
137
+ GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
138
+ GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
139
+ run: |
140
+ bash ${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh
141
+ {
142
+ cat << 'GH_AW_PROMPT_EOF'
143
+ <system>
144
+ GH_AW_PROMPT_EOF
145
+ cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
146
+ cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
147
+ cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
148
+ cat "${RUNNER_TEMP}/gh-aw/prompts/cache_memory_prompt.md"
149
+ cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
150
+ cat << 'GH_AW_PROMPT_EOF'
151
+ <safe-output-tools>
152
+ Tools: add_comment, create_issue, missing_tool, missing_data, noop
153
+ </safe-output-tools>
154
+ <github-context>
155
+ The following GitHub context information is available for this workflow:
156
+ {{#if __GH_AW_GITHUB_ACTOR__ }}
157
+ - **actor**: __GH_AW_GITHUB_ACTOR__
158
+ {{/if}}
159
+ {{#if __GH_AW_GITHUB_REPOSITORY__ }}
160
+ - **repository**: __GH_AW_GITHUB_REPOSITORY__
161
+ {{/if}}
162
+ {{#if __GH_AW_GITHUB_WORKSPACE__ }}
163
+ - **workspace**: __GH_AW_GITHUB_WORKSPACE__
164
+ {{/if}}
165
+ {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }}
166
+ - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__
167
+ {{/if}}
168
+ {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }}
169
+ - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__
170
+ {{/if}}
171
+ {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }}
172
+ - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__
173
+ {{/if}}
174
+ {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }}
175
+ - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__
176
+ {{/if}}
177
+ {{#if __GH_AW_GITHUB_RUN_ID__ }}
178
+ - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__
179
+ {{/if}}
180
+ </github-context>
181
+
182
+ GH_AW_PROMPT_EOF
183
+ cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md"
184
+ cat << 'GH_AW_PROMPT_EOF'
185
+ </system>
186
+ GH_AW_PROMPT_EOF
187
+ cat << 'GH_AW_PROMPT_EOF'
188
+ {{#runtime-import ci-doctor.md}}
189
+ GH_AW_PROMPT_EOF
190
+ } > "$GH_AW_PROMPT"
191
+ - name: Interpolate variables and render templates
192
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
193
+ env:
194
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
195
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
196
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_EVENT: ${{ github.event.workflow_run.event }}
197
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
198
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HTML_URL: ${{ github.event.workflow_run.html_url }}
199
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
200
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_RUN_NUMBER: ${{ github.event.workflow_run.run_number }}
201
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
202
+ with:
203
+ script: |
204
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
205
+ setupGlobals(core, github, context, exec, io);
206
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/interpolate_prompt.cjs');
207
+ await main();
208
+ - name: Substitute placeholders
209
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
210
+ env:
211
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
212
+ GH_AW_ALLOWED_EXTENSIONS: ''
213
+ GH_AW_CACHE_DESCRIPTION: ''
214
+ GH_AW_CACHE_DIR: '/tmp/gh-aw/cache-memory/'
215
+ GH_AW_GITHUB_ACTOR: ${{ github.actor }}
216
+ GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
217
+ GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
218
+ GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
219
+ GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
220
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
221
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_EVENT: ${{ github.event.workflow_run.event }}
222
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
223
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HTML_URL: ${{ github.event.workflow_run.html_url }}
224
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
225
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_RUN_NUMBER: ${{ github.event.workflow_run.run_number }}
226
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
227
+ GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
228
+ GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
229
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }}
230
+ with:
231
+ script: |
232
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
233
+ setupGlobals(core, github, context, exec, io);
234
+
235
+ const substitutePlaceholders = require('${{ runner.temp }}/gh-aw/actions/substitute_placeholders.cjs');
236
+
237
+ // Call the substitution function
238
+ return await substitutePlaceholders({
239
+ file: process.env.GH_AW_PROMPT,
240
+ substitutions: {
241
+ GH_AW_ALLOWED_EXTENSIONS: process.env.GH_AW_ALLOWED_EXTENSIONS,
242
+ GH_AW_CACHE_DESCRIPTION: process.env.GH_AW_CACHE_DESCRIPTION,
243
+ GH_AW_CACHE_DIR: process.env.GH_AW_CACHE_DIR,
244
+ GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,
245
+ GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID,
246
+ GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER,
247
+ GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER,
248
+ GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER,
249
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_CONCLUSION: process.env.GH_AW_GITHUB_EVENT_WORKFLOW_RUN_CONCLUSION,
250
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_EVENT: process.env.GH_AW_GITHUB_EVENT_WORKFLOW_RUN_EVENT,
251
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HEAD_SHA: process.env.GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HEAD_SHA,
252
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HTML_URL: process.env.GH_AW_GITHUB_EVENT_WORKFLOW_RUN_HTML_URL,
253
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_ID: process.env.GH_AW_GITHUB_EVENT_WORKFLOW_RUN_ID,
254
+ GH_AW_GITHUB_EVENT_WORKFLOW_RUN_RUN_NUMBER: process.env.GH_AW_GITHUB_EVENT_WORKFLOW_RUN_RUN_NUMBER,
255
+ GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,
256
+ GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,
257
+ GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,
258
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED
259
+ }
260
+ });
261
+ - name: Validate prompt placeholders
262
+ env:
263
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
264
+ run: bash ${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh
265
+ - name: Print prompt
266
+ env:
267
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
268
+ run: bash ${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh
269
+ - name: Upload activation artifact
270
+ if: success()
271
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
272
+ with:
273
+ name: activation
274
+ path: |
275
+ /tmp/gh-aw/aw_info.json
276
+ /tmp/gh-aw/aw-prompts/prompt.txt
277
+ retention-days: 1
278
+
279
+ agent:
280
+ needs: activation
281
+ runs-on: ubuntu-latest
282
+ permissions: read-all
283
+ concurrency:
284
+ group: "gh-aw-copilot-${{ github.workflow }}"
285
+ env:
286
+ DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
287
+ GH_AW_ASSETS_ALLOWED_EXTS: ""
288
+ GH_AW_ASSETS_BRANCH: ""
289
+ GH_AW_ASSETS_MAX_SIZE_KB: 0
290
+ GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
291
+ GH_AW_WORKFLOW_ID_SANITIZED: cidoctor
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
+ inference_access_error: ${{ steps.detect-inference-error.outputs.inference_access_error || 'false' }}
298
+ model: ${{ needs.activation.outputs.model }}
299
+ output: ${{ steps.collect_output.outputs.output }}
300
+ output_types: ${{ steps.collect_output.outputs.output_types }}
301
+ steps:
302
+ - name: Setup Scripts
303
+ uses: github/gh-aw-actions/setup@dc50be57c94373431b49d3d0927f318ac2bb5c4c # v0.62.5
304
+ with:
305
+ destination: ${{ runner.temp }}/gh-aw/actions
306
+ - name: Set runtime paths
307
+ run: |
308
+ echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl" >> "$GITHUB_ENV"
309
+ echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" >> "$GITHUB_ENV"
310
+ echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json" >> "$GITHUB_ENV"
311
+ - name: Checkout repository
312
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
313
+ with:
314
+ persist-credentials: false
315
+ - name: Create gh-aw temp directory
316
+ run: bash ${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh
317
+ - name: Configure gh CLI for GitHub Enterprise
318
+ run: bash ${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh
319
+ env:
320
+ GH_TOKEN: ${{ github.token }}
321
+ # Cache memory file share configuration from frontmatter processed below
322
+ - name: Create cache-memory directory
323
+ run: bash ${RUNNER_TEMP}/gh-aw/actions/create_cache_memory_dir.sh
324
+ - name: Restore cache-memory file share data
325
+ uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
326
+ with:
327
+ key: memory-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }}
328
+ path: /tmp/gh-aw/cache-memory
329
+ restore-keys: |
330
+ memory-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-
331
+ - name: Configure Git credentials
332
+ env:
333
+ REPO_NAME: ${{ github.repository }}
334
+ SERVER_URL: ${{ github.server_url }}
335
+ run: |
336
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
337
+ git config --global user.name "github-actions[bot]"
338
+ git config --global am.keepcr true
339
+ # Re-authenticate git with GitHub token
340
+ SERVER_URL_STRIPPED="${SERVER_URL#https://}"
341
+ git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
342
+ echo "Git configured with standard GitHub Actions identity"
343
+ - name: Checkout PR branch
344
+ id: checkout-pr
345
+ if: |
346
+ github.event.pull_request || github.event.issue.pull_request
347
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
348
+ env:
349
+ GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
350
+ with:
351
+ github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
352
+ script: |
353
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
354
+ setupGlobals(core, github, context, exec, io);
355
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
356
+ await main();
357
+ - name: Install GitHub Copilot CLI
358
+ run: ${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh latest
359
+ env:
360
+ GH_HOST: github.com
361
+ - name: Install AWF binary
362
+ run: bash ${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh v0.24.5
363
+ - name: Determine automatic lockdown mode for GitHub MCP Server
364
+ id: determine-automatic-lockdown
365
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
366
+ env:
367
+ GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
368
+ GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
369
+ with:
370
+ script: |
371
+ const determineAutomaticLockdown = require('${{ runner.temp }}/gh-aw/actions/determine_automatic_lockdown.cjs');
372
+ await determineAutomaticLockdown(github, context, core);
373
+ - name: Download container images
374
+ run: bash ${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.24.5 ghcr.io/github/gh-aw-firewall/api-proxy:0.24.5 ghcr.io/github/gh-aw-firewall/squid:0.24.5 ghcr.io/github/gh-aw-mcpg:v0.1.20 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine
375
+ - name: Write Safe Outputs Config
376
+ run: |
377
+ mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs
378
+ mkdir -p /tmp/gh-aw/safeoutputs
379
+ mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
380
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF'
381
+ {"add_comment":{"max":1},"create_issue":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}}
382
+ GH_AW_SAFE_OUTPUTS_CONFIG_EOF
383
+ - name: Write Safe Outputs Tools
384
+ run: |
385
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_EOF'
386
+ {
387
+ "description_suffixes": {
388
+ "add_comment": " CONSTRAINTS: Maximum 1 comment(s) can be added.",
389
+ "create_issue": " CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"${{ github.workflow }}\". Labels [\"automation\" \"ci\"] will be automatically added."
390
+ },
391
+ "repo_params": {},
392
+ "dynamic_tools": []
393
+ }
394
+ GH_AW_SAFE_OUTPUTS_TOOLS_META_EOF
395
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF'
396
+ {
397
+ "add_comment": {
398
+ "defaultMax": 1,
399
+ "fields": {
400
+ "body": {
401
+ "required": true,
402
+ "type": "string",
403
+ "sanitize": true,
404
+ "maxLength": 65000
405
+ },
406
+ "item_number": {
407
+ "issueOrPRNumber": true
408
+ },
409
+ "repo": {
410
+ "type": "string",
411
+ "maxLength": 256
412
+ }
413
+ }
414
+ },
415
+ "create_issue": {
416
+ "defaultMax": 1,
417
+ "fields": {
418
+ "body": {
419
+ "required": true,
420
+ "type": "string",
421
+ "sanitize": true,
422
+ "maxLength": 65000
423
+ },
424
+ "labels": {
425
+ "type": "array",
426
+ "itemType": "string",
427
+ "itemSanitize": true,
428
+ "itemMaxLength": 128
429
+ },
430
+ "parent": {
431
+ "issueOrPRNumber": true
432
+ },
433
+ "repo": {
434
+ "type": "string",
435
+ "maxLength": 256
436
+ },
437
+ "temporary_id": {
438
+ "type": "string"
439
+ },
440
+ "title": {
441
+ "required": true,
442
+ "type": "string",
443
+ "sanitize": true,
444
+ "maxLength": 128
445
+ }
446
+ }
447
+ },
448
+ "missing_data": {
449
+ "defaultMax": 20,
450
+ "fields": {
451
+ "alternatives": {
452
+ "type": "string",
453
+ "sanitize": true,
454
+ "maxLength": 256
455
+ },
456
+ "context": {
457
+ "type": "string",
458
+ "sanitize": true,
459
+ "maxLength": 256
460
+ },
461
+ "data_type": {
462
+ "type": "string",
463
+ "sanitize": true,
464
+ "maxLength": 128
465
+ },
466
+ "reason": {
467
+ "type": "string",
468
+ "sanitize": true,
469
+ "maxLength": 256
470
+ }
471
+ }
472
+ },
473
+ "missing_tool": {
474
+ "defaultMax": 20,
475
+ "fields": {
476
+ "alternatives": {
477
+ "type": "string",
478
+ "sanitize": true,
479
+ "maxLength": 512
480
+ },
481
+ "reason": {
482
+ "required": true,
483
+ "type": "string",
484
+ "sanitize": true,
485
+ "maxLength": 256
486
+ },
487
+ "tool": {
488
+ "type": "string",
489
+ "sanitize": true,
490
+ "maxLength": 128
491
+ }
492
+ }
493
+ },
494
+ "noop": {
495
+ "defaultMax": 1,
496
+ "fields": {
497
+ "message": {
498
+ "required": true,
499
+ "type": "string",
500
+ "sanitize": true,
501
+ "maxLength": 65000
502
+ }
503
+ }
504
+ }
505
+ }
506
+ GH_AW_SAFE_OUTPUTS_VALIDATION_EOF
507
+ node ${RUNNER_TEMP}/gh-aw/actions/generate_safe_outputs_tools.cjs
508
+ - name: Generate Safe Outputs MCP Server Config
509
+ id: safe-outputs-config
510
+ run: |
511
+ # Generate a secure random API key (360 bits of entropy, 40+ chars)
512
+ # Mask immediately to prevent timing vulnerabilities
513
+ API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
514
+ echo "::add-mask::${API_KEY}"
515
+
516
+ PORT=3001
517
+
518
+ # Set outputs for next steps
519
+ {
520
+ echo "safe_outputs_api_key=${API_KEY}"
521
+ echo "safe_outputs_port=${PORT}"
522
+ } >> "$GITHUB_OUTPUT"
523
+
524
+ echo "Safe Outputs MCP server will run on port ${PORT}"
525
+
526
+ - name: Start Safe Outputs MCP HTTP Server
527
+ id: safe-outputs-start
528
+ env:
529
+ DEBUG: '*'
530
+ GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }}
531
+ GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }}
532
+ GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/tools.json
533
+ GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json
534
+ GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
535
+ run: |
536
+ # Environment variables are set above to prevent template injection
537
+ export DEBUG
538
+ export GH_AW_SAFE_OUTPUTS_PORT
539
+ export GH_AW_SAFE_OUTPUTS_API_KEY
540
+ export GH_AW_SAFE_OUTPUTS_TOOLS_PATH
541
+ export GH_AW_SAFE_OUTPUTS_CONFIG_PATH
542
+ export GH_AW_MCP_LOG_DIR
543
+
544
+ bash ${RUNNER_TEMP}/gh-aw/actions/start_safe_outputs_server.sh
545
+
546
+ - name: Start MCP Gateway
547
+ id: start-mcp-gateway
548
+ env:
549
+ GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
550
+ GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }}
551
+ GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }}
552
+ GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }}
553
+ GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }}
554
+ GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
555
+ run: |
556
+ set -eo pipefail
557
+ mkdir -p /tmp/gh-aw/mcp-config
558
+
559
+ # Export gateway environment variables for MCP config and gateway script
560
+ export MCP_GATEWAY_PORT="80"
561
+ export MCP_GATEWAY_DOMAIN="host.docker.internal"
562
+ MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
563
+ echo "::add-mask::${MCP_GATEWAY_API_KEY}"
564
+ export MCP_GATEWAY_API_KEY
565
+ export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads"
566
+ mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}"
567
+ export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288"
568
+ export DEBUG="*"
569
+
570
+ export GH_AW_ENGINE="copilot"
571
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.20'
572
+
573
+ mkdir -p /home/runner/.copilot
574
+ cat << GH_AW_MCP_CONFIG_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh
575
+ {
576
+ "mcpServers": {
577
+ "github": {
578
+ "type": "stdio",
579
+ "container": "ghcr.io/github/github-mcp-server:v0.32.0",
580
+ "env": {
581
+ "GITHUB_HOST": "\${GITHUB_SERVER_URL}",
582
+ "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
583
+ "GITHUB_READ_ONLY": "1",
584
+ "GITHUB_TOOLSETS": "context,repos,issues,pull_requests"
585
+ },
586
+ "guard-policies": {
587
+ "allow-only": {
588
+ "min-integrity": "$GITHUB_MCP_GUARD_MIN_INTEGRITY",
589
+ "repos": "$GITHUB_MCP_GUARD_REPOS"
590
+ }
591
+ }
592
+ },
593
+ "safeoutputs": {
594
+ "type": "http",
595
+ "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT",
596
+ "headers": {
597
+ "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}"
598
+ },
599
+ "guard-policies": {
600
+ "write-sink": {
601
+ "accept": [
602
+ "*"
603
+ ]
604
+ }
605
+ }
606
+ }
607
+ },
608
+ "gateway": {
609
+ "port": $MCP_GATEWAY_PORT,
610
+ "domain": "${MCP_GATEWAY_DOMAIN}",
611
+ "apiKey": "${MCP_GATEWAY_API_KEY}",
612
+ "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
613
+ }
614
+ }
615
+ GH_AW_MCP_CONFIG_EOF
616
+ - name: Download activation artifact
617
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
618
+ with:
619
+ name: activation
620
+ path: /tmp/gh-aw
621
+ - name: Clean git credentials
622
+ continue-on-error: true
623
+ run: bash ${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh
624
+ - name: Execute GitHub Copilot CLI
625
+ id: agentic_execution
626
+ # Copilot CLI tool arguments (sorted):
627
+ timeout-minutes: 10
628
+ run: |
629
+ set -o pipefail
630
+ touch /tmp/gh-aw/agent-step-summary.md
631
+ # shellcheck disable=SC1003
632
+ sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --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,www.googleapis.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.24.5 --skip-pull --enable-api-proxy \
633
+ -- /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 --add-dir /tmp/gh-aw/cache-memory/ --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
634
+ env:
635
+ COPILOT_AGENT_RUNNER_TYPE: STANDALONE
636
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
637
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }}
638
+ GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
639
+ GH_AW_PHASE: agent
640
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
641
+ GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
642
+ GH_AW_VERSION: v0.62.5
643
+ GITHUB_API_URL: ${{ github.api_url }}
644
+ GITHUB_AW: true
645
+ GITHUB_HEAD_REF: ${{ github.head_ref }}
646
+ GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
647
+ GITHUB_REF_NAME: ${{ github.ref_name }}
648
+ GITHUB_SERVER_URL: ${{ github.server_url }}
649
+ GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
650
+ GITHUB_WORKSPACE: ${{ github.workspace }}
651
+ GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
652
+ GIT_AUTHOR_NAME: github-actions[bot]
653
+ GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
654
+ GIT_COMMITTER_NAME: github-actions[bot]
655
+ XDG_CONFIG_HOME: /home/runner
656
+ - name: Detect inference access error
657
+ id: detect-inference-error
658
+ if: always()
659
+ continue-on-error: true
660
+ run: bash ${RUNNER_TEMP}/gh-aw/actions/detect_inference_access_error.sh
661
+ - name: Configure Git credentials
662
+ env:
663
+ REPO_NAME: ${{ github.repository }}
664
+ SERVER_URL: ${{ github.server_url }}
665
+ run: |
666
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
667
+ git config --global user.name "github-actions[bot]"
668
+ git config --global am.keepcr true
669
+ # Re-authenticate git with GitHub token
670
+ SERVER_URL_STRIPPED="${SERVER_URL#https://}"
671
+ git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
672
+ echo "Git configured with standard GitHub Actions identity"
673
+ - name: Copy Copilot session state files to logs
674
+ if: always()
675
+ continue-on-error: true
676
+ run: |
677
+ # Copy Copilot session state files to logs folder for artifact collection
678
+ # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them
679
+ SESSION_STATE_DIR="$HOME/.copilot/session-state"
680
+ LOGS_DIR="/tmp/gh-aw/sandbox/agent/logs"
681
+
682
+ if [ -d "$SESSION_STATE_DIR" ]; then
683
+ echo "Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR"
684
+ mkdir -p "$LOGS_DIR"
685
+ cp -v "$SESSION_STATE_DIR"/*.jsonl "$LOGS_DIR/" 2>/dev/null || true
686
+ echo "Session state files copied successfully"
687
+ else
688
+ echo "No session-state directory found at $SESSION_STATE_DIR"
689
+ fi
690
+ - name: Stop MCP Gateway
691
+ if: always()
692
+ continue-on-error: true
693
+ env:
694
+ MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
695
+ MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }}
696
+ GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}
697
+ run: |
698
+ bash ${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh "$GATEWAY_PID"
699
+ - name: Redact secrets in logs
700
+ if: always()
701
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
702
+ with:
703
+ script: |
704
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
705
+ setupGlobals(core, github, context, exec, io);
706
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs');
707
+ await main();
708
+ env:
709
+ GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
710
+ SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
711
+ SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
712
+ SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
713
+ SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
714
+ - name: Append agent step summary
715
+ if: always()
716
+ run: bash ${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh
717
+ - name: Copy Safe Outputs
718
+ if: always()
719
+ run: |
720
+ mkdir -p /tmp/gh-aw
721
+ cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true
722
+ - name: Ingest agent output
723
+ id: collect_output
724
+ if: always()
725
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
726
+ env:
727
+ GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
728
+ 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,www.googleapis.com"
729
+ GITHUB_SERVER_URL: ${{ github.server_url }}
730
+ GITHUB_API_URL: ${{ github.api_url }}
731
+ with:
732
+ script: |
733
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
734
+ setupGlobals(core, github, context, exec, io);
735
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/collect_ndjson_output.cjs');
736
+ await main();
737
+ - name: Parse agent logs for step summary
738
+ if: always()
739
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
740
+ env:
741
+ GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/
742
+ with:
743
+ script: |
744
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
745
+ setupGlobals(core, github, context, exec, io);
746
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_copilot_log.cjs');
747
+ await main();
748
+ - name: Parse MCP Gateway logs for step summary
749
+ if: always()
750
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
751
+ with:
752
+ script: |
753
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
754
+ setupGlobals(core, github, context, exec, io);
755
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_mcp_gateway_log.cjs');
756
+ await main();
757
+ - name: Print firewall logs
758
+ if: always()
759
+ continue-on-error: true
760
+ env:
761
+ AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs
762
+ run: |
763
+ # Fix permissions on firewall logs so they can be uploaded as artifacts
764
+ # AWF runs with sudo, creating files owned by root
765
+ sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true
766
+ # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step)
767
+ if command -v awf &> /dev/null; then
768
+ awf logs summary | tee -a "$GITHUB_STEP_SUMMARY"
769
+ else
770
+ echo 'AWF binary not installed, skipping firewall log summary'
771
+ fi
772
+ - name: Upload cache-memory data as artifact
773
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
774
+ if: always()
775
+ with:
776
+ name: cache-memory
777
+ path: /tmp/gh-aw/cache-memory
778
+ - name: Upload agent artifacts
779
+ if: always()
780
+ continue-on-error: true
781
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
782
+ with:
783
+ name: agent
784
+ path: |
785
+ /tmp/gh-aw/aw-prompts/prompt.txt
786
+ /tmp/gh-aw/sandbox/agent/logs/
787
+ /tmp/gh-aw/redacted-urls.log
788
+ /tmp/gh-aw/mcp-logs/
789
+ /tmp/gh-aw/sandbox/firewall/logs/
790
+ /tmp/gh-aw/agent-stdio.log
791
+ /tmp/gh-aw/agent/
792
+ /tmp/gh-aw/safeoutputs.jsonl
793
+ /tmp/gh-aw/agent_output.json
794
+ if-no-files-found: ignore
795
+ # --- Threat Detection (inline) ---
796
+ - name: Check if detection needed
797
+ id: detection_guard
798
+ if: always()
799
+ env:
800
+ OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }}
801
+ HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}
802
+ run: |
803
+ if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then
804
+ echo "run_detection=true" >> "$GITHUB_OUTPUT"
805
+ echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH"
806
+ else
807
+ echo "run_detection=false" >> "$GITHUB_OUTPUT"
808
+ echo "Detection skipped: no agent outputs or patches to analyze"
809
+ fi
810
+ - name: Clear MCP configuration for detection
811
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
812
+ run: |
813
+ rm -f /tmp/gh-aw/mcp-config/mcp-servers.json
814
+ rm -f /home/runner/.copilot/mcp-config.json
815
+ rm -f "$GITHUB_WORKSPACE/.gemini/settings.json"
816
+ - name: Prepare threat detection files
817
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
818
+ run: |
819
+ mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
820
+ cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
821
+ cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
822
+ for f in /tmp/gh-aw/aw-*.patch; do
823
+ [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
824
+ done
825
+ echo "Prepared threat detection files:"
826
+ ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true
827
+ - name: Setup threat detection
828
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
829
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
830
+ env:
831
+ WORKFLOW_NAME: "CI Failure Doctor"
832
+ WORKFLOW_DESCRIPTION: "This workflow is an automated CI failure investigator that triggers when monitored workflows fail.\nPerforms deep analysis of GitHub Actions workflow failures to identify root causes,\npatterns, and provide actionable remediation steps. Analyzes logs, error messages,\nand workflow configuration to help diagnose and resolve CI issues efficiently."
833
+ HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}
834
+ with:
835
+ script: |
836
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
837
+ setupGlobals(core, github, context, exec, io);
838
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/setup_threat_detection.cjs');
839
+ await main();
840
+ - name: Ensure threat-detection directory and log
841
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
842
+ run: |
843
+ mkdir -p /tmp/gh-aw/threat-detection
844
+ touch /tmp/gh-aw/threat-detection/detection.log
845
+ - name: Execute GitHub Copilot CLI
846
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
847
+ id: detection_agentic_execution
848
+ # Copilot CLI tool arguments (sorted):
849
+ # --allow-tool shell(cat)
850
+ # --allow-tool shell(grep)
851
+ # --allow-tool shell(head)
852
+ # --allow-tool shell(jq)
853
+ # --allow-tool shell(ls)
854
+ # --allow-tool shell(tail)
855
+ # --allow-tool shell(wc)
856
+ timeout-minutes: 20
857
+ run: |
858
+ set -o pipefail
859
+ touch /tmp/gh-aw/agent-step-summary.md
860
+ # shellcheck disable=SC1003
861
+ sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --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.24.5 --skip-pull --enable-api-proxy \
862
+ -- /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
863
+ env:
864
+ COPILOT_AGENT_RUNNER_TYPE: STANDALONE
865
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
866
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }}
867
+ GH_AW_PHASE: detection
868
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
869
+ GH_AW_VERSION: v0.62.5
870
+ GITHUB_API_URL: ${{ github.api_url }}
871
+ GITHUB_AW: true
872
+ GITHUB_HEAD_REF: ${{ github.head_ref }}
873
+ GITHUB_REF_NAME: ${{ github.ref_name }}
874
+ GITHUB_SERVER_URL: ${{ github.server_url }}
875
+ GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
876
+ GITHUB_WORKSPACE: ${{ github.workspace }}
877
+ GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
878
+ GIT_AUTHOR_NAME: github-actions[bot]
879
+ GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
880
+ GIT_COMMITTER_NAME: github-actions[bot]
881
+ XDG_CONFIG_HOME: /home/runner
882
+ - name: Parse threat detection results
883
+ id: parse_detection_results
884
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
885
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
886
+ with:
887
+ script: |
888
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
889
+ setupGlobals(core, github, context, exec, io);
890
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs');
891
+ await main();
892
+ - name: Upload threat detection log
893
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
894
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
895
+ with:
896
+ name: detection
897
+ path: /tmp/gh-aw/threat-detection/detection.log
898
+ if-no-files-found: ignore
899
+ - name: Set detection conclusion
900
+ id: detection_conclusion
901
+ if: always()
902
+ env:
903
+ RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}
904
+ DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }}
905
+ run: |
906
+ if [[ "$RUN_DETECTION" != "true" ]]; then
907
+ echo "conclusion=skipped" >> "$GITHUB_OUTPUT"
908
+ echo "success=true" >> "$GITHUB_OUTPUT"
909
+ echo "Detection was not needed, marking as skipped"
910
+ elif [[ "$DETECTION_SUCCESS" == "true" ]]; then
911
+ echo "conclusion=success" >> "$GITHUB_OUTPUT"
912
+ echo "success=true" >> "$GITHUB_OUTPUT"
913
+ echo "Detection passed successfully"
914
+ else
915
+ echo "conclusion=failure" >> "$GITHUB_OUTPUT"
916
+ echo "success=false" >> "$GITHUB_OUTPUT"
917
+ echo "Detection found issues"
918
+ fi
919
+
920
+ conclusion:
921
+ needs:
922
+ - activation
923
+ - agent
924
+ - safe_outputs
925
+ - update_cache_memory
926
+ if: always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true')
927
+ runs-on: ubuntu-slim
928
+ permissions:
929
+ contents: read
930
+ discussions: write
931
+ issues: write
932
+ pull-requests: write
933
+ concurrency:
934
+ group: "gh-aw-conclusion-ci-doctor"
935
+ cancel-in-progress: false
936
+ outputs:
937
+ noop_message: ${{ steps.noop.outputs.noop_message }}
938
+ tools_reported: ${{ steps.missing_tool.outputs.tools_reported }}
939
+ total_count: ${{ steps.missing_tool.outputs.total_count }}
940
+ steps:
941
+ - name: Setup Scripts
942
+ uses: github/gh-aw-actions/setup@dc50be57c94373431b49d3d0927f318ac2bb5c4c # v0.62.5
943
+ with:
944
+ destination: ${{ runner.temp }}/gh-aw/actions
945
+ - name: Download agent output artifact
946
+ id: download-agent-output
947
+ continue-on-error: true
948
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
949
+ with:
950
+ name: agent
951
+ path: /tmp/gh-aw/
952
+ - name: Setup agent output environment variable
953
+ if: steps.download-agent-output.outcome == 'success'
954
+ run: |
955
+ mkdir -p /tmp/gh-aw/
956
+ find "/tmp/gh-aw/" -type f -print
957
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_ENV"
958
+ - name: Process No-Op Messages
959
+ id: noop
960
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
961
+ env:
962
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
963
+ GH_AW_NOOP_MAX: "1"
964
+ GH_AW_WORKFLOW_NAME: "CI Failure Doctor"
965
+ with:
966
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
967
+ script: |
968
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
969
+ setupGlobals(core, github, context, exec, io);
970
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/noop.cjs');
971
+ await main();
972
+ - name: Record Missing Tool
973
+ id: missing_tool
974
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
975
+ env:
976
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
977
+ GH_AW_WORKFLOW_NAME: "CI Failure Doctor"
978
+ with:
979
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
980
+ script: |
981
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
982
+ setupGlobals(core, github, context, exec, io);
983
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/missing_tool.cjs');
984
+ await main();
985
+ - name: Handle Agent Failure
986
+ id: handle_agent_failure
987
+ if: always()
988
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
989
+ env:
990
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
991
+ GH_AW_WORKFLOW_NAME: "CI Failure Doctor"
992
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
993
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
994
+ GH_AW_WORKFLOW_ID: "ci-doctor"
995
+ GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }}
996
+ GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
997
+ GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }}
998
+ GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }}
999
+ GH_AW_GROUP_REPORTS: "false"
1000
+ GH_AW_FAILURE_REPORT_AS_ISSUE: "true"
1001
+ GH_AW_TIMEOUT_MINUTES: "10"
1002
+ with:
1003
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1004
+ script: |
1005
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
1006
+ setupGlobals(core, github, context, exec, io);
1007
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
1008
+ await main();
1009
+ - name: Handle No-Op Message
1010
+ id: handle_noop_message
1011
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
1012
+ env:
1013
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
1014
+ GH_AW_WORKFLOW_NAME: "CI Failure Doctor"
1015
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
1016
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
1017
+ GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }}
1018
+ GH_AW_NOOP_REPORT_AS_ISSUE: "true"
1019
+ with:
1020
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1021
+ script: |
1022
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
1023
+ setupGlobals(core, github, context, exec, io);
1024
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_noop_message.cjs');
1025
+ await main();
1026
+
1027
+ pre_activation:
1028
+ if: ${{ github.event.workflow_run.conclusion == 'failure' }}
1029
+ runs-on: ubuntu-slim
1030
+ outputs:
1031
+ activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }}
1032
+ matched_command: ''
1033
+ steps:
1034
+ - name: Setup Scripts
1035
+ uses: github/gh-aw-actions/setup@dc50be57c94373431b49d3d0927f318ac2bb5c4c # v0.62.5
1036
+ with:
1037
+ destination: ${{ runner.temp }}/gh-aw/actions
1038
+ - name: Check team membership for workflow
1039
+ id: check_membership
1040
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
1041
+ env:
1042
+ GH_AW_REQUIRED_ROLES: admin,maintainer,write
1043
+ with:
1044
+ github-token: ${{ secrets.GITHUB_TOKEN }}
1045
+ script: |
1046
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
1047
+ setupGlobals(core, github, context, exec, io);
1048
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/check_membership.cjs');
1049
+ await main();
1050
+
1051
+ safe_outputs:
1052
+ needs: agent
1053
+ if: (!cancelled()) && needs.agent.result != 'skipped' && needs.agent.outputs.detection_success == 'true'
1054
+ runs-on: ubuntu-slim
1055
+ permissions:
1056
+ contents: read
1057
+ discussions: write
1058
+ issues: write
1059
+ pull-requests: write
1060
+ timeout-minutes: 15
1061
+ env:
1062
+ GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/ci-doctor"
1063
+ GH_AW_ENGINE_ID: "copilot"
1064
+ GH_AW_WORKFLOW_ID: "ci-doctor"
1065
+ GH_AW_WORKFLOW_NAME: "CI Failure Doctor"
1066
+ outputs:
1067
+ code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
1068
+ code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
1069
+ comment_id: ${{ steps.process_safe_outputs.outputs.comment_id }}
1070
+ comment_url: ${{ steps.process_safe_outputs.outputs.comment_url }}
1071
+ create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}
1072
+ create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}
1073
+ created_issue_number: ${{ steps.process_safe_outputs.outputs.created_issue_number }}
1074
+ created_issue_url: ${{ steps.process_safe_outputs.outputs.created_issue_url }}
1075
+ process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}
1076
+ process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }}
1077
+ steps:
1078
+ - name: Setup Scripts
1079
+ uses: github/gh-aw-actions/setup@dc50be57c94373431b49d3d0927f318ac2bb5c4c # v0.62.5
1080
+ with:
1081
+ destination: ${{ runner.temp }}/gh-aw/actions
1082
+ - name: Download agent output artifact
1083
+ id: download-agent-output
1084
+ continue-on-error: true
1085
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
1086
+ with:
1087
+ name: agent
1088
+ path: /tmp/gh-aw/
1089
+ - name: Setup agent output environment variable
1090
+ if: steps.download-agent-output.outcome == 'success'
1091
+ run: |
1092
+ mkdir -p /tmp/gh-aw/
1093
+ find "/tmp/gh-aw/" -type f -print
1094
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_ENV"
1095
+ - name: Configure GH_HOST for enterprise compatibility
1096
+ shell: bash
1097
+ run: |
1098
+ # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
1099
+ # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
1100
+ GH_HOST="${GITHUB_SERVER_URL#https://}"
1101
+ GH_HOST="${GH_HOST#http://}"
1102
+ echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
1103
+ - name: Process Safe Outputs
1104
+ id: process_safe_outputs
1105
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
1106
+ env:
1107
+ GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
1108
+ 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,www.googleapis.com"
1109
+ GITHUB_SERVER_URL: ${{ github.server_url }}
1110
+ GITHUB_API_URL: ${{ github.api_url }}
1111
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_issue\":{\"labels\":[\"automation\",\"ci\"],\"max\":1,\"title_prefix\":\"${{ github.workflow }}\"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"}}"
1112
+ with:
1113
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1114
+ script: |
1115
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
1116
+ setupGlobals(core, github, context, exec, io);
1117
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs');
1118
+ await main();
1119
+ - name: Upload safe output items
1120
+ if: always()
1121
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
1122
+ with:
1123
+ name: safe-output-items
1124
+ path: /tmp/gh-aw/safe-output-items.jsonl
1125
+ if-no-files-found: ignore
1126
+
1127
+ update_cache_memory:
1128
+ needs: agent
1129
+ if: always() && needs.agent.outputs.detection_success == 'true'
1130
+ runs-on: ubuntu-latest
1131
+ permissions: {}
1132
+ env:
1133
+ GH_AW_WORKFLOW_ID_SANITIZED: cidoctor
1134
+ steps:
1135
+ - name: Setup Scripts
1136
+ uses: github/gh-aw-actions/setup@dc50be57c94373431b49d3d0927f318ac2bb5c4c # v0.62.5
1137
+ with:
1138
+ destination: ${{ runner.temp }}/gh-aw/actions
1139
+ - name: Download cache-memory artifact (default)
1140
+ id: download_cache_default
1141
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
1142
+ continue-on-error: true
1143
+ with:
1144
+ name: cache-memory
1145
+ path: /tmp/gh-aw/cache-memory
1146
+ - name: Check if cache-memory folder has content (default)
1147
+ id: check_cache_default
1148
+ shell: bash
1149
+ run: |
1150
+ if [ -d "/tmp/gh-aw/cache-memory" ] && [ "$(ls -A /tmp/gh-aw/cache-memory 2>/dev/null)" ]; then
1151
+ echo "has_content=true" >> "$GITHUB_OUTPUT"
1152
+ else
1153
+ echo "has_content=false" >> "$GITHUB_OUTPUT"
1154
+ fi
1155
+ - name: Save cache-memory to cache (default)
1156
+ if: steps.check_cache_default.outputs.has_content == 'true'
1157
+ uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
1158
+ with:
1159
+ key: memory-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }}
1160
+ path: /tmp/gh-aw/cache-memory
1161
+