@juangcarmona/lighthouse-sdlc 0.13.0 → 0.14.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.
Files changed (39) hide show
  1. package/README.md +61 -12
  2. package/completion.md +6 -4
  3. package/execution-environments.md +43 -0
  4. package/package.json +2 -1
  5. package/schemas/execution-environment.schema.json +12 -0
  6. package/skills/implement/SKILL.md +9 -8
  7. package/src/actions-artifact.mjs +17 -0
  8. package/src/completion-actions.mjs +30 -10
  9. package/src/completion.mjs +19 -0
  10. package/src/delivery-events.mjs +42 -0
  11. package/src/execution-environment.mjs +78 -0
  12. package/src/implementation-runtime.mjs +56 -32
  13. package/src/implementation.mjs +31 -19
  14. package/src/install-workflows.mjs +10 -7
  15. package/src/integration-evidence.mjs +25 -1
  16. package/src/issue-actions.mjs +260 -38
  17. package/src/opencode-execute.mjs +20 -10
  18. package/src/process-publication.mjs +1 -1
  19. package/src/proposal-review.mjs +91 -0
  20. package/src/proposal.mjs +22 -8
  21. package/src/stage-dispatch.mjs +148 -0
  22. package/src/stage-transition.mjs +25 -0
  23. package/src/worker-maintenance.mjs +83 -0
  24. package/src/worker-recovery.mjs +106 -0
  25. package/src/worker-reports.mjs +150 -0
  26. package/workflows/lighthouse-sdlc-apply-review.lock.yml +1335 -0
  27. package/workflows/lighthouse-sdlc-apply-review.md +205 -0
  28. package/workflows/lighthouse-sdlc-implement.lock.yml +51 -90
  29. package/workflows/lighthouse-sdlc-implement.md +40 -11
  30. package/workflows/lighthouse-sdlc-integrate.lock.yml +36 -83
  31. package/workflows/lighthouse-sdlc-integrate.md +25 -2
  32. package/workflows/lighthouse-sdlc-propose.lock.yml +44 -83
  33. package/workflows/lighthouse-sdlc-propose.md +33 -4
  34. package/workflows/lighthouse-sdlc-refine.lock.yml +45 -83
  35. package/workflows/lighthouse-sdlc-refine.md +32 -2
  36. package/workflows/lighthouse-sdlc-review.lock.yml +36 -83
  37. package/workflows/lighthouse-sdlc-review.md +25 -2
  38. package/workflows/lighthouse-sdlc-router.yml +70 -62
  39. package/workflows/lighthouse-worker-maintenance.yml +126 -0
