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.
- package/.github/code-foundry.yml +1 -1
- package/.github/workflows/codeql.yml +29 -59
- package/.github/workflows/opencode-security_self-ci.yml +20 -22
- package/.github/workflows/validation.yml +19 -34
- package/CHANGELOG.md +14 -0
- package/docs/WORKFLOWS.md +9 -7
- package/package.json +1 -1
- package/src/lib/validation-policy.mjs +8 -3
- package/src/runtime.mjs +0 -1
package/.github/code-foundry.yml
CHANGED
|
@@ -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:
|
|
43
|
-
#
|
|
44
|
-
#
|
|
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
|
|
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
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
|
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
|
-
|
|
13
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
|
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
|
|
86
|
-
audits run through a detection-built matrix, so a
|
|
87
|
-
checks for languages it actually uses
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
@@ -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
|
-
|
|
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:
|
|
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