@juangcarmona/lighthouse-sdlc 0.15.2 → 0.16.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,1838 @@
1
+ # gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5530e3e2ad741de623b5e1f5c7fb9a5b5bdaf1893968dbc9da17ca6cbdd91e21","body_hash":"900316ff8535f6f9b38fea05138e4e8aa8ed64b3d4844ebad51810faf4bddea5","compiler_version":"v0.93.2","agent_id":"copilot","engine_versions":{"copilot":"1.0.101"},"agent_image_runner":"[\"self-hosted\",\"linux\",\"lighthouse-workflow\"]"}
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/checkout","sha":"fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09","version":"v5"},{"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/setup-node","sha":"a0853c24544627f65ddf259abe73b1d18a591444","version":"v5"},{"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_me","get_pull_request","get_pull_request_comments","get_pull_request_diff","get_pull_request_files","get_pull_request_review_comments","get_pull_request_reviews","get_pull_request_status","get_release_by_tag","get_tag","issue_read","list_branches","list_commits","list_issue_types","list_issues","list_pull_requests","list_releases","list_starred_repositories","list_tags","pull_request_read","search_code","search_issues","search_pull_requests","search_repositories"]},{"name":"safeoutputs","tools":["noop","report_missing_data","report_missing_tool"]}],"threat_detection":{"mode":"disabled"},"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
+ # ___ _ _
6
+ # / _ \ | | (_)
7
+ # | |_| | __ _ ___ _ __ | |_ _ ___
8
+ # | _ |/ _` |/ _ \ '_ \| __| |/ __|
9
+ # | | | | (_| | __/ | | | |_| | (__
10
+ # \_| |_/\__, |\___|_| |_|\__|_|\___|
11
+ # __/ |
12
+ # _ _ |___/
13
+ # | | | | / _| |
14
+ # | | | | ___ _ __ _ __| |_| | _____ ____
15
+ # | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___|
16
+ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
17
+ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
18
+ #
19
+ #
20
+ # To update this file, edit the corresponding .md file and run:
21
+ # gh aw compile
22
+ # Not all edits will cause changes to this file.
23
+ #
24
+ # For more information: https://github.github.com/gh-aw/introduction/overview/
25
+ #
26
+ # Recheck an explicit owner decision, apply the provider delta without GitHub credentials, and publish its verified result.
27
+ #
28
+ # Frontmatter env variables:
29
+ # - LIGHTHOUSE_DISPATCH_REQUIRED: (main workflow)
30
+ # - LIGHTHOUSE_PRODUCT_CHANGE_ENABLED: (main workflow)
31
+ # - LIGHTHOUSE_STAGE: (main workflow)
32
+ # - LIGHTHOUSE_WORKER: (main workflow)
33
+ #
34
+ # Secrets used:
35
+ # - COPILOT_GITHUB_TOKEN
36
+ # - GH_AW_DEFAULT_OTLP_ENDPOINT
37
+ # - GH_AW_DEFAULT_OTLP_HEADERS
38
+ # - GH_AW_GITHUB_MCP_SERVER_TOKEN
39
+ # - GH_AW_GITHUB_TOKEN
40
+ # - GITHUB_TOKEN
41
+ #
42
+ # Custom actions used:
43
+ # - actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
44
+ # - actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
45
+ # - actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
46
+ # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
47
+ # - actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
48
+ # - actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
49
+ # - actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
50
+ # - github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
51
+ #
52
+ # Container images used:
53
+ # - ghcr.io/github/gh-aw-firewall/agent:0.28.70@sha256:b15ab48cbbab02904eb9bbd359a398db59690eebbea1e6934d47ed2bb407dd34
54
+ # - ghcr.io/github/gh-aw-firewall/api-proxy:0.28.70@sha256:9ac8f9c7294e892c916de3da9d2588dfd8cd4931e5c39b00143266d7ed9fd52a
55
+ # - ghcr.io/github/gh-aw-firewall/squid:0.28.70@sha256:b5bc53f4becfd96e926e63c83831f1b3c9512f713c83161d2b8c9b7204b3e917
56
+ # - ghcr.io/github/gh-aw-mcpg:v0.4.37@sha256:9c7f242f6dec2d7d7b55d4c9e07872d59b85377c6cb3de46c915a5d1ffb91442
57
+ # - ghcr.io/github/gh-aw-node@sha256:41835613992df88f51e923bad486f96dfb2e6cda29f13e217df41833284ae382
58
+ # - ghcr.io/github/github-mcp-server:v2.0.2@sha256:ffced0d76e77428532a2ced185516992d77fd146d69eec2f244e6237d1a97796
59
+
60
+ name: "apply-product-change"
61
+ on:
62
+ # roles: all # Roles processed as role check in pre-activation job
63
+ workflow_dispatch:
64
+ inputs:
65
+ aw_context:
66
+ default: ""
67
+ description: "Agent caller context (Reserved for Agentic Workflows)."
68
+ required: false
69
+ type: string
70
+ dispatch-request:
71
+ description: Authenticated router receipt comment ID
72
+ required: true
73
+ type: string
74
+ head:
75
+ description: Approved full PR head SHA
76
+ required: true
77
+ type: string
78
+ issue:
79
+ description: Linked issue
80
+ required: true
81
+ type: string
82
+ pull-request:
83
+ description: Product Change PR
84
+ required: true
85
+ type: string
86
+
87
+ # Jobs receive only their explicitly declared permissions.
88
+ permissions: {}
89
+
90
+ concurrency:
91
+ cancel-in-progress: false
92
+ group: lighthouse-issue-${{ inputs.issue }}
93
+ queue: max
94
+
95
+ run-name: "apply product change #${{ inputs.issue }} · PR #${{ inputs.pull-request }}"
96
+
97
+ env:
98
+ LIGHTHOUSE_DISPATCH_REQUIRED: "true"
99
+ LIGHTHOUSE_PRODUCT_CHANGE_ENABLED: "true"
100
+ LIGHTHOUSE_STAGE: propose
101
+ LIGHTHOUSE_WORKER: apply-product-change
102
+ OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.GH_AW_DEFAULT_OTLP_ENDPOINT || vars.GH_AW_DEFAULT_OTLP_ENDPOINT }}
103
+ OTEL_SERVICE_NAME: gh-aw.lighthouse-sdlc-apply-product-change
104
+ OTEL_RESOURCE_ATTRIBUTES: 'gh-aw.workflow.name=apply-product-change,gh-aw.repository=${{ github.repository }},gh-aw.run.id=${{ github.run_id }},github.run_id=${{ github.run_id }},gh-aw.engine.id=copilot'
105
+ OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }}
106
+ GH_AW_OTLP_ENDPOINTS: '[{"url":"${{ secrets.GH_AW_DEFAULT_OTLP_ENDPOINT || vars.GH_AW_DEFAULT_OTLP_ENDPOINT }}","headers":"${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }}"}]'
107
+ GH_AW_OTLP_IF_MISSING: ignore
108
+
109
+ jobs:
110
+ activation:
111
+ name: activation
112
+ needs:
113
+ - pre_activation
114
+ - prepare
115
+ if: needs.pre_activation.outputs.activated == 'true' && (needs.prepare.outputs.eligible == 'true')
116
+ runs-on: ubuntu-24.04
117
+ # Permissions for the activation job (workflow permissions default to none).
118
+ permissions:
119
+ actions: read
120
+ contents: read
121
+ env:
122
+ GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }}
123
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
124
+ outputs:
125
+ aw_context: ${{ steps.generate_aw_info.outputs.aw_context }}
126
+ comment_id: ""
127
+ comment_repo: ""
128
+ daily_ai_credits_estimated: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_estimated || '' }}
129
+ daily_ai_credits_exceeded: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }}
130
+ daily_ai_credits_guardrail_error: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_guardrail_error || '' }}
131
+ daily_ai_credits_guardrail_status: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_guardrail_status || '' }}
132
+ daily_ai_credits_threshold: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }}
133
+ daily_ai_credits_total: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_total || '' }}
134
+ engine_id: ${{ steps.generate_aw_info.outputs.engine_id }}
135
+ lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }}
136
+ model: ${{ steps.generate_aw_info.outputs.model }}
137
+ oauth_token_check_failed: ${{ steps.check-oauth-tokens.outputs.oauth_token_check_failed == 'true' }}
138
+ secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
139
+ setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
140
+ setup-span-id: ${{ steps.setup.outputs.span-id }}
141
+ setup-trace-id: ${{ steps.setup.outputs.trace-id }}
142
+ stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }}
143
+ steps:
144
+ - name: Setup Scripts
145
+ id: setup
146
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
147
+ with:
148
+ destination: ${{ runner.temp }}/gh-aw/actions
149
+ job-name: ${{ github.job }}
150
+ trace-id: ${{ needs.pre_activation.outputs.setup-trace-id }}
151
+ parent-span-id: ${{ needs.pre_activation.outputs.setup-parent-span-id || needs.pre_activation.outputs.setup-span-id }}
152
+ safe-output-artifact-client: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
153
+ env:
154
+ GH_AW_SETUP_WORKFLOW_NAME: "apply-product-change"
155
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-apply-product-change.lock.yml@${{ github.ref }}
156
+ GH_AW_INFO_VERSION: "1.0.101"
157
+ GH_AW_INFO_AWF_VERSION: "v0.28.70"
158
+ GH_AW_INFO_ENGINE_ID: "copilot"
159
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
160
+ - name: Mask OTLP telemetry headers
161
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh"
162
+ - name: Generate agentic run info
163
+ id: generate_aw_info
164
+ env:
165
+ GH_AW_INFO_ENGINE_ID: "copilot"
166
+ GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
167
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'auto' }}
168
+ GH_AW_INFO_VERSION: "1.0.101"
169
+ GH_AW_INFO_AGENT_VERSION: "1.0.101"
170
+ GH_AW_INFO_CLI_VERSION: "v0.93.2"
171
+ GH_AW_INFO_WORKFLOW_NAME: "apply-product-change"
172
+ GH_AW_INFO_WORKFLOW_ID: ${{ job.workflow_ref }}
173
+ GH_AW_INFO_EXPERIMENTAL: "false"
174
+ GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
175
+ GH_AW_INFO_STAGED: "false"
176
+ GH_AW_INFO_ALLOWED_DOMAINS: '[]'
177
+ GH_AW_INFO_FIREWALL_ENABLED: "true"
178
+ GH_AW_INFO_AWF_VERSION: "v0.28.70"
179
+ GH_AW_INFO_AWMG_VERSION: ""
180
+ GH_AW_INFO_FIREWALL_TYPE: "squid"
181
+ GH_AW_INFO_AGENT_RUNTIME: ""
182
+ GH_AW_INFO_ENGINE_HARNESS: "copilot-cli"
183
+ GH_AW_INFO_MODEL_CONFIG: '{"routing":{"enabled":false},"models":{"allowed":[],"blocked":[]},"max_ai_credits_source":"default"}'
184
+ GH_AW_INFO_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
185
+ GH_AW_COMPILED_STRICT: "false"
186
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
187
+ with:
188
+ script: |
189
+ const path = require('path');
190
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
191
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
192
+ setupGlobals(core, github, context, exec, io, getOctokit);
193
+ const { main } = require(path.join(actionsDir, 'generate_aw_info.cjs'));
194
+ await main(core, context);
195
+ - name: Enforce strict mode policy
196
+ if: ${{ vars.GH_AW_POLICY_STRICT == 'true' }}
197
+ run: |
198
+ echo "::error::GH_AW_POLICY_STRICT=true but this workflow was not compiled in strict mode. Recompile with --strict or strict: true."
199
+ exit 1
200
+ - name: Restore daily AIC scan observations
201
+ id: restore-daily-aic-cache-fallback
202
+ if: ${{ env.GH_AW_ADMISSION_RESULT != 'admitted' && env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
203
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
204
+ env:
205
+ GH_AW_HAS_SLASH_COMMAND: "false"
206
+ GH_AW_HAS_LABEL_COMMAND: "false"
207
+ with:
208
+ github-token: ${{ secrets.GITHUB_TOKEN }}
209
+ script: |
210
+ const path = require('path');
211
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
212
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
213
+ setupGlobals(core, github, context, exec, io, getOctokit);
214
+ const { main } = require(path.join(actionsDir, 'restore_aic_scan_cache.cjs'));
215
+ await main();
216
+ - name: Check daily workflow token guardrail
217
+ id: daily-ai-credits-workflow-guardrail
218
+ if: ${{ env.GH_AW_ADMISSION_RESULT != 'admitted' && env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
219
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
220
+ env:
221
+ GH_AW_WORKFLOW_NAME: "apply-product-change"
222
+ GH_AW_WORKFLOW_ID: "lighthouse-sdlc-apply-product-change"
223
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
224
+ GH_AW_WORKFLOW_DISPATCH_AW_CONTEXT: ${{ github.event.inputs.aw_context || '' }}
225
+ GH_AW_HAS_SLASH_COMMAND: "false"
226
+ GH_AW_HAS_LABEL_COMMAND: "false"
227
+ GH_AW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
228
+ GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }}
229
+ GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
230
+ with:
231
+ github-token: ${{ secrets.GITHUB_TOKEN }}
232
+ script: |
233
+ const path = require('path');
234
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
235
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
236
+ setupGlobals(core, github, context, exec, io, getOctokit);
237
+ const { main } = require(path.join(actionsDir, 'check_daily_aic_workflow_guardrail.cjs'));
238
+ await main();
239
+ - name: Publish daily AIC scan observations
240
+ if: always() && env.GH_AW_ADMISSION_RESULT != 'admitted' && env.GH_AW_MAX_DAILY_AI_CREDITS != ''
241
+ continue-on-error: true
242
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
243
+ with:
244
+ name: aic-usage-scan-v2
245
+ path: /tmp/gh-aw/agentic-workflow-usage-scan-v2.jsonl
246
+ overwrite: true
247
+ if-no-files-found: ignore
248
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '3' }}
249
+ - name: Validate COPILOT_GITHUB_TOKEN secret
250
+ id: validate-secret
251
+ 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
252
+ env:
253
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
254
+ - name: Check for OAuth tokens
255
+ id: check-oauth-tokens
256
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/check_oauth_tokens.sh"
257
+ env:
258
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
259
+ GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
260
+ GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
261
+ - name: Checkout .github and .agents folders
262
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
263
+ with:
264
+ persist-credentials: false
265
+ sparse-checkout: |
266
+ .github
267
+ .agents
268
+ .claude
269
+ .codex
270
+ .gemini
271
+ .pi
272
+ sparse-checkout-cone-mode: true
273
+ fetch-depth: 1
274
+ - name: Save agent config folders for base branch restoration
275
+ env:
276
+ GH_AW_AGENT_FOLDERS: ".agents .github"
277
+ GH_AW_AGENT_FILES: "AGENTS.md"
278
+ run: |
279
+ bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
280
+ - name: Check workflow lock file
281
+ id: check-lock-file
282
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
283
+ env:
284
+ GH_AW_WORKFLOW_FILE: "lighthouse-sdlc-apply-product-change.lock.yml"
285
+ GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}"
286
+ with:
287
+ script: |
288
+ const path = require('path');
289
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
290
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
291
+ setupGlobals(core, github, context, exec, io, getOctokit);
292
+ const { main } = require(path.join(actionsDir, 'check_workflow_timestamp_api.cjs'));
293
+ await main();
294
+ - name: Check compile-agentic version
295
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
296
+ env:
297
+ GH_AW_COMPILED_VERSION: "v0.93.2"
298
+ GH_AW_HAS_SAFE_OUTPUTS: "true"
299
+ GH_AW_BLOCKED_VERSION_REPORT_AS_ISSUE: "false"
300
+ GH_AW_WORKFLOW_NAME: "apply-product-change"
301
+ with:
302
+ script: |
303
+ const path = require('path');
304
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
305
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
306
+ setupGlobals(core, github, context, exec, io, getOctokit);
307
+ const { main } = require(path.join(actionsDir, 'check_version_updates.cjs'));
308
+ await main();
309
+ - name: Log runtime features
310
+ if: ${{ contains(toJSON(vars), '"GH_AW_RUNTIME_FEATURES":') }}
311
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/log_runtime_features_summary.sh"
312
+ - name: Create prompt with built-in context
313
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
314
+ env:
315
+ GH_AW_ACTIONS_DIR: ${{ runner.temp }}/gh-aw/actions
316
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
317
+ GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl
318
+ 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\"}],\"system_item_count\":12}"
319
+ 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) }}
320
+ GH_AW_EXPR_77C1A4D2: ${{ github.event.comment.id || fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').comment_id }}
321
+ 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) }}
322
+ 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) }}
323
+ GH_AW_GITHUB_ACTOR: ${{ github.actor }}
324
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
325
+ GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
326
+ GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
327
+ GH_AW_PROMPT_CONTENT_0000: "<system>\n"
328
+ GH_AW_PROMPT_CONTENT_0001: "<safe-output-tools>\nTools: report_missing_tool, report_missing_data, noop(max:2)\n"
329
+ GH_AW_PROMPT_CONTENT_0002: "</safe-output-tools>\n"
330
+ 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</github-context>\n\n"
331
+ GH_AW_PROMPT_CONTENT_0004: "</system>\n"
332
+ GH_AW_PROMPT_CONTENT_0005: "{{#runtime-import .github/workflows/lighthouse-sdlc-apply-product-change.md}}\n"
333
+ with:
334
+ script: |
335
+ const { setupGlobals } = require(process.env.GH_AW_ACTIONS_DIR + '/setup_globals.cjs');
336
+ setupGlobals(core, github, context, exec, io, getOctokit);
337
+ const { main } = require(process.env.GH_AW_ACTIONS_DIR + '/create_prompt.cjs');
338
+ await main(core);
339
+ - name: Interpolate variables and render templates
340
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
341
+ env:
342
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
343
+ GH_AW_ENGINE_ID: "copilot"
344
+ GH_AW_SUB_AGENT_DIR: ".github/agents"
345
+ GH_AW_SUB_AGENT_EXT: ".agent.md"
346
+ GH_AW_SKILL_DIR: ".github/skills"
347
+ GH_AW_SKILL_EXT: "/SKILL.md"
348
+ with:
349
+ script: |
350
+ const path = require('path');
351
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
352
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
353
+ setupGlobals(core, github, context, exec, io, getOctokit);
354
+ const { main } = require(path.join(actionsDir, 'interpolate_prompt.cjs'));
355
+ await main();
356
+ - name: Substitute placeholders
357
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
358
+ env:
359
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
360
+ 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) }}
361
+ GH_AW_EXPR_77C1A4D2: ${{ github.event.comment.id || fromJSON(steps.generate_aw_info.outputs.aw_context || '{}').comment_id }}
362
+ 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) }}
363
+ 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) }}
364
+ GH_AW_GITHUB_ACTOR: ${{ github.actor }}
365
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
366
+ GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
367
+ GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
368
+ GH_AW_MCP_CLI_SERVERS_LIST: "- `github` — run `github --help` to see available tools\n- `safeoutputs` — run `safeoutputs --help` to see available tools"
369
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }}
370
+ with:
371
+ script: |
372
+ const path = require('path');
373
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
374
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
375
+ setupGlobals(core, github, context, exec, io, getOctokit);
376
+
377
+ const substitutePlaceholders = require(path.join(actionsDir, 'substitute_placeholders.cjs'));
378
+
379
+ // Call the substitution function
380
+ return await substitutePlaceholders({
381
+ file: process.env.GH_AW_PROMPT,
382
+ substitutions: {
383
+ GH_AW_EXPR_76DF9333: process.env.GH_AW_EXPR_76DF9333,
384
+ GH_AW_EXPR_77C1A4D2: process.env.GH_AW_EXPR_77C1A4D2,
385
+ GH_AW_EXPR_7C248226: process.env.GH_AW_EXPR_7C248226,
386
+ GH_AW_EXPR_C19C384F: process.env.GH_AW_EXPR_C19C384F,
387
+ GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,
388
+ GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,
389
+ GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,
390
+ GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,
391
+ GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST,
392
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED
393
+ }
394
+ });
395
+ - name: Validate prompt placeholders
396
+ env:
397
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
398
+ run: |
399
+ bash "${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh"
400
+ - name: Print prompt
401
+ env:
402
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
403
+ run: |
404
+ bash "${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh"
405
+ - name: Inventory installed skills
406
+ if: success() || failure()
407
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
408
+ env:
409
+ GH_AW_SKILL_DIR: ".github/skills"
410
+ with:
411
+ script: |
412
+ const path = require('path');
413
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
414
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
415
+ setupGlobals(core, github, context, exec, io, getOctokit);
416
+ const { main } = require(path.join(actionsDir, 'skill_inventory.cjs'));
417
+ await main();
418
+ - name: Upload info artifact
419
+ if: success() || failure()
420
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
421
+ with:
422
+ name: info
423
+ path: /tmp/gh-aw/aw_info.json
424
+ if-no-files-found: ignore
425
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
426
+ - name: Stage prompt files for artifact upload
427
+ run: |
428
+ mkdir -p /tmp/gh-aw/aw-prompts
429
+ cp -a "${RUNNER_TEMP}/gh-aw/aw-prompts/." /tmp/gh-aw/aw-prompts/
430
+ - name: Upload activation artifact
431
+ if: success() || failure()
432
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
433
+ with:
434
+ name: activation
435
+ include-hidden-files: true
436
+ path: |
437
+ /tmp/gh-aw/aw_info.json
438
+ /tmp/gh-aw/models.json
439
+ /tmp/gh-aw/aw-prompts/prompt.txt
440
+ /tmp/gh-aw/aw-prompts/system.txt
441
+ /tmp/gh-aw/aw-prompts/user.txt
442
+ /tmp/gh-aw/aw-prompts/prompt-template.txt
443
+ /tmp/gh-aw/aw-prompts/prompt-import-tree.json
444
+ /tmp/gh-aw/github_rate_limits.jsonl
445
+ /tmp/gh-aw/base
446
+ /tmp/gh-aw/.github/agents
447
+ /tmp/gh-aw/.github/skills
448
+ /tmp/gh-aw/skill_inventory.json
449
+ if-no-files-found: ignore
450
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '1' }}
451
+
452
+ agent:
453
+ name: agent
454
+ needs:
455
+ - activation
456
+ - apply
457
+ - prepare
458
+ - publish
459
+ if: (needs.prepare.outputs.eligible == 'true') && (needs.activation.outputs.daily_ai_credits_exceeded != 'true')
460
+ runs-on:
461
+ - self-hosted
462
+ - linux
463
+ - lighthouse-workflow
464
+ # Permissions for the agent job (workflow permissions default to none).
465
+ permissions:
466
+ contents: read
467
+ timeout-minutes: 60
468
+ env:
469
+ DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
470
+ GH_AW_ASSETS_ALLOWED_EXTS: ""
471
+ GH_AW_ASSETS_BRANCH: ""
472
+ GH_AW_ASSETS_MAX_SIZE_KB: 0
473
+ GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
474
+ GH_AW_PR_HEAD_BASE_BRANCH: ""
475
+ GH_AW_PR_HEAD_BASE_PR_NUMBER: ""
476
+ GH_AW_PR_HEAD_BASE_REF: ""
477
+ GH_AW_PR_HEAD_BASE_REPO: ""
478
+ GH_AW_PR_HEAD_BASE_SHA: ""
479
+ GH_AW_PR_HEAD_REPO: ""
480
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
481
+ GH_AW_TARGET_REPO_SLUG: ""
482
+ GH_AW_WORKFLOW_ID_SANITIZED: lighthousesdlcapplyproductchange
483
+ outputs:
484
+ agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
485
+ ai_credits_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.ai_credits_rate_limit_error || 'false' }}
486
+ aic: ${{ steps.parse-token-usage.outputs.aic }}
487
+ ambient_context: ${{ steps.parse-token-usage.outputs.ambient_context }}
488
+ checkout_pr_invalidated: ${{ steps.checkout-pr.outputs.checkout_pr_invalidated || 'false' }}
489
+ checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
490
+ has_patch: ${{ steps.collect_output.outputs.has_patch }}
491
+ http_400_response_error: ${{ steps.detect-agent-errors.outputs.http_400_response_error || 'false' }}
492
+ inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
493
+ invocation_cap_exceeded: ${{ steps.detect-agent-errors.outputs.invocation_cap_exceeded || 'false' }}
494
+ max_cache_misses_exceeded: ${{ steps.detect-agent-errors.outputs.max_cache_misses_exceeded || 'false' }}
495
+ mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
496
+ missing_model_pricing_error: ${{ steps.detect-agent-errors.outputs.missing_model_pricing_error || 'false' }}
497
+ missing_model_pricing_model_name: ${{ steps.detect-agent-errors.outputs.missing_model_pricing_model_name || '' }}
498
+ model: ${{ needs.activation.outputs.model }}
499
+ model_endpoint_mismatch_error: ${{ steps.detect-agent-errors.outputs.model_endpoint_mismatch_error || 'false' }}
500
+ model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
501
+ output: ${{ steps.collect_output.outputs.output }}
502
+ output_types: ${{ steps.collect_output.outputs.output_types }}
503
+ setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
504
+ setup-span-id: ${{ steps.setup.outputs.span-id }}
505
+ setup-trace-id: ${{ steps.setup.outputs.trace-id }}
506
+ shell_expansion_guard_rejected: ${{ steps.detect-agent-errors.outputs.shell_expansion_guard_rejected || 'false' }}
507
+ unknown_model_ai_credits: ${{ steps.parse-mcp-gateway.outputs.unknown_model_ai_credits || 'false' }}
508
+ steps:
509
+ - name: Setup Scripts
510
+ id: setup
511
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
512
+ with:
513
+ destination: ${{ runner.temp }}/gh-aw/actions
514
+ job-name: ${{ github.job }}
515
+ trace-id: ${{ needs.activation.outputs.setup-trace-id }}
516
+ parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
517
+ env:
518
+ GH_AW_SETUP_WORKFLOW_NAME: "apply-product-change"
519
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-apply-product-change.lock.yml@${{ github.ref }}
520
+ GH_AW_INFO_VERSION: "1.0.101"
521
+ GH_AW_INFO_AWF_VERSION: "v0.28.70"
522
+ GH_AW_INFO_ENGINE_ID: "copilot"
523
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
524
+ - name: Set runtime paths
525
+ id: set-runtime-paths
526
+ env:
527
+ GH_AW_RUNNER_TOOL_CACHE: ${{ runner.tool_cache }}
528
+ run: | # zizmor: ignore[github-env] - runner.tool_cache is set by GitHub Actions, not user input.
529
+ if [ -z "${RUNNER_TOOL_CACHE:-}" ]; then
530
+ echo "RUNNER_TOOL_CACHE=${GH_AW_RUNNER_TOOL_CACHE}" >> "$GITHUB_ENV"
531
+ fi
532
+ {
533
+ echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl"
534
+ echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json"
535
+ echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json"
536
+ } >> "$GITHUB_OUTPUT"
537
+ - name: Mask OTLP telemetry headers
538
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh"
539
+ - name: Check OTLP telemetry configuration
540
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/check_otlp_default_credentials.sh"
541
+ - name: Checkout repository (gh-aw default)
542
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
543
+ with:
544
+ persist-credentials: false
545
+ - name: Initialize agent execution evidence
546
+ run: |
547
+ mkdir -p "/tmp/gh-aw"
548
+ evidence_tmp="/tmp/gh-aw/agent_execution.json.tmp"
549
+ printf '{"version":1,"component":"agent","run_id":%s,"run_attempt":%s,"state":"not_started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp"
550
+ mv "$evidence_tmp" "/tmp/gh-aw/agent_execution.json"
551
+ - name: Setup Node.js
552
+ uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
553
+ with:
554
+ node-version: '24'
555
+ package-manager-cache: false
556
+ - name: Create gh-aw temp directory
557
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh"
558
+ - name: Configure gh CLI for GitHub Enterprise
559
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh"
560
+ env:
561
+ GH_TOKEN: ${{ github.token }}
562
+ - name: Download activation artifact
563
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
564
+ with:
565
+ name: activation
566
+ path: /tmp/gh-aw
567
+ - name: Configure Git credentials
568
+ env:
569
+ GITHUB_REPOSITORY: ${{ github.repository }}
570
+ GITHUB_SERVER_URL: ${{ github.server_url }}
571
+ GITHUB_TOKEN: ${{ github.token }}
572
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_git_credentials.sh"
573
+ - name: Checkout PR branch
574
+ id: checkout-pr
575
+ if: |
576
+ github.event.pull_request || github.event.issue.pull_request || github.event_name == 'workflow_dispatch'
577
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
578
+ env:
579
+ GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
580
+ with:
581
+ github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
582
+ script: |
583
+ const path = require('path');
584
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
585
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
586
+ setupGlobals(core, github, context, exec, io, getOctokit);
587
+ const { main } = require(path.join(actionsDir, 'checkout_pr_branch.cjs'));
588
+ await main();
589
+ - name: Install GitHub Copilot CLI
590
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.101 --checksums-sha256 018625eac68670d66ede904b9b82cdcd6ab8f87ba20e6e1fbdf0b62c8295d5be --prefer-toolcache
591
+ env:
592
+ GH_HOST: github.com
593
+ GH_AW_COPILOT_MIN_VERSION: 1.0.35
594
+ - name: Install AWF binary
595
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.28.70 --rootless
596
+ - name: Determine automatic lockdown mode for GitHub MCP Server
597
+ id: determine-automatic-lockdown
598
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
599
+ env:
600
+ GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
601
+ GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
602
+ with:
603
+ script: |
604
+ const path = require('path');
605
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
606
+ const determineAutomaticLockdown = require(path.join(actionsDir, 'determine_automatic_lockdown.cjs'));
607
+ await determineAutomaticLockdown(github, context, core);
608
+ - name: Restore agent config folders from base branch
609
+ if: steps.checkout-pr.outcome == 'success'
610
+ env:
611
+ GH_AW_AGENT_FOLDERS: ".agents .github"
612
+ GH_AW_AGENT_FILES: "AGENTS.md"
613
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
614
+ - name: Restore inline sub-agents from activation artifact
615
+ env:
616
+ GH_AW_SUB_AGENT_DIR: ".github/agents"
617
+ GH_AW_SUB_AGENT_EXT: ".agent.md"
618
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
619
+ - name: Restore inline skills from activation artifact
620
+ env:
621
+ GH_AW_SKILL_DIR: ".github/skills"
622
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
623
+ - name: Download container images
624
+ 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
625
+ - name: Prepare Safe Outputs Directories
626
+ run: |
627
+ mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
628
+ mkdir -p /tmp/gh-aw/safeoutputs
629
+ mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
630
+ - name: Generate Safe Outputs Config
631
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
632
+ env:
633
+ GH_AW_FILE_ROOT: "${{ runner.temp }}/gh-aw"
634
+ GH_AW_FILE_CONFIG: "{\"files\":[{\"path\":\"safeoutputs/config.json\",\"content_env\":\"GH_AW_SAFE_OUTPUTS_CONFIG\"}]}"
635
+ GH_AW_SAFE_OUTPUTS_CONFIG: "{\"noop\":{\"max\":2,\"report-as-issue\":\"false\"},\"report_missing_data\":{},\"report_missing_tool\":{}}"
636
+ with:
637
+ script: |
638
+ const path = require('path');
639
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
640
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
641
+ setupGlobals(core, github, context, exec, io, getOctokit);
642
+ const { main } = require(path.join(actionsDir, 'create_files.cjs'));
643
+ await main();
644
+ - name: Generate Safe Outputs Tools
645
+ env:
646
+ GH_AW_TOOLS_META_JSON: |
647
+ {
648
+ "description_suffixes": {},
649
+ "repo_params": {},
650
+ "dynamic_tools": []
651
+ }
652
+ GH_AW_VALIDATION_JSON: |
653
+ {
654
+ "noop": {
655
+ "defaultMax": 2,
656
+ "fields": {
657
+ "message": {
658
+ "required": true,
659
+ "type": "string",
660
+ "sanitize": true,
661
+ "maxLength": 65000
662
+ }
663
+ }
664
+ },
665
+ "report_missing_data": {
666
+ "defaultMax": 20,
667
+ "fields": {
668
+ "alternatives": {
669
+ "type": "string",
670
+ "sanitize": true,
671
+ "maxLength": 256
672
+ },
673
+ "context": {
674
+ "type": "string",
675
+ "sanitize": true,
676
+ "maxLength": 256
677
+ },
678
+ "data_type": {
679
+ "type": "string",
680
+ "sanitize": true,
681
+ "maxLength": 128
682
+ },
683
+ "reason": {
684
+ "type": "string",
685
+ "sanitize": true,
686
+ "maxLength": 256
687
+ }
688
+ }
689
+ },
690
+ "report_missing_tool": {
691
+ "defaultMax": 20,
692
+ "fields": {
693
+ "alternatives": {
694
+ "type": "string",
695
+ "sanitize": true,
696
+ "maxLength": 512
697
+ },
698
+ "reason": {
699
+ "required": true,
700
+ "type": "string",
701
+ "sanitize": true,
702
+ "maxLength": 256
703
+ },
704
+ "tool": {
705
+ "type": "string",
706
+ "sanitize": true,
707
+ "maxLength": 128
708
+ }
709
+ }
710
+ }
711
+ }
712
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
713
+ with:
714
+ script: |
715
+ const path = require('path');
716
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
717
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
718
+ setupGlobals(core, github, context, exec, io, getOctokit);
719
+ const { main } = require(path.join(actionsDir, 'generate_safe_outputs_tools.cjs'));
720
+ await main();
721
+ - name: Start MCP Gateway
722
+ id: start-mcp-gateway
723
+ env:
724
+ DEBUG: ${{ env.DEBUG || runner.debug == '1' && '*' || '' }}
725
+ GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST: ${{ vars.GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST || 'true' }}
726
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
727
+ GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_CONFIG_PATH }}
728
+ GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_TOOLS_PATH }}
729
+ GH_AW_SINK_VISIBILITY: ${{ steps.determine-automatic-lockdown.outputs.visibility }}
730
+ GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }}
731
+ GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }}
732
+ GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
733
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
734
+ run: |
735
+ set -eo pipefail
736
+ mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-config"
737
+ if [ -n "${GITHUB_EVENT_PATH:-}" ] && [ -r "${GITHUB_EVENT_PATH}" ]; then
738
+ GH_AW_SAFEOUTPUTS_EVENT_PATH="${RUNNER_TEMP}/gh-aw/safeoutputs/github_event.json"
739
+ cp "${GITHUB_EVENT_PATH}" "${GH_AW_SAFEOUTPUTS_EVENT_PATH}"
740
+ export GITHUB_EVENT_PATH="${GH_AW_SAFEOUTPUTS_EVENT_PATH}"
741
+ fi
742
+
743
+ # Export gateway environment variables for MCP config and gateway script
744
+ export MCP_GATEWAY_PORT="8080"
745
+ export MCP_GATEWAY_DOMAIN="awmg-mcpg"
746
+ export MCP_GATEWAY_HOST_DOMAIN="localhost"
747
+ MCP_GATEWAY_AGENT_ID=$(openssl rand -base64 45 | tr -d '/+=')
748
+ echo "::add-mask::${MCP_GATEWAY_AGENT_ID}"
749
+ export MCP_GATEWAY_AGENT_ID
750
+ export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads"
751
+ mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}"
752
+ export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288"
753
+ 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"
754
+ export GH_AW_PR_HEAD_BASE_BRANCH="${GH_AW_PR_HEAD_BASE_BRANCH:-}"
755
+ export GH_AW_PR_HEAD_BASE_SHA="${GH_AW_PR_HEAD_BASE_SHA:-}"
756
+ export GH_AW_PR_HEAD_BASE_REPO="${GH_AW_PR_HEAD_BASE_REPO:-}"
757
+ export GH_AW_PR_HEAD_BASE_PR_NUMBER="${GH_AW_PR_HEAD_BASE_PR_NUMBER:-}"
758
+ export GH_AW_PR_HEAD_BASE_REF="${GH_AW_PR_HEAD_BASE_REF:-}"
759
+ export GH_AW_PR_HEAD_REPO="${GH_AW_PR_HEAD_REPO:-}"
760
+ export GH_AW_TARGET_REPO_SLUG="${GH_AW_TARGET_REPO_SLUG:-}"
761
+ export GH_AW_ENGINE="copilot"
762
+ MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0')
763
+ MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0')
764
+ source "${RUNNER_TEMP}/gh-aw/actions/resolve_docker_socket_gid.sh"
765
+ 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'
766
+
767
+ mkdir -p "$HOME/.copilot"
768
+ GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
769
+ cat << GH_AW_MCP_CONFIG_822d35bbd39501a6_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs"
770
+ {
771
+ "mcpServers": {
772
+ "github": {
773
+ "type": "stdio",
774
+ "container": "ghcr.io/github/github-mcp-server:v2.0.2",
775
+ "env": {
776
+ "GITHUB_FEATURES": "fields_param",
777
+ "GITHUB_HOST": "${GITHUB_SERVER_URL}",
778
+ "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_MCP_SERVER_TOKEN}",
779
+ "GITHUB_READ_ONLY": "1",
780
+ "GITHUB_TOOLSETS": "context,repos,issues,pull_requests"
781
+ },
782
+ "guard-policies": {
783
+ "allow-only": {
784
+ "min-integrity": "$GITHUB_MCP_GUARD_MIN_INTEGRITY",
785
+ "repos": "$GITHUB_MCP_GUARD_REPOS"
786
+ }
787
+ }
788
+ },
789
+ "safeoutputs": {
790
+ "type": "stdio",
791
+ "container": "ghcr.io/github/gh-aw-node@sha256:41835613992df88f51e923bad486f96dfb2e6cda29f13e217df41833284ae382",
792
+ "mounts": ["\${GITHUB_WORKSPACE}:\${GITHUB_WORKSPACE}:rw", "${RUNNER_TEMP}/gh-aw/safeoutputs:${RUNNER_TEMP}/gh-aw/safeoutputs:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"],
793
+ "args": ["-w", "\${GITHUB_WORKSPACE}"],
794
+ "entrypoint": "sh",
795
+ "entrypointArgs": ["-c", "sh ${RUNNER_TEMP}/gh-aw/safeoutputs/start_safe_outputs_mcp.sh"],
796
+ "env": {
797
+ "DEBUG": "\${DEBUG}",
798
+ "DEFAULT_BRANCH": "\${DEFAULT_BRANCH}",
799
+ "GH_AW_ASSETS_ALLOWED_EXTS": "\${GH_AW_ASSETS_ALLOWED_EXTS}",
800
+ "GH_AW_ASSETS_BRANCH": "\${GH_AW_ASSETS_BRANCH}",
801
+ "GH_AW_ASSETS_MAX_SIZE_KB": "\${GH_AW_ASSETS_MAX_SIZE_KB}",
802
+ "GH_AW_MCP_LOG_DIR": "\${GH_AW_MCP_LOG_DIR}",
803
+ "GH_AW_SAFE_OUTPUTS": "\${GH_AW_SAFE_OUTPUTS}",
804
+ "GH_AW_SAFE_OUTPUTS_CONFIG_PATH": "\${GH_AW_SAFE_OUTPUTS_CONFIG_PATH}",
805
+ "GH_AW_SAFE_OUTPUTS_TOOLS_PATH": "\${GH_AW_SAFE_OUTPUTS_TOOLS_PATH}",
806
+ "GH_AW_TARGET_REPO_SLUG": "\${GH_AW_TARGET_REPO_SLUG}",
807
+ "GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST": "\${GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST}",
808
+ "GH_AW_PR_HEAD_BASE_BRANCH": "\${GH_AW_PR_HEAD_BASE_BRANCH}",
809
+ "GH_AW_PR_HEAD_BASE_SHA": "\${GH_AW_PR_HEAD_BASE_SHA}",
810
+ "GH_AW_PR_HEAD_BASE_REPO": "\${GH_AW_PR_HEAD_BASE_REPO}",
811
+ "GH_AW_PR_HEAD_BASE_PR_NUMBER": "\${GH_AW_PR_HEAD_BASE_PR_NUMBER}",
812
+ "GH_AW_PR_HEAD_BASE_REF": "\${GH_AW_PR_HEAD_BASE_REF}",
813
+ "GH_AW_PR_HEAD_REPO": "\${GH_AW_PR_HEAD_REPO}",
814
+ "GITHUB_EVENT_NAME": "\${GITHUB_EVENT_NAME}",
815
+ "GITHUB_EVENT_PATH": "\${GITHUB_EVENT_PATH}",
816
+ "GITHUB_REPOSITORY": "\${GITHUB_REPOSITORY}",
817
+ "GITHUB_SHA": "\${GITHUB_SHA}",
818
+ "GITHUB_TOKEN": "\${GITHUB_TOKEN}",
819
+ "GITHUB_WORKSPACE": "\${GITHUB_WORKSPACE}",
820
+ "RUNNER_TEMP": "\${RUNNER_TEMP}"
821
+ },
822
+ "guard-policies": {
823
+ "write-sink": {
824
+ "accept": [
825
+ "*"
826
+ ],
827
+ "sink-visibility": "${GH_AW_SINK_VISIBILITY}"
828
+ }
829
+ }
830
+ }
831
+ },
832
+ "gateway": {
833
+ "port": $MCP_GATEWAY_PORT,
834
+ "domain": "${MCP_GATEWAY_DOMAIN}",
835
+ "agentId": "${MCP_GATEWAY_AGENT_ID}",
836
+ "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}",
837
+ "startupTimeout": 120,
838
+ "opentelemetry": {
839
+ "endpoint": "${OTEL_EXPORTER_OTLP_ENDPOINT}",
840
+ "traceId": "${GITHUB_AW_OTEL_TRACE_ID}",
841
+ "spanId": "${GITHUB_AW_OTEL_PARENT_SPAN_ID}"
842
+ }
843
+ }
844
+ }
845
+ GH_AW_MCP_CONFIG_822d35bbd39501a6_EOF
846
+ - name: Mount MCP servers as CLIs
847
+ id: mount-mcp-clis
848
+ continue-on-error: true
849
+ env:
850
+ MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }}
851
+ MCP_GATEWAY_DOMAIN: ${{ steps.start-mcp-gateway.outputs.gateway-domain }}
852
+ MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
853
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
854
+ with:
855
+ script: |
856
+ const path = require('path');
857
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
858
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
859
+ setupGlobals(core, github, context, exec, io);
860
+ const { main } = require(path.join(actionsDir, 'mount_mcp_as_cli.cjs'));
861
+ await main();
862
+ - name: Clean credentials
863
+ run: |
864
+ bash "${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh"
865
+ bash "${RUNNER_TEMP}/gh-aw/actions/verify_git_credentials.sh"
866
+ - name: Audit pre-agent workspace
867
+ id: pre_agent_audit
868
+ continue-on-error: true
869
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/audit_pre_agent_workspace.sh"
870
+ - name: Log GitHub rate limits at agent start
871
+ continue-on-error: true
872
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
873
+ with:
874
+ github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
875
+ script: |
876
+ const path = require('path');
877
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
878
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
879
+ setupGlobals(core, github, context, exec, io, getOctokit);
880
+ const { fetchAndLogRateLimit } = require(path.join(actionsDir, 'github_rate_limit_logger.cjs'));
881
+ await fetchAndLogRateLimit(github, 'agent_start', true);
882
+ - name: Execute GitHub Copilot CLI
883
+ id: agentic_execution
884
+ # Copilot CLI tool arguments (sorted):
885
+ # --allow-tool github
886
+ # --allow-tool safeoutputs
887
+ # --allow-tool shell(cat)
888
+ # --allow-tool shell(date)
889
+ # --allow-tool shell(echo)
890
+ # --allow-tool shell(git:*)
891
+ # --allow-tool shell(github:*)
892
+ # --allow-tool shell(grep)
893
+ # --allow-tool shell(head)
894
+ # --allow-tool shell(ls)
895
+ # --allow-tool shell(node)
896
+ # --allow-tool shell(npm:*)
897
+ # --allow-tool shell(npx:*)
898
+ # --allow-tool shell(printf)
899
+ # --allow-tool shell(pwd)
900
+ # --allow-tool shell(safeoutputs:*)
901
+ # --allow-tool shell(sort)
902
+ # --allow-tool shell(tail)
903
+ # --allow-tool shell(uniq)
904
+ # --allow-tool shell(wc)
905
+ # --allow-tool shell(yq)
906
+ # --allow-tool write
907
+ timeout-minutes: 30
908
+ run: |
909
+ set -o pipefail
910
+ printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt
911
+ gh_aw_exit_code=0
912
+ 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
913
+ mkdir -p "$HOME/.copilot"
914
+ printf '%s' '{"builtInAgents":{"rubberDuck":false},"enabledFeatureFlags":{"EXTENSIONS":false}}' > "$HOME/.copilot/settings.json"
915
+ export XDG_CONFIG_HOME="$HOME"
916
+ export GH_AW_MCP_CONFIG="$HOME/.copilot/mcp-config.json"
917
+ GH_AW_COPILOT_SRC="$(command -v copilot 2>/dev/null || true)"
918
+ if [ -z "$GH_AW_COPILOT_SRC" ] || [ ! -x "$GH_AW_COPILOT_SRC" ]; then
919
+ echo "GitHub Copilot CLI executable not found on PATH after installation" >&2
920
+ exit 127
921
+ fi
922
+ GH_AW_COPILOT_BIN="${RUNNER_TEMP}/gh-aw/bin/copilot"
923
+ mkdir -p "${RUNNER_TEMP}/gh-aw/bin"
924
+ if [ "$GH_AW_COPILOT_SRC" != "$GH_AW_COPILOT_BIN" ]; then
925
+ cp "$GH_AW_COPILOT_SRC" "$GH_AW_COPILOT_BIN"
926
+ fi
927
+ chmod 755 "$GH_AW_COPILOT_BIN"
928
+
929
+ touch /tmp/gh-aw/agent-step-summary.md
930
+ GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
931
+ export GH_AW_NODE_BIN
932
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
933
+ (umask 177 && touch /tmp/gh-aw/agent-stdio.log)
934
+ GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-1000}"
935
+ if [[ ! "$GH_AW_MAX_AI_CREDITS" =~ ^[0-9]+$ ]]; then
936
+ GH_AW_MAX_AI_CREDITS="1000"
937
+ fi
938
+ if [[ "${GH_AW_ADMISSION_RESULT:-}" == "admitted" && -z "${GH_AW_ADMISSION_MAX_AI_CREDITS:-}" ]]; then
939
+ echo "ERR_ADMISSION: Missing required runtime admission allowance." >&2
940
+ exit 1
941
+ fi
942
+
943
+ if [[ "${GH_AW_ADMISSION_RESULT:-}" == "admitted" && -n "${GH_AW_ADMISSION_MAX_AI_CREDITS:-}" ]]; then
944
+ if [[ ! "$GH_AW_ADMISSION_MAX_AI_CREDITS" =~ ^[1-9][0-9]{0,9}$ ]] || (( GH_AW_ADMISSION_MAX_AI_CREDITS > 2147483647 )); then
945
+ echo "ERR_ADMISSION: Invalid runtime admission allowance." >&2
946
+ exit 1
947
+ fi
948
+ GH_AW_MAX_AI_CREDITS="$GH_AW_ADMISSION_MAX_AI_CREDITS"
949
+ echo "Admission allowance applied (value withheld)."
950
+ else
951
+ echo "No component admission allowance; retaining existing budget policy (value withheld)."
952
+ fi
953
+ unset GH_AW_ADMISSION_RESULT GH_AW_ADMISSION_MAX_AI_CREDITS
954
+ printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.28.70/awf-config.schema.json\",\"network\":{\"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\",\"agentTimeout\":30},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json"
955
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
956
+ export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json"
957
+ GH_AW_DOCKER_HOST=""
958
+ if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
959
+ GH_AW_DOCKER_HOST="${DOCKER_HOST}"
960
+ fi
961
+ if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
962
+ 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"
963
+ fi
964
+ GH_AW_TOOL_CACHE_MOUNT=""
965
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"
966
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
967
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
968
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
969
+ fi
970
+ fi
971
+ # shellcheck disable=SC1003,SC2016,SC2086
972
+ mkdir -p "/tmp/gh-aw"
973
+ evidence_tmp="/tmp/gh-aw/agent_execution.json.tmp"
974
+ printf '{"version":1,"component":"agent","run_id":%s,"run_attempt":%s,"state":"started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp"
975
+ mv "$evidence_tmp" "/tmp/gh-aw/agent_execution.json"
976
+ export GH_AW_AWF_EXECUTION_COMPONENT="agent"
977
+ export GH_AW_AWF_EXECUTION_EVIDENCE_FILE="/tmp/gh-aw/agent_execution.json"
978
+ GH_AW_AWF_ENGINE_NAME=copilot \
979
+ GH_AW_AWF_HARNESS_MARKER='[copilot-harness]' \
980
+ GH_AW_AWF_LOG_FILE=/tmp/gh-aw/agent-stdio.log \
981
+ GH_AW_AWF_ATTEMPT_LOG_NAME=copilot \
982
+ bash "${RUNNER_TEMP}/gh-aw/actions/run_awf_with_startup_retries.sh" -- \
983
+ 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 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 \
984
+ -- /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(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(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'
985
+ env:
986
+ AWF_REFLECT_ENABLED: 1
987
+ COPILOT_AGENT_RUNNER_TYPE: STANDALONE
988
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
989
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
990
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'auto' }}
991
+ GH_AW_ADMISSION_MAX_AI_CREDITS: ${{ needs.activation.outputs.admission-max-ai-credits }}
992
+ GH_AW_ADMISSION_RESULT: ${{ needs.activation.outputs.admission-result }}
993
+ GH_AW_LLM_PROVIDER: github
994
+ GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
995
+ GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }}
996
+ GH_AW_PHASE: agent
997
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
998
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
999
+ GH_AW_TIMEOUT_MINUTES: 30
1000
+ GH_AW_VERSION: v0.93.2
1001
+ GITHUB_API_URL: ${{ github.api_url }}
1002
+ GITHUB_AW: true
1003
+ GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
1004
+ GITHUB_COPILOT_PROMPT_MODE_EXTENSIONS: false
1005
+ GITHUB_HEAD_REF: ${{ github.head_ref }}
1006
+ GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1007
+ GITHUB_REF_NAME: ${{ github.ref_name }}
1008
+ GITHUB_SERVER_URL: ${{ github.server_url }}
1009
+ GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
1010
+ GITHUB_WORKSPACE: ${{ github.workspace }}
1011
+ GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
1012
+ GIT_AUTHOR_NAME: github-actions[bot]
1013
+ GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
1014
+ GIT_COMMITTER_NAME: github-actions[bot]
1015
+ RUNNER_TEMP: ${{ runner.temp }}
1016
+ 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) || '' }}
1017
+ - name: Log GitHub rate limits at agent end
1018
+ if: always()
1019
+ continue-on-error: true
1020
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1021
+ with:
1022
+ github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1023
+ script: |
1024
+ const path = require('path');
1025
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1026
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1027
+ setupGlobals(core, github, context, exec, io, getOctokit);
1028
+ const { fetchAndLogRateLimit } = require(path.join(actionsDir, 'github_rate_limit_logger.cjs'));
1029
+ await fetchAndLogRateLimit(github, 'agent_end', true);
1030
+ - name: Detect agent errors
1031
+ if: always()
1032
+ id: detect-agent-errors
1033
+ continue-on-error: true
1034
+ env:
1035
+ GH_AW_AGENTIC_EXECUTION_OUTCOME: ${{ steps.agentic_execution.outcome }}
1036
+ GH_AW_ENGINE_STEP_TIMEOUT_MINUTES: 30
1037
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1038
+ with:
1039
+ script: |
1040
+ const path = require('path');
1041
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1042
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1043
+ setupGlobals(core, github, context, exec, io, getOctokit);
1044
+ const { main } = require(path.join(actionsDir, 'detect_agent_errors.cjs'));
1045
+ await main();
1046
+ - name: Configure Git credentials
1047
+ env:
1048
+ GITHUB_REPOSITORY: ${{ github.repository }}
1049
+ GITHUB_SERVER_URL: ${{ github.server_url }}
1050
+ GITHUB_TOKEN: ${{ github.token }}
1051
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_git_credentials.sh"
1052
+ - name: Copy Copilot session state files to logs
1053
+ if: always()
1054
+ continue-on-error: true
1055
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/copy_copilot_session_state.sh"
1056
+ - name: Stop MCP Gateway
1057
+ if: always()
1058
+ continue-on-error: true
1059
+ env:
1060
+ MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
1061
+ MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }}
1062
+ GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}
1063
+ run: |
1064
+ bash "${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh" "$GATEWAY_PID"
1065
+ - name: Redact secrets in logs
1066
+ id: redact_secrets
1067
+ if: always()
1068
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1069
+ with:
1070
+ script: |
1071
+ const path = require('path');
1072
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1073
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1074
+ setupGlobals(core, github, context, exec, io, getOctokit);
1075
+ const { main } = require(path.join(actionsDir, 'redact_secrets.cjs'));
1076
+ await main();
1077
+ env:
1078
+ GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
1079
+ SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
1080
+ SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
1081
+ SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
1082
+ SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1083
+ - name: Append agent step summary
1084
+ if: always()
1085
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh"
1086
+ - name: Copy Safe Outputs
1087
+ if: always()
1088
+ env:
1089
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
1090
+ run: |
1091
+ mkdir -p /tmp/gh-aw
1092
+ cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true
1093
+ - name: Ingest agent output
1094
+ id: collect_output
1095
+ if: always()
1096
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1097
+ env:
1098
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
1099
+ GITHUB_SERVER_URL: ${{ github.server_url }}
1100
+ GITHUB_API_URL: ${{ github.api_url }}
1101
+ with:
1102
+ script: |
1103
+ const path = require('path');
1104
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1105
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1106
+ setupGlobals(core, github, context, exec, io, getOctokit);
1107
+ const { main } = require(path.join(actionsDir, 'collect_ndjson_output.cjs'));
1108
+ await main();
1109
+ - name: Parse agent logs for step summary
1110
+ if: always()
1111
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1112
+ env:
1113
+ GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/
1114
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
1115
+ with:
1116
+ script: |
1117
+ const path = require('path');
1118
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1119
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1120
+ setupGlobals(core, github, context, exec, io, getOctokit);
1121
+ const { main } = require(path.join(actionsDir, 'parse_copilot_log.cjs'));
1122
+ await main();
1123
+ - name: Parse MCP Gateway logs for step summary
1124
+ if: always()
1125
+ id: parse-mcp-gateway
1126
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1127
+ with:
1128
+ script: |
1129
+ const path = require('path');
1130
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1131
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1132
+ setupGlobals(core, github, context, exec, io, getOctokit);
1133
+ const { main } = require(path.join(actionsDir, 'parse_mcp_gateway_log.cjs'));
1134
+ await main();
1135
+ - name: Print firewall logs
1136
+ if: always()
1137
+ continue-on-error: true
1138
+ env:
1139
+ AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs
1140
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/print_firewall_logs.sh" --rootless
1141
+ - name: Parse token usage for step summary
1142
+ if: always()
1143
+ id: parse-token-usage
1144
+ continue-on-error: true
1145
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1146
+ with:
1147
+ script: |
1148
+ const path = require('path');
1149
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1150
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1151
+ setupGlobals(core, github, context, exec, io, getOctokit);
1152
+ const { main } = require(path.join(actionsDir, 'parse_token_usage.cjs'));
1153
+ await main();
1154
+ - name: Print AWF reflect summary
1155
+ if: always()
1156
+ continue-on-error: true
1157
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1158
+ with:
1159
+ script: |
1160
+ const path = require('path');
1161
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1162
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1163
+ setupGlobals(core, github, context, exec, io, getOctokit);
1164
+ const { main } = require(path.join(actionsDir, 'awf_reflect_summary.cjs'));
1165
+ await main();
1166
+ - name: Generate observability summary
1167
+ if: always()
1168
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1169
+ with:
1170
+ script: |
1171
+ const path = require('path');
1172
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1173
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1174
+ setupGlobals(core, github, context, exec, io, getOctokit);
1175
+ const { main } = require(path.join(actionsDir, 'generate_observability_summary.cjs'));
1176
+ await main(core);
1177
+ - name: Write agent output placeholder if missing
1178
+ if: always()
1179
+ run: |
1180
+ if [ ! -f /tmp/gh-aw/agent_output.json ]; then
1181
+ echo '{"items":[]}' > /tmp/gh-aw/agent_output.json
1182
+ fi
1183
+ # Small dedicated copy of the agent output so safe-output processing
1184
+ # survives a failed or timed-out upload of the larger agent artifact
1185
+ - name: Upload agent output fallback artifact
1186
+ if: always() && steps.redact_secrets.outcome == 'success'
1187
+ continue-on-error: true
1188
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1189
+ with:
1190
+ name: agent-output-fallback
1191
+ path: |
1192
+ /tmp/gh-aw/agent_output.json
1193
+ /tmp/gh-aw/safeoutputs.jsonl
1194
+ /tmp/gh-aw/agent_execution.json
1195
+ /tmp/gh-aw/agent_execution_exit_code.txt
1196
+ /tmp/gh-aw/agent_usage.jsonl
1197
+ /tmp/gh-aw/agent_usage.json
1198
+ /tmp/gh-aw/agent/model-endpoint-mismatch.json
1199
+ /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl
1200
+ /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/model-routing.jsonl
1201
+ /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl
1202
+ /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/model-routing.jsonl
1203
+ /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl
1204
+ /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/model-routing.jsonl
1205
+ /tmp/gh-aw/awf-resolved-config.json
1206
+ if-no-files-found: ignore
1207
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
1208
+ - name: Upload agent artifacts
1209
+ if: always() && steps.redact_secrets.outcome == 'success'
1210
+ continue-on-error: true
1211
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1212
+ with:
1213
+ name: agent
1214
+ path: |
1215
+ /tmp/gh-aw/aw-prompts/prompt.txt
1216
+ /tmp/gh-aw/agent_execution.json
1217
+ /tmp/gh-aw/agent_execution_exit_code.txt
1218
+ /tmp/gh-aw/agent-session.jsonl
1219
+ /tmp/gh-aw/agent-errors.jsonl
1220
+ /tmp/gh-aw/aw-prompts/user.txt
1221
+ /tmp/gh-aw/aw-prompts/system.txt
1222
+ /tmp/gh-aw/skill_inventory.json
1223
+ /tmp/gh-aw/sandbox/agent/logs/
1224
+ /tmp/gh-aw/redacted-urls.log
1225
+ /tmp/gh-aw/mcp-logs/
1226
+ /tmp/gh-aw/agent_usage.json
1227
+ /tmp/gh-aw/runtime/aw_info.json
1228
+ /tmp/gh-aw/agent_usage.jsonl
1229
+ /tmp/gh-aw/agent/model-endpoint-mismatch.json
1230
+ /tmp/gh-aw/agent/model-resolution.json
1231
+ /tmp/gh-aw/agent-stdio.log
1232
+ /tmp/gh-aw/pre-agent-audit.txt
1233
+ /tmp/gh-aw/github_rate_limits.jsonl
1234
+ /tmp/gh-aw/otel.jsonl
1235
+ /tmp/gh-aw/otlp-export-errors.jsonl
1236
+ /tmp/gh-aw/safeoutputs.jsonl
1237
+ /tmp/gh-aw/agent_output.json
1238
+ /tmp/gh-aw/awf-config.json
1239
+ /tmp/gh-aw/awf-resolved-config.json
1240
+ /tmp/gh-aw/sandbox/firewall/logs/
1241
+ /tmp/gh-aw/sandbox/firewall/audit/
1242
+ /tmp/gh-aw/sandbox/firewall/awf-reflect.json
1243
+ if-no-files-found: ignore
1244
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
1245
+
1246
+ apply:
1247
+ name: Apply with the pinned ProductShape provider
1248
+ needs: prepare
1249
+ if: needs.prepare.outputs.eligible == 'true'
1250
+ runs-on: ubuntu-24.04
1251
+ # Permissions for the apply job (workflow permissions default to none).
1252
+ permissions: {}
1253
+ steps:
1254
+ - name: Configure GH_HOST for enterprise compatibility
1255
+ id: ghes-host-config
1256
+ shell: bash
1257
+ run: | # zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input.
1258
+ # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
1259
+ # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
1260
+ GH_HOST="${GITHUB_SERVER_URL#https://}"
1261
+ GH_HOST="${GH_HOST#http://}"
1262
+ echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
1263
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
1264
+ with:
1265
+ persist-credentials: false
1266
+ ref: ${{ needs.prepare.outputs.head }}
1267
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
1268
+ with:
1269
+ path: tools
1270
+ persist-credentials: false
1271
+ ref: __LIGHTHOUSE_REF__
1272
+ repository: juangcarmona/lighthouse
1273
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
1274
+ with:
1275
+ node-version: 24
1276
+ - name: Install provider packages without credentials
1277
+ run: |
1278
+ npm ci --ignore-scripts
1279
+ npm install --no-save --package-lock=false --ignore-scripts @prodshape/integration-openspec@0.6.6
1280
+ - name: Load the approval checkpoint
1281
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1282
+ with:
1283
+ name: lighthouse-product-apply-input-${{ inputs.issue }}-${{ github.run_attempt }}
1284
+ path: ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}
1285
+ - name: Run provider dry-run, apply and validation
1286
+ run: node tools/src/packages/sdlc/src/issue-actions.mjs product-apply
1287
+ - name: Preserve the provider output and apply receipt
1288
+ if: always()
1289
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1290
+ with:
1291
+ if-no-files-found: error
1292
+ name: lighthouse-product-apply-result-${{ inputs.issue }}-${{ github.run_attempt }}
1293
+ path: |
1294
+ ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}/apply-result.json
1295
+ ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}/affected-citations.json
1296
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '30' }}
1297
+
1298
+ conclusion:
1299
+ name: conclusion
1300
+ needs:
1301
+ - activation
1302
+ - agent
1303
+ - apply
1304
+ - prepare
1305
+ - publish
1306
+ - safe_outputs
1307
+ if: >
1308
+ always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' ||
1309
+ needs.activation.outputs.oauth_token_check_failed == 'true' || needs.activation.outputs.stale_lock_file_failed == 'true' ||
1310
+ needs.activation.outputs.secret_verification_result == 'failed' || needs.activation.outputs.daily_ai_credits_exceeded == 'true' ||
1311
+ needs.activation.outputs.daily_ai_credits_guardrail_status == 'structural_error' || needs.activation.outputs.daily_ai_credits_guardrail_status == 'transient_error')
1312
+ runs-on: ubuntu-24.04
1313
+ # Permissions for the conclusion job (workflow permissions default to none).
1314
+ permissions:
1315
+ actions: read
1316
+ issues: write
1317
+ concurrency:
1318
+ group: "gh-aw-conclusion-lighthouse-sdlc-apply-product-change-${{ github.run_id }}"
1319
+ cancel-in-progress: false
1320
+ queue: max
1321
+ env:
1322
+ GH_AW_JOB_DISPLAY_NAMES: "{\"activation\":\"activation\",\"agent\":\"agent\",\"apply\":\"Apply with the pinned ProductShape provider\",\"conclusion\":\"conclusion\",\"pre_activation\":\"pre_activation\",\"prepare\":\"Recheck product approval\",\"publish\":\"Recheck and publish provider output\",\"safe_outputs\":\"safe_outputs\"}"
1323
+ GH_AW_JOB_RESULTS: "{\"activation\":{\"result\":\"${{ needs.activation.result }}\"},\"agent\":{\"result\":\"${{ needs.agent.result }}\"},\"apply\":{\"result\":\"${{ needs.apply.result }}\"},\"prepare\":{\"result\":\"${{ needs.prepare.result }}\"},\"publish\":{\"result\":\"${{ needs.publish.result }}\"},\"safe_outputs\":{\"result\":\"${{ needs.safe_outputs.result }}\"}}"
1324
+ GH_AW_JOB_TIMING_ELIGIBLE: "{\"activation\":true,\"agent\":true,\"apply\":true,\"conclusion\":true,\"pre_activation\":true,\"prepare\":true,\"publish\":true,\"safe_outputs\":true}"
1325
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
1326
+ outputs:
1327
+ noop_comment_body: ${{ steps.noop.outputs.noop_comment_body }}
1328
+ noop_message: ${{ steps.noop.outputs.noop_message }}
1329
+ tools_reported: ${{ steps.missing_tool.outputs.tools_reported }}
1330
+ total_count: ${{ steps.missing_tool.outputs.total_count }}
1331
+ steps:
1332
+ - name: Setup Scripts
1333
+ id: setup
1334
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
1335
+ with:
1336
+ destination: ${{ runner.temp }}/gh-aw/actions
1337
+ job-name: ${{ github.job }}
1338
+ trace-id: ${{ needs.activation.outputs.setup-trace-id }}
1339
+ parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
1340
+ env:
1341
+ GH_AW_SETUP_WORKFLOW_NAME: "apply-product-change"
1342
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-apply-product-change.lock.yml@${{ github.ref }}
1343
+ GH_AW_INFO_VERSION: "1.0.101"
1344
+ GH_AW_INFO_AWF_VERSION: "v0.28.70"
1345
+ GH_AW_INFO_ENGINE_ID: "copilot"
1346
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
1347
+ - name: Download agent output artifact
1348
+ id: download-agent-output
1349
+ continue-on-error: true
1350
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1351
+ with:
1352
+ pattern: "{agent,agent-output-fallback}"
1353
+ merge-multiple: true
1354
+ path: /tmp/gh-aw/
1355
+ - name: Setup agent output environment variable
1356
+ id: setup-agent-output-env
1357
+ if: steps.download-agent-output.outcome == 'success'
1358
+ run: |
1359
+ mkdir -p /tmp/gh-aw/
1360
+ find "/tmp/gh-aw/" -type f -print
1361
+ if [ -f "/tmp/gh-aw/agent_output.json" ]; then
1362
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
1363
+ fi
1364
+ - name: Restore runtime model metadata
1365
+ if: always()
1366
+ run: |
1367
+ 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
1368
+ - name: Download Safe Outputs Items Manifest
1369
+ id: download-safe-outputs-manifest
1370
+ if: always()
1371
+ continue-on-error: true
1372
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1373
+ with:
1374
+ pattern: safe-outputs-items
1375
+ merge-multiple: true
1376
+ path: /tmp/gh-aw/
1377
+ - name: Process no-op messages
1378
+ id: noop
1379
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1380
+ env:
1381
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1382
+ GH_AW_NOOP_MAX: "2"
1383
+ GH_AW_WORKFLOW_NAME: "apply-product-change"
1384
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-apply-product-change.md"
1385
+ GH_AW_ENGINE_ID: "copilot"
1386
+ GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
1387
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
1388
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
1389
+ GH_AW_NOOP_REPORT_AS_ISSUE: "false"
1390
+ GH_AW_AIC: ${{ needs.agent.outputs.aic }}
1391
+ GH_AW_AMBIENT_CONTEXT: ${{ needs.agent.outputs.ambient_context }}
1392
+ GH_AW_WORKFLOW_ID: "lighthouse-sdlc-apply-product-change"
1393
+ with:
1394
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1395
+ script: |
1396
+ const path = require('path');
1397
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1398
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1399
+ setupGlobals(core, github, context, exec, io, getOctokit);
1400
+ const { main } = require(path.join(actionsDir, 'handle_noop_message.cjs'));
1401
+ await main();
1402
+ - name: Record missing tool
1403
+ id: missing_tool
1404
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1405
+ env:
1406
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1407
+ GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
1408
+ GH_AW_WORKFLOW_NAME: "apply-product-change"
1409
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-apply-product-change.md"
1410
+ GH_AW_ENGINE_ID: "copilot"
1411
+ GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
1412
+ with:
1413
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1414
+ script: |
1415
+ const path = require('path');
1416
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1417
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1418
+ setupGlobals(core, github, context, exec, io, getOctokit);
1419
+ const { main } = require(path.join(actionsDir, 'missing_tool.cjs'));
1420
+ await main();
1421
+ - name: Handle agent failure
1422
+ id: handle_agent_failure
1423
+ if: always()
1424
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1425
+ env:
1426
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1427
+ GH_AW_WORKFLOW_NAME: "apply-product-change"
1428
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-apply-product-change.md"
1429
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
1430
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
1431
+ GH_AW_WORKFLOW_ID: "lighthouse-sdlc-apply-product-change"
1432
+ GH_AW_ACTION_FAILURE_ISSUE_EXPIRES_HOURS: "0"
1433
+ GH_AW_ENGINE_ID: "copilot"
1434
+ GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }}
1435
+ 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"
1436
+ GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
1437
+ GH_AW_CHECKOUT_PR_INVALIDATED: ${{ needs.agent.outputs.checkout_pr_invalidated }}
1438
+ GH_AW_AI_CREDITS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.ai_credits_rate_limit_error || 'false' }}
1439
+ GH_AW_UNKNOWN_MODEL_AI_CREDITS: ${{ needs.agent.outputs.unknown_model_ai_credits || 'false' }}
1440
+ GH_AW_AIC: ${{ needs.agent.outputs.aic }}
1441
+ GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
1442
+ GH_AW_DEFAULT_CHECKOUT_USES_TRIGGER_REF: "true"
1443
+ GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }}
1444
+ GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }}
1445
+ GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }}
1446
+ GH_AW_MODEL_NOT_SUPPORTED_ERROR: ${{ needs.agent.outputs.model_not_supported_error }}
1447
+ GH_AW_MODEL_ENDPOINT_MISMATCH_ERROR: ${{ needs.agent.outputs.model_endpoint_mismatch_error }}
1448
+ GH_AW_HTTP_400_RESPONSE_ERROR: ${{ needs.agent.outputs.http_400_response_error }}
1449
+ GH_AW_MAX_CACHE_MISSES_EXCEEDED: ${{ needs.agent.outputs.max_cache_misses_exceeded }}
1450
+ GH_AW_MISSING_MODEL_PRICING_ERROR: ${{ needs.agent.outputs.missing_model_pricing_error }}
1451
+ GH_AW_MISSING_MODEL_PRICING_MODEL_NAME: ${{ needs.agent.outputs.missing_model_pricing_model_name }}
1452
+ GH_AW_SHELL_EXPANSION_GUARD_REJECTED: ${{ needs.agent.outputs.shell_expansion_guard_rejected }}
1453
+ GH_AW_ENGINE_API_HOSTS: "api.enterprise.githubcopilot.com,api.githubcopilot.com,api.business.githubcopilot.com,api.individual.githubcopilot.com"
1454
+ GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }}
1455
+ GH_AW_OAUTH_TOKEN_CHECK_FAILED: ${{ needs.activation.outputs.oauth_token_check_failed }}
1456
+ GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }}
1457
+ GH_AW_DAILY_AI_CREDITS_EXCEEDED: ${{ needs.activation.outputs.daily_ai_credits_exceeded }}
1458
+ GH_AW_DAILY_AI_CREDITS_GUARDRAIL_STATUS: ${{ needs.activation.outputs.daily_ai_credits_guardrail_status }}
1459
+ GH_AW_DAILY_AI_CREDITS_GUARDRAIL_ERROR: ${{ needs.activation.outputs.daily_ai_credits_guardrail_error }}
1460
+ GH_AW_DAILY_AI_CREDITS_TOTAL: ${{ needs.activation.outputs.daily_ai_credits_total }}
1461
+ GH_AW_DAILY_AI_CREDITS_ESTIMATED: ${{ needs.activation.outputs.daily_ai_credits_estimated }}
1462
+ GH_AW_DAILY_AI_CREDITS_THRESHOLD: ${{ needs.activation.outputs.daily_ai_credits_threshold }}
1463
+ GH_AW_DAILY_AI_CREDITS_CONTINUE_ON_ERROR: "false"
1464
+ GH_AW_GROUP_REPORTS: "false"
1465
+ GH_AW_FAILURE_REPORT_AS_ISSUE: "false"
1466
+ GH_AW_MISSING_TOOL_REPORT_AS_FAILURE: "true"
1467
+ GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true"
1468
+ GH_AW_TIMEOUT_MINUTES: "30"
1469
+ with:
1470
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1471
+ script: |
1472
+ const path = require('path');
1473
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1474
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1475
+ setupGlobals(core, github, context, exec, io, getOctokit);
1476
+ const { main } = require(path.join(actionsDir, 'handle_agent_failure.cjs'));
1477
+ await main();
1478
+ - name: Report failed jobs
1479
+ id: report_failed_jobs
1480
+ if: always()
1481
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1482
+ env:
1483
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1484
+ GH_AW_WORKFLOW_NAME: "apply-product-change"
1485
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-apply-product-change.md"
1486
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
1487
+ GH_AW_REPORT_FAILED_JOBS: "true"
1488
+ with:
1489
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1490
+ script: |
1491
+ const path = require('path');
1492
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1493
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1494
+ setupGlobals(core, github, context, exec, io, getOctokit);
1495
+ const { main } = require(path.join(actionsDir, 'report_failed_jobs.cjs'));
1496
+ await main();
1497
+ - name: Collect usage artifact files
1498
+ if: always()
1499
+ continue-on-error: true
1500
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/collect_usage_artifact_files.sh"
1501
+ - name: Generate usage activity summary and unified session
1502
+ if: always()
1503
+ continue-on-error: true
1504
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1505
+ env:
1506
+ GH_AW_ADMISSION_RESULT: ${{ needs.activation.outputs.admission-result }}
1507
+ GH_AW_ADMISSION_MAX_AI_CREDITS: ${{ needs.activation.outputs.admission-max-ai-credits }}
1508
+ GH_AW_ADMISSION_MAX_AI_CREDITS_THREAT_DETECTION: ${{ needs.activation.outputs.admission-max-ai-credits-threat-detection }}
1509
+ GH_AW_ADMISSION_MAX_AI_CREDITS_EVALS: ${{ needs.activation.outputs.admission-max-ai-credits-evals }}
1510
+ GH_AW_GRADER_MANIFEST_0: '{"version":2,"graders":[]}'
1511
+ GH_AW_GRADER_MANIFEST_CHUNKS: '1'
1512
+ GH_AW_JOB_DURATIONS: ${{ steps.report_failed_jobs.outputs.job_durations }}
1513
+ GH_AW_DAILY_AI_CREDITS_GUARDRAIL_STATUS: ${{ needs.activation.outputs.daily_ai_credits_guardrail_status }}
1514
+ GH_AW_DAILY_AI_CREDITS_EXCEEDED: ${{ needs.activation.outputs.daily_ai_credits_exceeded }}
1515
+ GH_AW_DAILY_AI_CREDITS_TOTAL: ${{ needs.activation.outputs.daily_ai_credits_total }}
1516
+ GH_AW_DAILY_AI_CREDITS_ESTIMATED: ${{ needs.activation.outputs.daily_ai_credits_estimated }}
1517
+ GH_AW_DAILY_AI_CREDITS_THRESHOLD: ${{ needs.activation.outputs.daily_ai_credits_threshold }}
1518
+ with:
1519
+ script: |
1520
+ const path = require('path');
1521
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1522
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1523
+ setupGlobals(core, github, context, exec, io, getOctokit);
1524
+ const { main } = require(path.join(actionsDir, 'generate_usage_artifacts.cjs'));
1525
+ await main();
1526
+ - name: Upload usage artifact
1527
+ id: upload-usage-artifact
1528
+ if: always()
1529
+ continue-on-error: true
1530
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1531
+ with:
1532
+ name: usage
1533
+ path: |
1534
+ /tmp/gh-aw/usage/aw_session.jsonl
1535
+ /tmp/gh-aw/usage/aw_info.json
1536
+ /tmp/gh-aw/usage/aw-info.jsonl
1537
+ /tmp/gh-aw/usage/agent_usage.json
1538
+ /tmp/gh-aw/usage/agent_usage.jsonl
1539
+ /tmp/gh-aw/usage/detection_usage.jsonl
1540
+ /tmp/gh-aw/usage/evals.jsonl
1541
+ /tmp/gh-aw/usage/graders/grader_manifest.json
1542
+ /tmp/gh-aw/usage/graders/grader_results.json
1543
+ /tmp/gh-aw/usage/github_rate_limits.jsonl
1544
+ /tmp/gh-aw/usage/agent/token_usage.jsonl
1545
+ /tmp/gh-aw/usage/agent/model-routing.jsonl
1546
+ /tmp/gh-aw/usage/agent/execution.json
1547
+ /tmp/gh-aw/usage/detection/token_usage.jsonl
1548
+ /tmp/gh-aw/usage/detection/execution.json
1549
+ /tmp/gh-aw/usage/detection/detection_result.json
1550
+ /tmp/gh-aw/usage/evals/token_usage.jsonl
1551
+ /tmp/gh-aw/usage/evals/execution.json
1552
+ /tmp/gh-aw/usage/experiment/state.jsonl
1553
+ /tmp/gh-aw/usage/experiment/state.json
1554
+ /tmp/gh-aw/usage/experiment/assignments.json
1555
+ /tmp/gh-aw/usage/activity/summary.json
1556
+ if-no-files-found: ignore
1557
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
1558
+ - name: Wait before retrying usage artifact upload
1559
+ if: always() && steps.upload-usage-artifact.outcome == 'failure'
1560
+ run: sleep 10
1561
+ - name: Retry upload usage artifact
1562
+ id: upload-usage-artifact-retry
1563
+ if: always() && steps.upload-usage-artifact.outcome == 'failure'
1564
+ continue-on-error: true
1565
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1566
+ with:
1567
+ name: usage
1568
+ path: |
1569
+ /tmp/gh-aw/usage/aw_session.jsonl
1570
+ /tmp/gh-aw/usage/aw_info.json
1571
+ /tmp/gh-aw/usage/aw-info.jsonl
1572
+ /tmp/gh-aw/usage/agent_usage.json
1573
+ /tmp/gh-aw/usage/agent_usage.jsonl
1574
+ /tmp/gh-aw/usage/detection_usage.jsonl
1575
+ /tmp/gh-aw/usage/evals.jsonl
1576
+ /tmp/gh-aw/usage/graders/grader_manifest.json
1577
+ /tmp/gh-aw/usage/graders/grader_results.json
1578
+ /tmp/gh-aw/usage/github_rate_limits.jsonl
1579
+ /tmp/gh-aw/usage/agent/token_usage.jsonl
1580
+ /tmp/gh-aw/usage/agent/model-routing.jsonl
1581
+ /tmp/gh-aw/usage/agent/execution.json
1582
+ /tmp/gh-aw/usage/detection/token_usage.jsonl
1583
+ /tmp/gh-aw/usage/detection/execution.json
1584
+ /tmp/gh-aw/usage/detection/detection_result.json
1585
+ /tmp/gh-aw/usage/evals/token_usage.jsonl
1586
+ /tmp/gh-aw/usage/evals/execution.json
1587
+ /tmp/gh-aw/usage/experiment/state.jsonl
1588
+ /tmp/gh-aw/usage/experiment/state.json
1589
+ /tmp/gh-aw/usage/experiment/assignments.json
1590
+ /tmp/gh-aw/usage/activity/summary.json
1591
+ if-no-files-found: ignore
1592
+ overwrite: true
1593
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
1594
+
1595
+ pre_activation:
1596
+ name: pre_activation
1597
+ needs: prepare
1598
+ runs-on: ubuntu-24.04
1599
+ env:
1600
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
1601
+ outputs:
1602
+ activated: ${{ 'true' }}
1603
+ matched_command: ''
1604
+ setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
1605
+ setup-span-id: ${{ steps.setup.outputs.span-id }}
1606
+ setup-trace-id: ${{ steps.setup.outputs.trace-id }}
1607
+ steps:
1608
+ - name: Setup Scripts
1609
+ id: setup
1610
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
1611
+ with:
1612
+ destination: ${{ runner.temp }}/gh-aw/actions
1613
+ job-name: ${{ github.job }}
1614
+ env:
1615
+ GH_AW_SETUP_WORKFLOW_NAME: "apply-product-change"
1616
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-apply-product-change.lock.yml@${{ github.ref }}
1617
+ GH_AW_INFO_VERSION: "1.0.101"
1618
+ GH_AW_INFO_AWF_VERSION: "v0.28.70"
1619
+ GH_AW_INFO_ENGINE_ID: "copilot"
1620
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
1621
+
1622
+ prepare:
1623
+ name: Recheck product approval
1624
+ runs-on: ubuntu-24.04
1625
+ # Permissions for the prepare job (workflow permissions default to none).
1626
+ permissions:
1627
+ actions: read
1628
+ contents: read
1629
+ issues: read
1630
+ pull-requests: read
1631
+ env:
1632
+ LIGHTHOUSE_DISPATCH_REQUIRED: true
1633
+ LIGHTHOUSE_ISSUE: ${{ inputs.issue }}
1634
+ LIGHTHOUSE_PRODUCT_CHANGE_ENABLED: true
1635
+ LIGHTHOUSE_STAGE: propose
1636
+ LIGHTHOUSE_WORKER: apply-product-change
1637
+ outputs:
1638
+ eligible: ${{ steps.prepare.outputs.eligible }}
1639
+ head: ${{ steps.prepare.outputs.head }}
1640
+ steps:
1641
+ - name: Configure GH_HOST for enterprise compatibility
1642
+ id: ghes-host-config
1643
+ shell: bash
1644
+ run: | # zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input.
1645
+ # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
1646
+ # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
1647
+ GH_HOST="${GITHUB_SERVER_URL#https://}"
1648
+ GH_HOST="${GH_HOST#http://}"
1649
+ echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
1650
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
1651
+ with:
1652
+ persist-credentials: false
1653
+ ref: __LIGHTHOUSE_REF__
1654
+ repository: juangcarmona/lighthouse
1655
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
1656
+ with:
1657
+ node-version: 24
1658
+ - name: Recheck the explicit current owner decision
1659
+ id: prepare
1660
+ run: node src/packages/sdlc/src/issue-actions.mjs product-apply-prepare
1661
+ env:
1662
+ GH_TOKEN: ${{ github.token }}
1663
+ - name: Preserve the approval checkpoint
1664
+ if: steps.prepare.outputs.eligible == 'true'
1665
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1666
+ with:
1667
+ if-no-files-found: error
1668
+ name: lighthouse-product-apply-input-${{ inputs.issue }}-${{ github.run_attempt }}
1669
+ path: ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}/product-apply.json
1670
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '14' }}
1671
+
1672
+ publish:
1673
+ name: Recheck and publish provider output
1674
+ needs:
1675
+ - apply
1676
+ - prepare
1677
+ if: always() && needs.prepare.outputs.eligible == 'true'
1678
+ runs-on: ubuntu-24.04
1679
+ # Permissions for the publish job (workflow permissions default to none).
1680
+ permissions:
1681
+ actions: read
1682
+ contents: write
1683
+ issues: write
1684
+ pull-requests: write
1685
+ env:
1686
+ LIGHTHOUSE_DISPATCH_REQUIRED: true
1687
+ LIGHTHOUSE_ISSUE: ${{ inputs.issue }}
1688
+ LIGHTHOUSE_PRODUCT_CHANGE_ENABLED: true
1689
+ LIGHTHOUSE_STAGE: propose
1690
+ LIGHTHOUSE_WORKER: apply-product-change
1691
+ steps:
1692
+ - name: Configure GH_HOST for enterprise compatibility
1693
+ id: ghes-host-config
1694
+ shell: bash
1695
+ run: | # zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input.
1696
+ # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
1697
+ # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
1698
+ GH_HOST="${GITHUB_SERVER_URL#https://}"
1699
+ GH_HOST="${GH_HOST#http://}"
1700
+ echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
1701
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
1702
+ with:
1703
+ persist-credentials: false
1704
+ ref: __LIGHTHOUSE_REF__
1705
+ repository: juangcarmona/lighthouse
1706
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
1707
+ with:
1708
+ node-version: 24
1709
+ - name: Load the approved checkpoint
1710
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1711
+ with:
1712
+ name: lighthouse-product-apply-input-${{ inputs.issue }}-${{ github.run_attempt }}
1713
+ path: ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}
1714
+ - name: Load provider output
1715
+ if: needs.apply.result == 'success'
1716
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1717
+ with:
1718
+ name: lighthouse-product-apply-result-${{ inputs.issue }}-${{ github.run_attempt }}
1719
+ path: ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}
1720
+ - name: Stop when the provider apply did not complete
1721
+ if: needs.apply.result != 'success'
1722
+ run: exit 1
1723
+ - name: Publish only the verified applied delta
1724
+ run: node src/packages/sdlc/src/issue-actions.mjs product-apply-publish
1725
+ env:
1726
+ GH_TOKEN: ${{ github.token }}
1727
+
1728
+ safe_outputs:
1729
+ name: safe_outputs
1730
+ needs:
1731
+ - activation
1732
+ - agent
1733
+ if: (!cancelled()) && needs.agent.result != 'skipped'
1734
+ runs-on: ubuntu-24.04
1735
+ # Permissions for the safe_outputs job (workflow permissions default to none).
1736
+ permissions: {}
1737
+ timeout-minutes: 45
1738
+ env:
1739
+ GH_AW_AGENT_AIC: ${{ needs.agent.outputs.aic }}
1740
+ GH_AW_AIC: ${{ needs.agent.outputs.aic }}
1741
+ GH_AW_AMBIENT_CONTEXT: ${{ needs.agent.outputs.ambient_context }}
1742
+ GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/lighthouse-sdlc-apply-product-change"
1743
+ GH_AW_ENGINE_ID: "copilot"
1744
+ GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
1745
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
1746
+ GH_AW_WORKFLOW_ID: "lighthouse-sdlc-apply-product-change"
1747
+ GH_AW_WORKFLOW_NAME: "apply-product-change"
1748
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-apply-product-change.md"
1749
+ outputs:
1750
+ code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
1751
+ code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
1752
+ create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}
1753
+ create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}
1754
+ process_safe_outputs_items_applied: ${{ steps.process_safe_outputs.outputs.items_applied }}
1755
+ process_safe_outputs_items_cancelled: ${{ steps.process_safe_outputs.outputs.items_cancelled }}
1756
+ process_safe_outputs_items_deferred: ${{ steps.process_safe_outputs.outputs.items_deferred }}
1757
+ process_safe_outputs_items_failed: ${{ steps.process_safe_outputs.outputs.items_failed }}
1758
+ process_safe_outputs_items_skipped: ${{ steps.process_safe_outputs.outputs.items_skipped }}
1759
+ process_safe_outputs_items_succeeded: ${{ steps.process_safe_outputs.outputs.items_succeeded }}
1760
+ process_safe_outputs_items_warnings: ${{ steps.process_safe_outputs.outputs.items_warnings }}
1761
+ process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}
1762
+ process_safe_outputs_status: ${{ steps.process_safe_outputs.outputs.status }}
1763
+ steps:
1764
+ - name: Setup Scripts
1765
+ id: setup
1766
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
1767
+ with:
1768
+ destination: ${{ runner.temp }}/gh-aw/actions
1769
+ job-name: ${{ github.job }}
1770
+ trace-id: ${{ needs.activation.outputs.setup-trace-id }}
1771
+ parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
1772
+ env:
1773
+ GH_AW_SETUP_WORKFLOW_NAME: "apply-product-change"
1774
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-apply-product-change.lock.yml@${{ github.ref }}
1775
+ GH_AW_INFO_VERSION: "1.0.101"
1776
+ GH_AW_INFO_AWF_VERSION: "v0.28.70"
1777
+ GH_AW_INFO_ENGINE_ID: "copilot"
1778
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
1779
+ - name: Mask OTLP telemetry headers
1780
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh"
1781
+ - name: Download agent output artifact
1782
+ id: download-agent-output
1783
+ continue-on-error: true
1784
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1785
+ with:
1786
+ pattern: "{agent,agent-output-fallback}"
1787
+ merge-multiple: true
1788
+ path: /tmp/gh-aw/
1789
+ - name: Setup agent output environment variable
1790
+ id: setup-agent-output-env
1791
+ if: steps.download-agent-output.outcome == 'success'
1792
+ run: |
1793
+ mkdir -p /tmp/gh-aw/
1794
+ find "/tmp/gh-aw/" -type f -print
1795
+ if [ -f "/tmp/gh-aw/agent_output.json" ]; then
1796
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
1797
+ fi
1798
+ - name: Configure GH_HOST for enterprise compatibility
1799
+ id: ghes-host-config
1800
+ shell: bash
1801
+ run: | # zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input.
1802
+ # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
1803
+ # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
1804
+ GH_HOST="${GITHUB_SERVER_URL#https://}"
1805
+ GH_HOST="${GH_HOST#http://}"
1806
+ echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
1807
+ - name: Process Safe Outputs
1808
+ id: process_safe_outputs
1809
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1810
+ env:
1811
+ GH_AW_JOB_CHECK_RUN_ID: ${{ job.check_run_id }}
1812
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1813
+ GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
1814
+ GH_AW_MENTIONS_GITHUB_TOKEN: ${{ github.token }}
1815
+ GITHUB_SERVER_URL: ${{ github.server_url }}
1816
+ GITHUB_API_URL: ${{ github.api_url }}
1817
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"noop\":{\"max\":2,\"report-as-issue\":\"false\"},\"report_missing_data\":{},\"report_missing_tool\":{}}"
1818
+ GH_AW_GITHUB_TOKEN_SOURCE: ${{ secrets.GH_AW_GITHUB_TOKEN != '' && 'pat' || 'github_actions' }}
1819
+ with:
1820
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1821
+ script: |
1822
+ const path = require('path');
1823
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1824
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1825
+ setupGlobals(core, github, context, exec, io, getOctokit, process.env.GH_AW_GITHUB_TOKEN_SOURCE);
1826
+ const { main } = require(path.join(actionsDir, 'process_safe_outputs.cjs'));
1827
+ await main();
1828
+ - name: Upload Safe Outputs Items
1829
+ if: always()
1830
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1831
+ with:
1832
+ name: safe-outputs-items
1833
+ path: |
1834
+ /tmp/gh-aw/safe-output-items.jsonl
1835
+ /tmp/gh-aw/temporary-id-map.json
1836
+ /tmp/gh-aw/safe-output-errors.json
1837
+ if-no-files-found: ignore
1838
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}