code-foundry 1.5.4 → 1.6.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.
@@ -19,7 +19,7 @@ Agents must follow these rules before changing code:
19
19
  3. Preserve user-owned changes. Never discard or overwrite unrelated work.
20
20
  4. Branch from `staging` and target pull requests at `staging`; do not work directly on `main`.
21
21
  5. Keep the change focused. Do not expand scope without documenting why.
22
- 6. Run the applicable format, lint, type-check, build, unit, integration, E2E, smoke, and security checks.
22
+ 6. Run the applicable format, lint, type-check, build, unit, performance, integration, E2E, smoke, and security checks.
23
23
  7. Report exact validation results, skipped checks, known limitations, and remaining risks.
24
24
  8. Never commit secrets, credentials, local environment files, generated artifacts, or machine-specific paths.
25
25
 
@@ -163,7 +163,7 @@ Keep pull requests focused and reviewable. Include screenshots or recordings for
163
163
  | Push to `staging` | Promotion PR workflow; canonical validation waits for the PR event |
164
164
  | Push to `main` | Release workflow; canonical validation already ran on the merged PR |
165
165
 
166
- The single validation caller keys concurrency by event and pull-request head. A newer update to the same pull request cancels its superseded validation run; scheduled and manual audits remain independent. The mode-aware orchestrator fans out only the jobs required by that event and always concludes with the stable aggregate gate.
166
+ Pull-request validation keys concurrency by event and pull-request head, so a newer update cancels its superseded run. Scheduled and manual audits use a separate caller pinned to the protected default branch; this prevents caller-selected runtime code from executing with default-branch cache access. Both callers use the mode-aware orchestrator, which fans out only the required jobs and concludes with the stable aggregate gate.
167
167
 
168
168
  Required checks are enforced by branch protection rulesets/branch protection. Do not duplicate their checklists in the pull request description; document validation commands and results instead.
169
169
 
@@ -129,6 +129,7 @@ runs:
129
129
  integration: ['test:integration'],
130
130
  e2e: ['test:e2e', 'e2e'],
131
131
  smoke: ['test:smoke', 'smoke'],
132
+ performance: ['performance:check', 'perf:check'],
132
133
  }[task] || [];
133
134
  const selected = candidates.find((name) => scripts[name]);
134
135
  const usesTurbo = Boolean(selected && /\bturbo(?:\s|$)/.test(scripts[selected]));
@@ -441,7 +442,7 @@ runs:
441
442
  - name: Install native test libraries
442
443
  if: >-
443
444
  inputs.install == 'true' &&
444
- inputs.task == 'unit' &&
445
+ (inputs.task == 'unit' || inputs.task == 'performance') &&
445
446
  hashFiles('**/package.json') != '' &&
446
447
  steps.profile.outputs.javascript == 'true'
447
448
  shell: bash
@@ -20,6 +20,7 @@ merge_strategy: rebase
20
20
  release_merge_strategy: rebase
21
21
  runner: ubuntu-latest
22
22
  unit_runner: ubuntu-slim
23
+ performance_runner: ubuntu-latest
23
24
  cache_packages: auto
24
25
  cache_build: auto
25
26
  coverage_minimum: 80
@@ -38,4 +39,6 @@ opencode_security: false
38
39
  sync_mode: overlay
39
40
  custom_workflows: preserve
40
41
  staging_validation_mode: fast
42
+ performance: auto
43
+ performance_command:
41
44
  opencode_security_model:
@@ -23,6 +23,11 @@ on:
23
23
  required: false
24
24
  type: string
25
25
  default: ubuntu-slim
26
+ performance-runner:
27
+ description: Runner used by deterministic performance regression checks.
28
+ required: false
29
+ type: string
30
+ default: ubuntu-latest
26
31
  unit-only:
27
32
  description: Run only the unit-test subset; skip integration, E2E, and smoke jobs.
28
33
  required: false
@@ -117,6 +122,71 @@ jobs:
117
122
  if-no-files-found: ignore
118
123
  retention-days: 14
119
124
 
