code-foundry 1.0.6 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,7 +39,9 @@ permissions:
39
39
  packages: read
40
40
  security-events: write
41
41
 
42
- # Every analyzer emits a successful check, including when its language is not applicable.
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.
43
45
  env:
44
46
  REPO_FOUNDRY_PROFILE: ${{ vars.REPO_FOUNDRY_PROFILE }}
45
47
  REPO_FOUNDRY_LANGUAGES: ${{ vars.REPO_FOUNDRY_LANGUAGES }}
@@ -58,6 +60,8 @@ jobs:
58
60
  outputs:
59
61
  languages: ${{ steps.languages.outputs.languages }}
60
62
  enabled: ${{ steps.languages.outputs.enabled }}
63
+ matrix: ${{ steps.matrix.outputs.matrix }}
64
+ rust_matrix: ${{ steps.matrix.outputs.rust_matrix }}
61
65
  code_security: ${{ steps.security.outputs.status }}
62
66
  actions_available: ${{ steps.languages.outputs.actions_available }}
63
67
  actions_changed: ${{ steps.languages.outputs.actions_changed }}
@@ -126,148 +130,65 @@ jobs:
126
130
  REPO_FOUNDRY_PRIVATE: ${{ github.event.repository.private }}
127
131
  REPO_FOUNDRY_VISIBILITY: ${{ github.event.repository.visibility }}
128
132
  run: node $RUNNER_TEMP/code-foundry/src/runtime.mjs codeql
129
-
130
- analyze-actions:
131
- name: Analyze (Actions)
132
- needs: detect
133
- if: >-
134
- vars.CI_BILLING_PAUSED != 'true' &&
135
- needs.detect.outputs.enabled == 'true' &&
136
- needs.detect.outputs.actions_available == 'true'
137
- runs-on: ${{ inputs.runner }}
138
- timeout-minutes: 30
139
- steps:
140
- - name: Checkout
141
- if: >-
142
- needs.detect.outputs.enabled == 'true' &&
143
- needs.detect.outputs.actions_available == 'true' &&
144
- needs.detect.outputs.actions_changed == 'true'
145
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
146
- with:
147
- persist-credentials: false
148
- - name: Runtime
149
- if: >-
150
- needs.detect.outputs.enabled == 'true' &&
151
- needs.detect.outputs.actions_available == 'true' &&
152
- needs.detect.outputs.actions_changed == 'true'
153
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
154
- with:
155
- persist-credentials: false
156
- repository: ${{ inputs.runtime-repository }}
157
- ref: ${{ inputs.runtime-ref }}
158
- path: .github/.code-foundry
159
- sparse-checkout: |
160
- .github/actions
161
- src/lib
162
- src/runtime.mjs
163
- - name: Install runtime
164
- if: >-
165
- needs.detect.outputs.enabled == 'true' &&
166
- needs.detect.outputs.actions_available == 'true' &&
167
- needs.detect.outputs.actions_changed == 'true'
168
- run: |
169
- mkdir -p .github/actions
170
- mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
171
- cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
172
- - name: Analyze
173
- if: >-
174
- needs.detect.outputs.enabled == 'true' &&
175
- needs.detect.outputs.actions_available == 'true' &&
176
- needs.detect.outputs.actions_changed == 'true'
177
- uses: ./.github/actions/codeql
178
- with:
179
- language: actions
180
- build-mode: ${{ needs.detect.outputs.actions_build_mode }}
181
- category: /language:actions
182
- - name: Not applicable
183
- if: >-
184
- needs.detect.outputs.enabled != 'true' ||
185
- needs.detect.outputs.actions_available != 'true' ||
186
- needs.detect.outputs.actions_changed != 'true'
187
- run: echo "CodeQL Actions analysis is not applicable to this change."
188
-
189
- analyze-typescript:
190
- name: Analyze (TypeScript)
191
- needs: detect
192
- if: >-
193
- vars.CI_BILLING_PAUSED != 'true' &&
194
- needs.detect.outputs.enabled == 'true' &&
195
- needs.detect.outputs.javascript_available == 'true'
196
- runs-on: ${{ inputs.runner }}
197
- timeout-minutes: 30
198
- steps:
199
- - name: Checkout
200
- if: >-
201
- needs.detect.outputs.enabled == 'true' &&
202
- needs.detect.outputs.javascript_available == 'true' &&
203
- needs.detect.outputs.javascript_changed == 'true'
204
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
205
- with:
206
- persist-credentials: false
207
- - name: Runtime
208
- if: >-
209
- needs.detect.outputs.enabled == 'true' &&
210
- needs.detect.outputs.javascript_available == 'true' &&
211
- needs.detect.outputs.javascript_changed == 'true'
212
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
213
- with:
214
- persist-credentials: false
215
- repository: ${{ inputs.runtime-repository }}
216
- ref: ${{ inputs.runtime-ref }}
217
- path: .github/.code-foundry
218
- sparse-checkout: |
219
- .github/actions
220
- src/lib
221
- src/runtime.mjs
222
- - name: Install runtime
223
- if: >-
224
- needs.detect.outputs.enabled == 'true' &&
225
- needs.detect.outputs.javascript_available == 'true' &&
226
- needs.detect.outputs.javascript_changed == 'true'
133
+ - id: matrix
134
+ name: Build analysis matrix
135
+ env:
136
+ MATRIX_ENABLED: ${{ steps.languages.outputs.enabled }}
137
+ MATRIX_LANGUAGES: ${{ steps.languages.outputs.languages }}
138
+ MATRIX_SHARDS: ${{ inputs.rust-shards }}
227
139
  run: |
