@juangcarmona/lighthouse-sdlc 0.15.2 → 0.16.1

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