@@ -0,0 +1,1335 @@
1
+ # gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"b53e69b59b107e49da418b572f7b91a908ecc6640f2e9a5ecf8af1e418467b0c","body_hash":"8151890e19043f86541decb00d0dc86741daec051c004feb7beab27b025e3621","compiler_version":"v0.93.2","agent_id":"opencode","engine_versions":{"opencode":"2.1.0"},"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-node","digest":"sha256:41835613992df88f51e923bad486f96dfb2e6cda29f13e217df41833284ae382","pinned_image":"ghcr.io/github/gh-aw-node@sha256:41835613992df88f51e923bad486f96dfb2e6cda29f13e217df41833284ae382"}],"mcp_servers":[{"name":"safeoutputs","tools":["noop"]}],"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
+ # Apply authorized feedback to the existing proposal or implementation PR.
27
+ #
28
+ # Resolved workflow manifest:
29
+ # Imports:
30
+ # - shared/lighthouse-opencode.md
31
+ #
32
+ # Frontmatter env variables:
33
+ # - LIGHTHOUSE_DISPATCH_REQUIRED: (main workflow)
34
+ # - LIGHTHOUSE_RECOVERY_ENABLED: (main workflow)
35
+ # - LIGHTHOUSE_WORKER: (main workflow)
36
+ #
37
+ # Secrets used:
38
+ # - COPILOT_GITHUB_TOKEN
39
+ # - GH_AW_DEFAULT_OTLP_ENDPOINT
40
+ # - GH_AW_DEFAULT_OTLP_HEADERS
41
+ # - GH_AW_GITHUB_MCP_SERVER_TOKEN
42
+ # - GH_AW_GITHUB_TOKEN
43
+ # - GITHUB_TOKEN
44
+ #
45
+ # Custom actions used:
46
+ # - actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
47
+ # - actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
48
+ # - actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
49
+ # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
50
+ # - actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
51
+ # - actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
52
+ # - actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
53
+ # - github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
54
+ #
55
+ # Container images used:
56
+ # - ghcr.io/github/gh-aw-node@sha256:41835613992df88f51e923bad486f96dfb2e6cda29f13e217df41833284ae382
57
+
58
+ name: "Lighthouse SDLC apply-review"
59
+ on:
60
+ # roles: all # Roles processed as role check in pre-activation job
61
+ workflow_dispatch:
62
+ inputs:
63
+ aw_context:
64
+ default: ""
65
+ description: "Agent caller context (Reserved for Agentic Workflows)."
66
+ required: false
67
+ type: string
68
+ dispatch-request:
69
+ description: Authenticated router receipt comment ID
70
+ required: true
71
+ type: string
72
+ issue:
73
+ description: Source issue
74
+ required: true
75
+ type: string
76
+
77
+ # Jobs receive only their explicitly declared permissions.
78
+ permissions: {}
79
+
80
+ concurrency:
81
+ cancel-in-progress: false
82
+ group: lighthouse-issue-${{ inputs.issue }}
83
+ queue: max
84
+
85
+ run-name: "apply-review #${{ inputs.issue }} · request ${{ inputs.dispatch-request }}"
86
+
87
+ env:
88
+ LIGHTHOUSE_DISPATCH_REQUIRED: "true"
89
+ LIGHTHOUSE_RECOVERY_ENABLED: ${{ vars.LIGHTHOUSE_RECOVERY_ENABLED }}
90
+ LIGHTHOUSE_WORKER: apply-review
91
+ OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.GH_AW_DEFAULT_OTLP_ENDPOINT || vars.GH_AW_DEFAULT_OTLP_ENDPOINT }}
92
+ OTEL_SERVICE_NAME: gh-aw.lighthouse-sdlc-apply-review
93
+ OTEL_RESOURCE_ATTRIBUTES: 'gh-aw.workflow.name=Lighthouse%20SDLC%20apply-review,gh-aw.repository=${{ github.repository }},gh-aw.run.id=${{ github.run_id }},github.run_id=${{ github.run_id }},gh-aw.engine.id=opencode'
94
+ OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }}
95
+ GH_AW_OTLP_ENDPOINTS: '[{"url":"${{ secrets.GH_AW_DEFAULT_OTLP_ENDPOINT || vars.GH_AW_DEFAULT_OTLP_ENDPOINT }}","headers":"${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }}"}]'
96
+ GH_AW_OTLP_IF_MISSING: ignore
97
+
98
+ jobs:
99
+ activation:
100
+ name: activation
101
+ needs:
102
+ - pre_activation
103
+ - prepare
104
+ if: needs.pre_activation.outputs.activated == 'true' && (needs.prepare.outputs.eligible == 'true')
105
+ runs-on: ubuntu-24.04
106
+ # Permissions for the activation job (workflow permissions default to none).
107
+ permissions:
108
+ actions: read
109
+ contents: read
110
+ env:
111
+ GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }}
112
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
113
+ outputs:
114
+ aw_context: ${{ steps.generate_aw_info.outputs.aw_context }}
115
+ comment_id: ""
116
+ comment_repo: ""
117
+ daily_ai_credits_estimated: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_estimated || '' }}
118
+ daily_ai_credits_exceeded: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }}
119
+ daily_ai_credits_guardrail_error: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_guardrail_error || '' }}
120
+ daily_ai_credits_guardrail_status: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_guardrail_status || '' }}
121
+ daily_ai_credits_threshold: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }}
122
+ daily_ai_credits_total: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_total || '' }}
123
+ engine_id: ${{ steps.generate_aw_info.outputs.engine_id }}
124
+ lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }}
125
+ model: ${{ steps.generate_aw_info.outputs.model }}
126
+ oauth_token_check_failed: ${{ steps.check-oauth-tokens.outputs.oauth_token_check_failed == 'true' }}
127
+ setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
128
+ setup-span-id: ${{ steps.setup.outputs.span-id }}
129
+ setup-trace-id: ${{ steps.setup.outputs.trace-id }}
130
+ stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }}
131
+ steps:
132
+ - name: Setup Scripts
133
+ id: setup
134
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
135
+ with:
136
+ destination: ${{ runner.temp }}/gh-aw/actions
137
+ job-name: ${{ github.job }}
138
+ trace-id: ${{ needs.pre_activation.outputs.setup-trace-id }}
139
+ parent-span-id: ${{ needs.pre_activation.outputs.setup-parent-span-id || needs.pre_activation.outputs.setup-span-id }}
140
+ safe-output-artifact-client: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
141
+ env:
142
+ GH_AW_SETUP_WORKFLOW_NAME: "Lighthouse SDLC apply-review"
143
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-apply-review.lock.yml@${{ github.ref }}
144
+ GH_AW_INFO_VERSION: "2.1.0"
145
+ GH_AW_INFO_ENGINE_ID: "opencode"
146
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
147
+ - name: Mask OTLP telemetry headers
148
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh"
149
+ - name: Generate agentic run info
150
+ id: generate_aw_info
151
+ env:
152
+ GH_AW_INFO_ENGINE_ID: "opencode"
153
+ GH_AW_INFO_ENGINE_NAME: "OpenCode"
154
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_CUSTOM || '' }}
155
+ GH_AW_INFO_VERSION: "2.1.0"
156
+ GH_AW_INFO_AGENT_VERSION: "2.1.0"
157
+ GH_AW_INFO_CLI_VERSION: "v0.93.2"
158
+ GH_AW_INFO_WORKFLOW_NAME: "Lighthouse SDLC apply-review"
159
+ GH_AW_INFO_WORKFLOW_ID: ${{ job.workflow_ref }}
160
+ GH_AW_INFO_EXPERIMENTAL: "false"
161
+ GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
162
+ GH_AW_INFO_STAGED: "false"
163
+ GH_AW_INFO_ALLOWED_DOMAINS: '[]'
164
+ GH_AW_INFO_FIREWALL_ENABLED: "false"
165
+ GH_AW_INFO_AWF_VERSION: ""
166
+ GH_AW_INFO_AWMG_VERSION: ""
167
+ GH_AW_INFO_FIREWALL_TYPE: ""
168
+ GH_AW_INFO_AGENT_RUNTIME: ""
169
+ GH_AW_INFO_MODEL_CONFIG: '{"routing":{"enabled":false}}'
170
+ GH_AW_COMPILED_STRICT: "false"
171
+ GH_AW_INFO_FEATURES: '{"dangerously-disable-sandbox-agent":true}'
172
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
173
+ with:
174
+ script: |
175
+ const path = require('path');
176
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
177
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
178
+ setupGlobals(core, github, context, exec, io, getOctokit);
179
+ const { main } = require(path.join(actionsDir, 'generate_aw_info.cjs'));
180
+ await main(core, context);
181
+ - name: Enforce strict mode policy
182
+ if: ${{ vars.GH_AW_POLICY_STRICT == 'true' }}
183
+ run: |
184
+ echo "::error::GH_AW_POLICY_STRICT=true but this workflow was not compiled in strict mode. Recompile with --strict or strict: true."
185
+ exit 1
186
+ - name: Restore daily AIC scan observations
187
+ id: restore-daily-aic-cache-fallback
188
+ if: ${{ env.GH_AW_ADMISSION_RESULT != 'admitted' && env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
189
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
190
+ env:
191
+ GH_AW_HAS_SLASH_COMMAND: "false"
192
+ GH_AW_HAS_LABEL_COMMAND: "false"
193
+ with:
194
+ github-token: ${{ secrets.GITHUB_TOKEN }}
195
+ script: |
196
+ const path = require('path');
197
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
198
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
199
+ setupGlobals(core, github, context, exec, io, getOctokit);
200
+ const { main } = require(path.join(actionsDir, 'restore_aic_scan_cache.cjs'));
201
+ await main();
202
+ - name: Check daily workflow token guardrail
203
+ id: daily-ai-credits-workflow-guardrail
204
+ if: ${{ env.GH_AW_ADMISSION_RESULT != 'admitted' && env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
205
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
206
+ env:
207
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC apply-review"
208
+ GH_AW_WORKFLOW_ID: "lighthouse-sdlc-apply-review"
209
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
210
+ GH_AW_WORKFLOW_DISPATCH_AW_CONTEXT: ${{ github.event.inputs.aw_context || '' }}
211
+ GH_AW_HAS_SLASH_COMMAND: "false"
212
+ GH_AW_HAS_LABEL_COMMAND: "false"
213
+ GH_AW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
214
+ GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }}
215
+ GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
216
+ with:
217
+ github-token: ${{ secrets.GITHUB_TOKEN }}
218
+ script: |
219
+ const path = require('path');
220
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
221
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
222
+ setupGlobals(core, github, context, exec, io, getOctokit);
223
+ const { main } = require(path.join(actionsDir, 'check_daily_aic_workflow_guardrail.cjs'));
224
+ await main();
225
+ - name: Publish daily AIC scan observations
226
+ if: always() && env.GH_AW_ADMISSION_RESULT != 'admitted' && env.GH_AW_MAX_DAILY_AI_CREDITS != ''
227
+ continue-on-error: true
228
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
229
+ with:
230
+ name: aic-usage-scan-v2
231
+ path: /tmp/gh-aw/agentic-workflow-usage-scan-v2.jsonl
232
+ overwrite: true
233
+ if-no-files-found: ignore
234
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '3' }}
235
+ - name: Check for OAuth tokens
236
+ id: check-oauth-tokens
237
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/check_oauth_tokens.sh"
238
+ env:
239
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
240
+ GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
241
+ GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
242
+ - name: Checkout .github and .agents folders
243
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
244
+ with:
245
+ persist-credentials: false
246
+ sparse-checkout: |
247
+ .github
248
+ .agents
249
+ .claude
250
+ .codex
251
+ .gemini
252
+ .pi
253
+ sparse-checkout-cone-mode: true
254
+ fetch-depth: 1
255
+ - name: Save agent config folders for base branch restoration
256
+ env:
257
+ GH_AW_AGENT_FOLDERS: ".agents .github"
258
+ GH_AW_AGENT_FILES: "AGENTS.md"
259
+ run: |
260
+ bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
261
+ - name: Check workflow lock file
262
+ id: check-lock-file
263
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
264
+ env:
265
+ GH_AW_WORKFLOW_FILE: "lighthouse-sdlc-apply-review.lock.yml"
266
+ GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}"
267
+ with:
268
+ script: |
269
+ const path = require('path');
270
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
271
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
272
+ setupGlobals(core, github, context, exec, io, getOctokit);
273
+ const { main } = require(path.join(actionsDir, 'check_workflow_timestamp_api.cjs'));
274
+ await main();
275
+ - name: Check compile-agentic version
276
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
277
+ env:
278
+ GH_AW_COMPILED_VERSION: "v0.93.2"
279
+ GH_AW_HAS_SAFE_OUTPUTS: "true"
280
+ GH_AW_BLOCKED_VERSION_REPORT_AS_ISSUE: "false"
281
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC apply-review"
282
+ with:
283
+ script: |
284
+ const path = require('path');
285
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
286
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
287
+ setupGlobals(core, github, context, exec, io, getOctokit);
288
+ const { main } = require(path.join(actionsDir, 'check_version_updates.cjs'));
289
+ await main();
290
+ - name: Log runtime features
291
+ if: ${{ contains(toJSON(vars), '"GH_AW_RUNTIME_FEATURES":') }}
292
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/log_runtime_features_summary.sh"
293
+ - name: Create prompt with built-in context
294
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
295
+ env:
296
+ GH_AW_ACTIONS_DIR: ${{ runner.temp }}/gh-aw/actions
297
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
298
+ GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl
299
+ 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\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0004\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0005\"}],\"system_item_count\":10}"
300
+ GH_AW_PROMPT_CONTENT_0000: "<system>\n"
301
+ GH_AW_PROMPT_CONTENT_0001: "<safe-output-tools>\nTools: noop(max:2)\n"
302
+ GH_AW_PROMPT_CONTENT_0002: "</safe-output-tools>\n"
303
+ GH_AW_PROMPT_CONTENT_0003: "</system>\n"
304
+ GH_AW_PROMPT_CONTENT_0004: "{{#runtime-import .github/workflows/shared/lighthouse-opencode.md}}\n"
305
+ GH_AW_PROMPT_CONTENT_0005: "{{#runtime-import .github/workflows/lighthouse-sdlc-apply-review.md}}\n"
306
+ with:
307
+ script: |
308
+ const { setupGlobals } = require(process.env.GH_AW_ACTIONS_DIR + '/setup_globals.cjs');
309
+ setupGlobals(core, github, context, exec, io, getOctokit);
310
+ const { main } = require(process.env.GH_AW_ACTIONS_DIR + '/create_prompt.cjs');
311
+ await main(core);
312
+ - name: Interpolate variables and render templates
313
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
314
+ env:
315
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
316
+ GH_AW_ENGINE_ID: "opencode"
317
+ GH_AW_SUB_AGENT_DIR: ".github/agents"
318
+ GH_AW_SUB_AGENT_EXT: ".agent.md"
319
+ GH_AW_SKILL_DIR: ".github/skills"
320
+ GH_AW_SKILL_EXT: "/SKILL.md"
321
+ with:
322
+ script: |
323
+ const path = require('path');
324
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
325
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
326
+ setupGlobals(core, github, context, exec, io, getOctokit);
327
+ const { main } = require(path.join(actionsDir, 'interpolate_prompt.cjs'));
328
+ await main();
329
+ - name: Substitute placeholders
330
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
331
+ env:
332
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
333
+ GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools'
334
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }}
335
+ with:
336
+ script: |
337
+ const path = require('path');
338
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
339
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
340
+ setupGlobals(core, github, context, exec, io, getOctokit);
341
+
342
+ const substitutePlaceholders = require(path.join(actionsDir, 'substitute_placeholders.cjs'));
343
+
344
+ // Call the substitution function
345
+ return await substitutePlaceholders({
346
+ file: process.env.GH_AW_PROMPT,
347
+ substitutions: {
348
+ GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST,
349
+ GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED
350
+ }
351
+ });
352
+ - name: Validate prompt placeholders
353
+ env:
354
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
355
+ run: |
356
+ bash "${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh"
357
+ - name: Print prompt
358
+ env:
359
+ GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt
360
+ run: |
361
+ bash "${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh"
362
+ - name: Inventory installed skills
363
+ if: success() || failure()
364
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
365
+ env:
366
+ GH_AW_SKILL_DIR: ".github/skills"
367
+ with:
368
+ script: |
369
+ const path = require('path');
370
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
371
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
372
+ setupGlobals(core, github, context, exec, io, getOctokit);
373
+ const { main } = require(path.join(actionsDir, 'skill_inventory.cjs'));
374
+ await main();
375
+ - name: Upload info artifact
376
+ if: success() || failure()
377
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
378
+ with:
379
+ name: info
380
+ path: /tmp/gh-aw/aw_info.json
381
+ if-no-files-found: ignore
382
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
383
+ - name: Stage prompt files for artifact upload
384
+ run: |
385
+ mkdir -p /tmp/gh-aw/aw-prompts
386
+ cp -a "${RUNNER_TEMP}/gh-aw/aw-prompts/." /tmp/gh-aw/aw-prompts/
387
+ - name: Upload activation artifact
388
+ if: success() || failure()
389
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
390
+ with:
391
+ name: activation
392
+ include-hidden-files: true
393
+ path: |
394
+ /tmp/gh-aw/aw_info.json
395
+ /tmp/gh-aw/models.json
396
+ /tmp/gh-aw/aw-prompts/prompt.txt
397
+ /tmp/gh-aw/aw-prompts/system.txt
398
+ /tmp/gh-aw/aw-prompts/user.txt
399
+ /tmp/gh-aw/aw-prompts/prompt-template.txt
400
+ /tmp/gh-aw/aw-prompts/prompt-import-tree.json
401
+ /tmp/gh-aw/github_rate_limits.jsonl
402
+ /tmp/gh-aw/base
403
+ /tmp/gh-aw/.github/agents
404
+ /tmp/gh-aw/.github/skills
405
+ /tmp/gh-aw/skill_inventory.json
406
+ if-no-files-found: ignore
407
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '1' }}
408
+
409
+ agent:
410
+ name: agent
411
+ needs:
412
+ - activation
413
+ - prepare
414
+ if: (needs.prepare.outputs.eligible == 'true') && (needs.activation.outputs.daily_ai_credits_exceeded != 'true')
415
+ runs-on:
416
+ - self-hosted
417
+ - linux
418
+ - lighthouse-workflow
419
+ # Permissions for the agent job (workflow permissions default to none).
420
+ permissions:
421
+ contents: read
422
+ timeout-minutes: 60
423
+ env:
424
+ DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
425
+ GH_AW_ASSETS_ALLOWED_EXTS: ""
426
+ GH_AW_ASSETS_BRANCH: ""
427
+ GH_AW_ASSETS_MAX_SIZE_KB: 0
428
+ GH_AW_ENGINE_VERSION: "2.1.0"
429
+ GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
430
+ GH_AW_PR_HEAD_BASE_BRANCH: ""
431
+ GH_AW_PR_HEAD_BASE_PR_NUMBER: ""
432
+ GH_AW_PR_HEAD_BASE_REF: ""
433
+ GH_AW_PR_HEAD_BASE_REPO: ""
434
+ GH_AW_PR_HEAD_BASE_SHA: ""
435
+ GH_AW_PR_HEAD_REPO: ""
436
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
437
+ GH_AW_TARGET_REPO_SLUG: ""
438
+ GH_AW_WORKFLOW_ID_SANITIZED: lighthousesdlcapplyreview
439
+ outputs:
440
+ ai_credits_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.ai_credits_rate_limit_error || 'false' }}
441
+ aic: ${{ steps.parse-mcp-gateway.outputs.aic }}
442
+ ambient_context: ${{ steps.parse-mcp-gateway.outputs.ambient_context }}
443
+ has_patch: ${{ steps.collect_output.outputs.has_patch }}
444
+ model: ${{ needs.activation.outputs.model }}
445
+ output: ${{ steps.collect_output.outputs.output }}
446
+ output_types: ${{ steps.collect_output.outputs.output_types }}
447
+ setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
448
+ setup-span-id: ${{ steps.setup.outputs.span-id }}
449
+ setup-trace-id: ${{ steps.setup.outputs.trace-id }}
450
+ unknown_model_ai_credits: ${{ steps.parse-mcp-gateway.outputs.unknown_model_ai_credits || 'false' }}
451
+ steps:
452
+ - name: Setup Scripts
453
+ id: setup
454
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
455
+ with:
456
+ destination: ${{ runner.temp }}/gh-aw/actions
457
+ job-name: ${{ github.job }}
458
+ trace-id: ${{ needs.activation.outputs.setup-trace-id }}
459
+ parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
460
+ env:
461
+ GH_AW_SETUP_WORKFLOW_NAME: "Lighthouse SDLC apply-review"
462
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-apply-review.lock.yml@${{ github.ref }}
463
+ GH_AW_INFO_VERSION: "2.1.0"
464
+ GH_AW_INFO_ENGINE_ID: "opencode"
465
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
466
+ - name: Set runtime paths
467
+ id: set-runtime-paths
468
+ env:
469
+ GH_AW_RUNNER_TOOL_CACHE: ${{ runner.tool_cache }}
470
+ run: | # zizmor: ignore[github-env] - runner.tool_cache is set by GitHub Actions, not user input.
471
+ if [ -z "${RUNNER_TOOL_CACHE:-}" ]; then
472
+ echo "RUNNER_TOOL_CACHE=${GH_AW_RUNNER_TOOL_CACHE}" >> "$GITHUB_ENV"
473
+ fi
474
+ {
475
+ echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl"
476
+ echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json"
477
+ echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json"
478
+ } >> "$GITHUB_OUTPUT"
479
+ - name: Mask OTLP telemetry headers
480
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh"
481
+ - name: Check OTLP telemetry configuration
482
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/check_otlp_default_credentials.sh"
483
+ - name: Initialize agent execution evidence
484
+ run: |
485
+ mkdir -p "/tmp/gh-aw"
486
+ evidence_tmp="/tmp/gh-aw/agent_execution.json.tmp"
487
+ printf '{"version":1,"component":"agent","run_id":%s,"run_attempt":%s,"state":"not_started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp"
488
+ mv "$evidence_tmp" "/tmp/gh-aw/agent_execution.json"
489
+ - name: Create gh-aw temp directory
490
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh"
491
+ - name: Configure gh CLI for GitHub Enterprise
492
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh"
493
+ env:
494
+ GH_TOKEN: ${{ github.token }}
495
+ - name: Download activation artifact
496
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
497
+ with:
498
+ name: activation
499
+ path: /tmp/gh-aw
500
+ - name: Check out the authorized product revision
501
+ uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
502
+ with:
503
+ persist-credentials: false
504
+ ref: ${{ needs.prepare.outputs.source_revision }}
505
+ - name: Setup Node.js
506
+ uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
507
+ with:
508
+ node-version: '24'
509
+ package-manager-cache: false
510
+ - name: Load the pinned harness package
511
+ uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
512
+ with:
513
+ path: tools
514
+ persist-credentials: false
515
+ ref: __LIGHTHOUSE_REF__
516
+ repository: juangcarmona/lighthouse
517
+ - name: Load the authorized issue context
518
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
519
+ with:
520
+ name: lighthouse-${{ needs.prepare.outputs.artifact_prefix }}input-${{ inputs.issue }}-${{ github.run_attempt }}
521
+ path: ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}
522
+
523
+ - name: Configure Git credentials
524
+ env:
525
+ GITHUB_REPOSITORY: ${{ github.repository }}
526
+ GITHUB_SERVER_URL: ${{ github.server_url }}
527
+ GITHUB_TOKEN: ${{ github.token }}
528
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_git_credentials.sh"
529
+ - name: Restore inline sub-agents from activation artifact
530
+ env:
531
+ GH_AW_SUB_AGENT_DIR: ".github/agents"
532
+ GH_AW_SUB_AGENT_EXT: ".agent.md"
533
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
534
+ - name: Restore inline skills from activation artifact
535
+ env:
536
+ GH_AW_SKILL_DIR: ".github/skills"
537
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
538
+ - name: Download container images
539
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-node@sha256:41835613992df88f51e923bad486f96dfb2e6cda29f13e217df41833284ae382
540
+ - name: Prepare Safe Outputs Directories
541
+ run: |
542
+ mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
543
+ mkdir -p /tmp/gh-aw/safeoutputs
544
+ mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
545
+ - name: Generate Safe Outputs Config
546
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
547
+ env:
548
+ GH_AW_FILE_ROOT: "${{ runner.temp }}/gh-aw"
549
+ GH_AW_FILE_CONFIG: "{\"files\":[{\"path\":\"safeoutputs/config.json\",\"content_env\":\"GH_AW_SAFE_OUTPUTS_CONFIG\"}]}"
550
+ GH_AW_SAFE_OUTPUTS_CONFIG: "{\"noop\":{\"max\":2,\"report-as-issue\":\"false\"}}"
551
+ with:
552
+ script: |
553
+ const path = require('path');
554
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
555
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
556
+ setupGlobals(core, github, context, exec, io, getOctokit);
557
+ const { main } = require(path.join(actionsDir, 'create_files.cjs'));
558
+ await main();
559
+ - name: Generate Safe Outputs Tools
560
+ env:
561
+ GH_AW_TOOLS_META_JSON: |
562
+ {
563
+ "description_suffixes": {},
564
+ "repo_params": {},
565
+ "dynamic_tools": []
566
+ }
567
+ GH_AW_VALIDATION_JSON: |
568
+ {
569
+ "noop": {
570
+ "defaultMax": 2,
571
+ "fields": {
572
+ "message": {
573
+ "required": true,
574
+ "type": "string",
575
+ "sanitize": true,
576
+ "maxLength": 65000
577
+ }
578
+ }
579
+ }
580
+ }
581
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
582
+ with:
583
+ script: |
584
+ const path = require('path');
585
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
586
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
587
+ setupGlobals(core, github, context, exec, io, getOctokit);
588
+ const { main } = require(path.join(actionsDir, 'generate_safe_outputs_tools.cjs'));
589
+ await main();
590
+ - name: Start MCP Gateway
591
+ id: start-mcp-gateway
592
+ env:
593
+ DEBUG: ${{ env.DEBUG || runner.debug == '1' && '*' || '' }}
594
+ GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST: ${{ vars.GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST || 'true' }}
595
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
596
+ GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_CONFIG_PATH }}
597
+ GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_TOOLS_PATH }}
598
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
599
+ run: |
600
+ set -eo pipefail
601
+ mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-config"
602
+ if [ -n "${GITHUB_EVENT_PATH:-}" ] && [ -r "${GITHUB_EVENT_PATH}" ]; then
603
+ GH_AW_SAFEOUTPUTS_EVENT_PATH="${RUNNER_TEMP}/gh-aw/safeoutputs/github_event.json"
604
+ cp "${GITHUB_EVENT_PATH}" "${GH_AW_SAFEOUTPUTS_EVENT_PATH}"
605
+ export GITHUB_EVENT_PATH="${GH_AW_SAFEOUTPUTS_EVENT_PATH}"
606
+ fi
607
+
608
+ # Export gateway environment variables for MCP config and gateway script
609
+ export MCP_GATEWAY_PORT="8080"
610
+ export MCP_GATEWAY_DOMAIN="localhost"
611
+ export MCP_GATEWAY_HOST_DOMAIN="localhost"
612
+ MCP_GATEWAY_AGENT_ID=$(openssl rand -base64 45 | tr -d '/+=')
613
+ echo "::add-mask::${MCP_GATEWAY_AGENT_ID}"
614
+ export MCP_GATEWAY_AGENT_ID
615
+ export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads"
616
+ mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}"
617
+ export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288"
618
+ 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"
619
+ export GH_AW_PR_HEAD_BASE_BRANCH="${GH_AW_PR_HEAD_BASE_BRANCH:-}"
620
+ export GH_AW_PR_HEAD_BASE_SHA="${GH_AW_PR_HEAD_BASE_SHA:-}"
621
+ export GH_AW_PR_HEAD_BASE_REPO="${GH_AW_PR_HEAD_BASE_REPO:-}"
622
+ export GH_AW_PR_HEAD_BASE_PR_NUMBER="${GH_AW_PR_HEAD_BASE_PR_NUMBER:-}"
623
+ export GH_AW_PR_HEAD_BASE_REF="${GH_AW_PR_HEAD_BASE_REF:-}"
624
+ export GH_AW_PR_HEAD_REPO="${GH_AW_PR_HEAD_REPO:-}"
625
+ export GH_AW_TARGET_REPO_SLUG="${GH_AW_TARGET_REPO_SLUG:-}"
626
+ export GH_AW_ENGINE="opencode"
627
+ MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0')
628
+ MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0')
629
+ source "${RUNNER_TEMP}/gh-aw/actions/resolve_docker_socket_gid.sh"
630
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --name awmg-mcpg --add-host host.docker.internal:127.0.0.1 --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'
631
+
632
+ GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
633
+ cat << GH_AW_MCP_CONFIG_6001799711bbe943_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs"
634
+ {
635
+ "mcpServers": {
636
+ "safeoutputs": {
637
+ "container": "ghcr.io/github/gh-aw-node@sha256:41835613992df88f51e923bad486f96dfb2e6cda29f13e217df41833284ae382",
638
+ "mounts": ["\${GITHUB_WORKSPACE}:\${GITHUB_WORKSPACE}:rw", "${RUNNER_TEMP}/gh-aw/safeoutputs:${RUNNER_TEMP}/gh-aw/safeoutputs:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"],
639
+ "args": ["-w", "\${GITHUB_WORKSPACE}"],
640
+ "entrypoint": "sh",
641
+ "entrypointArgs": ["-c", "sh ${RUNNER_TEMP}/gh-aw/safeoutputs/start_safe_outputs_mcp.sh"],
642
+ "env": {
643
+ "DEBUG": "\${DEBUG}",
644
+ "DEFAULT_BRANCH": "\${DEFAULT_BRANCH}",
645
+ "GH_AW_ASSETS_ALLOWED_EXTS": "\${GH_AW_ASSETS_ALLOWED_EXTS}",
646
+ "GH_AW_ASSETS_BRANCH": "\${GH_AW_ASSETS_BRANCH}",
647
+ "GH_AW_ASSETS_MAX_SIZE_KB": "\${GH_AW_ASSETS_MAX_SIZE_KB}",
648
+ "GH_AW_MCP_LOG_DIR": "\${GH_AW_MCP_LOG_DIR}",
649
+ "GH_AW_SAFE_OUTPUTS": "\${GH_AW_SAFE_OUTPUTS}",
650
+ "GH_AW_SAFE_OUTPUTS_CONFIG_PATH": "\${GH_AW_SAFE_OUTPUTS_CONFIG_PATH}",
651
+ "GH_AW_SAFE_OUTPUTS_TOOLS_PATH": "\${GH_AW_SAFE_OUTPUTS_TOOLS_PATH}",
652
+ "GH_AW_TARGET_REPO_SLUG": "\${GH_AW_TARGET_REPO_SLUG}",
653
+ "GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST": "\${GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST}",
654
+ "GH_AW_PR_HEAD_BASE_BRANCH": "\${GH_AW_PR_HEAD_BASE_BRANCH}",
655
+ "GH_AW_PR_HEAD_BASE_SHA": "\${GH_AW_PR_HEAD_BASE_SHA}",
656
+ "GH_AW_PR_HEAD_BASE_REPO": "\${GH_AW_PR_HEAD_BASE_REPO}",
657
+ "GH_AW_PR_HEAD_BASE_PR_NUMBER": "\${GH_AW_PR_HEAD_BASE_PR_NUMBER}",
658
+ "GH_AW_PR_HEAD_BASE_REF": "\${GH_AW_PR_HEAD_BASE_REF}",
659
+ "GH_AW_PR_HEAD_REPO": "\${GH_AW_PR_HEAD_REPO}",
660
+ "GITHUB_EVENT_NAME": "\${GITHUB_EVENT_NAME}",
661
+ "GITHUB_EVENT_PATH": "\${GITHUB_EVENT_PATH}",
662
+ "GITHUB_REPOSITORY": "\${GITHUB_REPOSITORY}",
663
+ "GITHUB_SHA": "\${GITHUB_SHA}",
664
+ "GITHUB_TOKEN": "\${GITHUB_TOKEN}",
665
+ "GITHUB_WORKSPACE": "\${GITHUB_WORKSPACE}",
666
+ "RUNNER_TEMP": "\${RUNNER_TEMP}"
667
+ }
668
+ }
669
+ },
670
+ "gateway": {
671
+ "port": $MCP_GATEWAY_PORT,
672
+ "domain": "${MCP_GATEWAY_DOMAIN}",
673
+ "agentId": "${MCP_GATEWAY_AGENT_ID}",
674
+ "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}",
675
+ "startupTimeout": 120,
676
+ "opentelemetry": {
677
+ "endpoint": "${OTEL_EXPORTER_OTLP_ENDPOINT}",
678
+ "traceId": "${GITHUB_AW_OTEL_TRACE_ID}",
679
+ "spanId": "${GITHUB_AW_OTEL_PARENT_SPAN_ID}"
680
+ }
681
+ }
682
+ }
683
+ GH_AW_MCP_CONFIG_6001799711bbe943_EOF
684
+ - name: Mount MCP servers as CLIs
685
+ id: mount-mcp-clis
686
+ continue-on-error: true
687
+ env:
688
+ MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }}
689
+ MCP_GATEWAY_DOMAIN: ${{ steps.start-mcp-gateway.outputs.gateway-domain }}
690
+ MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
691
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
692
+ with:
693
+ script: |
694
+ const path = require('path');
695
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
696
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
697
+ setupGlobals(core, github, context, exec, io);
698
+ const { main } = require(path.join(actionsDir, 'mount_mcp_as_cli.cjs'));
699
+ await main();
700
+ - name: Clean credentials
701
+ run: |
702
+ bash "${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh"
703
+ bash "${RUNNER_TEMP}/gh-aw/actions/verify_git_credentials.sh"
704
+ - name: Audit pre-agent workspace
705
+ id: pre_agent_audit
706
+ continue-on-error: true
707
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/audit_pre_agent_workspace.sh"
708
+ - name: Write OpenCode log parser script
709
+ if: always()
710
+ run: |
711
+ mkdir -p "${RUNNER_TEMP}/gh-aw/actions"
712
+ cat <<'GHAW_LOG_PARSER_SCRIPT_5d2e8b3f_EOF' > "${RUNNER_TEMP}/gh-aw/actions/opencode_log_parser.cjs"
713
+ // @ts-check
714
+ // Auto-generated log parser for behavior-defined engine "OpenCode".
715
+ const { createEngineLogParser } = require("./log_parser_shared.cjs");
716
+
717
+ // --- begin engine-provided parse function ---
718
+ function parseLog(logContent) {
719
+ const fs = require("fs");
720
+ const events = require("path").join(process.env.RUNNER_TEMP, "gh-aw", `opencode-events-${process.env.GITHUB_RUN_ID}-${process.env.GITHUB_RUN_ATTEMPT}.jsonl`);
721
+ return require("./parse_opencode_log.cjs").parseOpenCodeLog(fs.existsSync(events) ? fs.readFileSync(events, "utf8") : logContent);
722
+ }
723
+
724
+ // --- end engine-provided parse function ---
725
+
726
+ const main = createEngineLogParser({
727
+ parserName: "OpenCode",
728
+ parseFunction: parseLog,
729
+ supportsDirectories: false,
730
+ });
731
+
732
+ if (typeof module !== "undefined" && module.exports) {
733
+ module.exports = { main, parseLog };
734
+ }
735
+ GHAW_LOG_PARSER_SCRIPT_5d2e8b3f_EOF
736
+ chmod 755 "${RUNNER_TEMP}/gh-aw/actions/opencode_log_parser.cjs"
737
+ - name: OpenCode progress and result
738
+ id: agentic_execution
739
+ timeout-minutes: 55
740
+ run: |
741
+ set -o pipefail
742
+ gh_aw_exit_code=0
743
+ 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; if [ "$gh_aw_exit_code" -ne 0 ]; then echo "::error::Agent execution exited with code $gh_aw_exit_code"; fi' EXIT
744
+ mkdir -p "/tmp/gh-aw"
745
+ evidence_tmp="/tmp/gh-aw/agent_execution.json.tmp"
746
+ printf '{"version":1,"component":"agent","run_id":%s,"run_attempt":%s,"state":"started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp"
747
+ mv "$evidence_tmp" "/tmp/gh-aw/agent_execution.json"
748
+ export GH_AW_AWF_EXECUTION_COMPONENT="agent"
749
+ export GH_AW_AWF_EXECUTION_EVIDENCE_FILE="/tmp/gh-aw/agent_execution.json"
750
+ export no_proxy="${NO_PROXY:-}"
751
+ printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt
752
+ cd "${GITHUB_WORKSPACE}" && node tools/src/packages/sdlc/src/opencode-execute.mjs "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)" 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
753
+ env:
754
+ GH_AW_ADMISSION_MAX_AI_CREDITS: ${{ needs.activation.outputs.admission-max-ai-credits }}
755
+ GH_AW_ADMISSION_RESULT: ${{ needs.activation.outputs.admission-result }}
756
+ GH_AW_ENGINE_VERSION: 2.1.0
757
+ GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
758
+ GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }}
759
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
760
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
761
+ GITHUB_WORKSPACE: ${{ github.workspace }}
762
+ NO_PROXY: localhost,127.0.0.1,host.docker.internal,host.docker.internal:10000,host.docker.internal:10001,host.docker.internal:10002,host.docker.internal:10003,172.30.0.30,172.30.0.30:10000,172.30.0.30:10001,172.30.0.30:10002,172.30.0.30:10003
763
+ RUNNER_TEMP: ${{ runner.temp }}
764
+ 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) || '' }}
765
+ - name: Configure Git credentials
766
+ env:
767
+ GITHUB_REPOSITORY: ${{ github.repository }}
768
+ GITHUB_SERVER_URL: ${{ github.server_url }}
769
+ GITHUB_TOKEN: ${{ github.token }}
770
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_git_credentials.sh"
771
+ - name: Stop MCP Gateway
772
+ if: always()
773
+ continue-on-error: true
774
+ env:
775
+ MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
776
+ MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }}
777
+ GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}
778
+ run: |
779
+ bash "${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh" "$GATEWAY_PID"
780
+ - name: Redact secrets in logs
781
+ id: redact_secrets
782
+ if: always()
783
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
784
+ with:
785
+ script: |
786
+ const path = require('path');
787
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
788
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
789
+ setupGlobals(core, github, context, exec, io, getOctokit);
790
+ const { main } = require(path.join(actionsDir, 'redact_secrets.cjs'));
791
+ await main();
792
+ env:
793
+ GH_AW_SECRET_NAMES: 'GITHUB_TOKEN'
794
+ SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
795
+ - name: Append agent step summary
796
+ if: always()
797
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh"
798
+ - name: Copy Safe Outputs
799
+ if: always()
800
+ env:
801
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
802
+ run: |
803
+ mkdir -p /tmp/gh-aw
804
+ cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true
805
+ - name: Ingest agent output
806
+ id: collect_output
807
+ if: always()
808
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
809
+ env:
810
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
811
+ GITHUB_SERVER_URL: ${{ github.server_url }}
812
+ GITHUB_API_URL: ${{ github.api_url }}
813
+ with:
814
+ script: |
815
+ const path = require('path');
816
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
817
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
818
+ setupGlobals(core, github, context, exec, io, getOctokit);
819
+ const { main } = require(path.join(actionsDir, 'collect_ndjson_output.cjs'));
820
+ await main();
821
+ - name: Parse agent logs for step summary
822
+ if: always()
823
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
824
+ env:
825
+ GH_AW_AGENT_OUTPUT: /tmp/gh-aw/agent-stdio.log
826
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
827
+ with:
828
+ script: |
829
+ const path = require('path');
830
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
831
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
832
+ setupGlobals(core, github, context, exec, io, getOctokit);
833
+ const { main } = require(path.join(actionsDir, 'opencode_log_parser.cjs'));
834
+ await main();
835
+ - name: Parse MCP Gateway logs for step summary
836
+ if: always()
837
+ id: parse-mcp-gateway
838
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
839
+ with:
840
+ script: |
841
+ const path = require('path');
842
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
843
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
844
+ setupGlobals(core, github, context, exec, io, getOctokit);
845
+ const { main } = require(path.join(actionsDir, 'parse_mcp_gateway_log.cjs'));
846
+ await main();
847
+ - name: Generate observability summary
848
+ if: always()
849
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
850
+ with:
851
+ script: |
852
+ const path = require('path');
853
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
854
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
855
+ setupGlobals(core, github, context, exec, io, getOctokit);
856
+ const { main } = require(path.join(actionsDir, 'generate_observability_summary.cjs'));
857
+ await main(core);
858
+ - name: Write agent output placeholder if missing
859
+ if: always()
860
+ run: |
861
+ if [ ! -f /tmp/gh-aw/agent_output.json ]; then
862
+ echo '{"items":[]}' > /tmp/gh-aw/agent_output.json
863
+ fi
864
+ - name: Validate the Lighthouse result
865
+ run: node tools/src/packages/sdlc/src/issue-actions.mjs validate
866
+ - if: always()
867
+ name: Preserve the result and runtime receipt
868
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
869
+ with:
870
+ if-no-files-found: error
871
+ name: lighthouse-${{ needs.prepare.outputs.artifact_prefix }}result-${{ inputs.issue }}-${{ github.run_attempt }}
872
+ path: |
873
+ ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}/envelope.json
874
+ ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}/runtime.json
875
+ ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}/changes.json
876
+ ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}/checks.json
877
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '14' }}
878
+ - if: always()
879
+ name: Preserve implementation evidence
880
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
881
+ with:
882
+ if-no-files-found: ignore
883
+ name: implementation-evidence-${{ inputs.issue }}-${{ github.run_attempt }}
884
+ path: ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}/evidence/
885
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '30' }}
886
+ - if: always()
887
+ name: Preserve OpenCode diagnostic events
888
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
889
+ with:
890
+ if-no-files-found: ignore
891
+ name: opencode-implement-events-${{ inputs.issue }}-${{ github.run_attempt }}
892
+ path: ${{ runner.temp }}/gh-aw/opencode-events-${{ github.run_id }}-${{ github.run_attempt }}.jsonl
893
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '14' }}
894
+
895
+ # Small dedicated copy of the agent output so safe-output processing
896
+ # survives a failed or timed-out upload of the larger agent artifact
897
+ - name: Upload agent output fallback artifact
898
+ if: always() && steps.redact_secrets.outcome == 'success'
899
+ continue-on-error: true
900
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
901
+ with:
902
+ name: agent-output-fallback
903
+ path: |
904
+ /tmp/gh-aw/agent_output.json
905
+ /tmp/gh-aw/safeoutputs.jsonl
906
+ /tmp/gh-aw/agent_execution.json
907
+ /tmp/gh-aw/agent_execution_exit_code.txt
908
+ /tmp/gh-aw/agent_usage.jsonl
909
+ /tmp/gh-aw/agent_usage.json
910
+ /tmp/gh-aw/agent/model-endpoint-mismatch.json
911
+ /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl
912
+ /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/model-routing.jsonl
913
+ /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl
914
+ /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/model-routing.jsonl
915
+ /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl
916
+ /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/model-routing.jsonl
917
+ if-no-files-found: ignore
918
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
919
+ - name: Upload agent artifacts
920
+ if: always() && steps.redact_secrets.outcome == 'success'
921
+ continue-on-error: true
922
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
923
+ with:
924
+ name: agent
925
+ path: |
926
+ /tmp/gh-aw/aw-prompts/prompt.txt
927
+ /tmp/gh-aw/agent_execution.json
928
+ /tmp/gh-aw/agent_execution_exit_code.txt
929
+ /tmp/gh-aw/agent-session.jsonl
930
+ /tmp/gh-aw/agent-errors.jsonl
931
+ /tmp/gh-aw/aw-prompts/user.txt
932
+ /tmp/gh-aw/aw-prompts/system.txt
933
+ /tmp/gh-aw/skill_inventory.json
934
+ /tmp/gh-aw/mcp-logs/
935
+ /tmp/gh-aw/agent-stdio.log
936
+ /tmp/gh-aw/pre-agent-audit.txt
937
+ /tmp/gh-aw/github_rate_limits.jsonl
938
+ /tmp/gh-aw/otel.jsonl
939
+ /tmp/gh-aw/otlp-export-errors.jsonl
940
+ /tmp/gh-aw/safeoutputs.jsonl
941
+ /tmp/gh-aw/agent_output.json
942
+ if-no-files-found: ignore
943
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
944
+
945
+ conclusion:
946
+ name: conclusion
947
+ needs:
948
+ - activation
949
+ - agent
950
+ - prepare
951
+ - publish
952
+ if: >
953
+ always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' ||
954
+ needs.activation.outputs.oauth_token_check_failed == 'true' || needs.activation.outputs.stale_lock_file_failed == 'true' ||
955
+ needs.activation.outputs.daily_ai_credits_exceeded == 'true' || needs.activation.outputs.daily_ai_credits_guardrail_status == 'structural_error' ||
956
+ needs.activation.outputs.daily_ai_credits_guardrail_status == 'transient_error')
957
+ runs-on: ubuntu-24.04
958
+ # Permissions for the conclusion job (workflow permissions default to none).
959
+ permissions:
960
+ actions: read
961
+ issues: write
962
+ concurrency:
963
+ group: "gh-aw-conclusion-lighthouse-sdlc-apply-review-${{ github.run_id }}"
964
+ cancel-in-progress: false
965
+ queue: max
966
+ env:
967
+ GH_AW_JOB_DISPLAY_NAMES: "{\"activation\":\"activation\",\"agent\":\"agent\",\"conclusion\":\"conclusion\",\"pre_activation\":\"pre_activation\",\"prepare\":\"Authorize and reserve issue\",\"publish\":\"Validate, publish and release\"}"
968
+ GH_AW_JOB_RESULTS: "{\"activation\":{\"result\":\"${{ needs.activation.result }}\"},\"agent\":{\"result\":\"${{ needs.agent.result }}\"},\"prepare\":{\"result\":\"${{ needs.prepare.result }}\"},\"publish\":{\"result\":\"${{ needs.publish.result }}\"}}"
969
+ GH_AW_JOB_TIMING_ELIGIBLE: "{\"activation\":true,\"agent\":true,\"conclusion\":true,\"pre_activation\":true,\"prepare\":true,\"publish\":true}"
970
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
971
+ outputs:
972
+ noop_comment_body: ${{ steps.noop.outputs.noop_comment_body }}
973
+ noop_message: ${{ steps.noop.outputs.noop_message }}
974
+ steps:
975
+ - name: Setup Scripts
976
+ id: setup
977
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
978
+ with:
979
+ destination: ${{ runner.temp }}/gh-aw/actions
980
+ job-name: ${{ github.job }}
981
+ trace-id: ${{ needs.activation.outputs.setup-trace-id }}
982
+ parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
983
+ env:
984
+ GH_AW_SETUP_WORKFLOW_NAME: "Lighthouse SDLC apply-review"
985
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-apply-review.lock.yml@${{ github.ref }}
986
+ GH_AW_INFO_VERSION: "2.1.0"
987
+ GH_AW_INFO_ENGINE_ID: "opencode"
988
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
989
+ - name: Download agent output artifact
990
+ id: download-agent-output
991
+ continue-on-error: true
992
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
993
+ with:
994
+ pattern: "{agent,agent-output-fallback}"
995
+ merge-multiple: true
996
+ path: /tmp/gh-aw/
997
+ - name: Setup agent output environment variable
998
+ id: setup-agent-output-env
999
+ if: steps.download-agent-output.outcome == 'success'
1000
+ run: |
1001
+ mkdir -p /tmp/gh-aw/
1002
+ find "/tmp/gh-aw/" -type f -print
1003
+ if [ -f "/tmp/gh-aw/agent_output.json" ]; then
1004
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
1005
+ fi
1006
+ - name: Download Safe Outputs Items Manifest
1007
+ id: download-safe-outputs-manifest
1008
+ if: always()
1009
+ continue-on-error: true
1010
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1011
+ with:
1012
+ pattern: safe-outputs-items
1013
+ merge-multiple: true
1014
+ path: /tmp/gh-aw/
1015
+ - name: Process no-op messages
1016
+ id: noop
1017
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1018
+ env:
1019
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1020
+ GH_AW_NOOP_MAX: "2"
1021
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC apply-review"
1022
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-apply-review.md"
1023
+ GH_AW_ENGINE_ID: "opencode"
1024
+ GH_AW_ENGINE_VERSION: "2.1.0"
1025
+ GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
1026
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
1027
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
1028
+ GH_AW_NOOP_REPORT_AS_ISSUE: "false"
1029
+ GH_AW_AIC: ${{ needs.agent.outputs.aic }}
1030
+ GH_AW_AMBIENT_CONTEXT: ${{ needs.agent.outputs.ambient_context }}
1031
+ GH_AW_WORKFLOW_ID: "lighthouse-sdlc-apply-review"
1032
+ with:
1033
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1034
+ script: |
1035
+ const path = require('path');
1036
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1037
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1038
+ setupGlobals(core, github, context, exec, io, getOctokit);
1039
+ const { main } = require(path.join(actionsDir, 'handle_noop_message.cjs'));
1040
+ await main();
1041
+ - name: Handle agent failure
1042
+ id: handle_agent_failure
1043
+ if: always()
1044
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1045
+ env:
1046
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1047
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC apply-review"
1048
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-apply-review.md"
1049
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
1050
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
1051
+ GH_AW_WORKFLOW_ID: "lighthouse-sdlc-apply-review"
1052
+ GH_AW_ACTION_FAILURE_ISSUE_EXPIRES_HOURS: "0"
1053
+ GH_AW_ENGINE_ID: "opencode"
1054
+ GH_AW_AI_CREDITS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.ai_credits_rate_limit_error || 'false' }}
1055
+ GH_AW_UNKNOWN_MODEL_AI_CREDITS: ${{ needs.agent.outputs.unknown_model_ai_credits || 'false' }}
1056
+ GH_AW_AIC: ${{ needs.agent.outputs.aic }}
1057
+ GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
1058
+ GH_AW_DEFAULT_CHECKOUT_USES_TRIGGER_REF: "false"
1059
+ GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }}
1060
+ GH_AW_OAUTH_TOKEN_CHECK_FAILED: ${{ needs.activation.outputs.oauth_token_check_failed }}
1061
+ GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }}
1062
+ GH_AW_DAILY_AI_CREDITS_EXCEEDED: ${{ needs.activation.outputs.daily_ai_credits_exceeded }}
1063
+ GH_AW_DAILY_AI_CREDITS_GUARDRAIL_STATUS: ${{ needs.activation.outputs.daily_ai_credits_guardrail_status }}
1064
+ GH_AW_DAILY_AI_CREDITS_GUARDRAIL_ERROR: ${{ needs.activation.outputs.daily_ai_credits_guardrail_error }}
1065
+ GH_AW_DAILY_AI_CREDITS_TOTAL: ${{ needs.activation.outputs.daily_ai_credits_total }}
1066
+ GH_AW_DAILY_AI_CREDITS_ESTIMATED: ${{ needs.activation.outputs.daily_ai_credits_estimated }}
1067
+ GH_AW_DAILY_AI_CREDITS_THRESHOLD: ${{ needs.activation.outputs.daily_ai_credits_threshold }}
1068
+ GH_AW_DAILY_AI_CREDITS_CONTINUE_ON_ERROR: "false"
1069
+ GH_AW_GROUP_REPORTS: "false"
1070
+ GH_AW_FAILURE_REPORT_AS_ISSUE: "false"
1071
+ GH_AW_MISSING_TOOL_REPORT_AS_FAILURE: "true"
1072
+ GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true"
1073
+ GH_AW_TIMEOUT_MINUTES: "55"
1074
+ with:
1075
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1076
+ script: |
1077
+ const path = require('path');
1078
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1079
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1080
+ setupGlobals(core, github, context, exec, io, getOctokit);
1081
+ const { main } = require(path.join(actionsDir, 'handle_agent_failure.cjs'));
1082
+ await main();
1083
+ - name: Report failed jobs
1084
+ id: report_failed_jobs
1085
+ if: always()
1086
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1087
+ env:
1088
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
1089
+ GH_AW_WORKFLOW_NAME: "Lighthouse SDLC apply-review"
1090
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/lighthouse-sdlc-apply-review.md"
1091
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
1092
+ GH_AW_REPORT_FAILED_JOBS: "true"
1093
+ with:
1094
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
1095
+ script: |
1096
+ const path = require('path');
1097
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1098
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1099
+ setupGlobals(core, github, context, exec, io, getOctokit);
1100
+ const { main } = require(path.join(actionsDir, 'report_failed_jobs.cjs'));
1101
+ await main();
1102
+ - name: Collect usage artifact files
1103
+ if: always()
1104
+ continue-on-error: true
1105
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/collect_usage_artifact_files.sh"
1106
+ - name: Generate usage activity summary and unified session
1107
+ if: always()
1108
+ continue-on-error: true
1109
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
1110
+ env:
1111
+ GH_AW_ADMISSION_RESULT: ${{ needs.activation.outputs.admission-result }}
1112
+ GH_AW_ADMISSION_MAX_AI_CREDITS: ${{ needs.activation.outputs.admission-max-ai-credits }}
1113
+ GH_AW_ADMISSION_MAX_AI_CREDITS_THREAT_DETECTION: ${{ needs.activation.outputs.admission-max-ai-credits-threat-detection }}
1114
+ GH_AW_ADMISSION_MAX_AI_CREDITS_EVALS: ${{ needs.activation.outputs.admission-max-ai-credits-evals }}
1115
+ GH_AW_GRADER_MANIFEST_0: '{"version":2,"graders":[]}'
1116
+ GH_AW_GRADER_MANIFEST_CHUNKS: '1'
1117
+ GH_AW_JOB_DURATIONS: ${{ steps.report_failed_jobs.outputs.job_durations }}
1118
+ GH_AW_DAILY_AI_CREDITS_GUARDRAIL_STATUS: ${{ needs.activation.outputs.daily_ai_credits_guardrail_status }}
1119
+ GH_AW_DAILY_AI_CREDITS_EXCEEDED: ${{ needs.activation.outputs.daily_ai_credits_exceeded }}
1120
+ GH_AW_DAILY_AI_CREDITS_TOTAL: ${{ needs.activation.outputs.daily_ai_credits_total }}
1121
+ GH_AW_DAILY_AI_CREDITS_ESTIMATED: ${{ needs.activation.outputs.daily_ai_credits_estimated }}
1122
+ GH_AW_DAILY_AI_CREDITS_THRESHOLD: ${{ needs.activation.outputs.daily_ai_credits_threshold }}
1123
+ with:
1124
+ script: |
1125
+ const path = require('path');
1126
+ const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions');
1127
+ const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs'));
1128
+ setupGlobals(core, github, context, exec, io, getOctokit);
1129
+ const { main } = require(path.join(actionsDir, 'generate_usage_artifacts.cjs'));
1130
+ await main();
1131
+ - name: Upload usage artifact
1132
+ id: upload-usage-artifact
1133
+ if: always()
1134
+ continue-on-error: true
1135
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1136
+ with:
1137
+ name: usage
1138
+ path: |
1139
+ /tmp/gh-aw/usage/aw_session.jsonl
1140
+ /tmp/gh-aw/usage/aw_info.json
1141
+ /tmp/gh-aw/usage/aw-info.jsonl
1142
+ /tmp/gh-aw/usage/agent_usage.json
1143
+ /tmp/gh-aw/usage/agent_usage.jsonl
1144
+ /tmp/gh-aw/usage/detection_usage.jsonl
1145
+ /tmp/gh-aw/usage/evals.jsonl
1146
+ /tmp/gh-aw/usage/graders/grader_manifest.json
1147
+ /tmp/gh-aw/usage/graders/grader_results.json
1148
+ /tmp/gh-aw/usage/github_rate_limits.jsonl
1149
+ /tmp/gh-aw/usage/agent/token_usage.jsonl
1150
+ /tmp/gh-aw/usage/agent/model-routing.jsonl
1151
+ /tmp/gh-aw/usage/agent/execution.json
1152
+ /tmp/gh-aw/usage/detection/token_usage.jsonl
1153
+ /tmp/gh-aw/usage/detection/execution.json
1154
+ /tmp/gh-aw/usage/detection/detection_result.json
1155
+ /tmp/gh-aw/usage/evals/token_usage.jsonl
1156
+ /tmp/gh-aw/usage/evals/execution.json
1157
+ /tmp/gh-aw/usage/experiment/state.jsonl
1158
+ /tmp/gh-aw/usage/experiment/state.json
1159
+ /tmp/gh-aw/usage/experiment/assignments.json
1160
+ /tmp/gh-aw/usage/activity/summary.json
1161
+ if-no-files-found: ignore
1162
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
1163
+ - name: Wait before retrying usage artifact upload
1164
+ if: always() && steps.upload-usage-artifact.outcome == 'failure'
1165
+ run: sleep 10
1166
+ - name: Retry upload usage artifact
1167
+ id: upload-usage-artifact-retry
1168
+ if: always() && steps.upload-usage-artifact.outcome == 'failure'
1169
+ continue-on-error: true
1170
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1171
+ with:
1172
+ name: usage
1173
+ path: |
1174
+ /tmp/gh-aw/usage/aw_session.jsonl
1175
+ /tmp/gh-aw/usage/aw_info.json
1176
+ /tmp/gh-aw/usage/aw-info.jsonl
1177
+ /tmp/gh-aw/usage/agent_usage.json
1178
+ /tmp/gh-aw/usage/agent_usage.jsonl
1179
+ /tmp/gh-aw/usage/detection_usage.jsonl
1180
+ /tmp/gh-aw/usage/evals.jsonl
1181
+ /tmp/gh-aw/usage/graders/grader_manifest.json
1182
+ /tmp/gh-aw/usage/graders/grader_results.json
1183
+ /tmp/gh-aw/usage/github_rate_limits.jsonl
1184
+ /tmp/gh-aw/usage/agent/token_usage.jsonl
1185
+ /tmp/gh-aw/usage/agent/model-routing.jsonl
1186
+ /tmp/gh-aw/usage/agent/execution.json
1187
+ /tmp/gh-aw/usage/detection/token_usage.jsonl
1188
+ /tmp/gh-aw/usage/detection/execution.json
1189
+ /tmp/gh-aw/usage/detection/detection_result.json
1190
+ /tmp/gh-aw/usage/evals/token_usage.jsonl
1191
+ /tmp/gh-aw/usage/evals/execution.json
1192
+ /tmp/gh-aw/usage/experiment/state.jsonl
1193
+ /tmp/gh-aw/usage/experiment/state.json
1194
+ /tmp/gh-aw/usage/experiment/assignments.json
1195
+ /tmp/gh-aw/usage/activity/summary.json
1196
+ if-no-files-found: ignore
1197
+ overwrite: true
1198
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '0' }}
1199
+
1200
+ pre_activation:
1201
+ name: pre_activation
1202
+ needs: prepare
1203
+ runs-on: ubuntu-24.04
1204
+ env:
1205
+ GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }}
1206
+ outputs:
1207
+ activated: ${{ 'true' }}
1208
+ matched_command: ''
1209
+ setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
1210
+ setup-span-id: ${{ steps.setup.outputs.span-id }}
1211
+ setup-trace-id: ${{ steps.setup.outputs.trace-id }}
1212
+ steps:
1213
+ - name: Setup Scripts
1214
+ id: setup
1215
+ uses: github/gh-aw-actions/setup@d9128eb3ea40c18b77c76184eda03c0ff2608d79 # v0.93.2
1216
+ with:
1217
+ destination: ${{ runner.temp }}/gh-aw/actions
1218
+ job-name: ${{ github.job }}
1219
+ env:
1220
+ GH_AW_SETUP_WORKFLOW_NAME: "Lighthouse SDLC apply-review"
1221
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/lighthouse-sdlc-apply-review.lock.yml@${{ github.ref }}
1222
+ GH_AW_INFO_VERSION: "2.1.0"
1223
+ GH_AW_INFO_ENGINE_ID: "opencode"
1224
+ GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
1225
+
1226
+ prepare:
1227
+ name: Authorize and reserve issue
1228
+ runs-on: ubuntu-24.04
1229
+ # Permissions for the prepare job (workflow permissions default to none).
1230
+ permissions:
1231
+ actions: read
1232
+ contents: read
1233
+ issues: write
1234
+ env:
1235
+ LIGHTHOUSE_ISSUE: ${{ inputs.issue }}
1236
+ outputs:
1237
+ artifact_prefix: ${{ steps.prepare.outputs.artifact_prefix }}
1238
+ eligible: ${{ steps.prepare.outputs.eligible }}
1239
+ source_revision: ${{ steps.prepare.outputs.source_revision }}
1240
+ steps:
1241
+ - name: Configure GH_HOST for enterprise compatibility
1242
+ id: ghes-host-config
1243
+ shell: bash
1244
+ run: | # zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input.
1245
+ # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
1246
+ # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
1247
+ GH_HOST="${GITHUB_SERVER_URL#https://}"
1248
+ GH_HOST="${GH_HOST#http://}"
1249
+ echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
1250
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
1251
+ with:
1252
+ persist-credentials: false
1253
+ ref: __LIGHTHOUSE_REF__
1254
+ repository: juangcarmona/lighthouse
1255
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
1256
+ with:
1257
+ node-version: 24
1258
+ - name: Collect verified owner intent and reserve the issue
1259
+ id: prepare
1260
+ run: node src/packages/sdlc/src/issue-actions.mjs prepare
1261
+ env:
1262
+ GH_TOKEN: ${{ github.token }}
1263
+ - name: Preserve the execution request
1264
+ if: steps.prepare.outputs.eligible == 'true'
1265
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
1266
+ with:
1267
+ if-no-files-found: error
1268
+ name: lighthouse-${{ steps.prepare.outputs.artifact_prefix }}input-${{ inputs.issue }}-${{ github.run_attempt }}
1269
+ path: ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}/
1270
+ retention-days: ${{ vars.GH_AW_DEFAULT_ARTIFACT_RETENTION_DAYS || '14' }}
1271
+ - name: Release reservation if preparation failed
1272
+ if: failure()
1273
+ run: node src/packages/sdlc/src/issue-actions.mjs cleanup
1274
+ env:
1275
+ GH_TOKEN: ${{ github.token }}
1276
+
1277
+ publish:
1278
+ name: Validate, publish and release
1279
+ needs:
1280
+ - agent
1281
+ - prepare
1282
+ if: always() && needs.prepare.result == 'success' && needs.prepare.outputs.eligible == 'true'
1283
+ runs-on: ubuntu-24.04
1284
+ # Permissions for the publish job (workflow permissions default to none).
1285
+ permissions:
1286
+ actions: write
1287
+ contents: write
1288
+ issues: write
1289
+ pull-requests: write
1290
+ env:
1291
+ LIGHTHOUSE_ISSUE: ${{ inputs.issue }}
1292
+ steps:
1293
+ - name: Configure GH_HOST for enterprise compatibility
1294
+ id: ghes-host-config
1295
+ shell: bash
1296
+ run: | # zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input.
1297
+ # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
1298
+ # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
1299
+ GH_HOST="${GITHUB_SERVER_URL#https://}"
1300
+ GH_HOST="${GH_HOST#http://}"
1301
+ echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
1302
+ - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
1303
+ with:
1304
+ persist-credentials: false
1305
+ ref: __LIGHTHOUSE_REF__
1306
+ repository: juangcarmona/lighthouse
1307
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
1308
+ with:
1309
+ node-version: 24
1310
+ - name: Load the execution request
1311
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1312
+ with:
1313
+ name: lighthouse-${{ needs.prepare.outputs.artifact_prefix }}input-${{ inputs.issue }}-${{ github.run_attempt }}
1314
+ path: ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}
1315
+ - name: Load the candidate result
1316
+ if: needs.agent.result == 'success'
1317
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
1318
+ with:
1319
+ name: lighthouse-${{ needs.prepare.outputs.artifact_prefix }}result-${{ inputs.issue }}-${{ github.run_attempt }}
1320
+ path: ${{ runner.temp }}/lighthouse-${{ github.run_id }}-${{ github.run_attempt }}
1321
+ - name: Require an executed agent
1322
+ if: needs.agent.result != 'success'
1323
+ run: |
1324
+ echo 'The authorized agent did not complete successfully; inspect its execution.' >&2
1325
+ exit 1
1326
+ - name: Recheck authority and publish the validated result
1327
+ if: needs.agent.result == 'success'
1328
+ run: node src/packages/sdlc/src/issue-actions.mjs publish
1329
+ env:
1330
+ GH_TOKEN: ${{ github.token }}
1331
+ - name: Release the issue reservation
1332
+ if: always()
1333
+ run: node src/packages/sdlc/src/issue-actions.mjs cleanup
1334
+ env:
1335
+ GH_TOKEN: ${{ github.token }}