228
- mkdir -p .github/actions
229
- mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
230
- cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
231
- - name: Analyze
232
- if: >-
233
- needs.detect.outputs.enabled == 'true' &&
234
- needs.detect.outputs.javascript_available == 'true' &&
235
- needs.detect.outputs.javascript_changed == 'true'
236
- uses: ./.github/actions/codeql
237
- with:
238
- language: javascript-typescript
239
- build-mode: ${{ needs.detect.outputs.javascript_build_mode }}
240
- category: /language:javascript-typescript
241
- - name: Not applicable
242
- if: >-
243
- needs.detect.outputs.enabled != 'true' ||
244
- needs.detect.outputs.javascript_available != 'true' ||
245
- needs.detect.outputs.javascript_changed != 'true'
246
- run: echo "CodeQL TypeScript analysis is not applicable to this change."
140
+ node -e '
141
+ const fs = require("node:fs");
142
+ const out = process.env.GITHUB_OUTPUT;
143
+ function append(name, value) { fs.appendFileSync(out, name + "=" + value + "\n"); }
144
+ const enabled = process.env.MATRIX_ENABLED === "true";
145
+ if (!enabled) {
146
+ append("matrix", "[]");
147
+ append("rust_matrix", "[]");
148
+ } else {
149
+ const languages = JSON.parse(process.env.MATRIX_LANGUAGES || "[]");
150
+ const shards = JSON.parse(process.env.MATRIX_SHARDS || "[\"all\"]");
151
+ const display = { actions: "Actions", "javascript-typescript": "TypeScript", python: "Python" };
152
+ const matrix = languages
153
+ .filter((entry) => entry.language !== "rust")
154
+ .map((entry) => ({
155
+ display: display[entry.language] || entry.language,
156
+ language: entry.language,
157
+ category: "/language/" + entry.language,
158
+ build_mode: entry["build-mode"] || "none",
159
+ changed: entry.changed === true,
160
+ }));
161
+ 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) {
166
+ console.error("CodeQL analysis matrix is empty while analysis is enabled.");
167
+ process.exit(1);
168
+ }
169
+ append("matrix", JSON.stringify(matrix));
170
+ append("rust_matrix", JSON.stringify(rustMatrix));
171
+ }
172
+ '
247
173
 
248
- analyze-python:
249
- name: Analyze (Python)
174
+ analyze:
175
+ name: Analyze (${{ matrix.entry.display }})
250
176
  needs: detect
251
- if: >-
252
- vars.CI_BILLING_PAUSED != 'true' &&
253
- needs.detect.outputs.enabled == 'true' &&
254
- needs.detect.outputs.python_available == 'true'
177
+ if: vars.CI_BILLING_PAUSED != 'true' && needs.detect.outputs.enabled == 'true'
178
+ strategy:
179
+ fail-fast: false
180
+ matrix:
181
+ entry: ${{ fromJson(needs.detect.outputs.matrix || '[]') }}
255
182
  runs-on: ${{ inputs.runner }}
256
183
  timeout-minutes: 30
257
184
  steps:
258
185
  - name: Checkout