125
+ performance:
126
+ name: Performance
127
+ if: vars.CI_BILLING_PAUSED != 'true'
128
+ runs-on: ${{ inputs.performance-runner }}
129
+ timeout-minutes: 30
130
+ steps:
131
+ - name: Checkout
132
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
133
+ with:
134
+ persist-credentials: false
135
+ fetch-depth: 2
136
+ - name: Runtime
137
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
138
+ with:
139
+ persist-credentials: false
140
+ repository: ${{ inputs.runtime-repository }}
141
+ ref: ${{ inputs.runtime-ref }}
142
+ path: .github/.code-foundry
143
+ sparse-checkout: |
144
+ .github/actions
145
+ src/lib
146
+ src/runtime.mjs
147
+ - name: Install runtime
148
+ run: |
149
+ mkdir -p .github/actions
150
+ mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
151
+ cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
152
+ - name: Detect
153
+ id: applicability
154
+ run: node $RUNNER_TEMP/code-foundry/src/runtime.mjs ci task_profile performance >> "$GITHUB_OUTPUT"
155
+ - name: Setup
156
+ if: steps.applicability.outputs.applicable == 'true'
157
+ uses: ./.github/actions/setup
158
+ with:
159
+ install: true
160
+ install-javascript: ${{ steps.applicability.outputs.javascript == 'true' }}
161
+ install-python: ${{ steps.applicability.outputs.python == 'true' }}
162
+ install-rust: ${{ steps.applicability.outputs.rust == 'true' }}
163
+ cache-build: false
164
+ cache-environment: false
165
+ cache-save: false
166
+ cache-packages: ${{ vars.REPO_FOUNDRY_CACHE_PACKAGES || 'auto' }}
167
+ task: performance
168
+ task-javascript: ${{ steps.applicability.outputs.javascript }}
169
+ task-python: ${{ steps.applicability.outputs.python }}
170
+ task-rust: ${{ steps.applicability.outputs.rust }}
171
+ - name: Performance
172
+ if: steps.applicability.outputs.applicable == 'true'
173
+ run: node $RUNNER_TEMP/code-foundry/src/runtime.mjs ci performance
174
+ - name: Upload performance results
175
+ if: >-
176
+ always() &&
177
+ steps.applicability.outputs.applicable == 'true' &&
178
+ hashFiles('artifacts/performance/**', 'performance-results.json', 'performance-results/**') != ''
179
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
180
+ with:
181
+ name: performance-${{ github.run_id }}
182
+ path: |
183
+ artifacts/performance/**
184
+ performance-results.json
185
+ performance-results/**
186
+ compression-level: 1
187
+ if-no-files-found: ignore
188
+ retention-days: 14
189
+
120
190
  integration:
121
191
  name: Integration
122
192
  if: vars.CI_BILLING_PAUSED != 'true' && inputs.unit-only != true
@@ -32,6 +32,11 @@ on:
32
32
  required: false
33
33
  type: string
34
34
  default: ubuntu-slim
35
+ performance-runner:
36
+ description: Runner used by deterministic performance regression checks.
37
+ required: false
38
+ type: string
39
+ default: ubuntu-latest
35
40
  security-runner:
36
41
  description: Runner used by Security jobs.
37
42
  required: false
@@ -94,6 +99,7 @@ jobs:
94
99
  runtime-ref: ${{ inputs.runtime-ref }}
95
100
  runner: ${{ inputs.test-runner }}
96
101
  unit-runner: ${{ inputs.unit-runner }}
102
+ performance-runner: ${{ inputs.performance-runner }}
97
103
  unit-only: ${{ inputs.mode == 'fast' }}
98
104
  secrets:
99
105
  TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
@@ -0,0 +1,43 @@
1
+ name: Code Foundry Audit
2
+
3
+ on:
4
+ schedule:
5
+ - cron: '31 6 * * 1'
6
+ workflow_dispatch:
7
+
8
+ permissions: {}
9
+
10
+ concurrency:
11
+ group: code-foundry-audit-${{ github.event_name }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ # Default-branch-capable events must not call the local reusable workflow:
16
+ # a pull request could otherwise change that workflow and feed an untrusted
17
+ # runtime ref into steps that can populate the protected branch cache. Use
18
+ # the protected default branch for both workflow code and runtime code.
19
+ validation:
20
+ name: Validation
21
+ if: vars.CI_BILLING_PAUSED != 'true'
22
+ permissions:
23
+ actions: read
24
+ contents: read
25
+ packages: read
26
+ security-events: write
27
+ uses: 0xPlayerOne/code-foundry/.github/workflows/validation.yml@main
28
+ with:
29
+ mode: audit
30
+ runtime-repository: 0xPlayerOne/code-foundry
31
+ runtime-ref: main
32
+ ci-runner: ubuntu-latest
33
+ test-runner: ubuntu-latest
34
+ unit-runner: ubuntu-slim
35
+ performance-runner: ubuntu-latest
36
+ security-runner: ubuntu-slim
37
+ codeql-runner: ubuntu-latest
38
+ rust-shards: '["all"]'
39
+ rust-threads: '1'
40
+ rust-max-parallel: 1
41
+ secrets:
42
+ TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
43
+ NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
@@ -8,16 +8,12 @@ on:
8
8
  - synchronize
9
9
  - reopened
10
10
  - ready_for_review
11
- schedule:
12
- - cron: '31 6 * * 1'
13
- workflow_dispatch:
14
11
 
15
12
  # Default every caller job to no repository permissions. Individual jobs grant
16
13
  # only the scopes their own validation path consumes.
17
14
  permissions: {}
18
15
 
19
- # Superseded PR updates cancel the previous run; schedule and dispatch runs
20
- # are keyed by event so periodic audits and manual runs stay independent.
16
+ # Superseded PR updates cancel the previous run.
21
17
  concurrency:
22
18
  group: code-foundry-validation-${{ github.event_name }}-${{ github.event.pull_request.head.repo.full_name || github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}
23
19
  cancel-in-progress: true
@@ -77,12 +73,13 @@ jobs:
77
73
  mode: ${{ needs.mode.outputs.mode }}
78
74
  runtime-repository: 0xPlayerOne/code-foundry
79
75
  # Pull requests validate the proposed runtime commit. Scheduled and
80
- # manually dispatched audits stay on the protected default branch so a
81
- # selected branch cannot supply privileged runtime code.
82
- runtime-ref: ${{ github.event_name == 'pull_request' && github.sha || 'main' }}
76
+ # manually dispatched audits are isolated in validation_audit_self-ci.yml
77
+ # so this caller-selected ref never runs with default-branch cache access.
78
+ runtime-ref: ${{ github.sha }}
83
79
  ci-runner: ubuntu-latest
84
80
  test-runner: ubuntu-latest
85
81
  unit-runner: ubuntu-slim
82
+ performance-runner: ubuntu-latest
86
83
  security-runner: ubuntu-slim
87
84
  codeql-runner: ubuntu-latest
88
85
  rust-shards: '["all"]'
package/AGENTS.md CHANGED
@@ -120,6 +120,7 @@ node src/runtime.mjs ci unit
120
120
  node src/runtime.mjs ci integration
121
121
  node src/runtime.mjs ci e2e
122
122
  node src/runtime.mjs ci smoke
123
+ node src/runtime.mjs ci performance
123
124
  Security and dependency audits run through the GitHub Security workflow.
124
125
  ```
125
126
 
@@ -138,7 +139,7 @@ If a check cannot run, state the exact reason. A skipped check is not a passing
138
139
  ## Tests and coverage
139
140
 
140
141
  - Add or update tests for behavior changes and regressions.
141
- - Keep unit, integration, E2E, and smoke coverage in the suite where each applies.
142
+ - Keep unit, performance, integration, E2E, and smoke coverage in the suite where each applies.
142
143
  - Preserve project-specific coverage thresholds; do not lower them to make CI green.
143
144
  - Keep test data deterministic and remove secrets from logs and fixtures.
144
145
  - Use the narrowest test command while iterating, then run the affected package or workspace suite.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.6.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.6.0...v1.6.1) (2026-09-08)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **ci:** isolate default-branch security audits ([5ea0914](https://github.com/0xPlayerOne/code-foundry/commit/5ea09146af9995f16d1ab4e9a73f14a13582da36))
9
+
10
+ ## [1.6.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.5.4...v1.6.0) (2026-09-08)
11
+
12
+
13
+ ### Features
14
+
15
+ * **ci:** add shared performance validation ([#492](https://github.com/0xPlayerOne/code-foundry/issues/492)) ([ef12990](https://github.com/0xPlayerOne/code-foundry/commit/ef1299045b6d67e447def93e2096862cde64bbc7))
16
+
3
17
  ## [1.5.4](https://github.com/0xPlayerOne/code-foundry/compare/v1.5.3...v1.5.4) (2026-09-08)
4
18
 
5
19
 
@@ -36,6 +36,8 @@ repository manifests and source
36
36
  | `package_manager` | `bun`, `pnpm`, `yarn`, `npm`, `none` | JavaScript setup |
37
37
  | `toolchain` | `auto`, `native`, `mise` | Environment setup policy; defaults to `auto` |
38
38
  | `staging_validation_mode` | `fast`, `audit` | Validation tier for pull requests targeting `staging`; defaults to `fast` |
39
+ | `performance` | `auto`, `true`, `false` | Run a deterministic performance task when a supported entrypoint exists; defaults to `auto` |
40
+ | `performance_command` | JSON string array | Command argv for non-package performance harnesses; package scripts take precedence |
39
41
  | `features` | `all` or a list | Standard workflow callers |
40
42
  | `codeql` | `auto`, `true`, `false` | CodeQL policy; public repositories default to enabled, non-public repositories default to disabled |
41
43
  | `codeql_rust_shards` | JSON array of paths | Rust scan scopes; `["all"]` keeps the safe single full scan |
@@ -51,11 +53,30 @@ repository manifests and source
51
53
  | `git_workflow` | `direct` (default), `staging-release` | Branch/release model; `direct` opens feature branches into `main`, `staging-release` promotes `staging` into `main` |
52
54
  | `merge_strategy` | `rebase` | Promotion merge method for `staging` → `main`; only enforced by the `staging-release` topology |
53
55
  | `release_merge_strategy` | `rebase`, `squash` (direct topology only) | Merge method for Release Please version PRs into `main`; release automation fails closed on anything else |
54
- | `runner` fields | GitHub runner names | Per-workflow runner policy |
56
+ | `runner` fields | GitHub runner names | Per-workflow runner policy, including `performance_runner` |
55
57
 
56
58
  Supported features are `ci`, `codeql`, `security`, `test`, `draft-pr`,
57
59
  `release-pr`, `release`, and `dependabot`.
58
60
 
61
+ ## Performance validation
62
+
63
+ The shared Test workflow exposes a deterministic `Performance` job. In JavaScript
64
+ repositories it discovers `performance:check` first and `perf:check` second. Other
65
+ repositories can declare an argv array without shell interpolation:
66
+
67
+ ```yaml
68
+ performance: true
69
+ performance_command: '["python3","scripts/performance_audit.py","--check"]'
70
+ performance_runner: ubuntu-latest
71
+ ```
72
+
73
+ `performance: false` disables discovery. Performance budgets, fixtures, mock
74
+ providers, and live endpoint credentials remain repository-owned. The shared job
75
+ owns checkout, pinned setup, billing controls, concurrency, and artifact upload;
76
+ it uploads `artifacts/performance/**`, `performance-results.json`, or
77
+ `performance-results/**` when present. Network-dependent and post-deployment
78
+ checks should remain separate from this deterministic validation task.
79
+
59
80
  ## OpenCode Security opt-in and opt-out
60
81
 
61
82
  `opencode_security` controls the optional OpenCode scan, and the generated
package/docs/WORKFLOWS.md CHANGED
@@ -79,7 +79,7 @@ repositories can opt in or out without a code change.
79
79
  | Workflow | Responsibility |
80
80
  | ---------- | ------------------------------------------------------------- |
81
81
  | CI | Format, lint, type-check, and build |
82
- | Test | Unit, integration, E2E, and smoke tests |
82
+ | Test | Unit, performance, integration, E2E, and smoke tests |
83
83
  | Security | Profile, audits, and public-only Dependency Review |
84
84
  | CodeQL | GitHub-native code scanning, kept separate from CI |
85
85
  | Draft PR | Create/update development pull requests |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "1.5.4",
3
+ "version": "1.6.1",
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": {
@@ -549,6 +549,7 @@ function renderWorkflow(content, config, repository, ref, rustCodeql) {
549
549
  'security-runner': config.security_runner ?? config.runner,
550
550
  'codeql-runner': config.codeql_runner ?? config.runner,
551
551
  'unit-runner': config.unit_runner,
552
+ 'performance-runner': config.performance_runner ?? config.test_runner ?? config.runner,
552
553
  }
553
554
  for (const [input, value] of Object.entries(runnerInputs)) {
554
555
  if (!value) continue
@@ -1088,6 +1089,8 @@ function createDefaultConfig(root, source) {
1088
1089
  ...runners,
1089
1090
  toolchain: 'auto',
1090
1091
  staging_validation_mode: 'fast',
1092
+ performance: 'auto',
1093
+ performance_command: '',
1091
1094
  prune_standard: 'false',
1092
1095
  cache_packages: 'auto',
1093
1096
  cache_build: 'auto',
@@ -129,6 +129,7 @@ export function recommendRunners(root) {
129
129
  ci_runner: heavy ? 'ubuntu-latest' : 'ubuntu-slim',
130
130
  test_runner: heavy ? 'ubuntu-latest' : 'ubuntu-slim',
131
131
  unit_runner: heavy ? 'ubuntu-latest' : 'ubuntu-slim',
132
+ performance_runner: 'ubuntu-latest',
132
133
  security_runner: 'ubuntu-slim',
133
134
  codeql_runner: 'ubuntu-latest',
134
135
  pr_runner: 'ubuntu-slim',
package/src/runtime.mjs CHANGED
@@ -52,6 +52,29 @@ function readPackage() {
52
52
  }
53
53
  }
54
54
 
55
+ function performanceEnabled() {
56
+ return configured(config.performance, 'auto') !== 'false'
57
+ }
58
+
59
+ function performanceCommand() {
60
+ const raw = configured(config.performance_command, '').trim()
61
+ if (!raw) return null
62
+ let command
63
+ try {
64
+ command = JSON.parse(raw)
65
+ } catch {
66
+ throw new Error('performance_command must be a JSON array of command arguments.')
67
+ }
68
+ if (
69
+ !Array.isArray(command) ||
70
+ command.length === 0 ||
71
+ command.some((argument) => typeof argument !== 'string' || argument.length === 0)
72
+ ) {
73
+ throw new Error('performance_command must be a non-empty JSON array of non-empty strings.')
74
+ }
75
+ return command
76
+ }
77
+
55
78
  /** @param {string} task */
