code-foundry 1.1.1 → 1.2.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.
@@ -11,7 +11,7 @@ dependency_review: auto
11
11
  package_manager: bun
12
12
  toolchain: auto
13
13
  runtime_repository: 0xPlayerOne/code-foundry
14
- runtime_ref: v1.1.0
14
+ runtime_ref: v1.2.0
15
15
  release_type: node
16
16
  npm_publish: true
17
17
  license: agpl-3.0-or-later
@@ -33,15 +33,18 @@ on:
33
33
  required: false
34
34
  type: number
35
35
  default: 1
36
+ # Retained for caller compatibility. Rust shards share the single
37
+ # analysis matrix, so no separate throttle applies.
36
38
  permissions:
37
39
  actions: read
38
40
  contents: read
39
41
  packages: read
40
42
  security-events: write
41
43
 
42
- # Analyzers run only for detected languages: the analysis matrix is built from
43
- # detection, so repositories never see skipped checks for languages they do
44
- # not use. An empty matrix while analysis is enabled fails the build closed.
44
+ # Analyzers run only for detected languages: a single analysis matrix is
45
+ # built from detection (Rust shards expand inline), so repositories never
46
+ # see checks — not even skipped ones — for languages they do not use. An
47
+ # empty matrix while analysis is enabled fails the build closed.
45
48
  env:
46
49
  REPO_FOUNDRY_PROFILE: ${{ vars.REPO_FOUNDRY_PROFILE }}
47
50
  REPO_FOUNDRY_LANGUAGES: ${{ vars.REPO_FOUNDRY_LANGUAGES }}
@@ -61,7 +64,6 @@ jobs:
61
64
  languages: ${{ steps.languages.outputs.languages }}
62
65
  enabled: ${{ steps.languages.outputs.enabled }}
63
66
  matrix: ${{ steps.matrix.outputs.matrix }}
64
- rust_matrix: ${{ steps.matrix.outputs.rust_matrix }}
65
67
  code_security: ${{ steps.security.outputs.status }}
66
68
  actions_available: ${{ steps.languages.outputs.actions_available }}
67
69
  actions_changed: ${{ steps.languages.outputs.actions_changed }}
@@ -144,30 +146,40 @@ jobs:
144
146
  const enabled = process.env.MATRIX_ENABLED === "true";
