code-foundry 1.53.8 → 1.53.9

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,8 +39,10 @@ on:
39
39
  description: >-
40
40
  JSON object of the Detect job's outputs, computed by the caller's
41
41
  planning job (`validation plan`). When set, Detect is skipped and
42
- analysis reads the plan instead, saving one runner hop. Empty runs
43
- Detect here as before.
42
+ analysis reads the plan instead, saving one runner hop. Without a
43
+ code-scanning merge gate the planned matrix omits unchanged
44
+ languages and Rust shards. Empty runs Detect here as before, with
45
+ the full matrix.
44
46
  required: false
45
47
  type: string
46
48
  default: ''
@@ -160,17 +162,29 @@ jobs:
160
162
  set -euo pipefail
161
163
  # The code-scanning merge gate waits for results in every tracked
162
164
  # category, so change detection must never skip an upload while it
163
- # is active. Any ruleset API failure also disables change
164
- # detection: full analysis is the safe default.
165
+ # is active. Any ruleset API failure counts as an active gate: full
166
+ # analysis is the safe default, and the planner drops unchanged
167
+ # analyzers only on a positive "no gate" answer.
165
168
  gated=false
166
- for id in $(gh api "repos/$GITHUB_REPOSITORY/rulesets" --paginate \
167
- -q '.[] | select(.enforcement == "active") | .id' 2>/dev/null); do
168
- if gh api "repos/$GITHUB_REPOSITORY/rulesets/$id" \
169
- -q 'any(.rules[]?; .type == "code_scanning")' 2>/dev/null | grep -q true; then
170
- gated=true
171
- break
172
- fi
173
- done
169
+ if ! ids="$(gh api "repos/$GITHUB_REPOSITORY/rulesets" --paginate \
170
+ -q '.[] | select(.enforcement == "active") | .id')"; then
171
+ echo "Ruleset listing failed; treating the code-scanning merge gate as active."
172
+ gated=true
173
+ else
174
+ for id in $ids; do
175
+ if ! rule="$(gh api "repos/$GITHUB_REPOSITORY/rulesets/$id" \
176
+ -q 'any(.rules[]?; .type == "code_scanning")')"; then
177
+ echo "Ruleset $id lookup failed; treating the code-scanning merge gate as active."
178
+ gated=true
179
+ break
180
+ fi
181
+ if [ "$rule" = "true" ]; then
182
+ gated=true
183
+ break
184
+ fi
185
+ done
186
+ fi
187
+ echo "Code-scanning merge gate active: $gated"
174
188
  echo "gated=$gated" >> "$GITHUB_OUTPUT"
175
189
  - id: languages
176
190
  name: Detect languages
@@ -135,8 +135,9 @@ on:
135
135
  description: >-
136
136
  JSON CodeQL Detect outputs from the caller's planning job. When set,
137
137
  the CodeQL workflow skips its Detect job and reads the plan, and a
138
- plan marked idle (CodeQL unavailable) skips the workflow. Empty
139
- detects inside the workflow as before.
138
+ plan marked idle (CodeQL unavailable, or no analyzed language or
139
+ Rust shard changed) skips the workflow. Empty detects inside the
140
+ workflow as before.
140
141
  required: false
141
142
  type: string
142
143
  default: ''
@@ -113,8 +113,9 @@ on:
113
113
  description: >-
114
114
  JSON CodeQL Detect outputs from the caller's planning job. When set,
115
115
  the CodeQL workflow skips its Detect job and reads the plan, and a
116
- plan marked idle (CodeQL unavailable) skips the workflow. Empty
117
- detects inside the workflow as before.
116
+ plan marked idle (CodeQL unavailable, or no analyzed language or
117
+ Rust shard changed) skips the workflow. Empty detects inside the
118
+ workflow as before.
118
119
  required: false
119
120
  type: string
120
121
  default: ''
@@ -127,17 +127,29 @@ jobs:
127
127
  set -euo pipefail
128
128
  # The code-scanning merge gate waits for results in every tracked
129
129
  # category, so change detection must never skip an upload while it
130
- # is active. Any ruleset API failure also disables change
131
- # detection: full analysis is the safe default.
130
+ # is active. Any ruleset API failure counts as an active gate: full
131
+ # analysis is the safe default, and the planner drops unchanged
132
+ # analyzers only on a positive "no gate" answer.
132
133
  gated=false
