code-foundry 1.9.1 → 1.9.3
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/CONTRIBUTING.md +2 -0
- package/.github/SECURITY.md +2 -0
- package/.github/workflows/draft-pr.yml +5 -6
- package/.github/workflows/opencode-security_self-ci.yml +8 -1
- package/.github/workflows/release-pr.yml +5 -7
- package/.github/workflows/security.yml +6 -13
- package/.github/workflows/validation-no-codeql.yml +165 -0
- package/.github/workflows/validation_self-ci.yml +6 -2
- package/AGENTS.md +2 -0
- package/CHANGELOG.md +14 -0
- package/README.md +11 -3
- package/docs/WORKFLOWS.md +19 -10
- package/package.json +1 -1
- package/src/commands/sync.mjs +59 -3
package/.github/CONTRIBUTING.md
CHANGED
package/.github/SECURITY.md
CHANGED
|
@@ -80,9 +80,8 @@ jobs:
|
|
|
80
80
|
cat > "$BODY_FILE" <<EOF
|
|
81
81
|
CI PR created automatically by this workflow.
|
|
82
82
|
|
|
83
|
-
This PR is
|
|
84
|
-
|
|
85
|
-
as a draft for manual readiness.
|
|
83
|
+
This PR is intentionally opened as a draft. Mark it ready for review
|
|
84
|
+
when the proposed change is ready to start required validation.
|
|
86
85
|
|
|
87
86
|
**CI Status:** Pending — this workflow triggered on push to $BRANCH.
|
|
88
87
|
EOF
|
|
@@ -94,6 +93,7 @@ jobs:
|
|
|
94
93
|
--field head="$BRANCH"
|
|
95
94
|
--field title="$PR_TITLE"
|
|
96
95
|
--field body="@$BODY_FILE"
|
|
96
|
+
--field draft=true
|
|
97
97
|
)
|
|
98
98
|
|
|
99
99
|
CREATED=false
|
|
@@ -102,9 +102,7 @@ jobs:
|
|
|
102
102
|
fi
|
|
103
103
|
|
|
104
104
|
if [ "$CREATED" != true ]; then
|
|
105
|
-
|
|
106
|
-
if GH_TOKEN="$GITHUB_TOKEN" gh api "${DRAFT_ARGS[@]}" > /dev/null 2> "$ERROR_FILE"; then
|
|
107
|
-
echo "::notice title=Manual PR readiness required::The configured automation token was absent or rejected; this PR was opened as a draft with the short-lived workflow token."
|
|
105
|
+
if GH_TOKEN="$GITHUB_TOKEN" gh api "${CREATE_ARGS[@]}" > /dev/null 2> "$ERROR_FILE"; then
|
|
108
106
|
CREATED=true
|
|
109
107
|
fi
|
|
110
108
|
fi
|
|
@@ -113,3 +111,4 @@ jobs:
|
|
|
113
111
|
echo "::error title=Draft PR creation failed::Both the configured automation token and the workflow token failed to create the pull request."
|
|
114
112
|
exit 1
|
|
115
113
|
fi
|
|
114
|
+
echo "::notice title=Manual PR readiness required::The automated pull request was opened as a draft. Mark it ready for review to start validation."
|
|
@@ -3,6 +3,12 @@ name: Code Foundry
|
|
|
3
3
|
on:
|
|
4
4
|
pull_request:
|
|
5
5
|
branches: [main, staging]
|
|
6
|
+
types:
|
|
7
|
+
- opened
|
|
8
|
+
- synchronize
|
|
9
|
+
- reopened
|
|
10
|
+
- ready_for_review
|
|
11
|
+
- converted_to_draft
|
|
6
12
|
workflow_dispatch:
|
|
7
13
|
|
|
8
14
|
permissions:
|
|
@@ -14,7 +20,8 @@ jobs:
|
|
|
14
20
|
if: >-
|
|
15
21
|
vars.CI_BILLING_PAUSED != 'true' &&
|
|
16
22
|
(github.event_name == 'workflow_dispatch' ||
|
|
17
|
-
|
|
23
|
+
(github.event.pull_request.draft == false &&
|
|
24
|
+
startsWith(github.event.pull_request.head.ref, 'release-please--branches--main')))
|
|
18
25
|
runs-on: ubuntu-slim
|
|
19
26
|
outputs:
|
|
20
27
|
enabled: ${{ steps.detect.outputs.enabled }}
|
|
@@ -249,9 +249,9 @@ jobs:
|
|
|
249
249
|
# Creation uses authenticated REST (gh api POST) rather than
|
|
250
250
|
# `gh pr create`, which issues a GraphQL mutation that
|
|
251
251
|
# NiftyLeague's long-lived fine-grained token policy rejects. The
|
|
252
|
-
# REST payload keeps the exact base/head/title/body fields,
|
|
253
|
-
#
|
|
254
|
-
#
|
|
252
|
+
# REST payload keeps the exact base/head/title/body fields, always
|
|
253
|
+
# opens the automated promotion as a draft, and stays fail-closed
|
|
254
|
+
# through the create-race fallback below.
|
|
255
255
|
CREATE_ARGS=(
|
|
256
256
|
"repos/${GITHUB_REPOSITORY}/pulls"
|
|
257
257
|
--method POST
|
|
@@ -259,11 +259,9 @@ jobs:
|
|
|
259
259
|
--field head="$PROMOTION_BRANCH"
|
|
260
260
|
--field title="chore(main): promote staging to main ($DATE)"
|
|
261
261
|
--field body=@"$BODY_FILE"
|
|
262
|
+
--field draft=true
|
|
262
263
|
)
|
|
263
|
-
|
|
264
|
-
CREATE_ARGS+=(--field draft=true)
|
|
265
|
-
echo "::notice title=Manual PR readiness required::Created draft promotion PR because no automation token is configured. Configure CODE_FOUNDRY_TOKEN, or mark this PR ready manually to trigger validation."
|
|
266
|
-
fi
|
|
264
|
+
echo "::notice title=Manual PR readiness required::Created a draft promotion PR. Mark it ready for review to start validation."
|
|
267
265
|
|
|
268
266
|
# Prefer the configured automation token for the write, but
|
|
269
267
|
# NiftyLeague rejects long-lived fine-grained tokens with HTTP 403
|
|
@@ -123,6 +123,12 @@ jobs:
|
|
|
123
123
|
}
|
|
124
124
|
fs.appendFileSync(env.GITHUB_OUTPUT, "audit_matrix=" + JSON.stringify(entries) + "\n");
|
|
125
125
|
'
|
|
126
|
+
- name: Dependency Review
|
|
127
|
+
if: ${{ github.event_name == 'pull_request' && steps.profile.outputs.dependency_review == 'true' }}
|
|
128
|
+
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5
|
|
129
|
+
with:
|
|
130
|
+
fail-on-severity: high
|
|
131
|
+
license-check: true
|
|
126
132
|
|
|
127
133
|
# Audits run only for detected languages: the audit matrix is built from the
|
|
128
134
|
# profile, so repositories never see skipped checks for ecosystems they do
|
|
@@ -370,16 +376,3 @@ jobs:
|
|
|
370
376
|
- name: Audit Python dependencies
|
|
371
377
|
if: matrix.entry.language == 'python'
|
|
372
378
|
run: node $RUNNER_TEMP/code-foundry/src/runtime.mjs security audit python
|
|
373
|
-
|
|
374
|
-
dependency-review:
|
|
375
|
-
name: Dependency Review
|
|
376
|
-
needs: profile
|
|
377
|
-
if: ${{ vars.CI_BILLING_PAUSED != 'true' && github.event_name == 'pull_request' && needs.profile.outputs.dependency_review == 'true' }}
|
|
378
|
-
runs-on: ${{ inputs.runner }}
|
|
379
|
-
timeout-minutes: 10
|
|
380
|
-
steps:
|
|
381
|
-
- name: Review
|
|
382
|
-
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5
|
|
383
|
-
with:
|
|
384
|
-
fail-on-severity: high
|
|
385
|
-
license-check: true
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
name: Code Foundry Validation (CodeQL unavailable)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
inputs:
|
|
6
|
+
mode:
|
|
7
|
+
description: Validation tier (fast, audit, or release).
|
|
8
|
+
required: true
|
|
9
|
+
type: string
|
|
10
|
+
runtime-repository:
|
|
11
|
+
description: Repository containing the Code Foundry runtime.
|
|
12
|
+
required: false
|
|
13
|
+
type: string
|
|
14
|
+
default: 0xPlayerOne/code-foundry
|
|
15
|
+
runtime-ref:
|
|
16
|
+
description: Code Foundry runtime tag or ref.
|
|
17
|
+
required: false
|
|
18
|
+
type: string
|
|
19
|
+
default: v1.0.5
|
|
20
|
+
ci-runner:
|
|
21
|
+
description: Runner used by CI jobs.
|
|
22
|
+
required: false
|
|
23
|
+
type: string
|
|
24
|
+
default: ubuntu-latest
|
|
25
|
+
test-runner:
|
|
26
|
+
description: Runner used by non-unit test jobs.
|
|
27
|
+
required: false
|
|
28
|
+
type: string
|
|
29
|
+
default: ubuntu-latest
|
|
30
|
+
unit-runner:
|
|
31
|
+
description: Runner used by unit tests.
|
|
32
|
+
required: false
|
|
33
|
+
type: string
|
|
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
|
|
40
|
+
security-runner:
|
|
41
|
+
description: Runner used by Security jobs.
|
|
42
|
+
required: false
|
|
43
|
+
type: string
|
|
44
|
+
default: ubuntu-slim
|
|
45
|
+
codeql-runner:
|
|
46
|
+
description: Runner used by CodeQL jobs.
|
|
47
|
+
required: false
|
|
48
|
+
type: string
|
|
49
|
+
default: ubuntu-latest
|
|
50
|
+
rust-shards:
|
|
51
|
+
description: JSON array of Rust scope sharding values. Use ["all"] for single-pass behavior.
|
|
52
|
+
required: false
|
|
53
|
+
type: string
|
|
54
|
+
default: '["all"]'
|
|
55
|
+
rust-threads:
|
|
56
|
+
description: Threads used for Rust extraction and analysis. Values above 1 opt into local parallelism.
|
|
57
|
+
required: false
|
|
58
|
+
type: string
|
|
59
|
+
default: '1'
|
|
60
|
+
rust-max-parallel:
|
|
61
|
+
description: Maximum Rust shard jobs allowed to run concurrently.
|
|
62
|
+
required: false
|
|
63
|
+
type: number
|
|
64
|
+
default: 1
|
|
65
|
+
secrets:
|
|
66
|
+
TURBO_TOKEN:
|
|
67
|
+
required: false
|
|
68
|
+
NEXTAUTH_SECRET:
|
|
69
|
+
required: false
|
|
70
|
+
|
|
71
|
+
# The orchestrator keeps the union of permissions needed by the chain it calls
|
|
72
|
+
# (CodeQL uploads require security-events: write). Nested reusable workflows
|
|
73
|
+
# can only maintain or reduce permissions, never elevate them.
|
|
74
|
+
permissions:
|
|
75
|
+
actions: read
|
|
76
|
+
contents: read
|
|
77
|
+
packages: read
|
|
78
|
+
security-events: write
|
|
79
|
+
|
|
80
|
+
jobs:
|
|
81
|
+
ci:
|
|
82
|
+
name: CI
|
|
83
|
+
if: vars.CI_BILLING_PAUSED != 'true' && (inputs.mode == 'fast' || inputs.mode == 'audit')
|
|
84
|
+
uses: ./.github/workflows/ci.yml
|
|
85
|
+
with:
|
|
86
|
+
runtime-repository: ${{ inputs.runtime-repository }}
|
|
87
|
+
runtime-ref: ${{ inputs.runtime-ref }}
|
|
88
|
+
runner: ${{ inputs.ci-runner }}
|
|
89
|
+
secrets:
|
|
90
|
+
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
91
|
+
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
|
|
92
|
+
|
|
93
|
+
test:
|
|
94
|
+
name: Test
|
|
95
|
+
if: vars.CI_BILLING_PAUSED != 'true' && (inputs.mode == 'fast' || inputs.mode == 'audit')
|
|
96
|
+
uses: ./.github/workflows/test.yml
|
|
97
|
+
with:
|
|
98
|
+
runtime-repository: ${{ inputs.runtime-repository }}
|
|
99
|
+
runtime-ref: ${{ inputs.runtime-ref }}
|
|
100
|
+
runner: ${{ inputs.test-runner }}
|
|
101
|
+
unit-runner: ${{ inputs.unit-runner }}
|
|
102
|
+
performance-runner: ${{ inputs.performance-runner }}
|
|
103
|
+
unit-only: ${{ inputs.mode == 'fast' }}
|
|
104
|
+
secrets:
|
|
105
|
+
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
106
|
+
|
|
107
|
+
security:
|
|
108
|
+
name: Security
|
|
109
|
+
if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit'
|
|
110
|
+
uses: ./.github/workflows/security.yml
|
|
111
|
+
with:
|
|
112
|
+
runtime-repository: ${{ inputs.runtime-repository }}
|
|
113
|
+
runtime-ref: ${{ inputs.runtime-ref }}
|
|
114
|
+
runner: ${{ inputs.security-runner }}
|
|
115
|
+
|
|
116
|
+
# Aggregate check: "Validation / Gate" (caller job name + this job name).
|
|
117
|
+
# Always evaluates; only jobs required for the mode must have succeeded.
|
|
118
|
+
# The release tier runs no suite jobs: its policy (generated release diff
|
|
119
|
+
# validation) executes as a conditional step below, so no separate
|
|
120
|
+
# release-policy job renders skipped checks on ordinary pull requests.
|
|
121
|
+
gate:
|
|
122
|
+
name: Gate
|
|
123
|
+
needs: [ci, test, security]
|
|
124
|
+
if: vars.CI_BILLING_PAUSED != 'true' && always()
|
|
125
|
+
runs-on: ubuntu-slim
|
|
126
|
+
timeout-minutes: 10
|
|
127
|
+
env:
|
|
128
|
+
FOUNDRY_MODE: ${{ inputs.mode }}
|
|
129
|
+
FOUNDRY_CI: ${{ needs.ci.result }}
|
|
130
|
+
FOUNDRY_TEST: ${{ needs.test.result }}
|
|
131
|
+
FOUNDRY_SECURITY: ${{ needs.security.result }}
|
|
132
|
+
# This workflow is selected only for repositories whose canonical
|
|
133
|
+
# configuration explicitly disables unavailable CodeQL. Treat that
|
|
134
|
+
# policy decision as satisfied without registering a skipped PR check.
|
|
135
|
+
FOUNDRY_CODEQL: success
|
|
136
|
+
steps:
|
|
137
|
+
- name: Checkout runtime
|
|
138
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
139
|
+
with:
|
|
140
|
+
persist-credentials: false
|
|
141
|
+
repository: ${{ inputs.runtime-repository }}
|
|
142
|
+
ref: ${{ inputs.runtime-ref }}
|
|
143
|
+
path: .github/.code-foundry
|
|
144
|
+
sparse-checkout: |
|
|
145
|
+
src/lib
|
|
146
|
+
src/runtime.mjs
|
|
147
|
+
- name: Install runtime
|
|
148
|
+
run: mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
|
|
149
|
+
- name: Checkout consumer repository
|
|
150
|
+
if: ${{ inputs.mode == 'release' }}
|
|
151
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
152
|
+
with:
|
|
153
|
+
persist-credentials: false
|
|
154
|
+
fetch-depth: 0
|
|
155
|
+
filter: blob:none
|
|
156
|
+
- name: Validate generated release diff
|
|
157
|
+
if: ${{ inputs.mode == 'release' }}
|
|
158
|
+
env:
|
|
159
|
+
FOUNDRY_BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
160
|
+
FOUNDRY_HEAD_REF: ${{ github.event.pull_request.head.ref }}
|
|
161
|
+
FOUNDRY_HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}
|
|
162
|
+
FOUNDRY_REPOSITORY: ${{ github.repository }}
|
|
163
|
+
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" validation release_diff
|
|
164
|
+
- name: Evaluate aggregate gate
|
|
165
|
+
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" validation gate
|
|
@@ -8,6 +8,7 @@ on:
|
|
|
8
8
|
- synchronize
|
|
9
9
|
- reopened
|
|
10
10
|
- ready_for_review
|
|
11
|
+
- converted_to_draft
|
|
11
12
|
|
|
12
13
|
# Default every caller job to no repository permissions. Individual jobs grant
|
|
13
14
|
# only the scopes their own validation path consumes.
|
|
@@ -21,7 +22,10 @@ concurrency:
|
|
|
21
22
|
jobs:
|
|
22
23
|
mode:
|
|
23
24
|
name: Mode
|
|
24
|
-
|
|
25
|
+
# Draft updates still create a lightweight skipped workflow record so a
|
|
26
|
+
# converted-to-draft event can cancel in-flight validation, but no runner
|
|
27
|
+
# or reusable validation workflow starts until the PR is ready for review.
|
|
28
|
+
if: vars.CI_BILLING_PAUSED != 'true' && github.event.pull_request.draft == false
|
|
25
29
|
runs-on: ubuntu-slim
|
|
26
30
|
timeout-minutes: 10
|
|
27
31
|
permissions:
|
|
@@ -60,7 +64,7 @@ jobs:
|
|
|
60
64
|
validation:
|
|
61
65
|
name: Validation
|
|
62
66
|
needs: mode
|
|
63
|
-
if: vars.CI_BILLING_PAUSED != 'true'
|
|
67
|
+
if: vars.CI_BILLING_PAUSED != 'true' && github.event.pull_request.draft == false
|
|
64
68
|
# Reusable workflows can only maintain or reduce the caller job's scopes.
|
|
65
69
|
# The audit tier needs security-events: write for CodeQL uploads.
|
|
66
70
|
permissions:
|
package/AGENTS.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Agent Instructions
|
|
2
2
|
|
|
3
|
+
<!-- code-foundry-managed: config-aware-policy -->
|
|
4
|
+
|
|
3
5
|
These instructions are the repository-level operating contract for coding agents, including Hermes, OpenCode, and other automation.
|
|
4
6
|
|
|
5
7
|
They complement `CONTRIBUTING.md`. More specific instructions in nested `AGENTS.md` files and project documentation take precedence for their directory.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.9.3](https://github.com/0xPlayerOne/code-foundry/compare/v1.9.2...v1.9.3) (2026-09-08)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **ci:** suppress unavailable and draft checks ([#507](https://github.com/0xPlayerOne/code-foundry/issues/507)) ([e0b313a](https://github.com/0xPlayerOne/code-foundry/commit/e0b313ad1e4601ccd14066fb97a4f547400a6eaa))
|
|
9
|
+
|
|
10
|
+
## [1.9.2](https://github.com/0xPlayerOne/code-foundry/compare/v1.9.1...v1.9.2) (2026-09-08)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **sync:** refresh config-aware policies ([#505](https://github.com/0xPlayerOne/code-foundry/issues/505)) ([466150d](https://github.com/0xPlayerOne/code-foundry/commit/466150dcf263187e9cb08be2a2c2fe7ff67ef060))
|
|
16
|
+
|
|
3
17
|
## [1.9.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.9.0...v1.9.1) (2026-09-08)
|
|
4
18
|
|
|
5
19
|
|
package/README.md
CHANGED
|
@@ -74,8 +74,13 @@ The standard workflow triggers are:
|
|
|
74
74
|
- Pull requests targeting `main` (and `staging` in the staging-release topology).
|
|
75
75
|
- Draft PR automation for supported feature/fix branches.
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
Automated feature/fix and staging-promotion pull requests open as drafts.
|
|
78
|
+
Pull-request validation waits until a PR is marked ready for review; later
|
|
79
|
+
commits retrigger it, and converting the PR back to draft cancels in-flight
|
|
80
|
+
validation. Scheduled and manually dispatched audits are unaffected.
|
|
81
|
+
|
|
82
|
+
Jobs are language-aware and skip irrelevant setup inside the applicable
|
|
83
|
+
aggregate checks. TypeScript uses Oxlint, Oxfmt, and Bun's native
|
|
79
84
|
test runner (repositories using another linter or formatter keep full control
|
|
80
85
|
through their own `lint`/`format` scripts, which the runtime honors).
|
|
81
86
|
Rust uses `rustfmt`, Clippy with warnings as errors, and native
|
|
@@ -85,7 +90,10 @@ tests. Solidity projects retain their native toolchain and test runner.
|
|
|
85
90
|
CodeQL remains separate from CI and Security. With the default `codeql: auto`
|
|
86
91
|
and `dependency_review: auto` policies, public repositories use the free GitHub
|
|
87
92
|
security checks while private repositories skip them unless explicitly opted
|
|
88
|
-
in and supported by GitHub Advanced Security.
|
|
93
|
+
in and supported by GitHub Advanced Security. Set an unavailable private-repo
|
|
94
|
+
capability to `false` during sync to omit its CodeQL job from pull requests;
|
|
95
|
+
Dependency Review runs as a conditional Security step and does not register a
|
|
96
|
+
separate skipped check. JavaScript, Python, and Rust
|
|
89
97
|
audits remain available without Advanced Security. Code Foundry does not enable
|
|
90
98
|
GitHub Code Quality or other paid GitHub features.
|
|
91
99
|
|
package/docs/WORKFLOWS.md
CHANGED
|
@@ -12,6 +12,11 @@ pull_request:
|
|
|
12
12
|
# direct topology: branches: [main]
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
The generated caller suppresses runner and reusable-workflow jobs while the
|
|
16
|
+
pull request is a draft. It listens for `ready_for_review` to start validation,
|
|
17
|
+
for later `synchronize` events to rerun it, and for `converted_to_draft` to
|
|
18
|
+
cancel in-flight validation through the caller's concurrency group.
|
|
19
|
+
|
|
15
20
|
The separate `validation-audit.yml` caller is pinned to the configured released
|
|
16
21
|
runtime and handles scheduled and manual audits:
|
|
17
22
|
|
|
@@ -29,8 +34,9 @@ results satisfiable for the release commit). In the
|
|
|
29
34
|
`direct` topology (the default) every pull request targets `main` and runs the
|
|
30
35
|
full audit tier, because there is no integration branch for a fast pass.
|
|
31
36
|
Scheduled and manual runs select the audit tier in both topologies. Draft PR
|
|
32
|
-
automation separately listens to supported topic-branch pushes
|
|
33
|
-
automation listens to `staging` pushes
|
|
37
|
+
automation separately listens to supported topic-branch pushes and always
|
|
38
|
+
opens those PRs as drafts. Promotion automation listens to `staging` pushes
|
|
39
|
+
(staging-release only) and also always opens its PR as a draft. Release
|
|
34
40
|
automation listens to `main` pushes.
|
|
35
41
|
Custom deployment, indexing, search, Slither, or other workflows are
|
|
36
42
|
repository-owned extensions and should keep their own triggers and permissions.
|
|
@@ -204,8 +210,7 @@ validation gate. Land changes through the standard `direct` or
|
|
|
204
210
|
test/security workflows.
|
|
205
211
|
|
|
206
212
|
Jobs detect applicability before installing tools. Per-language CodeQL and
|
|
207
|
-
security-audit jobs are generated from detection
|
|
208
|
-
produce no checks at all instead of skipped rows; the aggregate
|
|
213
|
+
security-audit jobs are generated from detection; the aggregate
|
|
209
214
|
`Validation / Gate` keeps branch protection unambiguous for mixed-language
|
|
210
215
|
repositories by failing closed unless every generated check succeeds. An
|
|
211
216
|
empty analysis matrix while analysis is enabled fails the build instead of
|
|
@@ -214,12 +219,16 @@ silently skipping every analyzer.
|
|
|
214
219
|
## Security behavior
|
|
215
220
|
|
|
216
221
|
CodeQL is a separate workflow using GitHub's official actions. The default
|
|
217
|
-
`codeql: auto` policy enables it for public repositories and
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
222
|
+
`codeql: auto` policy enables it for public repositories and detects Advanced
|
|
223
|
+
Security availability for private repositories. When CodeQL is unavailable,
|
|
224
|
+
set `codeql: false` and sync: the generated caller selects an orchestrator that
|
|
225
|
+
omits CodeQL entirely, so pull requests do not show a skipped analyzer.
|
|
226
|
+
Dependency Review follows the same capability policy through
|
|
227
|
+
`dependency_review: auto`, but executes as a conditional step inside the
|
|
228
|
+
Security profile job and never registers a separate skipped pull-request
|
|
229
|
+
check. JavaScript, Python, and Rust audits remain available without Advanced
|
|
230
|
+
Security. If GitHub default setup is enabled, disable its generated CodeQL
|
|
231
|
+
workflow to avoid duplicate analysis.
|
|
223
232
|
|
|
224
233
|
Code Foundry does not enable GitHub Code Quality or any paid GitHub feature.
|
|
225
234
|
The repository's format and lint jobs are ordinary CI checks. Set `codeql:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "code-foundry",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.3",
|
|
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": {
|
package/src/commands/sync.mjs
CHANGED
|
@@ -65,6 +65,12 @@ const protectedFiles = new Set([
|
|
|
65
65
|
'NOTICE',
|
|
66
66
|
])
|
|
67
67
|
|
|
68
|
+
const configAwarePolicyFiles = new Set([
|
|
69
|
+
'AGENTS.md',
|
|
70
|
+
'.github/CONTRIBUTING.md',
|
|
71
|
+
'.github/SECURITY.md',
|
|
72
|
+
])
|
|
73
|
+
|
|
68
74
|
/** @type {Record<string, string>} */
|
|
69
75
|
const licenseFiles = {
|
|
70
76
|
'gpl-3.0-or-later': 'GPL-3.0-or-later.txt',
|
|
@@ -206,7 +212,7 @@ export function syncRepository(options) {
|
|
|
206
212
|
const destination = join(target, file)
|
|
207
213
|
if (!force && protectedFiles.has(file) && existsSync(destination)) {
|
|
208
214
|
const existing = readFileSync(destination, 'utf8')
|
|
209
|
-
if (!isLegacyManagedDoc(file, existing)) continue
|
|
215
|
+
if (!isLegacyManagedDoc(file, existing) && !isManagedConfigPolicy(file, existing)) continue
|
|
210
216
|
}
|
|
211
217
|
if (
|
|
212
218
|
(file === 'LICENSE' || file === 'NOTICE') &&
|
|
@@ -458,7 +464,7 @@ function shouldInclude(file, languages, features, config) {
|
|
|
458
464
|
if (workflow === 'release-pr' && !isStagingRelease(config.git_workflow)) return false
|
|
459
465
|
// The tiered validation caller supersedes the legacy ci/test/security/codeql
|
|
460
466
|
// event callers, so legacy feature names keep selecting it.
|
|
461
|
-
if (workflow === 'validation') {
|
|
467
|
+
if (workflow === 'validation' || workflow === 'validation-audit') {
|
|
462
468
|
return (
|
|
463
469
|
includesValue(features, 'validation') ||
|
|
464
470
|
LEGACY_GENERATED_CALLERS.some((legacy) => includesValue(features, legacy))
|
|
@@ -494,6 +500,15 @@ function renderWorkflow(content, config, repository, ref, rustCodeql) {
|
|
|
494
500
|
const localPrefix = 'uses: ./.github/workflows/'
|
|
495
501
|
const remotePrefix = `uses: ${repository}/.github/workflows/`
|
|
496
502
|
let rendered = content.replaceAll(localPrefix, remotePrefix)
|
|
503
|
+
// An explicitly unavailable CodeQL capability selects an orchestrator that
|
|
504
|
+
// omits the job entirely, so GitHub does not register a misleading skipped
|
|
505
|
+
// check on every pull request. `auto` retains runtime capability detection.
|
|
506
|
+
if (configured(config.codeql, 'auto') === 'false') {
|
|
507
|
+
rendered = rendered.replaceAll(
|
|
508
|
+
`${remotePrefix}validation.yml`,
|
|
509
|
+
`${remotePrefix}validation-no-codeql.yml`
|
|
510
|
+
)
|
|
511
|
+
}
|
|
497
512
|
rendered = rendered.replace(
|
|
498
513
|
new RegExp(`${escapeRegExp(remotePrefix)}([^\\s@]+)`, 'g'),
|
|
499
514
|
`$&@${ref}`
|
|
@@ -786,7 +801,10 @@ export function isGeneratedEventCaller(content, stem, runtimeRepository) {
|
|
|
786
801
|
const text = Buffer.isBuffer(content) ? content.toString('utf8') : String(content)
|
|
787
802
|
if (!/^name:\s*Code Foundry\s*$/m.test(text)) return false
|
|
788
803
|
if (/^\s*(runs-on|steps):/m.test(text)) return false
|
|
789
|
-
|
|
804
|
+
// Older generated staging-promotion callers predate the explicit runtime
|
|
805
|
+
// repository input. They are still safe to identify structurally by their
|
|
806
|
+
// single reusable-workflow job so direct-topology syncs can remove them.
|
|
807
|
+
if (stem !== 'release-pr' && !text.includes('runtime-repository:')) return false
|
|
790
808
|
if (!new RegExp(`^ ${stem}:`, 'm').test(text)) return false
|
|
791
809
|
return new RegExp(
|
|
792
810
|
`uses:\\s*${escapeRegExp(runtimeRepository)}/\\.github/workflows/${stem}\\.yml@`
|
|
@@ -1052,6 +1070,44 @@ function isLegacyManagedDoc(file, content) {
|
|
|
1052
1070
|
return false
|
|
1053
1071
|
}
|
|
1054
1072
|
|
|
1073
|
+
/**
|
|
1074
|
+
* Config-aware policy documents are generated contracts: a normal sync must
|
|
1075
|
+
* refresh them after branch-topology or validation-policy edits. The marker
|
|
1076
|
+
* owns future copies. Exact scaffold signatures migrate older generated
|
|
1077
|
+
* copies without treating arbitrary repository documentation as managed.
|
|
1078
|
+
* @param {string} file
|
|
1079
|
+
* @param {string} content
|
|
1080
|
+
*/
|
|
1081
|
+
function isManagedConfigPolicy(file, content) {
|
|
1082
|
+
if (!configAwarePolicyFiles.has(file)) return false
|
|
1083
|
+
if (content.includes('<!-- code-foundry-managed: config-aware-policy -->')) return true
|
|
1084
|
+
if (file === 'AGENTS.md') {
|
|
1085
|
+
return (
|
|
1086
|
+
content.startsWith('# Agent Instructions\n') &&
|
|
1087
|
+
content.includes(
|
|
1088
|
+
'These instructions are the repository-level operating contract for coding agents'
|
|
1089
|
+
) &&
|
|
1090
|
+
content.includes('They complement `CONTRIBUTING.md`.')
|
|
1091
|
+
)
|
|
1092
|
+
}
|
|
1093
|
+
if (file === '.github/CONTRIBUTING.md') {
|
|
1094
|
+
return (
|
|
1095
|
+
content.startsWith('# Contributing\n') &&
|
|
1096
|
+
content.includes(
|
|
1097
|
+
'This guide is the operating contract for humans and automation contributing to this repository.'
|
|
1098
|
+
) &&
|
|
1099
|
+
content.includes('[Agent contract](#agent-operating-contract)')
|
|
1100
|
+
)
|
|
1101
|
+
}
|
|
1102
|
+
return (
|
|
1103
|
+
content.startsWith('# Security Policy\n') &&
|
|
1104
|
+
content.includes('## Reporting a Vulnerability') &&
|
|
1105
|
+
content.includes(
|
|
1106
|
+
'This policy covers the code, configuration, dependencies, workflows, and generated artifacts maintained in this repository.'
|
|
1107
|
+
)
|
|
1108
|
+
)
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1055
1111
|
/** @param {string} target @param {string[]} args */
|
|
1056
1112
|
function git(target, args) {
|
|
1057
1113
|
spawnSync('git', args, { cwd: target, stdio: 'ignore' })
|