145
147
  if (!enabled) {
146
148
  append("matrix", "[]");
147
- append("rust_matrix", "[]");
148
149
  } else {
149
150
  const languages = JSON.parse(process.env.MATRIX_LANGUAGES || "[]");
150
151
  const shards = JSON.parse(process.env.MATRIX_SHARDS || "[\"all\"]");
151
152
  const display = { actions: "Actions", "javascript-typescript": "TypeScript", python: "Python" };
153
+ // SARIF categories are the code-scanning baseline keys: they must
154
+ // stay byte-identical to the pre-matrix values (/language:actions,
155
+ // /language:javascript-typescript, /language:python,
156
+ // /language:rust/<scope>). Any rename orphans the main-branch
157
+ // baseline and breaks alert comparison on every pull request.
152
158
  const matrix = languages
153
159
  .filter((entry) => entry.language !== "rust")
154
160
  .map((entry) => ({
155
161
  display: display[entry.language] || entry.language,
156
162
  language: entry.language,
157
- category: "/language/" + entry.language,
163
+ category: "/language:" + entry.language,
158
164
  build_mode: entry["build-mode"] || "none",
159
165
  changed: entry.changed === true,
160
166
  }));
161
167
  const rust = languages.find((entry) => entry.language === "rust");
162
- const rustMatrix = rust
163
- ? shards.map((shard) => ({ display: "Rust (" + shard + ")", shard: String(shard), changed: rust.changed === true }))
164
- : [];
165
- if (!matrix.length && !rustMatrix.length) {
168
+ for (const shard of rust ? shards : []) {
169
+ matrix.push({
170
+ display: String(shard) === "all" ? "Rust" : "Rust (" + shard + ")",
171
+ language: "rust",
172
+ category: "/language:rust",
173
+ build_mode: "none",
174
+ changed: rust.changed === true,
175
+ shard: String(shard),
176
+ });
177
+ }
178
+ if (!matrix.length) {
166
179
  console.error("CodeQL analysis matrix is empty while analysis is enabled.");
167
180
  process.exit(1);
168
181
  }
169
182
  append("matrix", JSON.stringify(matrix));
170
- append("rust_matrix", JSON.stringify(rustMatrix));
171
183
  }
172
184
  '
173
185
 
@@ -206,56 +218,14 @@ jobs:
206
218
  mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
207
219
  cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
208
220
  - name: Analyze
209
- if: ${{ matrix.entry.changed == true }}
221
+ if: ${{ matrix.entry.changed == true && matrix.entry.language != 'rust' }}
210
222
  uses: ./.github/actions/codeql
211
223
  with:
212
224
  language: ${{ matrix.entry.language }}
213
225
  build-mode: ${{ matrix.entry.build_mode }}
214
226
  category: ${{ matrix.entry.category }}
215
- - name: Not applicable
216
- if: ${{ matrix.entry.changed != true }}
217
- run: echo "CodeQL ${{ matrix.entry.display }} analysis is not applicable to this change."
218
-
219
- # Rust keeps its own job so shard fan-out stays behind the
220
- # rust-max-parallel throttle. The static name matches the pre-matrix check
221
- # name; per-shard detail stays in the SARIF category and step logs.
222
- analyze-rust:
223
- name: Analyze (Rust)
224
- needs: detect
225
- if: vars.CI_BILLING_PAUSED != 'true' && needs.detect.outputs.enabled == 'true' && needs.detect.outputs.rust_available == 'true'
226
- strategy:
227
- fail-fast: false
228
- max-parallel: ${{ inputs.rust-max-parallel }}
229
- matrix:
230
- entry: ${{ fromJson(needs.detect.outputs.rust_matrix || '[]') }}
231
- runs-on: ${{ inputs.runner }}
232
- timeout-minutes: 30
233
- steps:
234
- - name: Checkout
235
- if: ${{ matrix.entry.changed == true }}
236
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
237
- with:
238
- persist-credentials: false
239
- - name: Runtime
240
- if: ${{ matrix.entry.changed == true }}
241
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
242
- with:
243
- persist-credentials: false
244
- repository: ${{ inputs.runtime-repository }}
245
- ref: ${{ inputs.runtime-ref }}
246
- path: .github/.code-foundry
247
- sparse-checkout: |
248
- .github/actions
249
- src/lib
250
- src/runtime.mjs
251
- - name: Install runtime
252
- if: ${{ matrix.entry.changed == true }}
253
- run: |
254
- mkdir -p .github/actions
255
- mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
256
- cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
257
227
  - name: Configure Rust scope
258
- if: ${{ matrix.entry.changed == true }}
228
+ if: ${{ matrix.entry.changed == true && matrix.entry.language == 'rust' }}
259
229
  id: scope
260
230
  env:
261
231
  RUST_SCOPE: ${{ matrix.entry.shard }}
@@ -303,15 +273,15 @@ jobs:
303
273
  echo "config_file=$config_file" >> "$GITHUB_OUTPUT"
304
274
  echo "scope_id=$scope_id" >> "$GITHUB_OUTPUT"
305
275
  - name: Initialize
306
- if: ${{ matrix.entry.changed == true }}
276
+ if: ${{ matrix.entry.changed == true && matrix.entry.language == 'rust' }}
307
277
  uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
308
278
  with:
309
279
  languages: rust
310
280
  build-mode: ${{ needs.detect.outputs.rust_build_mode }}
311
281
  config-file: ${{ steps.scope.outputs.config_file }}
312
282
  threads: ${{ inputs.rust-threads }}
313
- - name: Analyze
314
- if: ${{ matrix.entry.changed == true }}
283
+ - name: Analyze Rust
284
+ if: ${{ matrix.entry.changed == true && matrix.entry.language == 'rust' }}
315
285
  uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
316
286
  with:
317
287
  category: /language:rust/${{ steps.scope.outputs.scope_id }}
@@ -319,4 +289,4 @@ jobs:
319
289
  wait-for-processing: false
320
290
  - name: Not applicable
321
291
  if: ${{ matrix.entry.changed != true }}
322
- run: echo "CodeQL Rust analysis is not applicable to this change."
292
+ run: echo "CodeQL ${{ matrix.entry.display }} analysis is not applicable to this change."
@@ -9,16 +9,17 @@ permissions:
9
9
  contents: read
10
10
 
11
11
  jobs:
12
- detect:
13
- name: OpenCode Security / Detect
12
+ # One job: the release-please branch gate stays at the job level so
13
+ # ordinary pull requests render a single skipped check instead of two.
14
+ # The scan itself still runs only for generated release pull requests
15
+ # (or manual dispatch) with the scanner configured and keyed.
16
+ scan:
17
+ name: OpenCode Security / Scan
14
18
  if: >-
15
19
  vars.CI_BILLING_PAUSED != 'true' &&
16
20
  (github.event_name == 'workflow_dispatch' ||
17
21
  startsWith(github.event.pull_request.head.ref, 'release-please--branches--main'))
18
22
  runs-on: ubuntu-slim
19
- outputs:
20
- enabled: ${{ steps.detect.outputs.enabled }}
21
- token: ${{ steps.detect.outputs.token }}
22
23
  steps:
23
24
  - name: Checkout
24
25
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
@@ -35,20 +36,17 @@ jobs:
35
36
  if [ -n "$OPENCODE_API_KEY" ]; then token=true; fi
36
37
  echo "enabled=$enabled" >> "$GITHUB_OUTPUT"
37
38
  echo "token=$token" >> "$GITHUB_OUTPUT"
38
-
39
- scan:
40
- name: OpenCode Security / Scan
41
- needs: detect
42
- if: vars.CI_BILLING_PAUSED != 'true' && needs.detect.outputs.enabled == 'true' && needs.detect.outputs.token == 'true'
43
- uses: 0xPlayerOne/opencode-security/.github/workflows/opencode-security.yml@137698ef3545204af8fad00fc8bd64d663c8122e # main
44
- with:
45
- # This is the scanner checkout ref, not the consumer PR ref. The
46
- # reusable workflow already checks out the consumer repository.
47
- source_ref: 137698ef3545204af8fad00fc8bd64d663c8122e
48
- runner: ubuntu-latest
49
- model: opencode-go/muse-spark-1.3-contributor
50
- mode: standard
51
- fail_on_severity: high
52
- max_cost_usd: 1
53
- secrets:
54
- OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
39
+ - name: Scan
40
+ if: steps.detect.outputs.enabled == 'true' && steps.detect.outputs.token == 'true'
41
+ uses: 0xPlayerOne/opencode-security/.github/workflows/opencode-security.yml@137698ef3545204af8fad00fc8bd64d663c8122e # main
42
+ with:
43
+ # This is the scanner checkout ref, not the consumer PR ref. The
44
+ # reusable workflow already checks out the consumer repository.
45
+ source_ref: 137698ef3545204af8fad00fc8bd64d663c8122e
46
+ runner: ubuntu-latest
47
+ model: opencode-go/muse-spark-1.3-contributor
48
+ mode: standard
49
+ fail_on_severity: high
50
+ max_cost_usd: 1
51
+ secrets:
52
+ OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
@@ -119,43 +119,14 @@ jobs:
119
119
  rust-threads: ${{ inputs.rust-threads }}
120
120
  rust-max-parallel: ${{ inputs.rust-max-parallel }}
121
121
 
122
- release-policy:
123
- name: Release Policy
124
- if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'release'
125
- runs-on: ubuntu-slim
126
- timeout-minutes: 10
127
- steps:
128
- - name: Checkout
129
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
130
- with:
131
- persist-credentials: false
132
- fetch-depth: 0
133
- filter: blob:none
134
- - name: Checkout runtime
135
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
136
- with:
137
- persist-credentials: false
138
- repository: ${{ inputs.runtime-repository }}
139
- ref: ${{ inputs.runtime-ref }}
140
- path: .github/.code-foundry
141
- sparse-checkout: |
142
- src/lib
143
- src/runtime.mjs
144
- - name: Install runtime
145
- run: mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
146
- - name: Validate generated release diff
147
- env:
148
- FOUNDRY_BASE_SHA: ${{ github.event.pull_request.base.sha }}
149
- FOUNDRY_HEAD_REF: ${{ github.event.pull_request.head.ref }}
150
- FOUNDRY_HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}
151
- FOUNDRY_REPOSITORY: ${{ github.repository }}
152
- run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" validation release_diff
153
-
154
122
  # Aggregate check: "Validation / Gate" (caller job name + this job name).