259
- if: >-
260
- needs.detect.outputs.enabled == 'true' &&
261
- needs.detect.outputs.python_available == 'true' &&
262
- needs.detect.outputs.python_changed == 'true'
186
+ if: ${{ matrix.entry.changed == true }}
263
187
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
264
188
  with:
265
189
  persist-credentials: false
266
190
  - name: Runtime
267
- if: >-
268
- needs.detect.outputs.enabled == 'true' &&
269
- needs.detect.outputs.python_available == 'true' &&
270
- needs.detect.outputs.python_changed == 'true'
191
+ if: ${{ matrix.entry.changed == true }}
271
192
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
272
193
  with:
273
194
  persist-credentials: false
@@ -279,59 +200,41 @@ jobs:
279
200
  src/lib
280
201
  src/runtime.mjs
281
202
  - name: Install runtime
282
- if: >-
283
- needs.detect.outputs.enabled == 'true' &&
284
- needs.detect.outputs.python_available == 'true' &&
285
- needs.detect.outputs.python_changed == 'true'
203
+ if: ${{ matrix.entry.changed == true }}
286
204
  run: |
287
205
  mkdir -p .github/actions
288
206
  mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
289
207
  cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
290
208
  - name: Analyze
291
- if: >-
292
- needs.detect.outputs.enabled == 'true' &&
293
- needs.detect.outputs.python_available == 'true' &&
294
- needs.detect.outputs.python_changed == 'true'
209
+ if: ${{ matrix.entry.changed == true }}
295
210
  uses: ./.github/actions/codeql
296
211
  with:
297
- language: python
298
- build-mode: ${{ needs.detect.outputs.python_build_mode }}
299
- category: /language:python
212
+ language: ${{ matrix.entry.language }}
213
+ build-mode: ${{ matrix.entry.build_mode }}
214
+ category: ${{ matrix.entry.category }}
300
215
  - name: Not applicable
301
- if: >-
302
- needs.detect.outputs.enabled != 'true' ||
303
- needs.detect.outputs.python_available != 'true' ||
304
- needs.detect.outputs.python_changed != 'true'
305
- run: echo "CodeQL Python analysis is not applicable to this change."
216
+ if: ${{ matrix.entry.changed != true }}
217
+ run: echo "CodeQL ${{ matrix.entry.display }} analysis is not applicable to this change."
306
218
 
307
219
  analyze-rust:
308
- name: Analyze (Rust)
220
+ name: Analyze (${{ matrix.entry.display }})
309
221
  needs: detect
310
- if: >-
311
- vars.CI_BILLING_PAUSED != 'true' &&
312
- needs.detect.outputs.enabled == 'true' &&
313
- needs.detect.outputs.rust_available == 'true'
222
+ if: vars.CI_BILLING_PAUSED != 'true' && needs.detect.outputs.enabled == 'true' && needs.detect.outputs.rust_available == 'true'
314
223
  strategy:
315
224
  fail-fast: false
316
225
  max-parallel: ${{ inputs.rust-max-parallel }}
317
226
  matrix:
318
- shard: ${{ fromJson(inputs.rust-shards) }}
227
+ entry: ${{ fromJson(needs.detect.outputs.rust_matrix || '[]') }}
319
228
  runs-on: ${{ inputs.runner }}
320
229
  timeout-minutes: 30
321
230
  steps:
322
231
  - name: Checkout
323
- if: >-
324
- needs.detect.outputs.enabled == 'true' &&
325
- needs.detect.outputs.rust_available == 'true' &&
326
- needs.detect.outputs.rust_changed == 'true'
232
+ if: ${{ matrix.entry.changed == true }}
327
233
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
328
234
  with:
329
235
  persist-credentials: false
330
236
  - name: Runtime
331
- if: >-
332
- needs.detect.outputs.enabled == 'true' &&
333
- needs.detect.outputs.rust_available == 'true' &&
334
- needs.detect.outputs.rust_changed == 'true'
237
+ if: ${{ matrix.entry.changed == true }}
335
238
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
336
239
  with:
337
240
  persist-credentials: false
@@ -343,22 +246,16 @@ jobs:
343
246
  src/lib
344
247
  src/runtime.mjs
345
248
  - name: Install runtime
346
- if: >-
347
- needs.detect.outputs.enabled == 'true' &&
348
- needs.detect.outputs.rust_available == 'true' &&
349
- needs.detect.outputs.rust_changed == 'true'
249
+ if: ${{ matrix.entry.changed == true }}
350
250
  run: |
