code-foundry 0.24.1 → 0.25.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.
@@ -1,17 +1,99 @@
1
- name: Release PR
1
+ name: Code Foundry Release PR
2
2
 
3
3
  on:
4
- push:
5
- branches: [staging]
4
+ workflow_call:
5
+ inputs:
6
+ runner:
7
+ description: Runner used to create the release PR.
8
+ required: false
9
+ type: string
10
+ default: ubuntu-slim
6
11
 
7
12
  permissions:
8
13
  contents: read
9
14
  pull-requests: write
10
15
 
16
+ env:
17
+ GH_TOKEN: ${{ github.token }}
18
+
11
19
  jobs:
12
- release-pr:
13
- name: Release PR
14
- uses: 0xPlayerOne/code-foundry/.github/workflows/reusable-release-pr.yml@v0.22.0
15
- with:
16
- runner: ubuntu-slim
17
- secrets: inherit
20
+ create-release-pr:
21
+ name: Create
22
+ runs-on: ${{ inputs.runner }}
23
+ timeout-minutes: 10
24
+ concurrency:
25
+ group: ${{ github.workflow }}-${{ github.ref }}
26
+ cancel-in-progress: true
27
+ steps:
28
+ - name: Check
29
+ id: check-pr
30
+ run: |
31
+ set -euo pipefail
32
+ EXISTING=$(gh pr list \
33
+ --repo "$GITHUB_REPOSITORY" \
34
+ --limit 1 \
35
+ --base main \
36
+ --head staging \
37
+ --state open \
38
+ --json number | jq 'length')
39
+ COMPARE_URL="repos/${GITHUB_REPOSITORY}/compare/main...staging"
40
+ TOTAL_COMMITS=$(gh api "$COMPARE_URL?per_page=1" --jq '.total_commits // 0')
41
+ echo "existing=$EXISTING" >> "$GITHUB_OUTPUT"
42
+ echo "commits=$TOTAL_COMMITS" >> "$GITHUB_OUTPUT"
43
+
44
+ - name: No changes
45
+ if: steps.check-pr.outputs.existing == '0' && steps.check-pr.outputs.commits == '0'
46
+ run: echo 'staging is already aligned with main; no promotion PR is needed.'
47
+
48
+ - name: Create
49
+ if: steps.check-pr.outputs.existing == '0' && steps.check-pr.outputs.commits != '0'
50
+ run: |
51
+ DATE=$(date +%Y-%m-%d)
52
+ BODY_FILE="$RUNNER_TEMP/release-pr.md"
53
+ COMPARE_URL="repos/${GITHUB_REPOSITORY}/compare/main...staging"
54
+ COMPARE_FILE="$RUNNER_TEMP/release-compare.json"
55
+ gh api "$COMPARE_URL?per_page=100" > "$COMPARE_FILE"
56
+ TOTAL_COMMITS=$(jq -r '.total_commits // 0' "$COMPARE_FILE")
57
+ if [ "$TOTAL_COMMITS" -gt 100 ]; then
58
+ LAST_PAGE=$(( (TOTAL_COMMITS + 99) / 100 ))
59
+ gh api "$COMPARE_URL?per_page=100&page=$LAST_PAGE" > "$COMPARE_FILE"
60
+ fi
61
+ COMMITS=$(jq -r '.commits[] | "- \(.commit.message | split("\\n")[0]) (\(.sha[0:7]))"' "$COMPARE_FILE")
62
+ if [ -z "$COMMITS" ]; then
63
+ COMMITS='- No commits found since main.'
64
+ fi
65
+
66
+ if [ "$TOTAL_COMMITS" -eq 1 ]; then
67
+ CHANGE_LABEL=change
68
+ else
69
+ CHANGE_LABEL=changes
70
+ fi
71
+
72
+ cat > "$BODY_FILE" <<EOF
73
+ ## Environment promotion
74
+
75
+ Promote the validated \`staging\` environment into \`main\`.
76
+ This is a deployment-promotion PR, not the version-release PR.
77
+
78
+ - **Source:** \`staging\`
79
+ - **Target:** \`main\`
80
+ - **Changes:** $TOTAL_COMMITS $CHANGE_LABEL
81
+ - **Created:** $DATE
82
+
83
+ ### Commit summary
84
+
85
+ $COMMITS
86
+
87
+ ### Validation
88
+
89
+ - Required CI, test, security, and CodeQL checks must pass before merge.
90
+ - Merge with **rebase** to preserve the linear Conventional Commit history.
91
+ - After merge, Release Please opens a separate versioned release PR with the changelog.
92
+ EOF
93
+
94
+ gh pr create \
95
+ --repo "$GITHUB_REPOSITORY" \
96
+ --base main \
97
+ --head staging \
98
+ --title "Promote staging -> main ($DATE)" \
99
+ --body-file "$BODY_FILE"
@@ -0,0 +1,17 @@
1
+ name: Release PR
2
+
3
+ on:
4
+ push:
5
+ branches: [staging]
6
+
7
+ permissions:
8
+ contents: read
9
+ pull-requests: write
10
+
11
+ jobs:
12
+ release-pr:
13
+ name: Release PR
14
+ uses: ./.github/workflows/release-pr.yml
15
+ with:
16
+ runner: ubuntu-slim
17
+ secrets: inherit
@@ -1,20 +1,117 @@
1
- name: Release
1
+ name: Code Foundry Release
2
2
 
3
3
  on:
4
- push:
5
- branches: [main]
6
- workflow_dispatch:
4
+ workflow_call:
5
+ inputs:
6
+ runner:
7
+ description: Runner used by release jobs.
8
+ required: false
9
+ type: string
10
+ default: ubuntu-slim
7
11
 
8
12
  permissions:
9
13
  contents: write
10
14
  issues: write
11
15
  pull-requests: write
12
- id-token: write
16
+
17
+ env:
18
+ REPO_FOUNDRY_PROFILE: ${{ vars.REPO_FOUNDRY_PROFILE }}
19
+ REPO_FOUNDRY_LANGUAGES: ${{ vars.REPO_FOUNDRY_LANGUAGES }}
20
+ REPO_FOUNDRY_FEATURES: ${{ vars.REPO_FOUNDRY_FEATURES }}
21
+ REPO_FOUNDRY_PACKAGE_MANAGER: ${{ vars.REPO_FOUNDRY_PACKAGE_MANAGER }}
22
+ REPO_FOUNDRY_RELEASE_TYPE: ${{ vars.REPO_FOUNDRY_RELEASE_TYPE }}
23
+ REPO_FOUNDRY_NPM_PUBLISH: ${{ vars.REPO_FOUNDRY_NPM_PUBLISH }}
13
24
 
14
25
  jobs:
15
26
  release:
16
- name: Release
17
- uses: 0xPlayerOne/code-foundry/.github/workflows/reusable-release.yml@v0.22.0
18
- with:
19
- runner: ubuntu-slim
20
- secrets: inherit
27
+ name: Release / Version
28
+ runs-on: ${{ inputs.runner }}
29
+ timeout-minutes: 20
30
+ concurrency:
31
+ group: ${{ github.workflow }}-${{ github.ref }}
32
+ cancel-in-progress: false
33
+ outputs:
34
+ release_created: ${{ steps.release.outputs.release_created || 'false' }}
35
+ tag_name: ${{ steps.release.outputs.tag_name }}
36
+ npm_publish: ${{ steps.profile.outputs.npm_publish }}
37
+ steps:
38
+ - name: Checkout
39
+ uses: actions/checkout@v7
40
+ with:
41
+ filter: blob:none
42
+ - name: Detect release profile
43
+ id: profile
44
+ shell: bash
45
+ run: |
46
+ if [ -x .github/scripts/profile.sh ]; then
47
+ release_type="$(bash .github/scripts/profile.sh get release_type)"
48
+ npm_publish="$(bash .github/scripts/profile.sh get npm_publish)"
49
+ else
50
+ config_file=.github/code-foundry.yml
51
+ release_type="$(awk -F': ' '/^release_type:/ {print $2; exit}' "$config_file" 2>/dev/null || true)"
52
+ npm_publish="$(awk -F': ' '/^npm_publish:/ {print $2; exit}' "$config_file" 2>/dev/null || true)"
53
+ fi
54
+ [ -n "$release_type" ] || release_type=auto
55
+ [ -n "$npm_publish" ] || npm_publish=false
56
+
57
+ if [ "$release_type" = auto ]; then
58
+ if [ -f package.json ]; then release_type=node
59
+ elif [ -f pyproject.toml ]; then release_type=python
60
+ elif [ -f Cargo.toml ]; then release_type=rust
61
+ elif [ -f version.txt ]; then release_type=simple
62
+ else release_type=none
63
+ fi
64
+ fi
65
+
66
+ case "$release_type" in
67
+ node|python|rust|simple) ;;
68
+ none) npm_publish=false ;;
69
+ *) echo "Unsupported release_type: $release_type" >&2; exit 2 ;;
70
+ esac
71
+ if [ ! -f package.json ]; then npm_publish=false; fi
72
+ printf 'release_type=%s\n' "$release_type" >> "$GITHUB_OUTPUT"
73
+ printf 'npm_publish=%s\n' "$npm_publish" >> "$GITHUB_OUTPUT"
74
+ - name: Release Please
75
+ id: release
76
+ if: steps.profile.outputs.release_type != 'none'
77
+ uses: googleapis/release-please-action@v5
78
+ with:
79
+ token: ${{ secrets.RELEASE_PLEASE_TOKEN || github.token }}
80
+ config-file: release-please-config.json
81
+ release-type: ${{ steps.profile.outputs.release_type }}
82
+
83
+ npm:
84
+ name: Release / Publish npm
85
+ needs: release
86
+ if: needs.release.outputs.release_created == 'true' && needs.release.outputs.npm_publish == 'true'
87
+ runs-on: ${{ inputs.runner }}
88
+ timeout-minutes: 15
89
+ permissions:
90
+ contents: read
91
+ id-token: write
92
+ env:
93
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
94
+ steps:
95
+ - name: Checkout release
96
+ uses: actions/checkout@v7
97
+ with:
98
+ ref: ${{ needs.release.outputs.tag_name }}
99
+ - name: Setup Node (trusted)
100
+ if: env.NPM_TOKEN == ''
101
+ uses: actions/setup-node@v5
102
+ with:
103
+ node-version: 24
104
+ - name: Setup Node (token)
105
+ if: env.NPM_TOKEN != ''
106
+ uses: actions/setup-node@v5
107
+ with:
108
+ node-version: 24
109
+ registry-url: https://registry.npmjs.org
110
+ - name: Publish npm with token
111
+ if: env.NPM_TOKEN != ''
112
+ env:
113
+ NODE_AUTH_TOKEN: ${{ env.NPM_TOKEN }}
114
+ run: npm publish --provenance --access public
115
+ - name: Publish npm with trusted publishing
116
+ if: env.NPM_TOKEN == ''
117
+ run: npm publish --provenance --access public
@@ -0,0 +1,20 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write
10
+ issues: write
11
+ pull-requests: write
12
+ id-token: write
13
+
14
+ jobs:
15
+ release:
16
+ name: Release
17
+ uses: ./.github/workflows/release.yml
18
+ with:
19
+ runner: ubuntu-slim
20
+ secrets: inherit
@@ -1,21 +1,296 @@
1
- name: Security
1
+ name: Code Foundry Security
2
2
 
3
3
  on:
4
- push:
5
- branches: [main, staging]
6
- pull_request:
7
- branches: [staging]
8
- workflow_dispatch:
4
+ workflow_call:
5
+ inputs:
6
+ runtime-repository:
7
+ description: Repository containing the Code Foundry runtime.
8
+ required: false
9
+ type: string
10
+ default: 0xPlayerOne/code-foundry
11
+ runtime-ref:
12
+ description: Code Foundry runtime tag or ref.
13
+ required: false
14
+ type: string
15
+ default: v0.20.2
16
+ runner:
17
+ description: Runner used by Security jobs.
18
+ required: false
19
+ type: string
20
+ default: ubuntu-slim
9
21
 
10
22
  permissions:
11
23
  contents: read
12
24
 
25
+ env:
26
+ REPO_FOUNDRY_PROFILE: ${{ vars.REPO_FOUNDRY_PROFILE }}
27
+ REPO_FOUNDRY_LANGUAGES: ${{ vars.REPO_FOUNDRY_LANGUAGES }}
28
+ REPO_FOUNDRY_FEATURES: ${{ vars.REPO_FOUNDRY_FEATURES }}
29
+ REPO_FOUNDRY_PACKAGE_MANAGER: ${{ vars.REPO_FOUNDRY_PACKAGE_MANAGER }}
30
+ REPO_FOUNDRY_CACHE_PACKAGES: ${{ vars.REPO_FOUNDRY_CACHE_PACKAGES || 'auto' }}
31
+ REPO_FOUNDRY_BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before || '' }}
32
+
33
+ concurrency:
34
+ group: ${{ github.workflow }}-${{ github.event.pull_request.head.repo.full_name || github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}
35
+ cancel-in-progress: true
36
+
13
37
  jobs:
14
- security:
15
- name: Security
16
- uses: 0xPlayerOne/code-foundry/.github/workflows/reusable-security.yml@v0.22.0
17
- with:
18
- runtime-repository: 0xPlayerOne/code-foundry
19
- runtime-ref: v0.22.0
20
- runner: ubuntu-slim
21
- secrets: inherit
38
+ profile:
39
+ name: Profile
40
+ runs-on: ${{ inputs.runner }}
41
+ timeout-minutes: 10
42
+ outputs:
43
+ javascript: ${{ steps.profile.outputs.javascript }}
44
+ rust: ${{ steps.profile.outputs.rust }}
45
+ python: ${{ steps.profile.outputs.python }}
46
+ python_requirements: ${{ steps.profile.outputs.python_requirements }}
47
+ steps:
48
+ - name: Checkout
49
+ uses: actions/checkout@v7
50
+ with:
51
+ fetch-depth: 2
52
+ filter: blob:none
53
+ sparse-checkout: |
54
+ .github
55
+ .mise.toml
56
+ mise.lock
57
+ .npmrc
58
+ .pnpmfile.cjs
59
+ .yarnrc*
60
+ **/package.json
61
+ **/bun.lock
62
+ **/bun.lockb
63
+ **/pnpm-lock.yaml
64
+ **/yarn.lock
65
+ **/package-lock.json
66
+ **/Cargo.toml
67
+ **/Cargo.lock
68
+ **/.cargo/**
69
+ **/pyproject.toml
70
+ **/requirements*.txt
71
+ **/setup.py
72
+ **/setup.cfg
73
+ **/Pipfile
74
+ **/Pipfile.lock
75
+ **/poetry.lock
76
+ **/uv.lock
77
+ sparse-checkout-cone-mode: false
78
+ - name: Runtime
79
+ uses: actions/checkout@v7
80
+ with:
81
+ repository: ${{ inputs.runtime-repository }}
82
+ ref: ${{ inputs.runtime-ref }}
83
+ path: .code-foundry
84
+ sparse-checkout: |
85
+ .github/actions
86
+ .github/scripts
87
+ - name: Install runtime
88
+ run: |
89
+ mkdir -p .github/actions .github/scripts
90
+ cp -R .code-foundry/.github/actions/. .github/actions/
91
+ cp -R .code-foundry/.github/scripts/. .github/scripts/
92
+ - name: Detect
93
+ id: profile
94
+ run: bash .github/scripts/security.sh profile >> "$GITHUB_OUTPUT"
95
+
96
+ dependency-audit-javascript:
97
+ name: Dependency Audit (JavaScript)
98
+ runs-on: ${{ inputs.runner }}
99
+ timeout-minutes: 20
100
+ steps:
101
+ - name: Checkout
102
+ uses: actions/checkout@v7
103
+ with:
104
+ filter: blob:none
105
+ sparse-checkout: |
106
+ .github
107
+ .mise.toml
108
+ mise.lock
109
+ .npmrc
110
+ .pnpmfile.cjs
111
+ .yarnrc*
112
+ **/package.json
113
+ **/bun.lock
114
+ **/bun.lockb
115
+ **/pnpm-lock.yaml
116
+ **/yarn.lock
117
+ **/package-lock.json
118
+ sparse-checkout-cone-mode: false
119
+ - name: Runtime
120
+ uses: actions/checkout@v7
121
+ with:
122
+ repository: ${{ inputs.runtime-repository }}
123
+ ref: ${{ inputs.runtime-ref }}
124
+ path: .code-foundry
125
+ sparse-checkout: |
126
+ .github/actions
127
+ .github/scripts
128
+ - name: Install runtime
129
+ run: |
130
+ mkdir -p .github/actions .github/scripts
131
+ cp -R .code-foundry/.github/actions/. .github/actions/
132
+ cp -R .code-foundry/.github/scripts/. .github/scripts/
133
+ - name: Detect
134
+ id: applicability
135
+ run: bash .github/scripts/security.sh should_run javascript >> "$GITHUB_OUTPUT"
136
+ - name: Setup
137
+ if: steps.applicability.outputs.applicable == 'true'
138
+ uses: ./.github/actions/setup
139
+ with:
140
+ mise-scope: javascript
141
+ cache-save: ${{ github.event_name != 'pull_request' }}
142
+ - name: Audit dependencies
143
+ if: steps.applicability.outputs.applicable == 'true'
144
+ run: bash .github/scripts/security.sh audit javascript
145
+
146
+ dependency-audit-rust:
147
+ name: Dependency Audit (Rust)
148
+ runs-on: ${{ inputs.runner }}
149
+ timeout-minutes: 20
150
+ steps:
151
+ - name: Checkout
152
+ uses: actions/checkout@v7
153
+ with:
154
+ filter: blob:none
155
+ sparse-checkout: |
156
+ .github
157
+ .mise.toml
158
+ mise.lock
159
+ **/Cargo.toml
160
+ **/Cargo.lock
161
+ **/.cargo/**
162
+ sparse-checkout-cone-mode: false
163
+ - name: Runtime
164
+ uses: actions/checkout@v7
165
+ with:
166
+ repository: ${{ inputs.runtime-repository }}
167
+ ref: ${{ inputs.runtime-ref }}
168
+ path: .code-foundry
169
+ sparse-checkout: |
170
+ .github/actions
171
+ .github/scripts
172
+ - name: Install runtime
173
+ run: |
174
+ mkdir -p .github/actions .github/scripts
175
+ cp -R .code-foundry/.github/actions/. .github/actions/
176
+ cp -R .code-foundry/.github/scripts/. .github/scripts/
177
+ - name: Detect
178
+ id: applicability
179
+ run: bash .github/scripts/security.sh should_run rust >> "$GITHUB_OUTPUT"
180
+ - name: Check Rust
181
+ id: system-rust
182
+ if: steps.applicability.outputs.applicable == 'true'
183
+ shell: bash
184
+ run: |
185
+ if command -v cargo >/dev/null 2>&1 && command -v rustc >/dev/null 2>&1; then
186
+ cargo --version
187
+ rustc --version
188
+ echo 'available=true' >> "$GITHUB_OUTPUT"
189
+ else
190
+ echo 'available=false' >> "$GITHUB_OUTPUT"
191
+ fi
192
+ - name: Setup
193
+ if: >-
194
+ steps.applicability.outputs.applicable == 'true' &&
195
+ steps.system-rust.outputs.available != 'true'
196
+ uses: ./.github/actions/setup
197
+ with:
198
+ mise-scope: rust
199
+ cache-save: ${{ github.event_name != 'pull_request' }}
200
+ - name: Install cargo-audit
201
+ if: steps.applicability.outputs.applicable == 'true'
202
+ uses: taiki-e/install-action@v2
203
+ with:
204
+ tool: cargo-audit
205
+ - name: Audit dependencies
206
+ if: steps.applicability.outputs.applicable == 'true'
207
+ run: bash .github/scripts/security.sh audit rust
208
+
209
+ dependency-audit-python:
210
+ name: Dependency Audit (Python) / ${{ matrix.requirement }}
211
+ needs: profile
212
+ if: >-
213
+ ${{ needs.profile.result == 'success' &&
214
+ needs.profile.outputs.python == 'true' &&
215
+ needs.profile.outputs.python_requirements != '["none"]' }}
216
+ strategy:
217
+ fail-fast: false
218
+ max-parallel: 8
219
+ matrix:
220
+ requirement: ${{ fromJSON(needs.profile.outputs.python_requirements) }}
221
+ runs-on: ${{ inputs.runner }}
222
+ timeout-minutes: 20
223
+ env:
224
+ REPO_FOUNDRY_PYTHON_REQUIREMENT: ${{ matrix.requirement }}
225
+ steps:
226
+ - name: Checkout
227
+ uses: actions/checkout@v7
228
+ with:
229
+ filter: blob:none
230
+ sparse-checkout: |
231
+ .github
232
+ .mise.toml
233
+ mise.lock
234
+ **/pyproject.toml
235
+ **/requirements*.txt
236
+ **/setup.py
237
+ **/setup.cfg
238
+ **/Pipfile
239
+ **/Pipfile.lock
240
+ **/poetry.lock
241
+ **/uv.lock
242
+ sparse-checkout-cone-mode: false
243
+ - name: Runtime
244
+ uses: actions/checkout@v7
245
+ with:
246
+ repository: ${{ inputs.runtime-repository }}
247
+ ref: ${{ inputs.runtime-ref }}
248
+ path: .code-foundry
249
+ sparse-checkout: |
250
+ .github/actions
251
+ .github/scripts
252
+ - name: Install runtime
253
+ run: |
254
+ mkdir -p .github/actions .github/scripts
255
+ cp -R .code-foundry/.github/actions/. .github/actions/
256
+ cp -R .code-foundry/.github/scripts/. .github/scripts/
257
+ - name: Setup
258
+ uses: ./.github/actions/setup
259
+ with:
260
+ mise-scope: python
261
+ cache-save: ${{ github.event_name != 'pull_request' }}
262
+ - name: Audit dependencies
263
+ run: bash .github/scripts/security.sh audit python
264
+
265
+ dependency-audit-python-gate:
266
+ name: Dependency Audit (Python)
267
+ needs: [profile, dependency-audit-python]
268
+ if: always()
269
+ runs-on: ${{ inputs.runner }}
270
+ timeout-minutes: 5
271
+ steps:
272
+ - name: Gate
273
+ env:
274
+ PROFILE_RESULT: ${{ needs.profile.result }}
275
+ AUDIT_RESULT: ${{ needs.dependency-audit-python.result }}
276
+ run: |
277
+ if [ "$PROFILE_RESULT" != success ]; then
278
+ echo "Python audit profile failed: $PROFILE_RESULT" >&2
279
+ exit 1
280
+ fi
281
+ case "$AUDIT_RESULT" in
282
+ success|skipped) exit 0 ;;
283
+ *) echo "Python dependency audit failed: $AUDIT_RESULT" >&2; exit 1 ;;
284
+ esac
285
+
286
+ dependency-review:
287
+ name: Dependency Review
288
+ if: ${{ github.event_name == 'pull_request' && !github.event.repository.private }}
289
+ runs-on: ${{ inputs.runner }}
290
+ timeout-minutes: 10
291
+ steps:
292
+ - name: Review
293
+ uses: actions/dependency-review-action@v5
294
+ with:
295
+ fail-on-severity: high
296
+ license-check: true
@@ -0,0 +1,21 @@
1
+ name: Security
2
+
3
+ on:
4
+ push:
5
+ branches: [main, staging]
6
+ pull_request:
7
+ branches: [staging]
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ security:
15
+ name: Security
16
+ uses: ./.github/workflows/security.yml
17
+ with:
18
+ runtime-repository: 0xPlayerOne/code-foundry
19
+ runtime-ref: v0.22.0
20
+ runner: ubuntu-slim
21
+ secrets: inherit