155
123
  # Always evaluates; only jobs required for the mode must have succeeded.
124
+ # The release tier runs no suite jobs: its policy (generated release diff
125
+ # validation) executes as a conditional step below, so no separate
126
+ # release-policy job renders skipped checks on ordinary pull requests.
156
127
  gate:
157
128
  name: Gate
158
- needs: [ci, test, security, codeql, release-policy]
129
+ needs: [ci, test, security, codeql]
159
130
  if: vars.CI_BILLING_PAUSED != 'true' && always()
160
131
  runs-on: ubuntu-slim
161
132
  timeout-minutes: 10
@@ -165,7 +136,6 @@ jobs:
165
136
  FOUNDRY_TEST: ${{ needs.test.result }}
166
137
  FOUNDRY_SECURITY: ${{ needs.security.result }}
167
138
  FOUNDRY_CODEQL: ${{ needs.codeql.result }}
168
- FOUNDRY_RELEASE_POLICY: ${{ needs.release-policy.result }}
169
139
  steps:
170
140
  - name: Checkout runtime
171
141
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
@@ -179,5 +149,20 @@ jobs:
179
149
  src/runtime.mjs
180
150
  - name: Install runtime
181
151
  run: mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
152
+ - name: Checkout consumer repository
153
+ if: ${{ inputs.mode == 'release' }}
154
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
155
+ with:
156
+ persist-credentials: false
157
+ fetch-depth: 0
158
+ filter: blob:none
159
+ - name: Validate generated release diff
160
+ if: ${{ inputs.mode == 'release' }}
161
+ env:
162
+ FOUNDRY_BASE_SHA: ${{ github.event.pull_request.base.sha }}
163
+ FOUNDRY_HEAD_REF: ${{ github.event.pull_request.head.ref }}
164
+ FOUNDRY_HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}
165
+ FOUNDRY_REPOSITORY: ${{ github.repository }}
166
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" validation release_diff
182
167
  - name: Evaluate aggregate gate