351
251
  mkdir -p .github/actions
352
252
  mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
353
253
  cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
354
254
  - name: Configure Rust scope
355
- if: >-
356
- needs.detect.outputs.enabled == 'true' &&
357
- needs.detect.outputs.rust_available == 'true' &&
358
- needs.detect.outputs.rust_changed == 'true'
255
+ if: ${{ matrix.entry.changed == true }}
359
256
  id: scope
360
257
  env:
361
- RUST_SCOPE: ${{ matrix.shard }}
258
+ RUST_SCOPE: ${{ matrix.entry.shard }}
362
259
  run: |
363
260
  set -euo pipefail
364
261
  scope="$RUST_SCOPE"
@@ -403,10 +300,7 @@ jobs:
403
300
  echo "config_file=$config_file" >> "$GITHUB_OUTPUT"
404
301
  echo "scope_id=$scope_id" >> "$GITHUB_OUTPUT"
405
302
  - name: Initialize
406
- if: >-
407
- needs.detect.outputs.enabled == 'true' &&
408
- needs.detect.outputs.rust_available == 'true' &&
409
- needs.detect.outputs.rust_changed == 'true'
303
+ if: ${{ matrix.entry.changed == true }}
410
304
  uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
411
305
  with:
412
306
  languages: rust
@@ -414,18 +308,12 @@ jobs:
414
308
  config-file: ${{ steps.scope.outputs.config_file }}
415
309
  threads: ${{ inputs.rust-threads }}
416
310
  - name: Analyze
417
- if: >-
418
- needs.detect.outputs.enabled == 'true' &&
419
- needs.detect.outputs.rust_available == 'true' &&
420
- needs.detect.outputs.rust_changed == 'true'
311
+ if: ${{ matrix.entry.changed == true }}
421
312
  uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
422
313
  with:
423
314
  category: /language:rust/${{ steps.scope.outputs.scope_id }}
424
315
  upload-database: false
425
316
  wait-for-processing: false
426
317
  - name: Not applicable
427
- if: >-
428
- needs.detect.outputs.enabled != 'true' ||
429
- needs.detect.outputs.rust_available != 'true' ||
430
- needs.detect.outputs.rust_changed != 'true'
431
- run: echo "CodeQL Rust analysis is not applicable to this change."
318
+ if: ${{ matrix.entry.changed != true }}
319
+ run: echo "CodeQL ${{ matrix.entry.display }} analysis is not applicable to this change."
@@ -45,6 +45,7 @@ jobs:
45
45
  python: ${{ steps.profile.outputs.python }}
46
46
  python_requirements: ${{ steps.profile.outputs.python_requirements }}
47
47
  dependency_review: ${{ steps.profile.outputs.dependency_review }}
48
+ audit_matrix: ${{ steps.matrix.outputs.audit_matrix }}
48
49
  steps:
49
50
  - name: Checkout
50
51
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
@@ -99,15 +100,49 @@ jobs:
99
100
  REPO_FOUNDRY_PRIVATE: ${{ github.event.repository.private }}
100
101
  REPO_FOUNDRY_VISIBILITY: ${{ github.event.repository.visibility }}
101
102
  run: node $RUNNER_TEMP/code-foundry/src/runtime.mjs security profile >> "$GITHUB_OUTPUT"
103
+ - id: matrix
104
+ name: Build audit matrix
105
+ env:
106
+ MATRIX_JAVASCRIPT: ${{ steps.profile.outputs.javascript }}
107
+ MATRIX_RUST: ${{ steps.profile.outputs.rust }}
108
+ MATRIX_PYTHON: ${{ steps.profile.outputs.python }}
109
+ MATRIX_REQUIREMENTS: ${{ steps.profile.outputs.python_requirements }}
110
+ run: |
111
+ node -e '
112
+ const fs = require("node:fs");
113
+ const env = process.env;
114
+ const entries = [];
115
+ if (env.MATRIX_JAVASCRIPT === "true") entries.push({ display: "JavaScript", language: "javascript" });
116
+ if (env.MATRIX_RUST === "true") entries.push({ display: "Rust", language: "rust" });
117
+ if (env.MATRIX_PYTHON === "true") {
118
+ let requirements = [];
119
+ try { requirements = JSON.parse(env.MATRIX_REQUIREMENTS || "[]"); } catch (error) { requirements = []; }
120
+ for (const requirement of requirements.filter((item) => item && item !== "none")) {
121
+ entries.push({ display: "Python / " + requirement, language: "python", requirement: requirement });
122
+ }
123
+ }
124
+ fs.appendFileSync(env.GITHUB_OUTPUT, "audit_matrix=" + JSON.stringify(entries) + "\n");
125
+ '
102
126
 
