code-foundry 1.1.1 → 1.2.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.
- package/.github/code-foundry.yml +1 -1
- package/.github/workflows/codeql.yml +23 -58
- package/.github/workflows/opencode-security_self-ci.yml +20 -22
- package/.github/workflows/validation.yml +19 -34
- package/CHANGELOG.md +7 -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,7 +146,6 @@ 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\"]");
|
|
@@ -159,15 +160,21 @@ jobs:
|
|
|
159
160
|
changed: entry.changed === true,
|
|
160
161
|
}));
|
|
161
162
|
const rust = languages.find((entry) => entry.language === "rust");
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
for (const shard of rust ? shards : []) {
|
|
164
|
+
matrix.push({
|
|
165
|
+
display: String(shard) === "all" ? "Rust" : "Rust (" + shard + ")",
|
|
166
|
+
language: "rust",
|
|
167
|
+
category: "/language/rust",
|
|
168
|
+
build_mode: "none",
|
|
169
|
+
changed: rust.changed === true,
|
|
170
|
+
shard: String(shard),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (!matrix.length) {
|
|
166
174
|
console.error("CodeQL analysis matrix is empty while analysis is enabled.");
|
|
167
175
|
process.exit(1);
|
|
168
176
|
}
|
|
169
177
|
append("matrix", JSON.stringify(matrix));
|
|
170
|
-
append("rust_matrix", JSON.stringify(rustMatrix));
|
|
171
178
|
}
|
|
172
179
|
'
|
|
173
180
|
|
|
@@ -206,56 +213,14 @@ jobs:
|
|
|
206
213
|
mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
|
|
207
214
|
cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
|
|
208
215
|
- name: Analyze
|
|
209
|
-
if: ${{ matrix.entry.changed == true }}
|
|
216
|
+
if: ${{ matrix.entry.changed == true && matrix.entry.language != 'rust' }}
|
|
210
217
|
uses: ./.github/actions/codeql
|
|
211
218
|
with:
|
|
212
219
|
language: ${{ matrix.entry.language }}
|
|
213
220
|
build-mode: ${{ matrix.entry.build_mode }}
|
|
214
221
|
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
222
|
- name: Configure Rust scope
|
|
258
|
-
if: ${{ matrix.entry.changed == true }}
|
|
223
|
+
if: ${{ matrix.entry.changed == true && matrix.entry.language == 'rust' }}
|
|
259
224
|
id: scope
|
|
260
225
|
env:
|
|
261
226
|
RUST_SCOPE: ${{ matrix.entry.shard }}
|
|
@@ -303,15 +268,15 @@ jobs:
|
|
|
303
268
|
echo "config_file=$config_file" >> "$GITHUB_OUTPUT"
|
|
304
269
|
echo "scope_id=$scope_id" >> "$GITHUB_OUTPUT"
|
|
305
270
|
- name: Initialize
|
|
306
|
-
if: ${{ matrix.entry.changed == true }}
|
|
271
|
+
if: ${{ matrix.entry.changed == true && matrix.entry.language == 'rust' }}
|
|
307
272
|
uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
|
|
308
273
|
with:
|
|
309
274
|
languages: rust
|
|
310
275
|
build-mode: ${{ needs.detect.outputs.rust_build_mode }}
|
|
311
276
|
config-file: ${{ steps.scope.outputs.config_file }}
|
|
312
277
|
threads: ${{ inputs.rust-threads }}
|
|
313
|
-
- name: Analyze
|
|
314
|
-
if: ${{ matrix.entry.changed == true }}
|
|
278
|
+
- name: Analyze Rust
|
|
279
|
+
if: ${{ matrix.entry.changed == true && matrix.entry.language == 'rust' }}
|
|
315
280
|
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
|
|
316
281
|
with:
|
|
317
282
|
category: /language:rust/${{ steps.scope.outputs.scope_id }}
|
|
@@ -319,4 +284,4 @@ jobs:
|
|
|
319
284
|
wait-for-processing: false
|
|
320
285
|
- name: Not applicable
|
|
321
286
|
if: ${{ matrix.entry.changed != true }}
|
|
322
|
-
run: echo "CodeQL
|
|
287
|
+
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,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.2.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.1.1...v1.2.0) (2026-09-06)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* 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))
|
|
9
|
+
|
|
3
10
|
## [1.1.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.1.0...v1.1.1) (2026-09-06)
|
|
4
11
|
|
|
5
12
|
|
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