56
79
  function validation(task) {
57
80
  if (task === 'mode') {
@@ -271,7 +294,14 @@ function relevant(task) {
271
294
  integration: ['test:integration'],
272
295
  e2e: ['test:e2e', 'e2e'],
273
296
  smoke: ['test:smoke', 'smoke'],
297
+ performance: ['performance:check', 'perf:check'],
274
298
  }[task]
299
+ if (task === 'performance') {
300
+ if (!performanceEnabled()) return false
301
+ return Boolean(
302
+ (scripted && scripted.some((candidate) => hasScript(candidate))) || performanceCommand()
303
+ )
304
+ }
275
305
  if (scripted && scripted.some((candidate) => hasScript(candidate)))
276
306
  return packageManager !== 'none'
277
307
  if (task === 'format' || task === 'lint' || task === 'type_check' || task === 'build') {
@@ -434,6 +464,13 @@ function ci(task) {
434
464
  run('cargo', ['build', '--all-targets'])
435
465
  return
436
466
  }
467
+ if (task === 'performance') {
468
+ if (!performanceEnabled()) return
469
+ if (runScript(['performance:check', 'perf:check'])) return
470
+ const command = performanceCommand()
471
+ if (command) run(command[0], command.slice(1))
472
+ return
473
+ }
437
474
  /** @type {Record<string, string[]>} */
438
475
  const scriptsByTask = {
439
476
  unit: ['test:unit', 'test:coverage', 'test'],