133
- for id in $(gh api "repos/$GITHUB_REPOSITORY/rulesets" --paginate \
134
- -q '.[] | select(.enforcement == "active") | .id' 2>/dev/null); do
135
- if gh api "repos/$GITHUB_REPOSITORY/rulesets/$id" \
136
- -q 'any(.rules[]?; .type == "code_scanning")' 2>/dev/null | grep -q true; then
137
- gated=true
138
- break
139
- fi
140
- done
134
+ if ! ids="$(gh api "repos/$GITHUB_REPOSITORY/rulesets" --paginate \
135
+ -q '.[] | select(.enforcement == "active") | .id')"; then
136
+ echo "Ruleset listing failed; treating the code-scanning merge gate as active."
137
+ gated=true
138
+ else
139
+ for id in $ids; do
140
+ if ! rule="$(gh api "repos/$GITHUB_REPOSITORY/rulesets/$id" \
141
+ -q 'any(.rules[]?; .type == "code_scanning")')"; then
142
+ echo "Ruleset $id lookup failed; treating the code-scanning merge gate as active."
143
+ gated=true
144
+ break
145
+ fi
146
+ if [ "$rule" = "true" ]; then
147
+ gated=true
148
+ break
149
+ fi
150
+ done
151
+ fi
152
+ echo "Code-scanning merge gate active: $gated"
141
153
  echo "gated=$gated" >> "$GITHUB_OUTPUT"
142
154
  - name: Plan security and CodeQL