183
168
  run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" validation gate
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.2.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.2.0...v1.2.1) (2026-09-06)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * restore pre-matrix CodeQL SARIF category strings ([#468](https://github.com/0xPlayerOne/code-foundry/issues/468)) ([8c51892](https://github.com/0xPlayerOne/code-foundry/commit/8c518921bf3632ba5b8ee4ca757efe3bc302739a))
9
+
10
+ ## [1.2.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.1.1...v1.2.0) (2026-09-06)
11
+
12
+
13
+ ### Features
14
+
15
+ * eliminate skipped checks with unified matrices and an in-gate release check ([#465](https://github.com/0xPlayerOne/code-foundry/issues/465)) ([55c3dca](https://github.com/0xPlayerOne/code-foundry/commit/55c3dca7a7d1460830464ec61f9b083d1350e3dd))
16
+
3
17
  ## [1.1.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.1.0...v1.1.1) (2026-09-06)
4
18
 
5
19
 
package/docs/WORKFLOWS.md CHANGED
@@ -82,13 +82,15 @@ honor the shared billing pause.
82
82
  | Release | Release Please, GitHub release, and optional npm publication |
83
83
 
84
84
  Use concise job names such as `CI / Format`, `Test / Unit`, and
85
- `CodeQL / Analyze (Python)`. Per-language CodeQL analyzers and security
86
- audits run through a detection-built matrix, so a repository only ever shows
87
- checks for languages it actually uses; inapplicable languages produce no
88
- checks instead of skipped rows. Required checks should match the jobs
89
- actually enabled for the repository profile — in practice, require only the
90
- aggregate `Validation / Gate`, which fails closed unless every generated
91
- check succeeds.
85
+ `CodeQL / Analyze (Python)`. Per-language CodeQL analyzers (Rust shards
86
+ included) and security audits run through a detection-built matrix, so a
87
+ repository only ever shows checks for languages it actually uses — never
88
+ skipped rows for other languages. The release tier validates the generated
89
+ diff as a step inside the gate rather than a separate job, for the same
90
+ reason. Required checks should match the jobs actually enabled for the
91
+ repository profile — in practice, require only the aggregate
92
+ `Validation / Gate`, which fails closed unless every generated check
93
+ succeeds.
92
94
 
93
95
  ## Merge methods
94
96
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "1.1.1",
3
+ "version": "1.2.1",
4
4
  "description": "A fast, language-aware repository factory for agent-ready workflows, testing, security, and release automation.",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-or-later",
@@ -19,8 +19,10 @@ export const RELEASE_PLEASE_PREFIX = 'release-please--branches--main'
19
19
 
20
20
  /** Stable aggregate check name emitted by the validation orchestrator's gate job. */
21
21
  export const AGGREGATE_CHECK_NAME = 'Validation / Gate'
22
- /** Job ids owned by the validation orchestrator. */
23
- export const VALIDATION_JOBS = ['ci', 'test', 'security', 'codeql', 'release-policy']
22
+ /** Job ids owned by the validation orchestrator. The release tier runs no
23
+ * suite jobs: its policy executes as a conditional step inside the gate, so
24
+ * no release-policy job id exists. */
25
+ export const VALIDATION_JOBS = ['ci', 'test', 'security', 'codeql']
24
26
 
25
27
  /** Events that may trigger canonical validation. */
26
28
  export const VALIDATION_EVENTS = ['pull_request', 'schedule', 'workflow_dispatch']
@@ -80,7 +82,10 @@ export function classifyValidationMode(input) {
80
82
  const REQUIRED_JOBS_BY_MODE = {
81
83
  fast: ['ci', 'test'],
82
84
  audit: ['ci', 'test', 'security', 'codeql'],
83
- release: ['release-policy'],
85
+ // The release tier requires no suite jobs: the generated release diff
86
+ // check runs as a conditional step inside the gate itself, so an empty
87
+ // requirement list is complete and any suite result is irrelevant.
88
+ release: [],
84
89
  }
85
90
 
86
91
  /**
package/src/runtime.mjs CHANGED
@@ -66,7 +66,6 @@ function validation(task) {
66
66
  test: process.env.FOUNDRY_TEST,
67
67
  security: process.env.FOUNDRY_SECURITY,
68
68
  codeql: process.env.FOUNDRY_CODEQL,
69
- 'release-policy': process.env.FOUNDRY_RELEASE_POLICY,
70
69
  },
71
70
  })
72
71
  if (gate.valid) {