103
- dependency-audit-javascript:
104
- name: Dependency Audit (JavaScript)
127
+ # Audits run only for detected languages: the audit matrix is built from the
128
+ # profile, so repositories never see skipped checks for ecosystems they do
129
+ # not use. An empty matrix skips this job with no per-language rows.
130
+ dependency-audit:
131
+ name: Dependency Audit (${{ matrix.entry.display }})
105
132
  needs: profile
106
- if: ${{ vars.CI_BILLING_PAUSED != 'true' && needs.profile.result == 'success' && needs.profile.outputs.javascript == 'true' }}
133
+ if: vars.CI_BILLING_PAUSED != 'true' && needs.profile.result == 'success'
134
+ strategy:
135
+ fail-fast: false
136
+ max-parallel: 8
137
+ matrix:
138
+ entry: ${{ fromJson(needs.profile.outputs.audit_matrix || '[]') }}
107
139
  runs-on: ${{ inputs.runner }}
108
140
  timeout-minutes: 20
141
+ env:
142
+ REPO_FOUNDRY_PYTHON_REQUIREMENT: ${{ matrix.entry.requirement }}
109
143
  steps:
110
- - name: Checkout
144
+ - name: Checkout JavaScript
145
+ if: matrix.entry.language == 'javascript'
111
146
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
112
147
  with:
113
148
  persist-credentials: false
@@ -126,43 +161,22 @@ jobs:
126
161
  **/yarn.lock
127
162
  **/package-lock.json
128
163
  sparse-checkout-cone-mode: false
129
- - name: Runtime
164
+ - name: Checkout Rust
165
+ if: matrix.entry.language == 'rust'
130
166
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
131
167
  with:
132
168
  persist-credentials: false
133
- repository: ${{ inputs.runtime-repository }}
134
- ref: ${{ inputs.runtime-ref }}
135
- path: .github/.code-foundry
169
+ filter: blob:none
136
170
  sparse-checkout: |
137
- .github/actions
138
- src/lib
139
- src/runtime.mjs
140
- - name: Install runtime
141
- run: |
142
- mkdir -p .github/actions
143
- mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
144
- cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
145
- - name: Detect
146
- id: applicability
147
- run: node $RUNNER_TEMP/code-foundry/src/runtime.mjs security should_run javascript >> "$GITHUB_OUTPUT"
148
- - name: Setup
149
- if: steps.applicability.outputs.applicable == 'true'
150
- uses: ./.github/actions/setup
151
- with:
152
- mise-scope: javascript
153
- cache-save: ${{ github.event_name == 'push' }}
154
- - name: Audit dependencies
155
- if: steps.applicability.outputs.applicable == 'true'
156
- run: node $RUNNER_TEMP/code-foundry/src/runtime.mjs security audit javascript
157
-
158
- dependency-audit-rust:
159
- name: Dependency Audit (Rust)
160
- needs: profile
161
- if: ${{ vars.CI_BILLING_PAUSED != 'true' && needs.profile.result == 'success' && needs.profile.outputs.rust == 'true' }}
162
- runs-on: ${{ inputs.runner }}
163
- timeout-minutes: 20
164
- steps:
165
- - name: Checkout
171
+ .github
172
+ .mise.toml
173
+ mise.lock
174
+ **/Cargo.toml
175
+ **/Cargo.lock
176
+ **/.cargo/**
177
+ sparse-checkout-cone-mode: false
178
+ - name: Checkout Python
179
+ if: matrix.entry.language == 'python'
166
180
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
167
181
  with:
168
182
  persist-credentials: false
@@ -171,9 +185,14 @@ jobs:
171
185
  .github
172
186
  .mise.toml
173
187
  mise.lock
174
- **/Cargo.toml
175
- **/Cargo.lock
176
- **/.cargo/**
188
+ **/pyproject.toml
189
+ **/requirements*.txt
190
+ **/setup.py
191
+ **/setup.cfg
192
+ **/Pipfile
193
+ **/Pipfile.lock
194
+ **/poetry.lock
195
+ **/uv.lock
177
196
  sparse-checkout-cone-mode: false