143
155
  id: plan
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.53.9](https://github.com/0xPlayerOne/code-foundry/compare/v1.53.8...v1.53.9) (2026-10-31)
4
+
5
+
6
+ ### Performance
7
+
8
+ * **codeql:** drop unchanged analyzers from the planned matrix ([#831](https://github.com/0xPlayerOne/code-foundry/issues/831)) ([35b891e](https://github.com/0xPlayerOne/code-foundry/commit/35b891e721ea2e5d2bd09ec44509b541120a3a64))
9
+
3
10
  ## [1.53.8](https://github.com/0xPlayerOne/code-foundry/compare/v1.53.7...v1.53.8) (2026-10-31)
4
11
 
5
12
 
@@ -143,16 +150,9 @@
143
150
 
144
151
  * **validation:** require release checks until evidence exists ([#789](https://github.com/0xPlayerOne/code-foundry/issues/789)) ([a5f8be6](https://github.com/0xPlayerOne/code-foundry/commit/a5f8be64b7b28d2248aa71b80e321aa0fe82f30a))
145
152
 
146
- ## [1.49.2](https://github.com/0xPlayerOne/code-foundry/compare/v1.49.1...v1.49.2) (2026-10-29)
147
-
148
-
149
- ### Bug Fixes
150
-
151
- * safely categorize npm publication failures ([#787](https://github.com/0xPlayerOne/code-foundry/issues/787)) ([a4268af](https://github.com/0xPlayerOne/code-foundry/commit/a4268af5ce7cd0a32407420424419c0cad01dce8))
152
-
153
153
  <!-- code-foundry: packaged changelog -->
154
154
 
155
155
  ---
156
156
 
157
- This packaged changelog lists the 20 most recent releases; 279 older releases are omitted to keep the package small.
157
+ This packaged changelog lists the 20 most recent releases; 280 older releases are omitted to keep the package small.
158
158
  See the [full changelog](https://github.com/0xPlayerOne/code-foundry/blob/main/CHANGELOG.md) for the complete history.
@@ -427,8 +427,14 @@ every tracked category. Two practical consequences:
427
427
 
428
428
  On pull requests without a code-scanning merge gate, analyzers run only for
429
429
  languages with changed files, and Rust shards run only when their scope (or a
430
- workspace-wide `Cargo` manifest or toolchain file) changed; unchanged matrix
431
- entries report `Not applicable` instead of analyzing. Repositories whose
430
+ workspace-wide `Cargo` manifest or toolchain file) changed. The caller's
431
+ `Plan` job drops unchanged languages and shards from the analysis matrix, so
432
+ they take no runner and register no `Analyze` check; when nothing changed, the
433
+ whole CodeQL workflow is a planned idle skip that the gate counts as success.
434
+ Entries are dropped only when the planner positively found no merge gate; a
435
+ failed ruleset lookup counts as an active gate, and any other planning failure
436
+ leaves the workflow to detect for itself, where unchanged entries still report
437
+ `Not applicable` on their own runner. Repositories whose
432
438
  rulesets enforce a code-scanning requirement are detected automatically and
433
439
  analyze everything, because that merge gate waits for results in every tracked
434
440
  category. Push, schedule, and merge-queue events always analyze the complete
package/docs/WORKFLOWS.md CHANGED
@@ -326,9 +326,13 @@ Security Profile and CodeQL language detection (Code Security status, changed
326
326
  files, code-scanning merge gate) and passes their outputs to the orchestrator
327
327
  as `security-plan` and `codeql-plan`. The Security workflow then skips its
328
328
  `Profile` job and the CodeQL workflow skips its `Detect` job, so audits and
329
- analyzers start one runner hop earlier. A plan marked idle (no audit or review
330
- to run, or CodeQL unavailable) skips that workflow, and the gate counts only
331
- that planned skip as success. Planning fails open: if any planning step fails,
329
+ analyzers start one runner hop earlier. Without a code-scanning merge gate,
330
+ the CodeQL plan also drops the languages and Rust shards that change detection
331
+ marked unchanged, so they no longer take a runner only to print `Not
332
+ applicable`; `Analyze` checks are not required checks, so no required check
333
+ name changes. A plan marked idle (no audit or review to run, CodeQL
334
+ unavailable, or no analyzed language or shard changed) skips that workflow,
335
+ and the gate counts only that planned skip as success. Planning fails open: if any planning step fails,
332
336
  the plans stay empty and each workflow profiles and detects for itself, as it
333
337
  does for callers that pass no plans (the scheduled audit and default-branch
334
338
  CodeQL lanes).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "1.53.8",
3
+ "version": "1.53.9",
4
4
  "description": "A fast, language-aware repository factory for agent-ready workflows, testing, security, and release automation.",
5
5
  "homepage": "https://github.com/0xPlayerOne/code-foundry#readme",
6
6
  "bugs": {
@@ -411,15 +411,18 @@ function validation(task) {
411
411
  }
412
412
  const detection = codeqlDetection()
413
413
  const enabled = detection.enabled === 'true'
414
+ const matrix = enabled
415
+ ? plannedCodeqlMatrix(
416
+ codeqlAnalysisMatrix(JSON.parse(detection.languages), configuredRustShards())
417
+ )
418
+ : []
414
419
  const codeqlPlan = {
415
420
  ...detection,
416
- matrix: enabled
417
- ? JSON.stringify(
418
- codeqlAnalysisMatrix(JSON.parse(detection.languages), configuredRustShards())
419
- )
420
- : '[]',
421
+ matrix: JSON.stringify(matrix),
421
422
  code_security: process.env.REPO_FOUNDRY_CODE_SECURITY ?? '',
422
- idle: enabled ? 'false' : 'true',
423
+ // Idle when CodeQL is unavailable, or when change detection left no
424
+ // entry to analyze: the gate counts that planned skip as success.
425
+ idle: matrix.length ? 'false' : 'true',
423
426
  }
424
427
  // Dependency Review rides on the first audit job of a planned run. With
425
428
  // no audit to ride on, leave Security unplanned so its Profile job runs
@@ -1260,6 +1263,24 @@ function codeqlAnalysisMatrix(detected, shards) {
1260
1263
  return matrix
1261
1264
  }
1262
1265
 
1266
+ /**
1267
+ * The planned CodeQL analysis matrix: the full matrix minus entries (whole
1268
+ * languages or single Rust shards) that change detection marked unchanged.
1269
+ * Such an entry would only take a runner to print "Not applicable": it
1270
+ * uploads nothing either way. Entries are dropped only when the planner
1271
+ * positively found no code-scanning merge gate (`FOUNDRY_CODEQL_MERGE_GATE`
1272
+ * is exactly `false`); an active gate waits on every tracked category, and
1273
+ * an unknown gate state keeps the full matrix. Analyze check names are not
1274
+ * required checks ("Validation / Gate" is), so dropping entries never changes
1275
+ * a required check. An empty result means nothing changed and the caller
1276
+ * marks the plan idle.
1277
+ * @param {Array<Record<string, string | boolean>>} matrix
1278
+ */
1279
+ function plannedCodeqlMatrix(matrix) {
1280
+ if ((process.env.FOUNDRY_CODEQL_MERGE_GATE ?? '') !== 'false') return matrix
1281
+ return matrix.filter((entry) => entry.changed === true)
1282
+ }
1283
+
1263
1284
  /**
1264
1285
  * Changed file paths for the current pull request, read from the list the
1265
1286
  * caller materializes with the pull request files API. Returns null when