@juangcarmona/lighthouse-sdlc 0.7.0 → 0.9.0

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.
@@ -0,0 +1,2207 @@
1
+ # gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"eb70f1d711ea5126bbe478ec05c0e7a68cb4c3bed9d2987449aa740d2c5db7e5","body_hash":"ecf132f588f1691b697be174527c5f7342d2f769678480dec54fd189a3f8d98e","compiler_version":"v0.93.2","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.101"},"agent_image_runner":"[\"self-hosted\",\"linux\",\"lighthouse-sdlc\"]"}
2
+ # gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_DEFAULT_OTLP_ENDPOINT","GH_AW_DEFAULT_OTLP_HEADERS","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"9000827ccba6bdab643e8b6fd33ac0654aef8333","version":"v8.0.2"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"949feb2413d6458794dcd2491c4babbbce0c15c1","version":"v7.1.0"},{"repo":"actions/upload-artifact","sha":"cf430e030ddbb5b0abf93d22962f4752f3646cd9","version":"v7.0.2"},{"repo":"github/gh-aw-actions/setup","sha":"d9128eb3ea40c18b77c76184eda03c0ff2608d79","version":"v0.93.2"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.28.70","digest":"sha256:b15ab48cbbab02904eb9bbd359a398db59690eebbea1e6934d47ed2bb407dd34","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.28.70@sha256:b15ab48cbbab02904eb9bbd359a398db59690eebbea1e6934d47ed2bb407dd34"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.70","digest":"sha256:9ac8f9c7294e892c916de3da9d2588dfd8cd4931e5c39b00143266d7ed9fd52a","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.70@sha256:9ac8f9c7294e892c916de3da9d2588dfd8cd4931e5c39b00143266d7ed9fd52a"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.28.70","digest":"sha256:b5bc53f4becfd96e926e63c83831f1b3c9512f713c83161d2b8c9b7204b3e917","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.28.70@sha256:b5bc53f4becfd96e926e63c83831f1b3c9512f713c83161d2b8c9b7204b3e917"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.37","digest":"sha256:9c7f242f6dec2d7d7b55d4c9e07872d59b85377c6cb3de46c915a5d1ffb91442","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.37@sha256:9c7f242f6dec2d7d7b55d4c9e07872d59b85377c6cb3de46c915a5d1ffb91442"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:41835613992df88f51e923bad486f96dfb2e6cda29f13e217df41833284ae382","pinned_image":"ghcr.io/github/gh-aw-node@sha256:41835613992df88f51e923bad486f96dfb2e6cda29f13e217df41833284ae382"},{"image":"ghcr.io/github/github-mcp-server:v2.0.2","digest":"sha256:ffced0d76e77428532a2ced185516992d77fd146d69eec2f244e6237d1a97796","pinned_image":"ghcr.io/github/github-mcp-server:v2.0.2@sha256:ffced0d76e77428532a2ced185516992d77fd146d69eec2f244e6237d1a97796"}],"mcp_servers":[{"name":"github","tools":["get_commit","get_file_contents","get_latest_release","get_pull_request","get_pull_request_comments","get_pull_request_diff","get_pull_request_files","get_pull_request_review_comments","get_pull_request_reviews","get_pull_request_status","get_release_by_tag","get_tag","issue_read","list_branches","list_commits","list_issue_types","list_issues","list_pull_requests","list_releases","list_starred_repositories","list_tags","pull_request_read","search_code","search_issues","search_pull_requests","search_repositories"]},{"name":"safeoutputs","tools":["noop","report_incomplete","report_missing_data","report_missing_tool"]}],"threat_detection":{"mode":"enabled"},"admission":false}
3
+ # This file was automatically generated by gh-aw (v0.93.2). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md
4
+ #
5
+ # To update this file, edit the corresponding .md file and run:
6
+ # gh aw compile
7
+ # Not all edits will cause changes to this file.
8
+ #
9
+ # For more information: https://github.github.com/gh-aw/introduction/overview/
10
+ #
11
+ # Execute only the Lighthouse review stage and return its declared stage result.
12
+ #
13
+ # Resolved workflow manifest:
14
+ # Imports:
15
+ # - shared/lighthouse-sdlc-stage.md
16
+ #
17
+ # Frontmatter env variables:
18
+ # - LIGHTHOUSE_SKILL: (main workflow)
19
+ # - LIGHTHOUSE_STAGE: (main workflow)
20
+ #
21
+ # Secrets used:
22
+ # - COPILOT_GITHUB_TOKEN
23
+ # - GH_AW_DEFAULT_OTLP_ENDPOINT
24
+ # - GH_AW_DEFAULT_OTLP_HEADERS
25
+ # - GH_AW_GITHUB_MCP_SERVER_TOKEN
26
+ # - GH_AW_GITHUB_TOKEN
27
+ # - GITHUB_TOKEN
28
+ #
29
+ # Custom actions used:
30
+ # - actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
31
+ # - actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
32
+ # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
33
+ # - actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
34
+ # - actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
35
+ # - github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
36
+ #
37
+ # Container images used:
38
+ # - ghcr.io/github/gh-aw-firewall/agent:0.28.70@sha256:b15ab48cbbab02904eb9bbd359a398db59690eebbea1e6934d47ed2bb407dd34
39
+ # - ghcr.io/github/gh-aw-firewall/api-proxy:0.28.70@sha256:9ac8f9c7294e892c916de3da9d2588dfd8cd4931e5c39b00143266d7ed9fd52a
40
+ # - ghcr.io/github/gh-aw-firewall/squid:0.28.70@sha256:b5bc53f4becfd96e926e63c83831f1b3c9512f713c83161d2b8c9b7204b3e917
41
+ # - ghcr.io/github/gh-aw-mcpg:v0.4.37@sha256:9c7f242f6dec2d7d7b55d4c9e07872d59b85377c6cb3de46c915a5d1ffb91442
42
+ # - ghcr.io/github/gh-aw-node@sha256:41835613992df88f51e923bad486f96dfb2e6cda29f13e217df41833284ae382
43
+ # - ghcr.io/github/github-mcp-server:v2.0.2@sha256:ffced0d76e77428532a2ced185516992d77fd146d69eec2f244e6237d1a97796
44
+
45
+ name: "Lighthouse SDLC review"
46
+ on:
47
+ workflow_call:
48
+ inputs:
49
+ aw_context:
50
+ default: ""
51
+ description: "Agent caller context (Reserved for Agentic Workflows)."
52
+ required: false
53
+ type: string
54
+ input:
55
+ default: "{}"
56
+ description: Compact JSON input for this stage.
57
+ required: false
58
+ type: string
59
+ previous-stage:
60
+ default: integrate
61
+ description: Previous stage artifact name.
62
+ required: false
63
+ type: string
64
+ route:
65
+ description: Lighthouse route selected by the host.
66
+ required: true
67
+ type: string
68
+ run-id:
69
+ description: Stable Lighthouse run identifier.
70
+ required: true
71
+ type: string
72
+ secrets:
73
+ COPILOT_GITHUB_TOKEN:
74
+ required: false
75
+ GH_AW_DEFAULT_OTLP_ENDPOINT:
76
+ required: false
77
+ GH_AW_DEFAULT_OTLP_HEADERS:
78
+ required: false
79
+ GH_AW_GITHUB_MCP_SERVER_TOKEN:
80
+ required: false
81
+ GH_AW_GITHUB_TOKEN:
82
+ required: false
83
+
84
+ # Jobs receive only their explicitly declared permissions.
85
+ permissions: {}
86
+
87
+ concurrency:
88
+ group: "gh-aw-lighthouse-sdlc-review-${{ github.run_id }}"
89
+ queue: max
90
+
91
+ run-name: "Lighthouse SDLC review"
92
+
93
+ env:
94
+ LIGHTHOUSE_SKILL: node_modules/@juangcarmona/lighthouse-sdlc/skills/review/SKILL.md
95
+ LIGHTHOUSE_STAGE: review
96
+ OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.GH_AW_DEFAULT_OTLP_ENDPOINT || vars.GH_AW_DEFAULT_OTLP_ENDPOINT }}
97
+ OTEL_SERVICE_NAME: gh-aw.lighthouse-sdlc-review
98
+ OTEL_RESOURCE_ATTRIBUTES: 'gh-aw.workflow.name=Lighthouse%20SDLC%20review,gh-aw.repository=${{ github.repository }},gh-aw.run.id=${{ github.run_id }},github.run_id=${{ github.run_id }},gh-aw.engine.id=copilot'
99
+ OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }}
100
+ GH_AW_OTLP_ENDPOINTS: '[{"url":"${{ secrets.GH_AW_DEFAULT_OTLP_ENDPOINT || vars.GH_AW_DEFAULT_OTLP_ENDPOINT }}","headers":"${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }}"}]'
101
+ GH_AW_OTLP_IF_MISSING: ignore
102
+
103
+ jobs:
104
+ activation:
105
+ name: activation
106
+ needs: pre_activation
107
+ if: needs.pre_activation.outputs.activated == 'true'
108
+ runs-on: ubuntu-24.04
109
+ # Permissions for the activation job (workflow permissions default to none).
110
+ permissions:
111
+ actions: read
112
+ contents: read
113
+ env:
114
+ GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }}
115
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
116
+ outputs:
117
+ artifact_prefix: ${{ steps.artifact-prefix.outputs.prefix }}
118
+ aw_context: ${{ steps.generate_aw_info.outputs.aw_context }}
119
+ comment_id: ""
120
+ comment_repo: ""
121
+ daily_ai_credits_estimated: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_estimated || '' }}
122
+ daily_ai_credits_exceeded: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }}
123
+ daily_ai_credits_guardrail_error: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_guardrail_error || '' }}
124
+ daily_ai_credits_guardrail_status: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_guardrail_status || '' }}
125
+ daily_ai_credits_threshold: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }}
126
+ daily_ai_credits_total: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_total || '' }}
127
+ engine_id: ${{ steps.generate_aw_info.outputs.engine_id }}
128
+ lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }}
129
+ model: ${{ steps.generate_aw_info.outputs.model }}
130
+ oauth_token_check_failed: ${{ steps.check-oauth-tokens.outputs.oauth_token_check_failed == 'true' }}
131
+ secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
132
+ setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
133
+ setup-span-id: ${{ steps.setup.outputs.span-id }}
134
+ setup-trace-id: ${{ steps.setup.outputs.trace-id }}
135
+ stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }}
136
+ target_checkout_ref: ${{ steps.resolve-host-repo.outputs.target_checkout_ref }}
137
+ target_ref: ${{ steps.resolve-host-repo.outputs.target_ref }}
138
+ target_repo: ${{ steps.resolve-host-repo.outputs.target_repo }}
139
+ target_repo_name: ${{ steps.resolve-host-repo.outputs.target_repo_name }}
140
+ steps:
141
+ - name: Setup Scripts
142
+ id: setup
143
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
144
+ with:
145
+ destination: ${{ runner.temp }}/gh-aw/actions
146
+ job-name: ${{ github.job }}
147
+ trace-id: ${{ needs.pre_activation.outputs.setup-trace-id }}
148
+ parent-span-id: ${{ needs.pre_activation.outputs.setup-parent-span-id || needs.pre_activation.outputs.setup-span-id }}
149
+ safe-output-artifact-client: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
150
+ env:
151
+ GH_AW_SETUP_WORKFLOW_NAME: "Lighthouse SDLC review"
152
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-review.lock.yml@${{ github.ref }}
153
+ GH_AW_INFO_VERSION: "1.0.101"
154
+ GH_AW_INFO_AWF_VERSION: "v0.28.70"
155
+ GH_AW_INFO_ENGINE_ID: "copilot"
156
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
157
+ - name: Mask OTLP telemetry headers
158
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh"
159
+ - name: Resolve host repo for activation checkout
160
+ id: resolve-host-repo
161
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
162
+ env:
163
+ JOB_WORKFLOW_REPOSITORY: ${{ job.workflow_repository }}
164
+ JOB_WORKFLOW_SHA: ${{ job.workflow_sha }}
165
+ JOB_WORKFLOW_REF: ${{ job.workflow_ref }}
166
+ JOB_WORKFLOW_FILE_PATH: ${{ job.workflow_file_path }}
167
+ with:
168
+ script: |
169
+ const path = require('path');
170
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
171
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
172
+ setupGlobals(core, github, context, exec, io, getOctokit);
173
+ const { main } = require(path.join(actionsDir, 'resolve_host_repo.cjs'));
174
+ await main();
175
+ - name: Compute artifact prefix
176
+ id: artifact-prefix
177
+ env:
178
+ INPUTS_JSON: ${{ toJSON(inputs) }}
179
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/compute_artifact_prefix.sh"
180
+ - name: Generate agentic run info
181
+ id: generate_aw_info
182
+ env:
183
+ GH_AW_INFO_ENGINE_ID: "copilot"
184
+ GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
185
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'auto' }}
186
+ GH_AW_INFO_VERSION: "1.0.101"
187
+ GH_AW_INFO_AGENT_VERSION: "1.0.101"
188
+ GH_AW_INFO_CLI_VERSION: "v0.93.2"
189
+ GH_AW_INFO_WORKFLOW_NAME: "Lighthouse SDLC review"
190
+ GH_AW_INFO_WORKFLOW_ID: ${{ job.workflow_ref }}
191
+ GH_AW_INFO_EXPERIMENTAL: "false"
192
+ GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
193
+ GH_AW_INFO_STAGED: "false"
194
+ GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]'
195
+ GH_AW_INFO_FIREWALL_ENABLED: "true"
196
+ GH_AW_INFO_AWF_VERSION: "v0.28.70"
197
+ GH_AW_INFO_AWMG_VERSION: ""
198
+ GH_AW_INFO_FIREWALL_TYPE: "squid"
199
+ GH_AW_INFO_AGENT_RUNTIME: ""
200
+ GH_AW_INFO_ENGINE_HARNESS: "copilot-cli"
201
+ GH_AW_INFO_MODEL_CONFIG: '{"routing":{"enabled":false},"models":{"allowed":[],"blocked":[]},"max_ai_credits_source":"default"}'
202
+ GH_AW_INFO_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
203
+ GH_AW_COMPILED_STRICT: "true"
204
+ GH_AW_INFO_TARGET_REPO: ${{ steps.resolve-host-repo.outputs.target_repo }}
205
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
206
+ with:
207
+ script: |
208
+ const path = require('path');
209
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
210
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
211
+ setupGlobals(core, github, context, exec, io, getOctokit);
212
+ const { main } = require(path.join(actionsDir, 'generate_aw_info.cjs'));
213
+ await main(core, context);
214
+ - name: Restore daily AIC scan observations
215
+ id: restore-daily-aic-cache-fallback
216
+ if: ${{ env.GH_AW_ADMISSION_RESULT != 'admitted' && env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
217
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
218
+ env:
219
+ GH_AW_HAS_SLASH_COMMAND: "false"
220
+ GH_AW_HAS_LABEL_COMMAND: "false"
221
+ with:
222
+ github-token: ${{ secrets.GITHUB_TOKEN }}
223
+ script: |
224
+ const path = require('path');
225
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
226
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
227
+ setupGlobals(core, github, context, exec, io, getOctokit);
228
+ const { main } = require(path.join(actionsDir, 'restore_aic_scan_cache.cjs'));
229
+ await main();
230
+ - name: Check daily workflow token guardrail
231
+ id: daily-ai-credits-workflow-guardrail
232
+ if: ${{ env.GH_AW_ADMISSION_RESULT != 'admitted' && env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
233
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
234
+ env:
235
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC review"
236
+ GH_AW_WORKFLOW_ID: "lighthouse-sdlc-review"
237
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
238
+ GH_AW_WORKFLOW_DISPATCH_AW_CONTEXT: ${{ github.event.inputs.aw_context || '' }}
239
+ GH_AW_HAS_SLASH_COMMAND: "false"
240
+ GH_AW_HAS_LABEL_COMMAND: "false"
241
+ GH_AW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
242
+ GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }}
243
+ GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
244
+ with:
245
+ github-token: ${{ secrets.GITHUB_TOKEN }}
246
+ script: |
247
+ const path = require('path');
248
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
249
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
250
+ setupGlobals(core, github, context, exec, io, getOctokit);
251
+ const { main } = require(path.join(actionsDir, 'check_daily_aic_workflow_guardrail.cjs'));
252
+ await main();
253
+ - name: Publish daily AIC scan observations
254
+ if: always() && env.GH_AW_ADMISSION_RESULT != 'admitted' && env.GH_AW_MAX_DAILY_AI_CREDITS != ''
255
+ continue-on-error: true
256
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
257
+ with:
258
+ name: aic-usage-scan-v2
259
+ path: /tmp/gh-aw/agentic-workflow-usage-scan-v2.jsonl
260
+ overwrite: true
261
+ if-no-files-found: ignore
262
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '3' }}
263
+ - name: Validate COPILOT_GITHUB_TOKEN secret
264
+ id: validate-secret
265
+ run: bash "${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
266
+ env:
267
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
268
+ - name: Check for OAuth tokens
269
+ id: check-oauth-tokens
270
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/check_oauth_tokens.sh"
271
+ env:
272
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
273
+ GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
274
+ GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
275
+ - name: Print cross-repo setup guidance
276
+ if: failure() && steps.resolve-host-repo.outputs.target_repo != github.repository
277
+ run: |
278
+ echo "::error::COPILOT_GITHUB_TOKEN must be configured in the CALLER repository's secrets."
279
+ echo "::error::For cross-repo workflow_call, secrets must be set in the repository that triggers the workflow."
280
+ echo "::error::See: https://github.github.com/gh-aw/patterns/central-repo-ops/#cross-repo-setup"
281
+ - name: Checkout .github and .agents folders
282
+ if: steps.resolve-host-repo.outputs.target_repo == github.repository
283
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
284
+ with:
285
+ persist-credentials: false
286
+ repository: ${{ steps.resolve-host-repo.outputs.target_repo }}
287
+ ref: ${{ steps.resolve-host-repo.outputs.target_checkout_ref }}
288
+ sparse-checkout: |
289
+ .github
290
+ .agents
291
+ .claude
292
+ .codex
293
+ .gemini
294
+ .pi
295
+ sparse-checkout-cone-mode: true
296
+ fetch-depth: 1
297
+ - name: Save agent config folders for base branch restoration
298
+ env:
299
+ GH_AW_AGENT_FOLDERS: ".agents .github"
300
+ GH_AW_AGENT_FILES: "AGENTS.md"
301
+ run: |
302
+ bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
303
+ - name: Check workflow lock file
304
+ id: check-lock-file
305
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
306
+ env:
307
+ GH_AW_WORKFLOW_FILE: "lighthouse-sdlc-review.lock.yml"
308
+ GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}"
309
+ with:
310
+ script: |
311
+ const path = require('path');
312
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
313
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
314
+ setupGlobals(core, github, context, exec, io, getOctokit);
315
+ const { main } = require(path.join(actionsDir, 'check_workflow_timestamp_api.cjs'));
316
+ await main();
317
+ - name: Check compile-agentic version
318
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
319
+ env:
320
+ GH_AW_COMPILED_VERSION: "v0.93.2"
321
+ GH_AW_HAS_SAFE_OUTPUTS: "true"
322
+ GH_AW_BLOCKED_VERSION_REPORT_AS_ISSUE: "false"
323
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC review"
324
+ with:
325
+ script: |
326
+ const path = require('path');
327
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
328
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
329
+ setupGlobals(core, github, context, exec, io, getOctokit);
330
+ const { main } = require(path.join(actionsDir, 'check_version_updates.cjs'));
331
+ await main();
332
+ - name: Log runtime features
333
+ if: ${{ contains(toJSON(vars), '"GH_AW_RUNTIME_FEATURES":') }}
334
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/log_runtime_features_summary.sh"
335
+ - name: Create prompt with built-in context
336
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
337
+ env:
338
+ GH_AW_ACTIONS_DIR: ${{ runner.temp }}/gh-aw/actions
339
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
340
+ GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl
341
+ GH_AW_PROMPT_CONFIG: "{\"items\":[{\"content_env\":\"GH_AW_PROMPT_CONTENT_0000\"},{\"file\":\"xpia.md\"},{\"file\":\"temp_folder_prompt.md\"},{\"file\":\"markdown.md\"},{\"file\":\"safe_outputs_mcp_transport_prompt.md\"},{\"file\":\"safe_outputs_prompt.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0001\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0002\"},{\"file\":\"mcp_cli_tools_with_safeoutputs_prompt.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0003\"},{\"file\":\"github_mcp_tools_with_safeoutputs_prompt.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0004\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0005\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0006\"}],\"system_item_count\":12}"
342
+ GH_AW_ENV_LIGHTHOUSE_SKILL: ${{ env.LIGHTHOUSE_SKILL }}
343
+ GH_AW_EXPR_76DF9333: ${{ github.event.pull_request.number || (fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').item_type == 'pull_request' && fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').item_number) }}
344
+ GH_AW_EXPR_77C1A4D2: ${{ github.event.comment.id || fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').comment_id }}
345
+ GH_AW_EXPR_79DC8BAA: ${{ inputs.run-id }}
346
+ GH_AW_EXPR_7C248226: ${{ github.event.issue.number || (fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').item_type == 'issue' && fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').item_number) }}
347
+ GH_AW_EXPR_C19C384F: ${{ github.event.discussion.number || (fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').item_type == 'discussion' && fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').item_number) }}
348
+ GH_AW_GITHUB_ACTOR: ${{ github.actor }}
349
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
350
+ GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
351
+ GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
352
+ GH_AW_PROMPT_CONTENT_0000: "<system>\n"
353
+ GH_AW_PROMPT_CONTENT_0001: "<safe-output-tools>\nTools: report_missing_tool, report_missing_data, noop\n"
354
+ GH_AW_PROMPT_CONTENT_0002: "</safe-output-tools>\n"
355
+ GH_AW_PROMPT_CONTENT_0003: "<github-context>\nThe following GitHub context information is available for this workflow:\n{{#if github.actor}}\n- **actor**: __GH_AW_GITHUB_ACTOR__\n{{/if}}\n{{#if github.repository}}\n- **repository**: __GH_AW_GITHUB_REPOSITORY__\n{{/if}}\n{{#if github.workspace}}\n- **workspace**: __GH_AW_GITHUB_WORKSPACE__\n{{/if}}\n{{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}}\n- **issue-number**: #__GH_AW_EXPR_7C248226__\n{{/if}}\n{{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}}\n- **discussion-number**: #__GH_AW_EXPR_C19C384F__\n{{/if}}\n{{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}}\n- **pull-request-number**: #__GH_AW_EXPR_76DF9333__\n{{/if}}\n{{#if github.event.comment.id || github.aw.context.comment_id}}\n- **comment-id**: __GH_AW_EXPR_77C1A4D2__\n{{/if}}\n{{#if github.run_id}}\n- **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__\n{{/if}}\n- **checkouts**: The following repositories have been checked out and are available in the workspace:\n - repo `__GH_AW_GITHUB_REPOSITORY__` → `__GH_AW_GITHUB_WORKSPACE__` (cwd) [full history, all branches available as remote-tracking refs]\n - **Note**: The workspace path reported above may contain a separate shallow, credential-free checkout of the host repository. Use the exact checkout path shown for the repository you need. Before concluding that a branch is unavailable, confirm your working directory matches that path and inspect refs there. If the branch is not present in that checkout and is not listed as an additional fetched ref, it has NOT been checked out. For private repositories you cannot fetch it. If the branch is required and not available, exit with an error and ask the user to add it to the `fetch:` option of the `checkout:` configuration (e.g., `fetch: [\"refs/pulls/open/*\"]` for all open PR refs, or `fetch: [\"main\", \"feature/my-branch\"]` for specific branches).\n - **Warning: No git credentials are available to the agent.** Credentials are\n intentionally removed after the checkout step for security. This means any git\n operation that needs to authenticate to the remote will fail. In private repositories, that includes:\n - `git fetch`, `git pull`, `git clone`, and `git push` (direct push, not via safe-output tools)\n - Checking out or switching to a remote branch that is not already fetched\n - Deepening a shallow clone (`git fetch --unshallow`)\n - On-demand blob fetches in partial/blobless clones (operations on files not in the initial checkout)\n Do NOT attempt to configure credentials, run `git credential fill`, or modify `.gitconfig` —\n authentication will not succeed. If you encounter credential prompts or authentication errors,\n stop immediately and report the limitation rather than spending turns trying to work around it.\n</github-context>\n\n"
356
+ GH_AW_PROMPT_CONTENT_0004: "</system>\n"
357
+ GH_AW_PROMPT_CONTENT_0005: "{{#runtime-import .github/workflows/shared/lighthouse-sdlc-stage.md}}\n"
358
+ GH_AW_PROMPT_CONTENT_0006: "{{#runtime-import .github/workflows/lighthouse-sdlc-review.md}}\n"
359
+ with:
360
+ script: |
361
+ const { setupGlobals } = require(process.env.GH_AW_ACTIONS_DIR + '/setup_globals.cjs');
362
+ setupGlobals(core, github, context, exec, io, getOctokit);
363
+ const { main } = require(process.env.GH_AW_ACTIONS_DIR + '/create_prompt.cjs');
364
+ await main(core);
365
+ - name: Interpolate variables and render templates
366
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
367
+ env:
368
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
369
+ GH_AW_ENGINE_ID: "copilot"
370
+ GH_AW_SUB_AGENT_DIR: ".github/agents"
371
+ GH_AW_SUB_AGENT_EXT: ".agent.md"
372
+ GH_AW_SKILL_DIR: ".github/skills"
373
+ GH_AW_SKILL_EXT: "/SKILL.md"
374
+ GH_AW_ENV_LIGHTHOUSE_SKILL: ${{ env.LIGHTHOUSE_SKILL }}
375
+ GH_AW_EXPR_79DC8BAA: ${{ inputs.run-id }}
376
+ with:
377
+ script: |
378
+ const path = require('path');
379
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
380
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
381
+ setupGlobals(core, github, context, exec, io, getOctokit);
382
+ const { main } = require(path.join(actionsDir, 'interpolate_prompt.cjs'));
383
+ await main();
384
+ - name: Substitute placeholders
385
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
386
+ env:
387
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
388
+ GH_AW_ENV_LIGHTHOUSE_SKILL: ${{ env.LIGHTHOUSE_SKILL }}
389
+ GH_AW_EXPR_76DF9333: ${{ github.event.pull_request.number || (fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').item_type == 'pull_request' && fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').item_number) }}
390
+ GH_AW_EXPR_77C1A4D2: ${{ github.event.comment.id || fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').comment_id }}
391
+ GH_AW_EXPR_79DC8BAA: ${{ inputs.run-id }}
392
+ GH_AW_EXPR_7C248226: ${{ github.event.issue.number || (fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').item_type == 'issue' && fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').item_number) }}
393
+ GH_AW_EXPR_C19C384F: ${{ github.event.discussion.number || (fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').item_type == 'discussion' && fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').item_number) }}
394
+ GH_AW_GITHUB_ACTOR: ${{ github.actor }}
395
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
396
+ GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
397
+ GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
398
+ GH_AW_MCP_CLI_SERVERS_LIST: "- `github` — run `github --help` to see available tools\n- `safeoutputs` — run `safeoutputs --help` to see available tools"
399
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }}
400
+ with:
401
+ script: |
402
+ const path = require('path');
403
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
404
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
405
+ setupGlobals(core, github, context, exec, io, getOctokit);
406
+
407
+ const substitutePlaceholders = require(path.join(actionsDir, 'substitute_placeholders.cjs'));
408
+
409
+ // Call the substitution function
410
+ return await substitutePlaceholders({
411
+ file: process.env.GH_AW_PROMPT,
412
+ substitutions: {
413
+ GH_AW_ENV_LIGHTHOUSE_SKILL: process.env.GH_AW_ENV_LIGHTHOUSE_SKILL,
414
+ GH_AW_EXPR_76DF9333: process.env.GH_AW_EXPR_76DF9333,
415
+ GH_AW_EXPR_77C1A4D2: process.env.GH_AW_EXPR_77C1A4D2,
416
+ GH_AW_EXPR_79DC8BAA: process.env.GH_AW_EXPR_79DC8BAA,
417
+ GH_AW_EXPR_7C248226: process.env.GH_AW_EXPR_7C248226,
418
+ GH_AW_EXPR_C19C384F: process.env.GH_AW_EXPR_C19C384F,
419
+ GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,
420
+ GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,
421
+ GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,
422
+ GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,
423
+ GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST,
424
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED
425
+ }
426
+ });
427
+ - name: Validate prompt placeholders
428
+ env:
429
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
430
+ run: |
431
+ bash "${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh"
432
+ - name: Print prompt
433
+ env:
434
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
435
+ run: |
436
+ bash "${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh"
437
+ - name: Inventory installed skills
438
+ if: success() || failure()
439
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
440
+ env:
441
+ GH_AW_SKILL_DIR: ".github/skills"
442
+ with:
443
+ script: |
444
+ const path = require('path');
445
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
446
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
447
+ setupGlobals(core, github, context, exec, io, getOctokit);
448
+ const { main } = require(path.join(actionsDir, 'skill_inventory.cjs'));
449
+ await main();
450
+ - name: Upload info artifact
451
+ if: success() || failure()
452
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
453
+ with:
454
+ name: ${{ steps.artifact-prefix.outputs.prefix }}info
455
+ path: /tmp/gh-aw/aw_info.json
456
+ if-no-files-found: ignore
457
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
458
+ - name: Stage prompt files for artifact upload
459
+ run: |
460
+ mkdir -p /tmp/gh-aw/aw-prompts
461
+ cp -a "${RUNNER_TEMP}/gh-aw/aw-prompts/." /tmp/gh-aw/aw-prompts/
462
+ - name: Upload activation artifact
463
+ if: success() || failure()
464
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
465
+ with:
466
+ name: ${{ steps.artifact-prefix.outputs.prefix }}activation
467
+ include-hidden-files: true
468
+ path: |
469
+ /tmp/gh-aw/aw_info.json
470
+ /tmp/gh-aw/models.json
471
+ /tmp/gh-aw/aw-prompts/prompt.txt
472
+ /tmp/gh-aw/aw-prompts/system.txt
473
+ /tmp/gh-aw/aw-prompts/user.txt
474
+ /tmp/gh-aw/aw-prompts/prompt-template.txt
475
+ /tmp/gh-aw/aw-prompts/prompt-import-tree.json
476
+ /tmp/gh-aw/github_rate_limits.jsonl
477
+ /tmp/gh-aw/base
478
+ /tmp/gh-aw/.github/agents
479
+ /tmp/gh-aw/.github/skills
480
+ /tmp/gh-aw/skill_inventory.json
481
+ if-no-files-found: ignore
482
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '1' }}
483
+
484
+ agent:
485
+ name: agent
486
+ needs: activation
487
+ if: needs.activation.outputs.daily_ai_credits_exceeded != 'true'
488
+ runs-on:
489
+ - self-hosted
490
+ - linux
491
+ - lighthouse-sdlc
492
+ # Permissions for the agent job (workflow permissions default to none).
493
+ permissions:
494
+ contents: read
495
+ concurrency:
496
+ group: "gh-aw-copilot-lighthouse-sdlc-review"
497
+ queue: max
498
+ timeout-minutes: 60
499
+ env:
500
+ DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
501
+ GH_AW_ASSETS_ALLOWED_EXTS: ""
502
+ GH_AW_ASSETS_BRANCH: ""
503
+ GH_AW_ASSETS_MAX_SIZE_KB: 0
504
+ GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
505
+ GH_AW_PR_HEAD_BASE_BRANCH: ""
506
+ GH_AW_PR_HEAD_BASE_PR_NUMBER: ""
507
+ GH_AW_PR_HEAD_BASE_REF: ""
508
+ GH_AW_PR_HEAD_BASE_REPO: ""
509
+ GH_AW_PR_HEAD_BASE_SHA: ""
510
+ GH_AW_PR_HEAD_REPO: ""
511
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
512
+ GH_AW_TARGET_REPO_SLUG: ""
513
+ GH_AW_WORKFLOW_ID_SANITIZED: lighthousesdlcreview
514
+ outputs:
515
+ agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
516
+ ai_credits_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.ai_credits_rate_limit_error || 'false' }}
517
+ aic: ${{ steps.parse-token-usage.outputs.aic }}
518
+ ambient_context: ${{ steps.parse-token-usage.outputs.ambient_context }}
519
+ artifact_prefix: ${{ needs.activation.outputs.artifact_prefix }}
520
+ checkout_pr_invalidated: ${{ steps.checkout-pr.outputs.checkout_pr_invalidated || 'false' }}
521
+ checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
522
+ has_patch: ${{ steps.collect_output.outputs.has_patch }}
523
+ http_400_response_error: ${{ steps.detect-agent-errors.outputs.http_400_response_error || 'false' }}
524
+ inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
525
+ invocation_cap_exceeded: ${{ steps.detect-agent-errors.outputs.invocation_cap_exceeded || 'false' }}
526
+ max_cache_misses_exceeded: ${{ steps.detect-agent-errors.outputs.max_cache_misses_exceeded || 'false' }}
527
+ mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
528
+ missing_model_pricing_error: ${{ steps.detect-agent-errors.outputs.missing_model_pricing_error || 'false' }}
529
+ missing_model_pricing_model_name: ${{ steps.detect-agent-errors.outputs.missing_model_pricing_model_name || '' }}
530
+ model: ${{ needs.activation.outputs.model }}
531
+ model_endpoint_mismatch_error: ${{ steps.detect-agent-errors.outputs.model_endpoint_mismatch_error || 'false' }}
532
+ model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
533
+ output: ${{ steps.collect_output.outputs.output }}
534
+ output_types: ${{ steps.collect_output.outputs.output_types }}
535
+ setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
536
+ setup-span-id: ${{ steps.setup.outputs.span-id }}
537
+ setup-trace-id: ${{ steps.setup.outputs.trace-id }}
538
+ shell_expansion_guard_rejected: ${{ steps.detect-agent-errors.outputs.shell_expansion_guard_rejected || 'false' }}
539
+ unknown_model_ai_credits: ${{ steps.parse-mcp-gateway.outputs.unknown_model_ai_credits || 'false' }}
540
+ steps:
541
+ - name: Setup Scripts
542
+ id: setup
543
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
544
+ with:
545
+ destination: ${{ runner.temp }}/gh-aw/actions
546
+ job-name: ${{ github.job }}
547
+ trace-id: ${{ needs.activation.outputs.setup-trace-id }}
548
+ parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
549
+ env:
550
+ GH_AW_SETUP_WORKFLOW_NAME: "Lighthouse SDLC review"
551
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-review.lock.yml@${{ github.ref }}
552
+ GH_AW_INFO_VERSION: "1.0.101"
553
+ GH_AW_INFO_AWF_VERSION: "v0.28.70"
554
+ GH_AW_INFO_ENGINE_ID: "copilot"
555
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
556
+ - name: Set runtime paths
557
+ id: set-runtime-paths
558
+ env:
559
+ GH_AW_RUNNER_TOOL_CACHE: ${{ runner.tool_cache }}
560
+ run: | # zizmor: ignore[github-env] - runner.tool_cache is set by GitHub Actions, not user input.
561
+ if [ -z "${RUNNER_TOOL_CACHE:-}" ]; then
562
+ echo "RUNNER_TOOL_CACHE=${GH_AW_RUNNER_TOOL_CACHE}" >> "$GITHUB_ENV"
563
+ fi
564
+ {
565
+ echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl"
566
+ echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json"
567
+ echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json"
568
+ } >> "$GITHUB_OUTPUT"
569
+ - name: Mask OTLP telemetry headers
570
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh"
571
+ - name: Check OTLP telemetry configuration
572
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/check_otlp_default_credentials.sh"
573
+ - name: Checkout repository (gh-aw default)
574
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
575
+ with:
576
+ persist-credentials: false
577
+ fetch-depth: 0
578
+ - name: Initialize agent execution evidence
579
+ run: |
580
+ mkdir -p "/tmp/gh-aw"
581
+ evidence_tmp="/tmp/gh-aw/agent_execution.json.tmp"
582
+ printf '{"version":1,"component":"agent","run_id":%s,"run_attempt":%s,"state":"not_started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp"
583
+ mv "$evidence_tmp" "/tmp/gh-aw/agent_execution.json"
584
+ - name: Setup Node.js
585
+ uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
586
+ with:
587
+ node-version: '24'
588
+ package-manager-cache: false
589
+ - name: Create gh-aw temp directory
590
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh"
591
+ - name: Configure gh CLI for GitHub Enterprise
592
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh"
593
+ env:
594
+ GH_TOKEN: ${{ github.token }}
595
+ - name: Download activation artifact
596
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
597
+ with:
598
+ name: ${{ needs.activation.outputs.artifact_prefix }}activation
599
+ path: /tmp/gh-aw
600
+ - name: Install the locked consumer packages
601
+ run: npm ci --ignore-scripts
602
+ - name: Check the installed SDLC version
603
+ run: node node_modules/@juangcarmona/lighthouse-sdlc/src/installation.mjs
604
+ - env:
605
+ STAGE_INPUT: ${{ inputs.input }}
606
+ name: Materialize the host input
607
+ run: "set -euo pipefail\nmkdir -p /tmp/gh-aw/agent\nprintf '%s\\n' \"${STAGE_INPUT:-\"{}\"}\" > /tmp/gh-aw/agent/input.json\n"
608
+ shell: bash
609
+ - if: inputs.previous-stage != ''
610
+ name: Load the previous stage result
611
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
612
+ with:
613
+ name: lighthouse-sdlc-${{ inputs.run-id }}-${{ inputs.previous-stage }}
614
+ path: /tmp/gh-aw/agent/previous
615
+
616
+ - name: Configure Git credentials
617
+ env:
618
+ GITHUB_REPOSITORY: ${{ github.repository }}
619
+ GITHUB_SERVER_URL: ${{ github.server_url }}
620
+ GITHUB_TOKEN: ${{ github.token }}
621
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_git_credentials.sh"
622
+ - name: Checkout PR branch
623
+ id: checkout-pr
624
+ if: |
625
+ github.event.pull_request || github.event.issue.pull_request || github.event_name == 'workflow_dispatch'
626
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
627
+ env:
628
+ GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
629
+ with:
630
+ github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
631
+ script: |
632
+ const path = require('path');
633
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
634
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
635
+ setupGlobals(core, github, context, exec, io, getOctokit);
636
+ const { main } = require(path.join(actionsDir, 'checkout_pr_branch.cjs'));
637
+ await main();
638
+ - name: Install GitHub Copilot CLI
639
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.101 --checksums-sha256 018625eac68670d66ede904b9b82cdcd6ab8f87ba20e6e1fbdf0b62c8295d5be --prefer-toolcache
640
+ env:
641
+ GH_HOST: github.com
642
+ GH_AW_COPILOT_MIN_VERSION: 1.0.35
643
+ - name: Install AWF binary
644
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.28.70 --rootless
645
+ - name: Determine automatic lockdown mode for GitHub MCP Server
646
+ id: determine-automatic-lockdown
647
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
648
+ env:
649
+ GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
650
+ GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
651
+ with:
652
+ script: |
653
+ const path = require('path');
654
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
655
+ const determineAutomaticLockdown = require(path.join(actionsDir, 'determine_automatic_lockdown.cjs'));
656
+ await determineAutomaticLockdown(github, context, core);
657
+ - name: Restore agent config folders from base branch
658
+ if: steps.checkout-pr.outcome == 'success'
659
+ env:
660
+ GH_AW_AGENT_FOLDERS: ".agents .github"
661
+ GH_AW_AGENT_FILES: "AGENTS.md"
662
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
663
+ - name: Restore inline sub-agents from activation artifact
664
+ env:
665
+ GH_AW_SUB_AGENT_DIR: ".github/agents"
666
+ GH_AW_SUB_AGENT_EXT: ".agent.md"
667
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
668
+ - name: Restore inline skills from activation artifact
669
+ env:
670
+ GH_AW_SKILL_DIR: ".github/skills"
671
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
672
+ - name: Download container images
673
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.28.70@sha256:b15ab48cbbab02904eb9bbd359a398db59690eebbea1e6934d47ed2bb407dd34 ghcr.io/github/gh-aw-firewall/api-proxy:0.28.70@sha256:9ac8f9c7294e892c916de3da9d2588dfd8cd4931e5c39b00143266d7ed9fd52a ghcr.io/github/gh-aw-firewall/squid:0.28.70@sha256:b5bc53f4becfd96e926e63c83831f1b3c9512f713c83161d2b8c9b7204b3e917 ghcr.io/github/gh-aw-mcpg:v0.4.37@sha256:9c7f242f6dec2d7d7b55d4c9e07872d59b85377c6cb3de46c915a5d1ffb91442 ghcr.io/github/gh-aw-node@sha256:41835613992df88f51e923bad486f96dfb2e6cda29f13e217df41833284ae382 ghcr.io/github/github-mcp-server:v2.0.2@sha256:ffced0d76e77428532a2ced185516992d77fd146d69eec2f244e6237d1a97796
674
+ - name: Prepare Safe Outputs Directories
675
+ run: |
676
+ mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
677
+ mkdir -p /tmp/gh-aw/safeoutputs
678
+ mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
679
+ - name: Generate Safe Outputs Config
680
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
681
+ env:
682
+ GH_AW_FILE_ROOT: "${{ runner.temp }}/gh-aw"
683
+ GH_AW_FILE_CONFIG: "{\"files\":[{\"path\":\"safeoutputs/config.json\",\"content_env\":\"GH_AW_SAFE_OUTPUTS_CONFIG\"}]}"
684
+ GH_AW_SAFE_OUTPUTS_CONFIG: "{\"create_report_incomplete_issue\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"false\"},\"report_incomplete\":{},\"report_missing_data\":{},\"report_missing_tool\":{}}"
685
+ with:
686
+ script: |
687
+ const path = require('path');
688
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
689
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
690
+ setupGlobals(core, github, context, exec, io, getOctokit);
691
+ const { main } = require(path.join(actionsDir, 'create_files.cjs'));
692
+ await main();
693
+ - name: Generate Safe Outputs Tools
694
+ env:
695
+ GH_AW_TOOLS_META_JSON: |
696
+ {
697
+ "description_suffixes": {},
698
+ "repo_params": {},
699
+ "dynamic_tools": []
700
+ }
701
+ GH_AW_VALIDATION_JSON: |
702
+ {
703
+ "noop": {
704
+ "defaultMax": 2,
705
+ "fields": {
706
+ "message": {
707
+ "required": true,
708
+ "type": "string",
709
+ "sanitize": true,
710
+ "maxLength": 65000
711
+ }
712
+ }
713
+ },
714
+ "report_incomplete": {
715
+ "defaultMax": 5,
716
+ "fields": {
717
+ "details": {
718
+ "type": "string",
719
+ "sanitize": true,
720
+ "maxLength": 65000
721
+ },
722
+ "reason": {
723
+ "required": true,
724
+ "type": "string",
725
+ "sanitize": true,
726
+ "maxLength": 1024
727
+ }
728
+ }
729
+ },
730
+ "report_missing_data": {
731
+ "defaultMax": 20,
732
+ "fields": {
733
+ "alternatives": {
734
+ "type": "string",
735
+ "sanitize": true,
736
+ "maxLength": 256
737
+ },
738
+ "context": {
739
+ "type": "string",
740
+ "sanitize": true,
741
+ "maxLength": 256
742
+ },
743
+ "data_type": {
744
+ "type": "string",
745
+ "sanitize": true,
746
+ "maxLength": 128
747
+ },
748
+ "reason": {
749
+ "type": "string",
750
+ "sanitize": true,
751
+ "maxLength": 256
752
+ }
753
+ }
754
+ },
755
+ "report_missing_tool": {
756
+ "defaultMax": 20,
757
+ "fields": {
758
+ "alternatives": {
759
+ "type": "string",
760
+ "sanitize": true,
761
+ "maxLength": 512
762
+ },
763
+ "reason": {
764
+ "required": true,
765
+ "type": "string",
766
+ "sanitize": true,
767
+ "maxLength": 256
768
+ },
769
+ "tool": {
770
+ "type": "string",
771
+ "sanitize": true,
772
+ "maxLength": 128
773
+ }
774
+ }
775
+ }
776
+ }
777
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
778
+ with:
779
+ script: |
780
+ const path = require('path');
781
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
782
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
783
+ setupGlobals(core, github, context, exec, io, getOctokit);
784
+ const { main } = require(path.join(actionsDir, 'generate_safe_outputs_tools.cjs'));
785
+ await main();
786
+ - name: Start MCP Gateway
787
+ id: start-mcp-gateway
788
+ env:
789
+ DEBUG: ${{ env.DEBUG || runner.debug == '1' && '*' || '' }}
790
+ GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST: ${{ vars.GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST || 'true' }}
791
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
792
+ GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_CONFIG_PATH }}
793
+ GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_TOOLS_PATH }}
794
+ GH_AW_SINK_VISIBILITY: ${{ steps.determine-automatic-lockdown.outputs.visibility }}
795
+ GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }}
796
+ GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }}
797
+ GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
798
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
799
+ run: |
800
+ set -eo pipefail
801
+ mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-config"
802
+ if [ -n "${GITHUB_EVENT_PATH:-}" ] && [ -r "${GITHUB_EVENT_PATH}" ]; then
803
+ GH_AW_SAFEOUTPUTS_EVENT_PATH="${RUNNER_TEMP}/gh-aw/safeoutputs/github_event.json"
804
+ cp "${GITHUB_EVENT_PATH}" "${GH_AW_SAFEOUTPUTS_EVENT_PATH}"
805
+ export GITHUB_EVENT_PATH="${GH_AW_SAFEOUTPUTS_EVENT_PATH}"
806
+ fi
807
+
808
+ # Export gateway environment variables for MCP config and gateway script
809
+ export MCP_GATEWAY_PORT="8080"
810
+ export MCP_GATEWAY_DOMAIN="awmg-mcpg"
811
+ export MCP_GATEWAY_HOST_DOMAIN="localhost"
812
+ MCP_GATEWAY_AGENT_ID=$(openssl rand -base64 45 | tr -d '/+=')
813
+ echo "::add-mask::${MCP_GATEWAY_AGENT_ID}"
814
+ export MCP_GATEWAY_AGENT_ID
815
+ export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads"
816
+ mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}"
817
+ export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288"
818
+ export MCP_GATEWAY_ALLOWED_MOUNT_ROOTS="${GITHUB_WORKSPACE}:rw,${RUNNER_TEMP}/gh-aw:ro,${RUNNER_TEMP}/gh-aw/safeoutputs:rw,/opt:ro,/tmp:rw,/usr/bin/gh:ro"
819
+ export GH_AW_PR_HEAD_BASE_BRANCH="${GH_AW_PR_HEAD_BASE_BRANCH:-}"
820
+ export GH_AW_PR_HEAD_BASE_SHA="${GH_AW_PR_HEAD_BASE_SHA:-}"
821
+ export GH_AW_PR_HEAD_BASE_REPO="${GH_AW_PR_HEAD_BASE_REPO:-}"
822
+ export GH_AW_PR_HEAD_BASE_PR_NUMBER="${GH_AW_PR_HEAD_BASE_PR_NUMBER:-}"
823
+ export GH_AW_PR_HEAD_BASE_REF="${GH_AW_PR_HEAD_BASE_REF:-}"
824
+ export GH_AW_PR_HEAD_REPO="${GH_AW_PR_HEAD_REPO:-}"
825
+ export GH_AW_TARGET_REPO_SLUG="${GH_AW_TARGET_REPO_SLUG:-}"
826
+ export GH_AW_ENGINE="copilot"
827
+ MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0')
828
+ MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0')
829
+ source "${RUNNER_TEMP}/gh-aw/actions/resolve_docker_socket_gid.sh"
830
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network bridge -p 127.0.0.1:'"${MCP_GATEWAY_PORT}"':'"${MCP_GATEWAY_PORT}"' --name awmg-mcpg --add-host host.docker.internal:host-gateway --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_AGENT_ID -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_TARGET_REPO_SLUG -e GH_AW_PR_HEAD_BASE_BRANCH -e GH_AW_PR_HEAD_BASE_SHA -e GH_AW_PR_HEAD_BASE_REPO -e GH_AW_PR_HEAD_BASE_PR_NUMBER -e GH_AW_PR_HEAD_BASE_REF -e GH_AW_PR_HEAD_REPO -e GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GH_AW_SINK_VISIBILITY -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e RUNNER_TEMP -e RUNNER_TOOL_CACHE -e MCP_GATEWAY_ALLOWED_MOUNT_ROOTS -e GITHUB_AW_OTEL_TRACE_ID -e GITHUB_AW_OTEL_PARENT_SPAN_ID -e OTEL_EXPORTER_OTLP_HEADERS -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:v0.4.37@sha256:9c7f242f6dec2d7d7b55d4c9e07872d59b85377c6cb3de46c915a5d1ffb91442'
831
+
832
+ mkdir -p "$HOME/.copilot"
833
+ GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
834
+ cat << GH_AW_MCP_CONFIG_3db6aaf67c51d953_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs"
835
+ {
836
+ "mcpServers": {
837
+ "github": {
838
+ "type": "stdio",
839
+ "container": "ghcr.io/github/github-mcp-server:v2.0.2",
840
+ "env": {
841
+ "GITHUB_FEATURES": "fields_param",
842
+ "GITHUB_HOST": "${GITHUB_SERVER_URL}",
843
+ "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_MCP_SERVER_TOKEN}",
844
+ "GITHUB_READ_ONLY": "1",
845
+ "GITHUB_TOOLSETS": "repos,issues,pull_requests"
846
+ },
847
+ "guard-policies": {
848
+ "allow-only": {
849
+ "min-integrity": "$GITHUB_MCP_GUARD_MIN_INTEGRITY",
850
+ "repos": "$GITHUB_MCP_GUARD_REPOS"
851
+ }
852
+ }
853
+ },
854
+ "safeoutputs": {
855
+ "type": "stdio",
856
+ "container": "ghcr.io/github/gh-aw-node@sha256:41835613992df88f51e923bad486f96dfb2e6cda29f13e217df41833284ae382",
857
+ "mounts": ["\${GITHUB_WORKSPACE}:\${GITHUB_WORKSPACE}:rw", "${RUNNER_TEMP}/gh-aw/safeoutputs:${RUNNER_TEMP}/gh-aw/safeoutputs:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"],
858
+ "args": ["-w", "\${GITHUB_WORKSPACE}"],
859
+ "entrypoint": "sh",
860
+ "entrypointArgs": ["-c", "sh ${RUNNER_TEMP}/gh-aw/safeoutputs/start_safe_outputs_mcp.sh"],
861
+ "env": {
862
+ "DEBUG": "\${DEBUG}",
863
+ "DEFAULT_BRANCH": "\${DEFAULT_BRANCH}",
864
+ "GH_AW_ASSETS_ALLOWED_EXTS": "\${GH_AW_ASSETS_ALLOWED_EXTS}",
865
+ "GH_AW_ASSETS_BRANCH": "\${GH_AW_ASSETS_BRANCH}",
866
+ "GH_AW_ASSETS_MAX_SIZE_KB": "\${GH_AW_ASSETS_MAX_SIZE_KB}",
867
+ "GH_AW_MCP_LOG_DIR": "\${GH_AW_MCP_LOG_DIR}",
868
+ "GH_AW_SAFE_OUTPUTS": "\${GH_AW_SAFE_OUTPUTS}",
869
+ "GH_AW_SAFE_OUTPUTS_CONFIG_PATH": "\${GH_AW_SAFE_OUTPUTS_CONFIG_PATH}",
870
+ "GH_AW_SAFE_OUTPUTS_TOOLS_PATH": "\${GH_AW_SAFE_OUTPUTS_TOOLS_PATH}",
871
+ "GH_AW_TARGET_REPO_SLUG": "\${GH_AW_TARGET_REPO_SLUG}",
872
+ "GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST": "\${GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST}",
873
+ "GH_AW_PR_HEAD_BASE_BRANCH": "\${GH_AW_PR_HEAD_BASE_BRANCH}",
874
+ "GH_AW_PR_HEAD_BASE_SHA": "\${GH_AW_PR_HEAD_BASE_SHA}",
875
+ "GH_AW_PR_HEAD_BASE_REPO": "\${GH_AW_PR_HEAD_BASE_REPO}",
876
+ "GH_AW_PR_HEAD_BASE_PR_NUMBER": "\${GH_AW_PR_HEAD_BASE_PR_NUMBER}",
877
+ "GH_AW_PR_HEAD_BASE_REF": "\${GH_AW_PR_HEAD_BASE_REF}",
878
+ "GH_AW_PR_HEAD_REPO": "\${GH_AW_PR_HEAD_REPO}",
879
+ "GITHUB_EVENT_NAME": "\${GITHUB_EVENT_NAME}",
880
+ "GITHUB_EVENT_PATH": "\${GITHUB_EVENT_PATH}",
881
+ "GITHUB_REPOSITORY": "\${GITHUB_REPOSITORY}",
882
+ "GITHUB_SHA": "\${GITHUB_SHA}",
883
+ "GITHUB_TOKEN": "\${GITHUB_TOKEN}",
884
+ "GITHUB_WORKSPACE": "\${GITHUB_WORKSPACE}",
885
+ "RUNNER_TEMP": "\${RUNNER_TEMP}"
886
+ },
887
+ "guard-policies": {
888
+ "write-sink": {
889
+ "accept": [
890
+ "*"
891
+ ],
892
+ "sink-visibility": "${GH_AW_SINK_VISIBILITY}"
893
+ }
894
+ }
895
+ }
896
+ },
897
+ "gateway": {
898
+ "port": $MCP_GATEWAY_PORT,
899
+ "domain": "${MCP_GATEWAY_DOMAIN}",
900
+ "agentId": "${MCP_GATEWAY_AGENT_ID}",
901
+ "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}",
902
+ "startupTimeout": 120,
903
+ "opentelemetry": {
904
+ "endpoint": "${OTEL_EXPORTER_OTLP_ENDPOINT}",
905
+ "traceId": "${GITHUB_AW_OTEL_TRACE_ID}",
906
+ "spanId": "${GITHUB_AW_OTEL_PARENT_SPAN_ID}"
907
+ }
908
+ }
909
+ }
910
+ GH_AW_MCP_CONFIG_3db6aaf67c51d953_EOF
911
+ - name: Mount MCP servers as CLIs
912
+ id: mount-mcp-clis
913
+ continue-on-error: true
914
+ env:
915
+ MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }}
916
+ MCP_GATEWAY_DOMAIN: ${{ steps.start-mcp-gateway.outputs.gateway-domain }}
917
+ MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
918
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
919
+ with:
920
+ script: |
921
+ const path = require('path');
922
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
923
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
924
+ setupGlobals(core, github, context, exec, io);
925
+ const { main } = require(path.join(actionsDir, 'mount_mcp_as_cli.cjs'));
926
+ await main();
927
+ - name: Clean credentials
928
+ run: |
929
+ bash "${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh"
930
+ bash "${RUNNER_TEMP}/gh-aw/actions/verify_git_credentials.sh"
931
+ - name: Audit pre-agent workspace
932
+ id: pre_agent_audit
933
+ continue-on-error: true
934
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/audit_pre_agent_workspace.sh"
935
+ - name: Log GitHub rate limits at agent start
936
+ continue-on-error: true
937
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
938
+ with:
939
+ github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
940
+ script: |
941
+ const path = require('path');
942
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
943
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
944
+ setupGlobals(core, github, context, exec, io, getOctokit);
945
+ const { fetchAndLogRateLimit } = require(path.join(actionsDir, 'github_rate_limit_logger.cjs'));
946
+ await fetchAndLogRateLimit(github, 'agent_start', true);
947
+ - name: Execute GitHub Copilot CLI
948
+ id: agentic_execution
949
+ # Copilot CLI tool arguments (sorted):
950
+ # --allow-tool github
951
+ # --allow-tool safeoutputs
952
+ # --allow-tool shell(cat)
953
+ # --allow-tool shell(date)
954
+ # --allow-tool shell(echo)
955
+ # --allow-tool shell(find)
956
+ # --allow-tool shell(git:*)
957
+ # --allow-tool shell(github:*)
958
+ # --allow-tool shell(grep)
959
+ # --allow-tool shell(head)
960
+ # --allow-tool shell(ls)
961
+ # --allow-tool shell(node)
962
+ # --allow-tool shell(npm:*)
963
+ # --allow-tool shell(npx:*)
964
+ # --allow-tool shell(printf)
965
+ # --allow-tool shell(pwd)
966
+ # --allow-tool shell(rg)
967
+ # --allow-tool shell(safeoutputs:*)
968
+ # --allow-tool shell(sort)
969
+ # --allow-tool shell(tail)
970
+ # --allow-tool shell(uniq)
971
+ # --allow-tool shell(wc)
972
+ # --allow-tool shell(yq)
973
+ # --allow-tool write
974
+ timeout-minutes: ${{ fromJSON(vars.GH_AW_DEFAULT_TIMEOUT_MINUTES || '20') }}
975
+ run: |
976
+ set -o pipefail
977
+ printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt
978
+ gh_aw_exit_code=0
979
+ trap 'gh_aw_exit_code=$?; mkdir -p /tmp/gh-aw >/dev/null 2>&1 || true; printf "%s" "$gh_aw_exit_code" > /tmp/gh-aw/agent_execution_exit_code.txt || true; rm -f "$HOME/.copilot/settings.json"; if [ "$gh_aw_exit_code" -ne 0 ]; then echo "::error::Agent execution exited with code $gh_aw_exit_code"; fi' EXIT
980
+ mkdir -p "$HOME/.copilot"
981
+ printf '%s' '{"builtInAgents":{"rubberDuck":false},"enabledFeatureFlags":{"EXTENSIONS":false}}' > "$HOME/.copilot/settings.json"
982
+ export XDG_CONFIG_HOME="$HOME"
983
+ export GH_AW_MCP_CONFIG="$HOME/.copilot/mcp-config.json"
984
+ GH_AW_COPILOT_SRC="$(command -v copilot 2>/dev/null || true)"
985
+ if [ -z "$GH_AW_COPILOT_SRC" ] || [ ! -x "$GH_AW_COPILOT_SRC" ]; then
986
+ echo "GitHub Copilot CLI executable not found on PATH after installation" >&2
987
+ exit 127
988
+ fi
989
+ GH_AW_COPILOT_BIN="${RUNNER_TEMP}/gh-aw/bin/copilot"
990
+ mkdir -p "${RUNNER_TEMP}/gh-aw/bin"
991
+ if [ "$GH_AW_COPILOT_SRC" != "$GH_AW_COPILOT_BIN" ]; then
992
+ cp "$GH_AW_COPILOT_SRC" "$GH_AW_COPILOT_BIN"
993
+ fi
994
+ chmod 755 "$GH_AW_COPILOT_BIN"
995
+
996
+ touch /tmp/gh-aw/agent-step-summary.md
997
+ GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
998
+ export GH_AW_NODE_BIN
999
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
1000
+ (umask 177 && touch /tmp/gh-aw/agent-stdio.log)
1001
+ GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-1000}"
1002
+ if [[ ! "$GH_AW_MAX_AI_CREDITS" =~ ^[0-9]+$ ]]; then
1003
+ GH_AW_MAX_AI_CREDITS="1000"
1004
+ fi
1005
+ if [[ "${GH_AW_ADMISSION_RESULT:-}" == "admitted" && -z "${GH_AW_ADMISSION_MAX_AI_CREDITS:-}" ]]; then
1006
+ echo "ERR_ADMISSION: Missing required runtime admission allowance." >&2
1007
+ exit 1
1008
+ fi
1009
+
1010
+ if [[ "${GH_AW_ADMISSION_RESULT:-}" == "admitted" && -n "${GH_AW_ADMISSION_MAX_AI_CREDITS:-}" ]]; then
1011
+ if [[ ! "$GH_AW_ADMISSION_MAX_AI_CREDITS" =~ ^[1-9][0-9]{0,9}$ ]] || (( GH_AW_ADMISSION_MAX_AI_CREDITS > 2147483647 )); then
1012
+ echo "ERR_ADMISSION: Invalid runtime admission allowance." >&2
1013
+ exit 1
1014
+ fi
1015
+ GH_AW_MAX_AI_CREDITS="$GH_AW_ADMISSION_MAX_AI_CREDITS"
1016
+ echo "Admission allowance applied (value withheld)."
1017
+ else
1018
+ echo "No component admission allowance; retaining existing budget policy (value withheld)."
1019
+ fi
1020
+ unset GH_AW_ADMISSION_RESULT GH_AW_ADMISSION_MAX_AI_CREDITS
1021
+ printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.28.70/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"json-schema.org\",\"json.schemastore.org\",\"keyserver.ubuntu.com\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"ppa.launchpad.net\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\"],\"isolation\":true,\"topologyAttach\":[\"awmg-mcpg\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-6\",\"gpt-5.4\",\"gpt-5.5\",\"gpt-5.6\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"auto\":[\"copilot/auto\",\"large\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"detection\":[\"small\"],\"evals\":[\"small\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-3.6-flash\":[\"copilot/gemini-3.6*flash*\",\"google/gemini-3.6*flash*\",\"gemini/gemini-3.6*flash*\"],\"gemini-3.7-flash\":[\"copilot/gemini-3.7*flash*\",\"google/gemini-3.7*flash*\",\"gemini/gemini-3.7*flash*\"],\"gemini-3.8-flash\":[\"copilot/gemini-3.8*flash*\",\"google/gemini-3.8*flash*\",\"gemini/gemini-3.8*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"gpt-6\":[\"copilot/gpt-6*\",\"openai/gpt-6*\"],\"grok\":[\"copilot/*grok*\",\"openai/*grok*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"sonnet\",\"gpt-6\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"raptor-mini\":[\"copilot/raptor*\",\"openai/raptor*\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-5*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\",\"anthropic/*sonnet-5*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.28.70,squid=sha256:b5bc53f4becfd96e926e63c83831f1b3c9512f713c83161d2b8c9b7204b3e917,agent=sha256:b15ab48cbbab02904eb9bbd359a398db59690eebbea1e6934d47ed2bb407dd34,api-proxy=sha256:9ac8f9c7294e892c916de3da9d2588dfd8cd4931e5c39b00143266d7ed9fd52a,cli-proxy=sha256:372ac51a5cccffdfe484f3f7be427d2d1c566e8ae550d55bd45d9fd166a154b4\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json"
1022
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
1023
+ export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json"
1024
+ GH_AW_DOCKER_HOST=""
1025
+ if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
1026
+ GH_AW_DOCKER_HOST="${DOCKER_HOST}"
1027
+ fi
1028
+ if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
1029
+ GH_AW_CHROOT_BINARIES_SOURCE_PATH="${RUNNER_TEMP}/gh-aw" GH_AW_CHROOT_IDENTITY_HOME="${RUNNER_TEMP}/gh-aw/home" node "${RUNNER_TEMP}/gh-aw/actions/patch_awf_chroot_config.cjs"
1030
+ fi
1031
+ GH_AW_TOOL_CACHE_MOUNT=""
1032
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"
1033
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
1034
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
1035
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
1036
+ fi
1037
+ fi
1038
+ # shellcheck disable=SC1003,SC2016,SC2086
1039
+ mkdir -p "/tmp/gh-aw"
1040
+ evidence_tmp="/tmp/gh-aw/agent_execution.json.tmp"
1041
+ printf '{"version":1,"component":"agent","run_id":%s,"run_attempt":%s,"state":"started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp"
1042
+ mv "$evidence_tmp" "/tmp/gh-aw/agent_execution.json"
1043
+ export GH_AW_AWF_EXECUTION_COMPONENT="agent"
1044
+ export GH_AW_AWF_EXECUTION_EVIDENCE_FILE="/tmp/gh-aw/agent_execution.json"
1045
+ GH_AW_AWF_ENGINE_NAME=copilot \
1046
+ GH_AW_AWF_HARNESS_MARKER='[copilot-harness]' \
1047
+ GH_AW_AWF_LOG_FILE=/tmp/gh-aw/agent-stdio.log \
1048
+ GH_AW_AWF_ATTEMPT_LOG_NAME=copilot \
1049
+ bash "${RUNNER_TEMP}/gh-aw/actions/run_awf_with_startup_retries.sh" -- \
1050
+ awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_ENGINE_STEP_TIMEOUT_MINUTES:+--agent-timeout "$GH_AW_ENGINE_STEP_TIMEOUT_MINUTES"} ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --env-all --exclude-env ACTIONS_ID_TOKEN_REQUEST_TOKEN --exclude-env ACTIONS_ID_TOKEN_REQUEST_URL --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GH_AW_OTLP_ALL_HEADERS --exclude-env GH_AW_OTLP_ENDPOINTS --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_AGENT_ID --exclude-env OTEL_EXPORTER_OTLP_ENDPOINT --exclude-env OTEL_EXPORTER_OTLP_HEADERS --mount /tmp/gh-aw:/tmp/gh-aw:rw --log-level info --session-state-dir /tmp/gh-aw/sandbox/agent/session-state --skip-pull \
1051
+ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; GH_AW_TOOL_BINS="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr "\n" ":")"; GH_AW_TOOL_BINS="${GH_AW_TOOL_BINS%:}"; export PATH="$PATH${GH_AW_TOOL_BINS:+:}$GH_AW_TOOL_BINS"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" "${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs" "${RUNNER_TEMP}/gh-aw/bin/copilot" --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(find)'\'' --allow-tool '\''shell(git:*)'\'' --allow-tool '\''shell(github:*)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(node)'\'' --allow-tool '\''shell(npm:*)'\'' --allow-tool '\''shell(npx:*)'\'' --allow-tool '\''shell(printf)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(rg)'\'' --allow-tool '\''shell(safeoutputs:*)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --deny-tool workflow --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt'
1052
+ env:
1053
+ AWF_REFLECT_ENABLED: 1
1054
+ COPILOT_AGENT_RUNNER_TYPE: STANDALONE
1055
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
1056
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
1057
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'auto' }}
1058
+ GH_AW_ADMISSION_MAX_AI_CREDITS: ${{ needs.activation.outputs.admission-max-ai-credits }}
1059
+ GH_AW_ADMISSION_RESULT: ${{ needs.activation.outputs.admission-result }}
1060
+ GH_AW_ENGINE_STEP_TIMEOUT_MINUTES: ${{ fromJSON(vars.GH_AW_DEFAULT_TIMEOUT_MINUTES || '20') }}
1061
+ GH_AW_LLM_PROVIDER: github
1062
+ GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
1063
+ GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }}
1064
+ GH_AW_PHASE: agent
1065
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
1066
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
1067
+ GH_AW_TIMEOUT_MINUTES: ${{ fromJSON(vars.GH_AW_DEFAULT_TIMEOUT_MINUTES || '20') }}
1068
+ GH_AW_VERSION: v0.93.2
1069
+ GITHUB_API_URL: ${{ github.api_url }}
1070
+ GITHUB_AW: true
1071
+ GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
1072
+ GITHUB_COPILOT_PROMPT_MODE_EXTENSIONS: false
1073
+ GITHUB_HEAD_REF: ${{ github.head_ref }}
1074
+ GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1075
+ GITHUB_REF_NAME: ${{ github.ref_name }}
1076
+ GITHUB_SERVER_URL: ${{ github.server_url }}
1077
+ GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
1078
+ GITHUB_WORKSPACE: ${{ github.workspace }}
1079
+ GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
1080
+ GIT_AUTHOR_NAME: github-actions[bot]
1081
+ GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
1082
+ GIT_COMMITTER_NAME: github-actions[bot]
1083
+ RUNNER_TEMP: ${{ runner.temp }}
1084
+ TRACEPARENT: ${{ env.GITHUB_AW_OTEL_TRACE_ID != '' && env.GITHUB_AW_OTEL_PARENT_SPAN_ID != '' && format('00-{0}-{1}-01', env.GITHUB_AW_OTEL_TRACE_ID, env.GITHUB_AW_OTEL_PARENT_SPAN_ID) || '' }}
1085
+ - name: Log GitHub rate limits at agent end
1086
+ if: always()
1087
+ continue-on-error: true
1088
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1089
+ with:
1090
+ github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1091
+ script: |
1092
+ const path = require('path');
1093
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1094
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1095
+ setupGlobals(core, github, context, exec, io, getOctokit);
1096
+ const { fetchAndLogRateLimit } = require(path.join(actionsDir, 'github_rate_limit_logger.cjs'));
1097
+ await fetchAndLogRateLimit(github, 'agent_end', true);
1098
+ - name: Detect agent errors
1099
+ if: always()
1100
+ id: detect-agent-errors
1101
+ continue-on-error: true
1102
+ env:
1103
+ GH_AW_AGENTIC_EXECUTION_OUTCOME: ${{ steps.agentic_execution.outcome }}
1104
+ GH_AW_ENGINE_STEP_TIMEOUT_MINUTES: ${{ fromJSON(vars.GH_AW_DEFAULT_TIMEOUT_MINUTES || '20') }}
1105
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1106
+ with:
1107
+ script: |
1108
+ const path = require('path');
1109
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1110
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1111
+ setupGlobals(core, github, context, exec, io, getOctokit);
1112
+ const { main } = require(path.join(actionsDir, 'detect_agent_errors.cjs'));
1113
+ await main();
1114
+ - name: Configure Git credentials
1115
+ env:
1116
+ GITHUB_REPOSITORY: ${{ github.repository }}
1117
+ GITHUB_SERVER_URL: ${{ github.server_url }}
1118
+ GITHUB_TOKEN: ${{ github.token }}
1119
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_git_credentials.sh"
1120
+ - name: Copy Copilot session state files to logs
1121
+ if: always()
1122
+ continue-on-error: true
1123
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/copy_copilot_session_state.sh"
1124
+ - name: Stop MCP Gateway
1125
+ if: always()
1126
+ continue-on-error: true
1127
+ env:
1128
+ MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
1129
+ MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }}
1130
+ GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}
1131
+ run: |
1132
+ bash "${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh" "$GATEWAY_PID"
1133
+ - name: Redact secrets in logs
1134
+ id: redact_secrets
1135
+ if: always()
1136
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1137
+ with:
1138
+ script: |
1139
+ const path = require('path');
1140
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1141
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1142
+ setupGlobals(core, github, context, exec, io, getOctokit);
1143
+ const { main } = require(path.join(actionsDir, 'redact_secrets.cjs'));
1144
+ await main();
1145
+ env:
1146
+ GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
1147
+ SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
1148
+ SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
1149
+ SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
1150
+ SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1151
+ - name: Append agent step summary
1152
+ if: always()
1153
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh"
1154
+ - name: Copy Safe Outputs
1155
+ if: always()
1156
+ env:
1157
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
1158
+ run: |
1159
+ mkdir -p /tmp/gh-aw
1160
+ cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true
1161
+ - name: Ingest agent output
1162
+ id: collect_output
1163
+ if: always()
1164
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1165
+ env:
1166
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
1167
+ GH_AW_ALLOWED_DOMAINS: "api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
1168
+ GITHUB_SERVER_URL: ${{ github.server_url }}
1169
+ GITHUB_API_URL: ${{ github.api_url }}
1170
+ with:
1171
+ script: |
1172
+ const path = require('path');
1173
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1174
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1175
+ setupGlobals(core, github, context, exec, io, getOctokit);
1176
+ const { main } = require(path.join(actionsDir, 'collect_ndjson_output.cjs'));
1177
+ await main();
1178
+ - name: Parse agent logs for step summary
1179
+ if: always()
1180
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1181
+ env:
1182
+ GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/
1183
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
1184
+ with:
1185
+ script: |
1186
+ const path = require('path');
1187
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1188
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1189
+ setupGlobals(core, github, context, exec, io, getOctokit);
1190
+ const { main } = require(path.join(actionsDir, 'parse_copilot_log.cjs'));
1191
+ await main();
1192
+ - name: Parse MCP Gateway logs for step summary
1193
+ if: always()
1194
+ id: parse-mcp-gateway
1195
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1196
+ with:
1197
+ script: |
1198
+ const path = require('path');
1199
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1200
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1201
+ setupGlobals(core, github, context, exec, io, getOctokit);
1202
+ const { main } = require(path.join(actionsDir, 'parse_mcp_gateway_log.cjs'));
1203
+ await main();
1204
+ - name: Print firewall logs
1205
+ if: always()
1206
+ continue-on-error: true
1207
+ env:
1208
+ AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs
1209
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/print_firewall_logs.sh" --rootless
1210
+ - name: Parse token usage for step summary
1211
+ if: always()
1212
+ id: parse-token-usage
1213
+ continue-on-error: true
1214
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1215
+ with:
1216
+ script: |
1217
+ const path = require('path');
1218
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1219
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1220
+ setupGlobals(core, github, context, exec, io, getOctokit);
1221
+ const { main } = require(path.join(actionsDir, 'parse_token_usage.cjs'));
1222
+ await main();
1223
+ - name: Print AWF reflect summary
1224
+ if: always()
1225
+ continue-on-error: true
1226
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1227
+ with:
1228
+ script: |
1229
+ const path = require('path');
1230
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1231
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1232
+ setupGlobals(core, github, context, exec, io, getOctokit);
1233
+ const { main } = require(path.join(actionsDir, 'awf_reflect_summary.cjs'));
1234
+ await main();
1235
+ - name: Generate observability summary
1236
+ if: always()
1237
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1238
+ with:
1239
+ script: |
1240
+ const path = require('path');
1241
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1242
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1243
+ setupGlobals(core, github, context, exec, io, getOctokit);
1244
+ const { main } = require(path.join(actionsDir, 'generate_observability_summary.cjs'));
1245
+ await main(core);
1246
+ - name: Write agent output placeholder if missing
1247
+ if: always()
1248
+ run: |
1249
+ if [ ! -f /tmp/gh-aw/agent_output.json ]; then
1250
+ echo '{"items":[]}' > /tmp/gh-aw/agent_output.json
1251
+ fi
1252
+ - if: always()
1253
+ name: Preserve the stage result
1254
+ run: |
1255
+ set -euo pipefail
1256
+ mkdir -p "$GITHUB_WORKSPACE/.lighthouse/gh-aw"
1257
+ result=/tmp/gh-aw/agent/stage-result.json
1258
+ if [ -f "$result" ]; then
1259
+ cp "$result" "$GITHUB_WORKSPACE/.lighthouse/gh-aw/stage-result.json"
1260
+ else
1261
+ echo "::error::The worker did not produce /tmp/gh-aw/agent/stage-result.json"
1262
+ exit 1
1263
+ fi
1264
+ shell: bash
1265
+ - env:
1266
+ EXPECTED_RUN_ID: ${{ inputs.run-id }}
1267
+ EXPECTED_STAGE: ${{ env.LIGHTHOUSE_STAGE }}
1268
+ RESULT_FILE: /tmp/gh-aw/agent/stage-result.json
1269
+ if: always()
1270
+ name: Require completion of the dispatched stage
1271
+ run: "set -euo pipefail\nnode node_modules/@juangcarmona/lighthouse-sdlc/src/sdlc.mjs stage-result --input \"$RESULT_FILE\" \\\n --require-complete --stage \"$EXPECTED_STAGE\" --run-id \"$EXPECTED_RUN_ID\" --format json\n"
1272
+ shell: bash
1273
+ - if: always()
1274
+ name: Upload stage evidence
1275
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1276
+ with:
1277
+ if-no-files-found: warn
1278
+ name: lighthouse-sdlc-${{ inputs.run-id }}-${{ env.LIGHTHOUSE_STAGE }}
1279
+ path: ${{ github.workspace }}/.lighthouse/gh-aw/stage-result.json
1280
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '14' }}
1281
+
1282
+ # Small dedicated copy of the agent output so safe-output processing
1283
+ # survives a failed or timed-out upload of the larger agent artifact
1284
+ - name: Upload agent output fallback artifact
1285
+ if: always() && steps.redact_secrets.outcome == 'success'
1286
+ continue-on-error: true
1287
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1288
+ with:
1289
+ name: ${{ needs.activation.outputs.artifact_prefix }}agent-output-fallback
1290
+ path: |
1291
+ /tmp/gh-aw/agent_output.json
1292
+ /tmp/gh-aw/safeoutputs.jsonl
1293
+ /tmp/gh-aw/agent_execution.json
1294
+ /tmp/gh-aw/agent_execution_exit_code.txt
1295
+ /tmp/gh-aw/agent_usage.jsonl
1296
+ /tmp/gh-aw/agent_usage.json
1297
+ /tmp/gh-aw/agent/model-endpoint-mismatch.json
1298
+ /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl
1299
+ /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/model-routing.jsonl
1300
+ /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl
1301
+ /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/model-routing.jsonl
1302
+ /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl
1303
+ /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/model-routing.jsonl
1304
+ /tmp/gh-aw/awf-resolved-config.json
1305
+ if-no-files-found: ignore
1306
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
1307
+ - name: Upload agent artifacts
1308
+ if: always() && steps.redact_secrets.outcome == 'success'
1309
+ continue-on-error: true
1310
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1311
+ with:
1312
+ name: ${{ needs.activation.outputs.artifact_prefix }}agent
1313
+ path: |
1314
+ /tmp/gh-aw/aw-prompts/prompt.txt
1315
+ /tmp/gh-aw/agent_execution.json
1316
+ /tmp/gh-aw/agent_execution_exit_code.txt
1317
+ /tmp/gh-aw/agent-session.jsonl
1318
+ /tmp/gh-aw/agent-errors.jsonl
1319
+ /tmp/gh-aw/aw-prompts/user.txt
1320
+ /tmp/gh-aw/aw-prompts/system.txt
1321
+ /tmp/gh-aw/skill_inventory.json
1322
+ /tmp/gh-aw/sandbox/agent/logs/
1323
+ /tmp/gh-aw/redacted-urls.log
1324
+ /tmp/gh-aw/mcp-logs/
1325
+ /tmp/gh-aw/agent_usage.json
1326
+ /tmp/gh-aw/runtime/aw_info.json
1327
+ /tmp/gh-aw/agent_usage.jsonl
1328
+ /tmp/gh-aw/agent/model-endpoint-mismatch.json
1329
+ /tmp/gh-aw/agent/model-resolution.json
1330
+ /tmp/gh-aw/agent-stdio.log
1331
+ /tmp/gh-aw/pre-agent-audit.txt
1332
+ /tmp/gh-aw/github_rate_limits.jsonl
1333
+ /tmp/gh-aw/otel.jsonl
1334
+ /tmp/gh-aw/otlp-export-errors.jsonl
1335
+ /tmp/gh-aw/safeoutputs.jsonl
1336
+ /tmp/gh-aw/agent_output.json
1337
+ /tmp/gh-aw/aw-*.patch
1338
+ /tmp/gh-aw/aw-*.bundle
1339
+ /tmp/gh-aw/awf-config.json
1340
+ /tmp/gh-aw/awf-resolved-config.json
1341
+ /tmp/gh-aw/sandbox/firewall/logs/
1342
+ /tmp/gh-aw/sandbox/firewall/audit/
1343
+ /tmp/gh-aw/sandbox/firewall/awf-reflect.json
1344
+ if-no-files-found: ignore
1345
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
1346
+
1347
+ conclusion:
1348
+ name: conclusion
1349
+ needs:
1350
+ - activation
1351
+ - agent
1352
+ - detection
1353
+ - safe_outputs
1354
+ if: >
1355
+ always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' ||
1356
+ needs.activation.outputs.oauth_token_check_failed == 'true' || needs.activation.outputs.stale_lock_file_failed == 'true' ||
1357
+ needs.activation.outputs.secret_verification_result == 'failed' || needs.activation.outputs.daily_ai_credits_exceeded == 'true' ||
1358
+ needs.activation.outputs.daily_ai_credits_guardrail_status == 'structural_error' || needs.activation.outputs.daily_ai_credits_guardrail_status == 'transient_error')
1359
+ runs-on: ubuntu-24.04
1360
+ # Permissions for the conclusion job (workflow permissions default to none).
1361
+ permissions:
1362
+ actions: read
1363
+ issues: write
1364
+ concurrency:
1365
+ group: "gh-aw-conclusion-lighthouse-sdlc-review"
1366
+ cancel-in-progress: false
1367
+ queue: max
1368
+ env:
1369
+ GH_AW_JOB_DISPLAY_NAMES: "{\"activation\":\"activation\",\"agent\":\"agent\",\"conclusion\":\"conclusion\",\"detection\":\"detection\",\"pre_activation\":\"pre_activation\",\"safe_outputs\":\"safe_outputs\"}"
1370
+ GH_AW_JOB_RESULTS: "{\"activation\":{\"result\":\"${{ needs.activation.result }}\"},\"agent\":{\"result\":\"${{ needs.agent.result }}\"},\"detection\":{\"result\":\"${{ needs.detection.result }}\"},\"safe_outputs\":{\"result\":\"${{ needs.safe_outputs.result }}\"}}"
1371
+ GH_AW_JOB_TIMING_ELIGIBLE: "{\"activation\":true,\"agent\":true,\"conclusion\":true,\"detection\":true,\"pre_activation\":true,\"safe_outputs\":true}"
1372
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
1373
+ outputs:
1374
+ incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }}
1375
+ noop_comment_body: ${{ steps.noop.outputs.noop_comment_body }}
1376
+ noop_message: ${{ steps.noop.outputs.noop_message }}
1377
+ tools_reported: ${{ steps.missing_tool.outputs.tools_reported }}
1378
+ total_count: ${{ steps.missing_tool.outputs.total_count }}
1379
+ steps:
1380
+ - name: Setup Scripts
1381
+ id: setup
1382
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
1383
+ with:
1384
+ destination: ${{ runner.temp }}/gh-aw/actions
1385
+ job-name: ${{ github.job }}
1386
+ trace-id: ${{ needs.activation.outputs.setup-trace-id }}
1387
+ parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
1388
+ env:
1389
+ GH_AW_SETUP_WORKFLOW_NAME: "Lighthouse SDLC review"
1390
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-review.lock.yml@${{ github.ref }}
1391
+ GH_AW_INFO_VERSION: "1.0.101"
1392
+ GH_AW_INFO_AWF_VERSION: "v0.28.70"
1393
+ GH_AW_INFO_ENGINE_ID: "copilot"
1394
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
1395
+ - name: Download agent output artifact
1396
+ id: download-agent-output
1397
+ continue-on-error: true
1398
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1399
+ with:
1400
+ pattern: "{${{ needs.activation.outputs.artifact_prefix }}agent,${{ needs.activation.outputs.artifact_prefix }}agent-output-fallback}"
1401
+ merge-multiple: true
1402
+ path: /tmp/gh-aw/
1403
+ - name: Setup agent output environment variable
1404
+ id: setup-agent-output-env
1405
+ if: steps.download-agent-output.outcome == 'success'
1406
+ run: |
1407
+ mkdir -p /tmp/gh-aw/
1408
+ find "/tmp/gh-aw/" -type f -print
1409
+ if [ -f "/tmp/gh-aw/agent_output.json" ]; then
1410
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
1411
+ fi
1412
+ - name: Restore runtime model metadata
1413
+ if: always()
1414
+ run: |
1415
+ if [ -f /tmp/gh-aw/runtime/aw_info.json ]; then cp /tmp/gh-aw/runtime/aw_info.json /tmp/gh-aw/aw_info.json; fi
1416
+ - name: Warn if threat detection produced no verdict
1417
+ if: always() && needs.detection.result != 'skipped' && (needs.detection.outputs.detection_reason == 'agent_failure' || needs.detection.outputs.detection_reason == 'parse_error' || needs.detection.outputs.detection_conclusion == '')
1418
+ run: echo "::warning::Threat detection produced no security verdict. Review the detection job logs before trusting the agent outputs."
1419
+ - name: Download detection artifact
1420
+ id: download-detection-artifact
1421
+ continue-on-error: true
1422
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1423
+ with:
1424
+ name: ${{ needs.activation.outputs.artifact_prefix }}detection
1425
+ path: /tmp/gh-aw/threat-detection/
1426
+ - name: Download Safe Outputs Items Manifest
1427
+ id: download-safe-outputs-manifest
1428
+ if: always()
1429
+ continue-on-error: true
1430
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1431
+ with:
1432
+ pattern: ${{ needs.activation.outputs.artifact_prefix }}safe-outputs-items
1433
+ merge-multiple: true
1434
+ path: /tmp/gh-aw/
1435
+ - name: Process no-op messages
1436
+ id: noop
1437
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1438
+ env:
1439
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1440
+ GH_AW_NOOP_MAX: "1"
1441
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC review"
1442
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-review.md"
1443
+ GH_AW_ENGINE_ID: "copilot"
1444
+ GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
1445
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
1446
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
1447
+ GH_AW_NOOP_REPORT_AS_ISSUE: "false"
1448
+ GH_AW_AIC: ${{ needs.agent.outputs.aic }}
1449
+ GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }}
1450
+ GH_AW_AMBIENT_CONTEXT: ${{ needs.agent.outputs.ambient_context }}
1451
+ GH_AW_WORKFLOW_ID: "lighthouse-sdlc-review"
1452
+ with:
1453
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1454
+ script: |
1455
+ const path = require('path');
1456
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1457
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1458
+ setupGlobals(core, github, context, exec, io, getOctokit);
1459
+ const { main } = require(path.join(actionsDir, 'handle_noop_message.cjs'));
1460
+ await main();
1461
+ - name: Log detection run
1462
+ id: detection_runs
1463
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1464
+ env:
1465
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1466
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC review"
1467
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-review.md"
1468
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
1469
+ GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
1470
+ GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
1471
+ with:
1472
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1473
+ script: |
1474
+ const path = require('path');
1475
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1476
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1477
+ setupGlobals(core, github, context, exec, io, getOctokit);
1478
+ const { main } = require(path.join(actionsDir, 'handle_detection_runs.cjs'));
1479
+ await main();
1480
+ - name: Record missing tool
1481
+ id: missing_tool
1482
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1483
+ env:
1484
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1485
+ GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
1486
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC review"
1487
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-review.md"
1488
+ GH_AW_ENGINE_ID: "copilot"
1489
+ GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
1490
+ with:
1491
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1492
+ script: |
1493
+ const path = require('path');
1494
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1495
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1496
+ setupGlobals(core, github, context, exec, io, getOctokit);
1497
+ const { main } = require(path.join(actionsDir, 'missing_tool.cjs'));
1498
+ await main();
1499
+ - name: Record incomplete
1500
+ id: report_incomplete
1501
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1502
+ env:
1503
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1504
+ GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
1505
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC review"
1506
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-review.md"
1507
+ GH_AW_ENGINE_ID: "copilot"
1508
+ GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
1509
+ with:
1510
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1511
+ script: |
1512
+ const path = require('path');
1513
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1514
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1515
+ setupGlobals(core, github, context, exec, io, getOctokit);
1516
+ const { main } = require(path.join(actionsDir, 'report_incomplete_handler.cjs'));
1517
+ await main();
1518
+ - name: Handle agent failure
1519
+ id: handle_agent_failure
1520
+ if: always()
1521
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1522
+ env:
1523
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1524
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC review"
1525
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-review.md"
1526
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
1527
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
1528
+ GH_AW_WORKFLOW_ID: "lighthouse-sdlc-review"
1529
+ GH_AW_ACTION_FAILURE_ISSUE_EXPIRES_HOURS: "0"
1530
+ GH_AW_ENGINE_ID: "copilot"
1531
+ GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }}
1532
+ GH_AW_ENGINE_SECRET_FAILURE_MESSAGE: "**Alternative**: If your organization has a Copilot subscription, you can avoid the need for a personal access token by adding a top-level `permissions` block to your workflow file. This enables Copilot inference through the org using the built-in GitHub Actions token.\n\n```yaml\npermissions:\n copilot-requests: write\n```\n\nSee: https://github.github.com/gh-aw/reference/engines/#github-copilot-default"
1533
+ GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
1534
+ GH_AW_CHECKOUT_PR_INVALIDATED: ${{ needs.agent.outputs.checkout_pr_invalidated }}
1535
+ GH_AW_AI_CREDITS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.ai_credits_rate_limit_error || 'false' }}
1536
+ GH_AW_UNKNOWN_MODEL_AI_CREDITS: ${{ needs.agent.outputs.unknown_model_ai_credits || 'false' }}
1537
+ GH_AW_AIC: ${{ needs.agent.outputs.aic }}
1538
+ GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }}
1539
+ GH_AW_DETECTION_JOB_RESULT: ${{ needs.detection.result }}
1540
+ GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
1541
+ GH_AW_DEFAULT_CHECKOUT_USES_TRIGGER_REF: "true"
1542
+ GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }}
1543
+ GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }}
1544
+ GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }}
1545
+ GH_AW_MODEL_NOT_SUPPORTED_ERROR: ${{ needs.agent.outputs.model_not_supported_error }}
1546
+ GH_AW_MODEL_ENDPOINT_MISMATCH_ERROR: ${{ needs.agent.outputs.model_endpoint_mismatch_error }}
1547
+ GH_AW_HTTP_400_RESPONSE_ERROR: ${{ needs.agent.outputs.http_400_response_error }}
1548
+ GH_AW_MAX_CACHE_MISSES_EXCEEDED: ${{ needs.agent.outputs.max_cache_misses_exceeded }}
1549
+ GH_AW_MISSING_MODEL_PRICING_ERROR: ${{ needs.agent.outputs.missing_model_pricing_error }}
1550
+ GH_AW_MISSING_MODEL_PRICING_MODEL_NAME: ${{ needs.agent.outputs.missing_model_pricing_model_name }}
1551
+ GH_AW_SHELL_EXPANSION_GUARD_REJECTED: ${{ needs.agent.outputs.shell_expansion_guard_rejected }}
1552
+ GH_AW_ENGINE_API_HOSTS: "api.enterprise.githubcopilot.com,api.githubcopilot.com,api.business.githubcopilot.com,api.individual.githubcopilot.com"
1553
+ GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }}
1554
+ GH_AW_OAUTH_TOKEN_CHECK_FAILED: ${{ needs.activation.outputs.oauth_token_check_failed }}
1555
+ GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }}
1556
+ GH_AW_DAILY_AI_CREDITS_EXCEEDED: ${{ needs.activation.outputs.daily_ai_credits_exceeded }}
1557
+ GH_AW_DAILY_AI_CREDITS_GUARDRAIL_STATUS: ${{ needs.activation.outputs.daily_ai_credits_guardrail_status }}
1558
+ GH_AW_DAILY_AI_CREDITS_GUARDRAIL_ERROR: ${{ needs.activation.outputs.daily_ai_credits_guardrail_error }}
1559
+ GH_AW_DAILY_AI_CREDITS_TOTAL: ${{ needs.activation.outputs.daily_ai_credits_total }}
1560
+ GH_AW_DAILY_AI_CREDITS_ESTIMATED: ${{ needs.activation.outputs.daily_ai_credits_estimated }}
1561
+ GH_AW_DAILY_AI_CREDITS_THRESHOLD: ${{ needs.activation.outputs.daily_ai_credits_threshold }}
1562
+ GH_AW_DAILY_AI_CREDITS_CONTINUE_ON_ERROR: "false"
1563
+ GH_AW_GROUP_REPORTS: "false"
1564
+ GH_AW_FAILURE_REPORT_AS_ISSUE: "false"
1565
+ GH_AW_MISSING_TOOL_REPORT_AS_FAILURE: "true"
1566
+ GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true"
1567
+ GH_AW_TIMEOUT_MINUTES: "${{ fromJSON(vars.GH_AW_DEFAULT_TIMEOUT_MINUTES || '20') }}"
1568
+ with:
1569
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1570
+ script: |
1571
+ const path = require('path');
1572
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1573
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1574
+ setupGlobals(core, github, context, exec, io, getOctokit);
1575
+ const { main } = require(path.join(actionsDir, 'handle_agent_failure.cjs'));
1576
+ await main();
1577
+ - name: Report failed jobs
1578
+ id: report_failed_jobs
1579
+ if: always()
1580
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1581
+ env:
1582
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1583
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC review"
1584
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-review.md"
1585
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
1586
+ GH_AW_REPORT_FAILED_JOBS: "true"
1587
+ with:
1588
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1589
+ script: |
1590
+ const path = require('path');
1591
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1592
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1593
+ setupGlobals(core, github, context, exec, io, getOctokit);
1594
+ const { main } = require(path.join(actionsDir, 'report_failed_jobs.cjs'));
1595
+ await main();
1596
+ - name: Collect usage artifact files
1597
+ if: always()
1598
+ continue-on-error: true
1599
+ env:
1600
+ GH_AW_DETECTION_JOB_RESULT: ${{ needs.detection.result }}
1601
+ GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
1602
+ GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
1603
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/collect_usage_artifact_files.sh"
1604
+ - name: Generate usage activity summary and unified session
1605
+ if: always()
1606
+ continue-on-error: true
1607
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1608
+ env:
1609
+ GH_AW_ADMISSION_RESULT: ${{ needs.activation.outputs.admission-result }}
1610
+ GH_AW_ADMISSION_MAX_AI_CREDITS: ${{ needs.activation.outputs.admission-max-ai-credits }}
1611
+ GH_AW_ADMISSION_MAX_AI_CREDITS_THREAT_DETECTION: ${{ needs.activation.outputs.admission-max-ai-credits-threat-detection }}
1612
+ GH_AW_ADMISSION_MAX_AI_CREDITS_EVALS: ${{ needs.activation.outputs.admission-max-ai-credits-evals }}
1613
+ GH_AW_GRADER_MANIFEST_0: '{"version":2,"graders":[]}'
1614
+ GH_AW_GRADER_MANIFEST_CHUNKS: '1'
1615
+ GH_AW_JOB_DURATIONS: ${{ steps.report_failed_jobs.outputs.job_durations }}
1616
+ GH_AW_DAILY_AI_CREDITS_GUARDRAIL_STATUS: ${{ needs.activation.outputs.daily_ai_credits_guardrail_status }}
1617
+ GH_AW_DAILY_AI_CREDITS_EXCEEDED: ${{ needs.activation.outputs.daily_ai_credits_exceeded }}
1618
+ GH_AW_DAILY_AI_CREDITS_TOTAL: ${{ needs.activation.outputs.daily_ai_credits_total }}
1619
+ GH_AW_DAILY_AI_CREDITS_ESTIMATED: ${{ needs.activation.outputs.daily_ai_credits_estimated }}
1620
+ GH_AW_DAILY_AI_CREDITS_THRESHOLD: ${{ needs.activation.outputs.daily_ai_credits_threshold }}
1621
+ with:
1622
+ script: |
1623
+ const path = require('path');
1624
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1625
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1626
+ setupGlobals(core, github, context, exec, io, getOctokit);
1627
+ const { main } = require(path.join(actionsDir, 'generate_usage_artifacts.cjs'));
1628
+ await main();
1629
+ - name: Upload usage artifact
1630
+ id: upload-usage-artifact
1631
+ if: always()
1632
+ continue-on-error: true
1633
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1634
+ with:
1635
+ name: ${{ needs.activation.outputs.artifact_prefix }}usage
1636
+ path: |
1637
+ /tmp/gh-aw/usage/aw_session.jsonl
1638
+ /tmp/gh-aw/usage/aw_info.json
1639
+ /tmp/gh-aw/usage/aw-info.jsonl
1640
+ /tmp/gh-aw/usage/agent_usage.json
1641
+ /tmp/gh-aw/usage/agent_usage.jsonl
1642
+ /tmp/gh-aw/usage/detection_usage.jsonl
1643
+ /tmp/gh-aw/usage/evals.jsonl
1644
+ /tmp/gh-aw/usage/graders/grader_manifest.json
1645
+ /tmp/gh-aw/usage/graders/grader_results.json
1646
+ /tmp/gh-aw/usage/github_rate_limits.jsonl
1647
+ /tmp/gh-aw/usage/agent/token_usage.jsonl
1648
+ /tmp/gh-aw/usage/agent/model-routing.jsonl
1649
+ /tmp/gh-aw/usage/agent/execution.json
1650
+ /tmp/gh-aw/usage/detection/token_usage.jsonl
1651
+ /tmp/gh-aw/usage/detection/execution.json
1652
+ /tmp/gh-aw/usage/detection/detection_result.json
1653
+ /tmp/gh-aw/usage/evals/token_usage.jsonl
1654
+ /tmp/gh-aw/usage/evals/execution.json
1655
+ /tmp/gh-aw/usage/experiment/state.jsonl
1656
+ /tmp/gh-aw/usage/experiment/state.json
1657
+ /tmp/gh-aw/usage/experiment/assignments.json
1658
+ /tmp/gh-aw/usage/activity/summary.json
1659
+ if-no-files-found: ignore
1660
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
1661
+ - name: Wait before retrying usage artifact upload
1662
+ if: always() && steps.upload-usage-artifact.outcome == 'failure'
1663
+ run: sleep 10
1664
+ - name: Retry upload usage artifact
1665
+ id: upload-usage-artifact-retry
1666
+ if: always() && steps.upload-usage-artifact.outcome == 'failure'
1667
+ continue-on-error: true
1668
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1669
+ with:
1670
+ name: ${{ needs.activation.outputs.artifact_prefix }}usage
1671
+ path: |
1672
+ /tmp/gh-aw/usage/aw_session.jsonl
1673
+ /tmp/gh-aw/usage/aw_info.json
1674
+ /tmp/gh-aw/usage/aw-info.jsonl
1675
+ /tmp/gh-aw/usage/agent_usage.json
1676
+ /tmp/gh-aw/usage/agent_usage.jsonl
1677
+ /tmp/gh-aw/usage/detection_usage.jsonl
1678
+ /tmp/gh-aw/usage/evals.jsonl
1679
+ /tmp/gh-aw/usage/graders/grader_manifest.json
1680
+ /tmp/gh-aw/usage/graders/grader_results.json
1681
+ /tmp/gh-aw/usage/github_rate_limits.jsonl
1682
+ /tmp/gh-aw/usage/agent/token_usage.jsonl
1683
+ /tmp/gh-aw/usage/agent/model-routing.jsonl
1684
+ /tmp/gh-aw/usage/agent/execution.json
1685
+ /tmp/gh-aw/usage/detection/token_usage.jsonl
1686
+ /tmp/gh-aw/usage/detection/execution.json
1687
+ /tmp/gh-aw/usage/detection/detection_result.json
1688
+ /tmp/gh-aw/usage/evals/token_usage.jsonl
1689
+ /tmp/gh-aw/usage/evals/execution.json
1690
+ /tmp/gh-aw/usage/experiment/state.jsonl
1691
+ /tmp/gh-aw/usage/experiment/state.json
1692
+ /tmp/gh-aw/usage/experiment/assignments.json
1693
+ /tmp/gh-aw/usage/activity/summary.json
1694
+ if-no-files-found: ignore
1695
+ overwrite: true
1696
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
1697
+
1698
+ detection:
1699
+ name: detection
1700
+ needs:
1701
+ - activation
1702
+ - agent
1703
+ if: always() && needs.agent.result != 'skipped'
1704
+ runs-on: ubuntu-latest
1705
+ # Permissions for the detection job (workflow permissions default to none).
1706
+ permissions:
1707
+ contents: read
1708
+ timeout-minutes: 10
1709
+ env:
1710
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
1711
+ outputs:
1712
+ aic: ${{ steps.parse_detection_token_usage.outputs.aic }}
1713
+ detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}
1714
+ detection_reason: ${{ steps.detection_conclusion.outputs.reason }}
1715
+ detection_success: ${{ steps.detection_conclusion.outputs.success }}
1716
+ run_detection: ${{ steps.detection_guard.outputs.run_detection }}
1717
+ steps:
1718
+ - name: Setup Scripts
1719
+ id: setup
1720
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
1721
+ with:
1722
+ destination: ${{ runner.temp }}/gh-aw/actions
1723
+ job-name: ${{ github.job }}
1724
+ trace-id: ${{ needs.activation.outputs.setup-trace-id }}
1725
+ parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
1726
+ env:
1727
+ GH_AW_SETUP_WORKFLOW_NAME: "Lighthouse SDLC review"
1728
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-review.lock.yml@${{ github.ref }}
1729
+ GH_AW_INFO_VERSION: "1.0.101"
1730
+ GH_AW_INFO_AWF_VERSION: "v0.28.70"
1731
+ GH_AW_INFO_ENGINE_ID: "copilot"
1732
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
1733
+ - name: Download activation artifact
1734
+ continue-on-error: true
1735
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1736
+ with:
1737
+ name: ${{ needs.activation.outputs.artifact_prefix }}activation
1738
+ path: /tmp/gh-aw
1739
+ - name: Download agent output artifact
1740
+ id: download-agent-output
1741
+ continue-on-error: true
1742
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1743
+ with:
1744
+ pattern: "{${{ needs.agent.outputs.artifact_prefix }}agent,${{ needs.agent.outputs.artifact_prefix }}agent-output-fallback}"
1745
+ merge-multiple: true
1746
+ path: /tmp/gh-aw/
1747
+ - name: Setup agent output environment variable
1748
+ id: setup-agent-output-env
1749
+ if: steps.download-agent-output.outcome == 'success'
1750
+ run: |
1751
+ mkdir -p /tmp/gh-aw/
1752
+ find "/tmp/gh-aw/" -type f -print
1753
+ if [ -f "/tmp/gh-aw/agent_output.json" ]; then
1754
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
1755
+ fi
1756
+ - name: Checkout repository for patch context
1757
+ if: needs.agent.outputs.has_patch == 'true'
1758
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
1759
+ with:
1760
+ persist-credentials: false
1761
+ # --- Threat Detection ---
1762
+ - name: Initialize detection execution evidence
1763
+ run: |
1764
+ mkdir -p "/tmp/gh-aw/threat-detection"
1765
+ evidence_tmp="/tmp/gh-aw/threat-detection/execution.json.tmp"
1766
+ printf '{"version":1,"component":"detection","run_id":%s,"run_attempt":%s,"state":"not_started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp"
1767
+ mv "$evidence_tmp" "/tmp/gh-aw/threat-detection/execution.json"
1768
+ - name: Clear inherited Copilot session state
1769
+ run: rm -rf /tmp/gh-aw/sandbox/agent/logs/copilot-session-state
1770
+ - name: Clean stale firewall files from agent artifact
1771
+ run: |
1772
+ rm -rf /tmp/gh-aw/sandbox/firewall/logs
1773
+ rm -rf /tmp/gh-aw/sandbox/firewall/audit
1774
+ - name: Download container images
1775
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.28.70@sha256:b15ab48cbbab02904eb9bbd359a398db59690eebbea1e6934d47ed2bb407dd34 ghcr.io/github/gh-aw-firewall/api-proxy:0.28.70@sha256:9ac8f9c7294e892c916de3da9d2588dfd8cd4931e5c39b00143266d7ed9fd52a ghcr.io/github/gh-aw-firewall/squid:0.28.70@sha256:b5bc53f4becfd96e926e63c83831f1b3c9512f713c83161d2b8c9b7204b3e917
1776
+ - name: Check if detection needed
1777
+ id: detection_guard
1778
+ if: always()
1779
+ env:
1780
+ OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }}
1781
+ HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
1782
+ run: |
1783
+ if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then
1784
+ echo "run_detection=true" >> "$GITHUB_OUTPUT"
1785
+ echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH"
1786
+ else
1787
+ echo "run_detection=false" >> "$GITHUB_OUTPUT"
1788
+ echo "Detection skipped: no agent outputs or patches to analyze"
1789
+ fi
1790
+ - name: Clear MCP Config for detection
1791
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
1792
+ run: |
1793
+ rm -f "${RUNNER_TEMP}/gh-aw/mcp-config/mcp-servers.json"
1794
+ rm -f "$HOME/.copilot/mcp-config.json"
1795
+ rm -f "$GITHUB_WORKSPACE/.gemini/settings.json"
1796
+ - name: Prepare threat detection files
1797
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
1798
+ run: |
1799
+ bash "${RUNNER_TEMP}/gh-aw/actions/prepare_threat_detection_files.sh"
1800
+ - name: Setup threat detection
1801
+ id: detection_setup
1802
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
1803
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1804
+ env:
1805
+ WORKFLOW_NAME: "Lighthouse SDLC review"
1806
+ WORKFLOW_DESCRIPTION: "Execute only the Lighthouse review stage and return its declared stage result."
1807
+ HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
1808
+ GH_AW_DETECTION_CONTINUE_ON_ERROR: "true"
1809
+ GH_AW_DETECTION_SKIP_PROMPT_SUMMARY: "true"
1810
+ with:
1811
+ script: |
1812
+ const path = require('path');
1813
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1814
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1815
+ setupGlobals(core, github, context, exec, io, getOctokit);
1816
+ const { main } = require(path.join(actionsDir, 'setup_threat_detection.cjs'));
1817
+ await main();
1818
+ - name: Ensure threat-detection directory and log
1819
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
1820
+ run: |
1821
+ mkdir -p /tmp/gh-aw/threat-detection
1822
+ touch /tmp/gh-aw/threat-detection/detection.log
1823
+ - name: Install AWF binary
1824
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.28.70 --rootless
1825
+ - name: Setup Node.js
1826
+ uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
1827
+ with:
1828
+ node-version: '24'
1829
+ package-manager-cache: false
1830
+ - name: Install GitHub Copilot CLI
1831
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.101 --checksums-sha256 018625eac68670d66ede904b9b82cdcd6ab8f87ba20e6e1fbdf0b62c8295d5be --prefer-toolcache
1832
+ env:
1833
+ GH_HOST: github.com
1834
+ GH_AW_COPILOT_MIN_VERSION: 1.0.35
1835
+ - name: Install threat-detect binary
1836
+ id: threat_detect_install
1837
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
1838
+ continue-on-error: true
1839
+ run: |
1840
+ bash "${RUNNER_TEMP}/gh-aw/actions/install_threat_detect_binary.sh" v0.5.2 --artifact-base-url https://github.com/github/gh-aw-threat-detection/releases/download --sha256-amd64 b4ecda6a8f1ee09913c40b58e5e9d3337d2173618d41b1bfdef9207e4e7959b9 --sha256-arm64 f6260a0f9ad72bcb67c7af19c4ce262ca34e2c3d5ccbf912832a8bd277200904
1841
+ - name: Execute threat detection with AWF
1842
+ id: detection_agentic_execution
1843
+ if: always() && steps.detection_guard.outputs.run_detection == 'true' && steps.detection_setup.outcome == 'success' && steps.detection_setup.outputs.ready == 'true' && steps.threat_detect_install.outcome == 'success'
1844
+ continue-on-error: true
1845
+ timeout-minutes: 10
1846
+ env:
1847
+ AWF_REFLECT_ENABLED: 1
1848
+ COPILOT_AGENT_RUNNER_TYPE: STANDALONE
1849
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
1850
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
1851
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'detection' }}
1852
+ GH_AW_ADMISSION_MAX_AI_CREDITS: ${{ needs.activation.outputs.admission-max-ai-credits-threat-detection }}
1853
+ GH_AW_ADMISSION_RESULT: ${{ needs.activation.outputs.admission-result }}
1854
+ GH_AW_HARNESS_MAX_RETRIES: 0
1855
+ GH_AW_LLM_PROVIDER: github
1856
+ GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_DETECTION_MAX_AI_CREDITS || '400' }}
1857
+ GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }}
1858
+ GH_AW_MODEL_FALLBACK: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'auto' }}
1859
+ GH_AW_PHASE: detection
1860
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
1861
+ GH_AW_TIMEOUT_MINUTES: 10
1862
+ GH_AW_VERSION: v0.93.2
1863
+ GITHUB_API_URL: ${{ github.api_url }}
1864
+ GITHUB_AW: true
1865
+ GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
1866
+ GITHUB_COPILOT_PROMPT_MODE_EXTENSIONS: false
1867
+ GITHUB_HEAD_REF: ${{ github.head_ref }}
1868
+ GITHUB_REF_NAME: ${{ github.ref_name }}
1869
+ GITHUB_SERVER_URL: ${{ github.server_url }}
1870
+ GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
1871
+ GITHUB_WORKSPACE: ${{ github.workspace }}
1872
+ GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
1873
+ GIT_AUTHOR_NAME: github-actions[bot]
1874
+ GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
1875
+ GIT_COMMITTER_NAME: github-actions[bot]
1876
+ RUNNER_TEMP: ${{ runner.temp }}
1877
+ TRACEPARENT: ${{ env.GITHUB_AW_OTEL_TRACE_ID != '' && env.GITHUB_AW_OTEL_PARENT_SPAN_ID != '' && format('00-{0}-{1}-01', env.GITHUB_AW_OTEL_TRACE_ID, env.GITHUB_AW_OTEL_PARENT_SPAN_ID) || '' }}
1878
+ WORKFLOW_NAME: "Lighthouse SDLC review"
1879
+ WORKFLOW_DESCRIPTION: "Execute only the Lighthouse review stage and return its declared stage result."
1880
+ HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
1881
+ GH_AW_DETECTION_CONTINUE_ON_ERROR: "true"
1882
+ run: |
1883
+ mkdir -p "/tmp/gh-aw/threat-detection"
1884
+ evidence_tmp="/tmp/gh-aw/threat-detection/execution.json.tmp"
1885
+ printf '{"version":1,"component":"detection","run_id":%s,"run_attempt":%s,"state":"started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp"
1886
+ mv "$evidence_tmp" "/tmp/gh-aw/threat-detection/execution.json"
1887
+ export GH_AW_AWF_EXECUTION_COMPONENT="detection"
1888
+ export GH_AW_AWF_EXECUTION_EVIDENCE_FILE="/tmp/gh-aw/threat-detection/execution.json"
1889
+ set -o pipefail
1890
+ printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt
1891
+ GH_AW_COPILOT_SRC="$(command -v copilot 2>/dev/null || true)"
1892
+ if [ -z "$GH_AW_COPILOT_SRC" ] || [ ! -x "$GH_AW_COPILOT_SRC" ]; then
1893
+ echo "GitHub Copilot CLI executable not found on PATH after installation" >&2
1894
+ exit 127
1895
+ fi
1896
+ GH_AW_COPILOT_BIN="${RUNNER_TEMP}/gh-aw/bin/copilot"
1897
+ mkdir -p "${RUNNER_TEMP}/gh-aw/bin"
1898
+ if [ "$GH_AW_COPILOT_SRC" != "$GH_AW_COPILOT_BIN" ]; then
1899
+ cp "$GH_AW_COPILOT_SRC" "$GH_AW_COPILOT_BIN"
1900
+ fi
1901
+ chmod 755 "$GH_AW_COPILOT_BIN"
1902
+
1903
+ (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
1904
+ GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-400}"
1905
+ if [[ ! "$GH_AW_MAX_AI_CREDITS" =~ ^[0-9]+$ ]]; then
1906
+ GH_AW_MAX_AI_CREDITS="400"
1907
+ fi
1908
+
1909
+ if [[ "${GH_AW_ADMISSION_RESULT:-}" == "admitted" && -n "${GH_AW_ADMISSION_MAX_AI_CREDITS:-}" ]]; then
1910
+ if [[ ! "$GH_AW_ADMISSION_MAX_AI_CREDITS" =~ ^[1-9][0-9]{0,9}$ ]] || (( GH_AW_ADMISSION_MAX_AI_CREDITS > 2147483647 )); then
1911
+ echo "ERR_ADMISSION: Invalid runtime admission allowance." >&2
1912
+ exit 1
1913
+ fi
1914
+ GH_AW_MAX_AI_CREDITS="$GH_AW_ADMISSION_MAX_AI_CREDITS"
1915
+ echo "Admission allowance applied (value withheld)."
1916
+ else
1917
+ echo "No component admission allowance; retaining existing budget policy (value withheld)."
1918
+ fi
1919
+ unset GH_AW_ADMISSION_RESULT GH_AW_ADMISSION_MAX_AI_CREDITS
1920
+ printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.28.70/awf-config.schema.json\",\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-6\",\"gpt-5.4\",\"gpt-5.5\",\"gpt-5.6\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"auto\":[\"copilot/auto\",\"large\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"detection\":[\"small\"],\"evals\":[\"small\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-3.6-flash\":[\"copilot/gemini-3.6*flash*\",\"google/gemini-3.6*flash*\",\"gemini/gemini-3.6*flash*\"],\"gemini-3.7-flash\":[\"copilot/gemini-3.7*flash*\",\"google/gemini-3.7*flash*\",\"gemini/gemini-3.7*flash*\"],\"gemini-3.8-flash\":[\"copilot/gemini-3.8*flash*\",\"google/gemini-3.8*flash*\",\"gemini/gemini-3.8*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"gpt-6\":[\"copilot/gpt-6*\",\"openai/gpt-6*\"],\"grok\":[\"copilot/*grok*\",\"openai/*grok*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"sonnet\",\"gpt-6\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"raptor-mini\":[\"copilot/raptor*\",\"openai/raptor*\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-5*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\",\"anthropic/*sonnet-5*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.28.70,squid=sha256:b5bc53f4becfd96e926e63c83831f1b3c9512f713c83161d2b8c9b7204b3e917,agent=sha256:b15ab48cbbab02904eb9bbd359a398db59690eebbea1e6934d47ed2bb407dd34,api-proxy=sha256:9ac8f9c7294e892c916de3da9d2588dfd8cd4931e5c39b00143266d7ed9fd52a,cli-proxy=sha256:372ac51a5cccffdfe484f3f7be427d2d1c566e8ae550d55bd45d9fd166a154b4\",\"agentTimeout\":10},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json"
1921
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
1922
+ export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json"
1923
+ GH_AW_DOCKER_HOST=""
1924
+ if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
1925
+ GH_AW_DOCKER_HOST="${DOCKER_HOST}"
1926
+ fi
1927
+ if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
1928
+ _GH_AW_CHROOT_JSON=$(jq -c --arg src "${RUNNER_TEMP}/gh-aw" --arg user "$(id -un)" --argjson uid "$(id -u)" --argjson gid "$(id -g)" --arg home "${RUNNER_TEMP}/gh-aw/home" '.chroot={"binariesSourcePath":$src,"identity":{"user":$user,"uid":$uid,"gid":$gid,"home":$home}}' "${RUNNER_TEMP}/gh-aw/awf-config.json") || { echo "chroot config patch failed" >&2; exit 1; }
1929
+ printf '%s\n' "$_GH_AW_CHROOT_JSON" > "${RUNNER_TEMP}/gh-aw/awf-config.json"
1930
+ fi
1931
+ GH_AW_TOOL_CACHE_MOUNT=""
1932
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"
1933
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
1934
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
1935
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
1936
+ fi
1937
+ fi
1938
+ # shellcheck disable=SC1003,SC2016,SC2086
1939
+ awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --env-all --exclude-env ACTIONS_ID_TOKEN_REQUEST_TOKEN --exclude-env ACTIONS_ID_TOKEN_REQUEST_URL --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GH_AW_OTLP_ALL_HEADERS --exclude-env GH_AW_OTLP_ENDPOINTS --exclude-env OTEL_EXPORTER_OTLP_ENDPOINT --exclude-env OTEL_EXPORTER_OTLP_HEADERS --mount /tmp/gh-aw:/tmp/gh-aw:rw --mount /tmp/gh-aw/threat-detection:/tmp/gh-aw/threat-detection:rw --log-level info --session-state-dir /tmp/gh-aw/sandbox/agent/session-state --skip-pull \
1940
+ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; GH_AW_TOOL_BINS="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr "\n" ":")"; GH_AW_TOOL_BINS="${GH_AW_TOOL_BINS%:}"; export PATH="$PATH${GH_AW_TOOL_BINS:+:}$GH_AW_TOOL_BINS"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && threat-detect --engine copilot --output /tmp/gh-aw/threat-detection/detection_result.json /tmp/gh-aw/threat-detection' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
1941
+ - name: Copy detection firewall logs
1942
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
1943
+ continue-on-error: true
1944
+ run: |
1945
+ mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall
1946
+ if [ -d /tmp/gh-aw/sandbox/firewall/logs ]; then mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall/logs && cp -r /tmp/gh-aw/sandbox/firewall/logs/. /tmp/gh-aw/threat-detection/sandbox/firewall/logs/; fi
1947
+ if [ -d /tmp/gh-aw/sandbox/firewall/audit ]; then mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall/audit && cp -r /tmp/gh-aw/sandbox/firewall/audit/. /tmp/gh-aw/threat-detection/sandbox/firewall/audit/; fi
1948
+ - name: Redact secrets in detection logs
1949
+ id: redact_detection_logs
1950
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
1951
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1952
+ env:
1953
+ GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_DEFAULT_OTLP_ENDPOINT,GH_AW_DEFAULT_OTLP_HEADERS'
1954
+ SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
1955
+ SECRET_GH_AW_DEFAULT_OTLP_ENDPOINT: ${{ secrets.GH_AW_DEFAULT_OTLP_ENDPOINT }}
1956
+ SECRET_GH_AW_DEFAULT_OTLP_HEADERS: ${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }}
1957
+ with:
1958
+ script: |
1959
+ const path = require('path');
1960
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1961
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1962
+ setupGlobals(core, github, context, exec, io, getOctokit);
1963
+ const { main } = require(path.join(actionsDir, 'redact_secrets.cjs'));
1964
+ const { persistDetectionMasks } = require(path.join(actionsDir, 'detection_mask_state.cjs'));
1965
+ await main({ additionalDirectories: ["/tmp/gh-aw/threat-detection/sandbox/firewall"], persistDetectionMasks });
1966
+ - name: Parse threat detection token usage for step summary
1967
+ id: parse_detection_token_usage
1968
+ if: always() && steps.detection_guard.outputs.run_detection == 'true' && steps.redact_detection_logs.outcome == 'success'
1969
+ continue-on-error: true
1970
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1971
+ env:
1972
+ GH_AW_TOKEN_USAGE_SUMMARY_TITLE: Threat Detection Token Usage
1973
+ GH_AW_PHASE: detection
1974
+ GH_AW_AGENT_USAGE_PATH: /tmp/gh-aw/threat-detection/detection_usage.json
1975
+ GH_AW_AGENT_USAGE_JSONL_PATH: /tmp/gh-aw/threat-detection/detection_usage.jsonl
1976
+ GH_AW_WRITE_EMPTY_USAGE: "true"
1977
+ with:
1978
+ script: |
1979
+ const path = require('path');
1980
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1981
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1982
+ setupGlobals(core, github, context, exec, io, getOctokit);
1983
+ const { main } = require(path.join(actionsDir, 'parse_token_usage.cjs'));
1984
+ await main();
1985
+ - name: Redact secrets in detection artifacts
1986
+ id: redact_detection_artifacts
1987
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
1988
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1989
+ env:
1990
+ GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_DEFAULT_OTLP_ENDPOINT,GH_AW_DEFAULT_OTLP_HEADERS'
1991
+ SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
1992
+ SECRET_GH_AW_DEFAULT_OTLP_ENDPOINT: ${{ secrets.GH_AW_DEFAULT_OTLP_ENDPOINT }}
1993
+ SECRET_GH_AW_DEFAULT_OTLP_HEADERS: ${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }}
1994
+ with:
1995
+ script: |
1996
+ const path = require('path');
1997
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1998
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1999
+ setupGlobals(core, github, context, exec, io, getOctokit);
2000
+ const { main } = require(path.join(actionsDir, 'redact_secrets.cjs'));
2001
+ const { persistDetectionMasks } = require(path.join(actionsDir, 'detection_mask_state.cjs'));
2002
+ await main({ additionalDirectories: ["/tmp/gh-aw/threat-detection/sandbox/firewall"], persistDetectionMasks });
2003
+ - name: Render detection log
2004
+ if: always() && steps.detection_guard.outputs.run_detection == 'true' && steps.redact_detection_logs.outcome == 'success' && steps.redact_detection_artifacts.outcome == 'success'
2005
+ continue-on-error: true
2006
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
2007
+ with:
2008
+ script: |
2009
+ const path = require('path');
2010
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
2011
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
2012
+ setupGlobals(core, github, context, exec, io, getOctokit);
2013
+ const { main } = require(path.join(actionsDir, 'render_detection_log.cjs'));
2014
+ await main();
2015
+ - name: Upload threat detection artifact
2016
+ if: always() && steps.detection_guard.outputs.run_detection == 'true' && steps.redact_detection_logs.outcome == 'success' && steps.redact_detection_artifacts.outcome == 'success'
2017
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
2018
+ with:
2019
+ name: ${{ needs.agent.outputs.artifact_prefix }}detection
2020
+ path: |
2021
+ /tmp/gh-aw/threat-detection/detection_result.json
2022
+ /tmp/gh-aw/threat-detection/execution.json
2023
+ /tmp/gh-aw/threat-detection/detection_usage.json
2024
+ /tmp/gh-aw/threat-detection/detection_usage.jsonl
2025
+ /tmp/gh-aw/threat-detection/sandbox/firewall/logs/
2026
+ /tmp/gh-aw/threat-detection/sandbox/firewall/audit/
2027
+ if-no-files-found: ignore
2028
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
2029
+ - name: Conclude threat detection
2030
+ id: detection_conclusion
2031
+ if: always() && steps.detection_guard.outputs.run_detection == 'false' || (always() && steps.detection_guard.outputs.run_detection == 'true' && steps.redact_detection_logs.outcome == 'success' && steps.redact_detection_artifacts.outcome == 'success')
2032
+ continue-on-error: true
2033
+ env:
2034
+ RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}
2035
+ DETECTION_AGENTIC_EXECUTION_OUTCOME: ${{ steps.detection_agentic_execution.outcome }}
2036
+ THREAT_DETECT_INSTALL_OUTCOME: ${{ steps.threat_detect_install.outcome }}
2037
+ GH_AW_DETECTION_CONTINUE_ON_ERROR: "true"
2038
+ run: |
2039
+ bash "${RUNNER_TEMP}/gh-aw/actions/conclude_threat_detection.sh" /tmp/gh-aw/threat-detection/detection_result.json
2040
+ - name: Upload skipped detection execution evidence
2041
+ if: always() && steps.detection_guard.outputs.run_detection == 'false'
2042
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
2043
+ with:
2044
+ name: ${{ needs.agent.outputs.artifact_prefix }}detection
2045
+ path: /tmp/gh-aw/threat-detection/execution.json
2046
+ if-no-files-found: ignore
2047
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
2048
+
2049
+ pre_activation:
2050
+ name: pre_activation
2051
+ runs-on: ubuntu-24.04
2052
+ env:
2053
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
2054
+ outputs:
2055
+ activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }}
2056
+ matched_command: ''
2057
+ setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
2058
+ setup-span-id: ${{ steps.setup.outputs.span-id }}
2059
+ setup-trace-id: ${{ steps.setup.outputs.trace-id }}
2060
+ steps:
2061
+ - name: Setup Scripts
2062
+ id: setup
2063
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
2064
+ with:
2065
+ destination: ${{ runner.temp }}/gh-aw/actions
2066
+ job-name: ${{ github.job }}
2067
+ env:
2068
+ GH_AW_SETUP_WORKFLOW_NAME: "Lighthouse SDLC review"
2069
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-review.lock.yml@${{ github.ref }}
2070
+ GH_AW_INFO_VERSION: "1.0.101"
2071
+ GH_AW_INFO_AWF_VERSION: "v0.28.70"
2072
+ GH_AW_INFO_ENGINE_ID: "copilot"
2073
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
2074
+ - name: Check team membership for workflow
2075
+ id: check_membership
2076
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
2077
+ env:
2078
+ GH_AW_REQUIRED_ROLES: "admin,maintainer,write"
2079
+ with:
2080
+ github-token: ${{ secrets.GITHUB_TOKEN }}
2081
+ script: |
2082
+ const path = require('path');
2083
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
2084
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
2085
+ setupGlobals(core, github, context, exec, io, getOctokit);
2086
+ const { main } = require(path.join(actionsDir, 'check_membership.cjs'));
2087
+ await main();
2088
+
2089
+ safe_outputs:
2090
+ name: safe_outputs
2091
+ needs:
2092
+ - activation
2093
+ - agent
2094
+ - detection
2095
+ if: (!cancelled()) && needs.agent.result != 'skipped' && needs.detection.result == 'success'
2096
+ runs-on: ubuntu-24.04
2097
+ # Permissions for the safe_outputs job (workflow permissions default to none).
2098
+ permissions:
2099
+ issues: write
2100
+ pull-requests: read
2101
+ timeout-minutes: 45
2102
+ env:
2103
+ GH_AW_AGENT_AIC: ${{ needs.agent.outputs.aic }}
2104
+ GH_AW_AIC: ${{ needs.agent.outputs.aic }}
2105
+ GH_AW_AMBIENT_CONTEXT: ${{ needs.agent.outputs.ambient_context }}
2106
+ GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/lighthouse-sdlc-review"
2107
+ GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
2108
+ GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
2109
+ GH_AW_ENGINE_ID: "copilot"
2110
+ GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
2111
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
2112
+ GH_AW_RUN_DETECTION: ${{ needs.detection.outputs.run_detection }}
2113
+ GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }}
2114
+ GH_AW_WORKFLOW_ID: "lighthouse-sdlc-review"
2115
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC review"
2116
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-review.md"
2117
+ outputs:
2118
+ code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
2119
+ code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
2120
+ create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}
2121
+ create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}
2122
+ process_safe_outputs_items_applied: ${{ steps.process_safe_outputs.outputs.items_applied }}
2123
+ process_safe_outputs_items_cancelled: ${{ steps.process_safe_outputs.outputs.items_cancelled }}
2124
+ process_safe_outputs_items_deferred: ${{ steps.process_safe_outputs.outputs.items_deferred }}
2125
+ process_safe_outputs_items_failed: ${{ steps.process_safe_outputs.outputs.items_failed }}
2126
+ process_safe_outputs_items_skipped: ${{ steps.process_safe_outputs.outputs.items_skipped }}
2127
+ process_safe_outputs_items_succeeded: ${{ steps.process_safe_outputs.outputs.items_succeeded }}
2128
+ process_safe_outputs_items_warnings: ${{ steps.process_safe_outputs.outputs.items_warnings }}
2129
+ process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}
2130
+ process_safe_outputs_status: ${{ steps.process_safe_outputs.outputs.status }}
2131
+ steps:
2132
+ - name: Setup Scripts
2133
+ id: setup
2134
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
2135
+ with:
2136
+ destination: ${{ runner.temp }}/gh-aw/actions
2137
+ job-name: ${{ github.job }}
2138
+ trace-id: ${{ needs.activation.outputs.setup-trace-id }}
2139
+ parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
2140
+ env:
2141
+ GH_AW_SETUP_WORKFLOW_NAME: "Lighthouse SDLC review"
2142
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-review.lock.yml@${{ github.ref }}
2143
+ GH_AW_INFO_VERSION: "1.0.101"
2144
+ GH_AW_INFO_AWF_VERSION: "v0.28.70"
2145
+ GH_AW_INFO_ENGINE_ID: "copilot"
2146
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
2147
+ - name: Mask OTLP telemetry headers
2148
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh"
2149
+ - name: Download agent output artifact
2150
+ id: download-agent-output
2151
+ continue-on-error: true
2152
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
2153
+ with:
2154
+ pattern: "{${{ needs.activation.outputs.artifact_prefix }}agent,${{ needs.activation.outputs.artifact_prefix }}agent-output-fallback}"
2155
+ merge-multiple: true
2156
+ path: /tmp/gh-aw/
2157
+ - name: Setup agent output environment variable
2158
+ id: setup-agent-output-env
2159
+ if: steps.download-agent-output.outcome == 'success'
2160
+ run: |
2161
+ mkdir -p /tmp/gh-aw/
2162
+ find "/tmp/gh-aw/" -type f -print
2163
+ if [ -f "/tmp/gh-aw/agent_output.json" ]; then
2164
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
2165
+ fi
2166
+ - name: Configure GH_HOST for enterprise compatibility
2167
+ id: ghes-host-config
2168
+ shell: bash
2169
+ run: | # zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input.
2170
+ # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
2171
+ # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
2172
+ GH_HOST="${GITHUB_SERVER_URL#https://}"
2173
+ GH_HOST="${GH_HOST#http://}"
2174
+ echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
2175
+ - name: Process Safe Outputs
2176
+ id: process_safe_outputs
2177
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
2178
+ env:
2179
+ GH_AW_JOB_CHECK_RUN_ID: ${{ job.check_run_id }}
2180
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
2181
+ GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
2182
+ GH_AW_MENTIONS_GITHUB_TOKEN: ${{ github.token }}
2183
+ GH_AW_ALLOWED_DOMAINS: "api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
2184
+ GITHUB_SERVER_URL: ${{ github.server_url }}
2185
+ GITHUB_API_URL: ${{ github.api_url }}
2186
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_report_incomplete_issue\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"false\"},\"report_incomplete\":{},\"report_missing_data\":{},\"report_missing_tool\":{}}"
2187
+ GH_AW_GITHUB_TOKEN_SOURCE: ${{ secrets.GH_AW_GITHUB_TOKEN != '' && 'pat' || 'github_actions' }}
2188
+ with:
2189
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
2190
+ script: |
2191
+ const path = require('path');
2192
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
2193
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
2194
+ setupGlobals(core, github, context, exec, io, getOctokit, process.env.GH_AW_GITHUB_TOKEN_SOURCE);
2195
+ const { main } = require(path.join(actionsDir, 'process_safe_outputs.cjs'));
2196
+ await main();
2197
+ - name: Upload Safe Outputs Items
2198
+ if: always()
2199
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
2200
+ with:
2201
+ name: ${{ needs.activation.outputs.artifact_prefix }}safe-outputs-items
2202
+ path: |
2203
+ /tmp/gh-aw/safe-output-items.jsonl
2204
+ /tmp/gh-aw/temporary-id-map.json
2205
+ /tmp/gh-aw/safe-output-errors.json
2206
+ if-no-files-found: ignore
2207
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}