178
197
  - name: Runtime
179
198
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
@@ -191,12 +210,32 @@ jobs:
191
210
  mkdir -p .github/actions
192
211
  mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
193
212
  cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
194
- - name: Detect
195
- id: applicability
213
+ - name: Detect JavaScript
214
+ id: applicability-javascript
215
+ if: matrix.entry.language == 'javascript'
216
+ run: node $RUNNER_TEMP/code-foundry/src/runtime.mjs security should_run javascript >> "$GITHUB_OUTPUT"
217
+ - name: Detect Rust
218
+ id: applicability-rust
219
+ if: matrix.entry.language == 'rust'
196
220
  run: node $RUNNER_TEMP/code-foundry/src/runtime.mjs security should_run rust >> "$GITHUB_OUTPUT"
221
+ - name: Setup JavaScript
222
+ if: >-
223
+ matrix.entry.language == 'javascript' &&
224
+ steps.applicability-javascript.outputs.applicable == 'true'
225
+ uses: ./.github/actions/setup
226
+ with:
227
+ mise-scope: javascript
228
+ cache-save: ${{ github.event_name == 'push' }}
229
+ - name: Audit JavaScript dependencies
230
+ if: >-
231
+ matrix.entry.language == 'javascript' &&
232
+ steps.applicability-javascript.outputs.applicable == 'true'
233
+ run: node $RUNNER_TEMP/code-foundry/src/runtime.mjs security audit javascript
197
234
  - name: Check Rust
198
235
  id: system-rust
199
- if: steps.applicability.outputs.applicable == 'true'
236
+ if: >-
237
+ matrix.entry.language == 'rust' &&
238
+ steps.applicability-rust.outputs.applicable == 'true'
200
239
  shell: bash
201
240
  run: |
202
241
  if command -v cargo >/dev/null 2>&1 && command -v rustc >/dev/null 2>&1; then
@@ -206,109 +245,37 @@ jobs:
206
245
  else
207
246
  echo 'available=false' >> "$GITHUB_OUTPUT"
208
247
  fi
209
- - name: Setup
248
+ - name: Setup Rust
210
249
  if: >-
211
- steps.applicability.outputs.applicable == 'true' &&
250
+ matrix.entry.language == 'rust' &&
251
+ steps.applicability-rust.outputs.applicable == 'true' &&
212
252
  steps.system-rust.outputs.available != 'true'
213
253
  uses: ./.github/actions/setup
214
254
  with:
215
255
  mise-scope: rust
216
256
  cache-save: ${{ github.event_name == 'push' }}
217
257
  - name: Install cargo-audit
218
- if: steps.applicability.outputs.applicable == 'true'
258
+ if: >-
259
+ matrix.entry.language == 'rust' &&
260
+ steps.applicability-rust.outputs.applicable == 'true'
219
261
  uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2
220
262
  with:
221
263
  tool: cargo-audit
222
- - name: Audit dependencies
223
- if: steps.applicability.outputs.applicable == 'true'
264
+ - name: Audit Rust dependencies
265
+ if: >-
266
+ matrix.entry.language == 'rust' &&
267
+ steps.applicability-rust.outputs.applicable == 'true'
224
268
  run: node $RUNNER_TEMP/code-foundry/src/runtime.mjs security audit rust
225
-
226
- dependency-audit-python:
227
- name: Dependency Audit (Python) / ${{ matrix.requirement }}
228
- needs: profile
229
- if: >-
230
- ${{ vars.CI_BILLING_PAUSED != 'true' &&
231
- needs.profile.result == 'success' &&
232
- needs.profile.outputs.python == 'true' &&
233
- needs.profile.outputs.python_requirements != '["none"]' }}
234
- strategy:
235
- fail-fast: false
236
- max-parallel: 8
237
- matrix:
238
- requirement: ${{ fromJSON(needs.profile.outputs.python_requirements) }}
239
- runs-on: ${{ inputs.runner }}
240
- timeout-minutes: 20
241
- env:
242
- REPO_FOUNDRY_PYTHON_REQUIREMENT: ${{ matrix.requirement }}
243
- steps:
244
- - name: Checkout
245
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
246
- with:
247
- persist-credentials: false
248
- filter: blob:none
249
- sparse-checkout: |
250
- .github
251
- .mise.toml
252
- mise.lock
253
- **/pyproject.toml
254
- **/requirements*.txt
255
- **/setup.py
256
- **/setup.cfg
257
- **/Pipfile
258
- **/Pipfile.lock
259
- **/poetry.lock
260
- **/uv.lock
261
- sparse-checkout-cone-mode: false
262
- - name: Runtime
263
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
264
- with:
265
- persist-credentials: false
266
- repository: ${{ inputs.runtime-repository }}
267
- ref: ${{ inputs.runtime-ref }}
268
- path: .github/.code-foundry
269
- sparse-checkout: |
270
- .github/actions
271
- src/lib
272
- src/runtime.mjs
273
- - name: Install runtime
274
- run: |
275
- mkdir -p .github/actions
276
- mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
277
- cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
278
- - name: Setup
269
+ - name: Setup Python
270
+ if: matrix.entry.language == 'python'
279
271
  uses: ./.github/actions/setup
