@plainconceptsplatform/workflows 0.28.12 → 0.28.13

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.
@@ -1,260 +1,260 @@
1
- # Managed by @plainconceptsplatform/workflows. Source: loops/templates/ci/app-ci-node-monorepo.yml. Update with `workflows update --force`; consumer edits may be overwritten.
2
- name: "App: CI (Node monorepo)"
3
-
4
- on:
5
- pull_request:
6
- schedule:
7
- - cron: "0 6 * * 1"
8
- workflow_dispatch:
9
-
10
- env:
11
- NODE_VERSION: "22"
12
- PNPM_VERSION: "10"
13
- WEB_PACKAGE: "@app/web"
14
- DESKTOP_PACKAGE: "@app/desktop"
15
- MOBILE_PACKAGE: "@app/mobile"
16
- WEB_EXPORT_PATH: apps/web/out
17
- PLAYWRIGHT_REPORT_PATH: apps/web/playwright-report
18
- DESKTOP_MAIN_PATH: apps/desktop/out/main/index.js
19
- DESKTOP_PRELOAD_PATH: apps/desktop/out/preload/index.cjs
20
- DESKTOP_PRELOAD_BRIDGE_PATTERN: exposeInMainWorld
21
- MOBILE_IOS_PATH: apps/mobile/ios
22
- MOBILE_ANDROID_PATH: apps/mobile/android
23
- WEB_ARTIFACT_NAME: web-export
24
- PLAYWRIGHT_ARTIFACT_NAME: playwright-report
25
- TRUFFLEHOG_IMAGE: "trufflesecurity/trufflehog:latest"
26
- SEMGREP_IMAGE: "semgrep/semgrep:1.168.0"
27
- SBOM_ARTIFACT_NAME: app-sbom.cyclonedx.json
28
- MUTATION_THRESHOLD: "60"
29
-
30
- permissions:
31
- contents: read
32
-
33
- concurrency:
34
- group: ci-${{ github.workflow }}-${{ github.head_ref || github.ref }}
35
- cancel-in-progress: ${{ github.event_name == 'pull_request' }}
36
-
37
- jobs:
38
- lint:
39
- name: Lint (Biome)
40
- if: github.event_name != 'schedule'
41
- runs-on: RunnerLandingZone
42
- steps:
43
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
44
- - uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
45
- with: { version: "${{ env.PNPM_VERSION }}", run_install: false }
46
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
47
- with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm }
48
- - run: pnpm install --frozen-lockfile
49
- - run: pnpm exec biome check .
50
-
51
- web:
52
- name: Web (Next.js static export)
53
- if: github.event_name != 'schedule'
54
- runs-on: RunnerLandingZone
55
- steps:
56
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
57
- - uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
58
- with: { version: "${{ env.PNPM_VERSION }}", run_install: false }
59
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
60
- with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm }
61
- - run: pnpm install --frozen-lockfile
62
- - run: pnpm --filter "$WEB_PACKAGE" run typecheck
63
- - run: pnpm --filter "$WEB_PACKAGE" run test
64
- - run: pnpm --filter "$WEB_PACKAGE" run lint:fsd
65
- - run: pnpm --filter "$WEB_PACKAGE" run build
66
- - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
67
- with:
68
- name: ${{ env.WEB_ARTIFACT_NAME }}
69
- path: ${{ env.WEB_EXPORT_PATH }}
70
- retention-days: 3
71
- if-no-files-found: error
72
-
73
- mutation-web:
74
- name: Mutation (web, diff)
75
- if: github.event_name == 'pull_request'
76
- runs-on: RunnerLandingZone
77
- timeout-minutes: 25
78
- steps:
79
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
80
- with:
81
- fetch-depth: 0
82
- - uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
83
- with: { version: "${{ env.PNPM_VERSION }}", run_install: false }
84
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
85
- with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm }
86
- - name: Detect web changes
87
- id: scope
88
- run: |
89
- git fetch origin "$GITHUB_BASE_REF" --depth=1
90
- if git diff --name-only "origin/$GITHUB_BASE_REF" HEAD | grep -qE "^apps/web/"; then
91
- echo "run=true" >> "$GITHUB_OUTPUT"
92
- else
93
- echo "run=false" >> "$GITHUB_OUTPUT"
94
- echo "No apps/web changes in this PR; skipping web mutation."
95
- fi
96
- - run: pnpm install --frozen-lockfile
97
- if: steps.scope.outputs.run == 'true'
98
- - name: StrykerJS (changed files only)
99
- if: steps.scope.outputs.run == 'true'
100
- run: pnpm --filter "$WEB_PACKAGE" exec stryker run --since="origin/$GITHUB_BASE_REF"
101
-
102
- e2e:
103
- name: E2E (Playwright)
104
- if: github.event_name != 'schedule'
105
- needs: web
106
- runs-on: RunnerLandingZone
107
- steps:
108
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
109
- - uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
110
- with: { version: "${{ env.PNPM_VERSION }}", run_install: false }
111
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
112
- with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm }
113
- - run: pnpm install --frozen-lockfile
114
- - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
115
- with:
116
- name: ${{ env.WEB_ARTIFACT_NAME }}
117
- path: ${{ env.WEB_EXPORT_PATH }}
118
- - run: pnpm --filter "$WEB_PACKAGE" exec playwright install --with-deps chromium webkit
119
- - run: pnpm --filter "$WEB_PACKAGE" run e2e
120
- - if: failure()
121
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
122
- with:
123
- name: ${{ env.PLAYWRIGHT_ARTIFACT_NAME }}
124
- path: ${{ env.PLAYWRIGHT_REPORT_PATH }}
125
- retention-days: 7
126
-
127
- desktop:
128
- name: Desktop (Electron)
129
- if: github.event_name != 'schedule'
130
- needs: web
131
- runs-on: RunnerLandingZone
132
- steps:
133
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
134
- - uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
135
- with: { version: "${{ env.PNPM_VERSION }}", run_install: false }
136
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
137
- with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm }
138
- - run: pnpm install --frozen-lockfile
139
- - run: pnpm --filter "$DESKTOP_PACKAGE" run typecheck
140
- - run: pnpm --filter "$DESKTOP_PACKAGE" run build
141
- - run: |
142
- test -f "$DESKTOP_MAIN_PATH"
143
- test -f "$DESKTOP_PRELOAD_PATH"
144
- grep -q "$DESKTOP_PRELOAD_BRIDGE_PATTERN" "$DESKTOP_PRELOAD_PATH"
145
- - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
146
- with:
147
- name: ${{ env.WEB_ARTIFACT_NAME }}
148
- path: ${{ env.WEB_EXPORT_PATH }}
149
- - run: pnpm --filter "$DESKTOP_PACKAGE" exec playwright install-deps chromium
150
- - run: xvfb-run --auto-servernum pnpm --filter "$DESKTOP_PACKAGE" run e2e
151
-
152
- mobile:
153
- name: Mobile (Capacitor)
154
- if: github.event_name != 'schedule'
155
- runs-on: RunnerLandingZone
156
- steps:
157
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
158
- - uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
159
- with: { version: "${{ env.PNPM_VERSION }}", run_install: false }
160
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
161
- with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm }
162
- - run: pnpm install --frozen-lockfile
163
- - run: pnpm --filter "$MOBILE_PACKAGE" run typecheck
164
- - run: |
165
- if [ -d "$MOBILE_IOS_PATH" ] || [ -d "$MOBILE_ANDROID_PATH" ]; then
166
- pnpm --filter "$WEB_PACKAGE" run build
167
- pnpm --filter "$MOBILE_PACKAGE" run sync
168
- else
169
- echo "::notice::Native projects absent; skipping Capacitor sync."
170
- fi
171
-
172
- secret-scan:
173
- name: Secret scan (TruffleHog)
174
- runs-on: RunnerLandingZone
175
- steps:
176
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
177
- - run: docker run --rm -v "${{ github.workspace }}:/repo" "$TRUFFLEHOG_IMAGE" filesystem /repo --only-verified --fail --no-update
178
-
179
- deps-and-iac-scan:
180
- name: Dependencies and IaC (Trivy)
181
- runs-on: RunnerLandingZone
182
- steps:
183
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
184
- - uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
185
- with:
186
- scan-type: fs
187
- scanners: vuln,misconfig,secret
188
- severity: CRITICAL,HIGH
189
- ignore-unfixed: true
190
- exit-code: "1"
191
- format: table
192
-
193
- sast-scan:
194
- name: SAST (Semgrep)
195
- runs-on: RunnerLandingZone
196
- steps:
197
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
198
- - run: docker run --rm -v "${{ github.workspace }}:/src" -w /src "$SEMGREP_IMAGE" semgrep scan --error --metrics=off --oss-only --disable-version-check --config p/default --config p/security-audit --config p/secrets --config p/typescript --config p/react --exclude-rule yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag
199
-
200
- sbom:
201
- name: SBOM (CycloneDX)
202
- runs-on: RunnerLandingZone
203
- steps:
204
- - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
205
- - uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0
206
- with:
207
- format: cyclonedx-json
208
- artifact-name: ${{ env.SBOM_ARTIFACT_NAME }}
209
-
210
- # A bot pull request is opened with GITHUB_TOKEN, and GitHub delivers no workflow_run event
211
- # for the CI runs that follow (the run's actor is the bot). The router's CI-completion route
212
- # never sees them, so this job hands the verdict over from inside CI. workflow_dispatch is
213
- # one of the two events GITHUB_TOKEN may raise, so no App token is needed here, and the
214
- # router treats a dispatch as trusted. Human pull requests are left to the workflow_run
215
- # route, which does fire for them. The reconcile belt remains the hourly fallback.
216
- #
217
- # If a deploy pipeline calls this workflow with `uses:`, that caller must also grant
218
- # `actions: write`. A called workflow may not request a scope its caller withheld, and the
219
- # whole run fails to start with zero jobs and no annotation when it does.
220
- dispatch-merge-gate:
221
- name: Dispatch merge gate
222
- needs: [lint, web, mutation-web, e2e, desktop, mobile]
223
- if: >
224
- always() &&
225
- github.event_name == 'pull_request' &&
226
- github.event.pull_request.head.repo.full_name == github.repository &&
227
- github.event.pull_request.draft == false &&
228
- github.event.pull_request.user.type == 'Bot'
229
- runs-on: RunnerLandingZone
230
- timeout-minutes: 5
231
- permissions:
232
- contents: read
233
- actions: write
234
- steps:
235
- - name: Dispatch the merge gate with this run's verdict
236
- env:
237
- GH_TOKEN: ${{ github.token }}
238
- REPO: ${{ github.repository }}
239
- REF: ${{ github.event.repository.default_branch }}
240
- PR_NUMBER: ${{ github.event.pull_request.number }}
241
- RUN_ID: ${{ github.run_id }}
242
- RESULTS: ${{ join(needs.*.result, ' ') }}
243
- run: |
244
- set -euo pipefail
245
- conclusion=success
246
- for result in $RESULTS; do
247
- case "$result" in
248
- failure) conclusion=failure; break ;;
249
- cancelled | timed_out) conclusion=cancelled ;;
250
- esac
251
- done
252
- # A cancelled run was superseded by a newer push, whose own run dispatches.
253
- if [ "$conclusion" = cancelled ]; then
254
- echo "CI was cancelled; not dispatching the merge gate."
255
- exit 0
256
- fi
257
- echo "Dispatching the merge gate for PR #$PR_NUMBER with CI $conclusion (run $RUN_ID)."
258
- gh workflow run work-router.yml --repo "$REPO" --ref "$REF" \
259
- -f operation=merge-gate -f pr-number="$PR_NUMBER" \
260
- -f ci-conclusion="$conclusion" -f ci-run-id="$RUN_ID"
1
+ # Managed by @plainconceptsplatform/workflows. Source: loops/templates/ci/app-ci-node-monorepo.yml. Update with `workflows update --force`; consumer edits may be overwritten.
2
+ name: "App: CI (Node monorepo)"
3
+
4
+ on:
5
+ pull_request:
6
+ schedule:
7
+ - cron: "0 6 * * 1"
8
+ workflow_dispatch:
9
+
10
+ env:
11
+ NODE_VERSION: "22"
12
+ PNPM_VERSION: "10"
13
+ WEB_PACKAGE: "@app/web"
14
+ DESKTOP_PACKAGE: "@app/desktop"
15
+ MOBILE_PACKAGE: "@app/mobile"
16
+ WEB_EXPORT_PATH: apps/web/out
17
+ PLAYWRIGHT_REPORT_PATH: apps/web/playwright-report
18
+ DESKTOP_MAIN_PATH: apps/desktop/out/main/index.js
19
+ DESKTOP_PRELOAD_PATH: apps/desktop/out/preload/index.cjs
20
+ DESKTOP_PRELOAD_BRIDGE_PATTERN: exposeInMainWorld
21
+ MOBILE_IOS_PATH: apps/mobile/ios
22
+ MOBILE_ANDROID_PATH: apps/mobile/android
23
+ WEB_ARTIFACT_NAME: web-export
24
+ PLAYWRIGHT_ARTIFACT_NAME: playwright-report
25
+ TRUFFLEHOG_IMAGE: "trufflesecurity/trufflehog:latest"
26
+ SEMGREP_IMAGE: "semgrep/semgrep:1.168.0"
27
+ SBOM_ARTIFACT_NAME: app-sbom.cyclonedx.json
28
+ MUTATION_THRESHOLD: "60"
29
+
30
+ permissions:
31
+ contents: read
32
+
33
+ concurrency:
34
+ group: ci-${{ github.workflow }}-${{ github.head_ref || github.ref }}
35
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
36
+
37
+ jobs:
38
+ lint:
39
+ name: Lint (Biome)
40
+ if: github.event_name != 'schedule'
41
+ runs-on: RunnerLandingZone
42
+ steps:
43
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
44
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
45
+ with: { version: "${{ env.PNPM_VERSION }}", run_install: false }
46
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
47
+ with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm }
48
+ - run: pnpm install --frozen-lockfile
49
+ - run: pnpm exec biome check .
50
+
51
+ web:
52
+ name: Web (Next.js static export)
53
+ if: github.event_name != 'schedule'
54
+ runs-on: RunnerLandingZone
55
+ steps:
56
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
57
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
58
+ with: { version: "${{ env.PNPM_VERSION }}", run_install: false }
59
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
60
+ with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm }
61
+ - run: pnpm install --frozen-lockfile
62
+ - run: pnpm --filter "$WEB_PACKAGE" run typecheck
63
+ - run: pnpm --filter "$WEB_PACKAGE" run test
64
+ - run: pnpm --filter "$WEB_PACKAGE" run lint:fsd
65
+ - run: pnpm --filter "$WEB_PACKAGE" run build
66
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
67
+ with:
68
+ name: ${{ env.WEB_ARTIFACT_NAME }}
69
+ path: ${{ env.WEB_EXPORT_PATH }}
70
+ retention-days: 3
71
+ if-no-files-found: error
72
+
73
+ mutation-web:
74
+ name: Mutation (web, diff)
75
+ if: github.event_name == 'pull_request'
76
+ runs-on: RunnerLandingZone
77
+ timeout-minutes: 25
78
+ steps:
79
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
80
+ with:
81
+ fetch-depth: 0
82
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
83
+ with: { version: "${{ env.PNPM_VERSION }}", run_install: false }
84
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
85
+ with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm }
86
+ - name: Detect web changes
87
+ id: scope
88
+ run: |
89
+ git fetch origin "$GITHUB_BASE_REF" --depth=1
90
+ if git diff --name-only "origin/$GITHUB_BASE_REF" HEAD | grep -qE "^apps/web/"; then
91
+ echo "run=true" >> "$GITHUB_OUTPUT"
92
+ else
93
+ echo "run=false" >> "$GITHUB_OUTPUT"
94
+ echo "No apps/web changes in this PR; skipping web mutation."
95
+ fi
96
+ - run: pnpm install --frozen-lockfile
97
+ if: steps.scope.outputs.run == 'true'
98
+ - name: StrykerJS (changed files only)
99
+ if: steps.scope.outputs.run == 'true'
100
+ run: pnpm --filter "$WEB_PACKAGE" exec stryker run --since="origin/$GITHUB_BASE_REF"
101
+
102
+ e2e:
103
+ name: E2E (Playwright)
104
+ if: github.event_name != 'schedule'
105
+ needs: web
106
+ runs-on: RunnerLandingZone
107
+ steps:
108
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
109
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
110
+ with: { version: "${{ env.PNPM_VERSION }}", run_install: false }
111
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
112
+ with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm }
113
+ - run: pnpm install --frozen-lockfile
114
+ - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
115
+ with:
116
+ name: ${{ env.WEB_ARTIFACT_NAME }}
117
+ path: ${{ env.WEB_EXPORT_PATH }}
118
+ - run: pnpm --filter "$WEB_PACKAGE" exec playwright install --with-deps chromium webkit
119
+ - run: pnpm --filter "$WEB_PACKAGE" run e2e
120
+ - if: failure()
121
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
122
+ with:
123
+ name: ${{ env.PLAYWRIGHT_ARTIFACT_NAME }}
124
+ path: ${{ env.PLAYWRIGHT_REPORT_PATH }}
125
+ retention-days: 7
126
+
127
+ desktop:
128
+ name: Desktop (Electron)
129
+ if: github.event_name != 'schedule'
130
+ needs: web
131
+ runs-on: RunnerLandingZone
132
+ steps:
133
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
134
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
135
+ with: { version: "${{ env.PNPM_VERSION }}", run_install: false }
136
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
137
+ with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm }
138
+ - run: pnpm install --frozen-lockfile
139
+ - run: pnpm --filter "$DESKTOP_PACKAGE" run typecheck
140
+ - run: pnpm --filter "$DESKTOP_PACKAGE" run build
141
+ - run: |
142
+ test -f "$DESKTOP_MAIN_PATH"
143
+ test -f "$DESKTOP_PRELOAD_PATH"
144
+ grep -q "$DESKTOP_PRELOAD_BRIDGE_PATTERN" "$DESKTOP_PRELOAD_PATH"
145
+ - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
146
+ with:
147
+ name: ${{ env.WEB_ARTIFACT_NAME }}
148
+ path: ${{ env.WEB_EXPORT_PATH }}
149
+ - run: pnpm --filter "$DESKTOP_PACKAGE" exec playwright install-deps chromium
150
+ - run: xvfb-run --auto-servernum pnpm --filter "$DESKTOP_PACKAGE" run e2e
151
+
152
+ mobile:
153
+ name: Mobile (Capacitor)
154
+ if: github.event_name != 'schedule'
155
+ runs-on: RunnerLandingZone
156
+ steps:
157
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
158
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
159
+ with: { version: "${{ env.PNPM_VERSION }}", run_install: false }
160
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
161
+ with: { node-version: "${{ env.NODE_VERSION }}", cache: pnpm }
162
+ - run: pnpm install --frozen-lockfile
163
+ - run: pnpm --filter "$MOBILE_PACKAGE" run typecheck
164
+ - run: |
165
+ if [ -d "$MOBILE_IOS_PATH" ] || [ -d "$MOBILE_ANDROID_PATH" ]; then
166
+ pnpm --filter "$WEB_PACKAGE" run build
167
+ pnpm --filter "$MOBILE_PACKAGE" run sync
168
+ else
169
+ echo "::notice::Native projects absent; skipping Capacitor sync."
170
+ fi
171
+
172
+ secret-scan:
173
+ name: Secret scan (TruffleHog)
174
+ runs-on: RunnerLandingZone
175
+ steps:
176
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
177
+ - run: docker run --rm -v "${{ github.workspace }}:/repo" "$TRUFFLEHOG_IMAGE" filesystem /repo --only-verified --fail --no-update
178
+
179
+ deps-and-iac-scan:
180
+ name: Dependencies and IaC (Trivy)
181
+ runs-on: RunnerLandingZone
182
+ steps:
183
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
184
+ - uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
185
+ with:
186
+ scan-type: fs
187
+ scanners: vuln,misconfig,secret
188
+ severity: CRITICAL,HIGH
189
+ ignore-unfixed: true
190
+ exit-code: "1"
191
+ format: table
192
+
193
+ sast-scan:
194
+ name: SAST (Semgrep)
195
+ runs-on: RunnerLandingZone
196
+ steps:
197
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
198
+ - run: docker run --rm -v "${{ github.workspace }}:/src" -w /src "$SEMGREP_IMAGE" semgrep scan --error --metrics=off --oss-only --disable-version-check --config p/default --config p/security-audit --config p/secrets --config p/typescript --config p/react --exclude-rule yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag
199
+
200
+ sbom:
201
+ name: SBOM (CycloneDX)
202
+ runs-on: RunnerLandingZone
203
+ steps:
204
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
205
+ - uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0
206
+ with:
207
+ format: cyclonedx-json
208
+ artifact-name: ${{ env.SBOM_ARTIFACT_NAME }}
209
+
210
+ # A bot pull request is opened with GITHUB_TOKEN, and GitHub delivers no workflow_run event
211
+ # for the CI runs that follow (the run's actor is the bot). The router's CI-completion route
212
+ # never sees them, so this job hands the verdict over from inside CI. workflow_dispatch is
213
+ # one of the two events GITHUB_TOKEN may raise, so no App token is needed here, and the
214
+ # router treats a dispatch as trusted. Human pull requests are left to the workflow_run
215
+ # route, which does fire for them. The reconcile belt remains the hourly fallback.
216
+ #
217
+ # If a deploy pipeline calls this workflow with `uses:`, that caller must also grant
218
+ # `actions: write`. A called workflow may not request a scope its caller withheld, and the
219
+ # whole run fails to start with zero jobs and no annotation when it does.
220
+ dispatch-merge-gate:
221
+ name: Dispatch merge gate
222
+ needs: [lint, web, mutation-web, e2e, desktop, mobile]
223
+ if: >
224
+ always() &&
225
+ github.event_name == 'pull_request' &&
226
+ github.event.pull_request.head.repo.full_name == github.repository &&
227
+ github.event.pull_request.draft == false &&
228
+ github.event.pull_request.user.type == 'Bot'
229
+ runs-on: RunnerLandingZone
230
+ timeout-minutes: 5
231
+ permissions:
232
+ contents: read
233
+ actions: write
234
+ steps:
235
+ - name: Dispatch the merge gate with this run's verdict
236
+ env:
237
+ GH_TOKEN: ${{ github.token }}
238
+ REPO: ${{ github.repository }}
239
+ REF: ${{ github.event.repository.default_branch }}
240
+ PR_NUMBER: ${{ github.event.pull_request.number }}
241
+ RUN_ID: ${{ github.run_id }}
242
+ RESULTS: ${{ join(needs.*.result, ' ') }}
243
+ run: |
244
+ set -euo pipefail
245
+ conclusion=success
246
+ for result in $RESULTS; do
247
+ case "$result" in
248
+ failure) conclusion=failure; break ;;
249
+ cancelled | timed_out) conclusion=cancelled ;;
250
+ esac
251
+ done
252
+ # A cancelled run was superseded by a newer push, whose own run dispatches.
253
+ if [ "$conclusion" = cancelled ]; then
254
+ echo "CI was cancelled; not dispatching the merge gate."
255
+ exit 0
256
+ fi
257
+ echo "Dispatching the merge gate for PR #$PR_NUMBER with CI $conclusion (run $RUN_ID)."
258
+ gh workflow run work-router.yml --repo "$REPO" --ref "$REF" \
259
+ -f operation=merge-gate -f pr-number="$PR_NUMBER" \
260
+ -f ci-conclusion="$conclusion" -f ci-run-id="$RUN_ID"
@@ -43,11 +43,33 @@
43
43
  "models": {
44
44
  "glm-5-2": {
45
45
  "name": "GLM 5.3",
46
- "attachment": true
46
+ "tool_call": true,
47
+ "reasoning": true,
48
+ "attachment": true,
49
+ "modalities": {
50
+ "input": ["text", "image"],
51
+ "output": ["text"]
52
+ },
53
+ "limit": {
54
+ "context": 1048576,
55
+ "input": 1048576,
56
+ "output": 131072
57
+ }
47
58
  },
48
59
  "quasar-438b": {
49
60
  "name": "GLM 5.2",
50
- "attachment": true
61
+ "tool_call": true,
62
+ "reasoning": true,
63
+ "attachment": true,
64
+ "modalities": {
65
+ "input": ["text", "image"],
66
+ "output": ["text"]
67
+ },
68
+ "limit": {
69
+ "context": 1048576,
70
+ "input": 1048576,
71
+ "output": 131072
72
+ }
51
73
  }
52
74
  }
53
75
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plainconceptsplatform/workflows",
3
- "version": "0.28.12",
3
+ "version": "0.28.13",
4
4
  "description": "Install and update Platform GitHub agentic workflows.",
5
5
  "keywords": [
6
6
  "github-actions",