280
272
  with:
281
273
  mise-scope: python
282
274
  cache-save: ${{ github.event_name == 'push' }}
283
- - name: Audit dependencies
275
+ - name: Audit Python dependencies
276
+ if: matrix.entry.language == 'python'
284
277
  run: node $RUNNER_TEMP/code-foundry/src/runtime.mjs security audit python
285
278
 
286
- dependency-audit-python-gate:
287
- name: Dependency Audit (Python)
288
- needs: [profile, dependency-audit-python]
289
- if: >-
290
- ${{ vars.CI_BILLING_PAUSED != 'true' &&
291
- always() &&
292
- needs.profile.result == 'success' &&
293
- needs.profile.outputs.python == 'true' &&
294
- needs.profile.outputs.python_requirements != '["none"]' }}
295
- runs-on: ${{ inputs.runner }}
296
- timeout-minutes: 5
297
- steps:
298
- - name: Gate
299
- env:
300
- PROFILE_RESULT: ${{ needs.profile.result }}
301
- AUDIT_RESULT: ${{ needs.dependency-audit-python.result }}
302
- run: |
303
- if [ "$PROFILE_RESULT" != success ]; then
304
- echo "Python audit profile failed: $PROFILE_RESULT" >&2
305
- exit 1
306
- fi
307
- case "$AUDIT_RESULT" in
308
- success|skipped) exit 0 ;;
309
- *) echo "Python dependency audit failed: $AUDIT_RESULT" >&2; exit 1 ;;
310
- esac
311
-
312
279
  dependency-review:
313
280
  name: Dependency Review
314
281
  needs: profile
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.1.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.0.6...v1.1.0) (2026-09-06)
4
+
5
+
6
+ ### Features
7
+
8
+ * scope per-language checks to detected languages via matrix ([#459](https://github.com/0xPlayerOne/code-foundry/issues/459)) ([71f8985](https://github.com/0xPlayerOne/code-foundry/commit/71f8985b9732d39b7b68df40a4c8cbe5a90175fe))
9
+
3
10
  ## [1.0.6](https://github.com/0xPlayerOne/code-foundry/compare/v1.0.5...v1.0.6) (2026-09-06)
4
11
 
5
12
 
package/docs/WORKFLOWS.md CHANGED
@@ -82,8 +82,13 @@ 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)`. Required checks should match the jobs actually
86
- enabled for the repository profile.
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.
87
92
 
88
93
  ## Merge methods
89
94
 
@@ -178,9 +183,13 @@ validation gate. Land changes through the standard `direct` or
178
183
  - Solidity: preserve the repository's native Hardhat, Foundry, or specialized
179
184
  test/security workflows.
180
185
 
181
- Jobs detect applicability before installing tools. Empty language or test
182
- surfaces remain successful and visible, so branch protection does not become
183
- ambiguous for mixed-language repositories.
186
+ Jobs detect applicability before installing tools. Per-language CodeQL and
187
+ security-audit jobs are generated from detection, so empty language surfaces
188
+ produce no checks at all instead of skipped rows; the aggregate
189
+ `Validation / Gate` keeps branch protection unambiguous for mixed-language
190
+ repositories by failing closed unless every generated check succeeds. An
191
+ empty analysis matrix while analysis is enabled fails the build instead of
192
+ silently skipping every analyzer.
184
193
 
185
194
  ## Security behavior
186
195
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "1.0.6",
3
+ "version": "1.1.0",
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",