code-foundry 0.34.9 → 0.34.10

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.
@@ -54,6 +54,7 @@ jobs:
54
54
  release_created: ${{ steps.release.outputs.release_created || 'false' }}
55
55
  tag_name: ${{ steps.release.outputs.tag_name }}
56
56
  npm_publish: ${{ steps.profile.outputs.npm_publish }}
57
+ token_source: ${{ steps.credentials.outputs.token_source }}
57
58
  steps:
58
59
  - name: Checkout
59
60
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
@@ -116,25 +117,80 @@ jobs:
116
117
  id: credentials
117
118
  env:
118
119
  HAS_AUTOMATION_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN != '' || secrets.RELEASE_PLEASE_TOKEN != '' }}
120
+ GH_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN }}
119
121
  run: |
120
- if [ "$HAS_AUTOMATION_TOKEN" = true ]; then
122
+ set -euo pipefail
123
+ # NiftyLeague rejects long-lived fine-grained automation tokens with
124
+ # HTTP 403 even on REST (observed in the release-pr promotion flow),
125
+ # so the configured automation token is validated against the current
126
+ # repository before any write. gh api authenticates through the
127
+ # GH_TOKEN environment variable and never prints the token; the
128
+ # response body is discarded and only the exit status selects the
129
+ # credential for the rest of the job.
130
+ if [ "$HAS_AUTOMATION_TOKEN" = true ] && gh api "repos/${GITHUB_REPOSITORY}" --jq '.full_name' >/dev/null 2>&1; then
121
131
  echo "auto_merge=true" >> "$GITHUB_OUTPUT"
132
+ echo "token_source=configured" >> "$GITHUB_OUTPUT"
122
133
  else
123
134
  echo "auto_merge=false" >> "$GITHUB_OUTPUT"
135
+ echo "token_source=fallback" >> "$GITHUB_OUTPUT"
136
+ if [ "$HAS_AUTOMATION_TOKEN" = true ]; then
137
+ echo "::warning title=Release token fallback::The configured CODE_FOUNDRY_TOKEN or RELEASE_PLEASE_TOKEN was rejected by GitHub; failing over to the short-lived workflow token. The version pull request will be left for manual merge."
138
+ fi
124
139
  fi
125
- - name: Release Please
126
- id: release
127
- if: steps.profile.outputs.release_type != 'none'
140
+ - name: Release Please (automation token)
141
+ id: release_automation
142
+ if: steps.profile.outputs.release_type != 'none' && steps.credentials.outputs.token_source == 'configured'
128
143
  uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5
129
144
  with:
130
- token: ${{ secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN || github.token }}
145
+ token: ${{ secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN }}
131
146
  config-file: release-please-config.json
132
147
  release-type: ${{ steps.profile.outputs.legacy_release_type }}
148
+ - name: Release Please (workflow token)
149
+ id: release_workflow
150
+ if: steps.profile.outputs.release_type != 'none' && steps.credentials.outputs.token_source != 'configured'
151
+ uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5
152
+ with:
153
+ token: ${{ github.token }}
154
+ config-file: release-please-config.json
155
+ release-type: ${{ steps.profile.outputs.legacy_release_type }}
156
+ - name: Normalize Release Please outputs
157
+ id: release
158
+ if: steps.profile.outputs.release_type != 'none'
159
+ env:
160
+ AUTOMATION_RELEASE_CREATED: ${{ steps.release_automation.outputs.release_created }}
161
+ AUTOMATION_TAG_NAME: ${{ steps.release_automation.outputs.tag_name }}
162
+ AUTOMATION_PRS_CREATED: ${{ steps.release_automation.outputs.prs_created }}
163
+ WORKFLOW_RELEASE_CREATED: ${{ steps.release_workflow.outputs.release_created }}
164
+ WORKFLOW_TAG_NAME: ${{ steps.release_workflow.outputs.tag_name }}
165
+ WORKFLOW_PRS_CREATED: ${{ steps.release_workflow.outputs.prs_created }}
166
+ run: |
167
+ set -euo pipefail
168
+ # Exactly one of the two Release Please steps runs, so selecting the
169
+ # source by a non-empty release_created is deterministic. The stable
170
+ # release step id keeps the job outputs and downstream jobs reading
171
+ # steps.release.outputs.* unchanged.
172
+ if [ -n "$AUTOMATION_RELEASE_CREATED" ]; then
173
+ {
174
+ echo "release_created=$AUTOMATION_RELEASE_CREATED"
175
+ echo "tag_name=$AUTOMATION_TAG_NAME"
176
+ echo "prs_created=$AUTOMATION_PRS_CREATED"
177
+ } >> "$GITHUB_OUTPUT"
178
+ else
179
+ {
180
+ echo "release_created=$WORKFLOW_RELEASE_CREATED"
181
+ echo "tag_name=$WORKFLOW_TAG_NAME"
182
+ echo "prs_created=$WORKFLOW_PRS_CREATED"
183
+ } >> "$GITHUB_OUTPUT"
184
+ fi
133
185
  - name: Normalize generated release PR draft state
134
186
  if: steps.release.outcome == 'success'
135
187
  env:
136
- HAS_AUTOMATION_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN != '' || secrets.RELEASE_PLEASE_TOKEN != '' }}
137
- GH_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN || github.token }}
188
+ # The credential selected by the validation step is reused verbatim
189
+ # for every release-PR shell operation: the configured token only
190
+ # when it validated, github.token after fallback. The token value
191
+ # lives only in this masked env expression, never in step outputs.
192
+ AUTO_MERGE: ${{ steps.credentials.outputs.auto_merge }}
193
+ GH_TOKEN: ${{ steps.credentials.outputs.token_source == 'configured' && (secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN) || github.token }}
138
194
  run: |
139
195
  set -euo pipefail
140
196
  mapfile -t release_prs < <(
@@ -152,7 +208,7 @@ jobs:
152
208
 
153
209
  for pr in "${release_prs[@]}"; do
154
210
  PR_DRAFT=$(gh pr view "$pr" --repo "$GITHUB_REPOSITORY" --json isDraft --jq '.isDraft')
155
- if [ "$HAS_AUTOMATION_TOKEN" = true ]; then
211
+ if [ "$AUTO_MERGE" = true ]; then
156
212
  if [ "$PR_DRAFT" = true ]; then
157
213
  gh pr ready "$pr" --repo "$GITHUB_REPOSITORY"
158
214
  fi
@@ -160,22 +216,18 @@ jobs:
160
216
  if [ "$PR_DRAFT" = false ]; then
161
217
  gh pr ready --undo "$pr" --repo "$GITHUB_REPOSITORY"
162
218
  fi
163
- echo "::notice title=Manual release merge required::Release Please created or updated a version pull request. No CODE_FOUNDRY_TOKEN or RELEASE_PLEASE_TOKEN is configured, so release PRs are left in draft and need manual readiness before validation and merge workflows trigger."
219
+ echo "::notice title=Manual release merge required::Release Please created or updated a version pull request. No valid automation token is available (absent or rejected by GitHub), so release PRs are left in draft and need manual readiness before validation and merge workflows trigger."
164
220
  fi
165
221
  done
166
222
  - name: Leave release pull request for manual merge
167
223
  if: steps.release.outputs.prs_created == 'true' && steps.credentials.outputs.auto_merge != 'true'
168
- env:
169
- HAS_AUTOMATION_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN != '' || secrets.RELEASE_PLEASE_TOKEN != '' }}
170
224
  run: |
171
- if [ "$HAS_AUTOMATION_TOKEN" != true ]; then
172
- echo "::notice title=Manual release merge required::Release Please created or updated a version pull request. Configure CODE_FOUNDRY_TOKEN or RELEASE_PLEASE_TOKEN to enable guarded auto-merge when downstream release workflows require it."
173
- fi
225
+ echo "::notice title=Manual release merge required::Release Please created or updated a version pull request. Configure a valid CODE_FOUNDRY_TOKEN or RELEASE_PLEASE_TOKEN to enable guarded auto-merge when downstream release workflows require it."
174
226
 
175
227
  - name: Merge generated version pull requests
176
228
  if: steps.credentials.outputs.auto_merge == 'true'
177
229
  env:
178
- GH_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN || github.token }}
230
+ GH_TOKEN: ${{ steps.credentials.outputs.token_source == 'configured' && (secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN) || github.token }}
179
231
  run: |
180
232
  set -euo pipefail
181
233
  mapfile -t release_prs < <(
@@ -388,8 +440,11 @@ jobs:
388
440
  actions: write
389
441
  contents: read
390
442
  env:
391
- RELEASE_PLEASE_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN }}
392
- GH_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN || github.token }}
443
+ # The release job validates the configured automation token and exposes
444
+ # the selection; the post hook reuses the same selected credential so a
445
+ # rejected long-lived token is never used after fallback.
446
+ RELEASE_PLEASE_TOKEN: ${{ needs.release.outputs.token_source == 'configured' && (secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN) || github.token }}
447
+ GH_TOKEN: ${{ needs.release.outputs.token_source == 'configured' && (secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN) || github.token }}
393
448
  steps:
394
449
  - name: Checkout repository
395
450
  uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.34.10](https://github.com/0xPlayerOne/code-foundry/compare/v0.34.9...v0.34.10) (2026-08-02)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **release:** validate automation token before Release Please ([654094f](https://github.com/0xPlayerOne/code-foundry/commit/654094f452a4a6351de247aa82bf2448d7ea79c6))
9
+
3
10
  ## [0.34.9](https://github.com/0xPlayerOne/code-foundry/compare/v0.34.8...v0.34.9) (2026-08-02)
4
11
 
5
12
 
package/docs/RELEASES.md CHANGED
@@ -71,17 +71,26 @@ its manifest.
71
71
 
72
72
  ## Pull request permissions
73
73
 
74
- Release Please falls back to the repository's `GITHUB_TOKEN` when a
75
- `RELEASE_PLEASE_TOKEN` secret is unavailable. In that mode, Code Foundry opens
76
- or updates the version pull request, leaves it for manual merge, and completes
77
- the release job successfully.
78
-
79
- Configure a narrowly scoped `RELEASE_PLEASE_TOKEN` repository or organization
80
- secret to enable guarded automatic merging and downstream workflows triggered
81
- by the resulting release. The token needs `contents`, `issues`, and
82
- `pull-requests` write permissions. Code Foundry validates every changed path in
83
- the generated version pull request before using the token to merge it, waits
84
- for the required checks to finish, and then polls the pull request's
74
+ The release job validates the configured automation token
75
+ (`CODE_FOUNDRY_TOKEN`, falling back to `RELEASE_PLEASE_TOKEN`) against the
76
+ current repository with an authenticated REST probe before any write. When no
77
+ automation token is configured, or the configured token is rejected by GitHub
78
+ (observed with long-lived fine-grained tokens that GitHub rejects with HTTP
79
+ 403 even on REST), the release job fails over to the repository's short-lived
80
+ `GITHUB_TOKEN`. In that mode, Code Foundry opens or updates the version pull
81
+ request, leaves it for manual merge, and completes the release job
82
+ successfully. The token value is never printed or written to step outputs.
83
+
84
+ Guarded automatic merging and the downstream workflows triggered by the
85
+ resulting release are enabled only when the configured automation token was
86
+ validated successfully; a rejected token never falls through to any write.
87
+ Configure a valid, narrowly scoped `CODE_FOUNDRY_TOKEN` or
88
+ `RELEASE_PLEASE_TOKEN` repository or organization secret to enable guarded
89
+ automatic merging and downstream workflows triggered by the resulting
90
+ release. The token needs `contents`, `issues`, and `pull-requests` write
91
+ permissions. Code Foundry validates every changed path in the generated
92
+ version pull request before using the token to merge it, waits for the
93
+ required checks to finish, and then polls the pull request's
85
94
  `mergeStateStatus` until it is `CLEAN`, or `UNSTABLE` with `mergeable`
86
95
  `MERGEABLE`, before merging. Non-required checks that branch policy does not
87
96
  require (for example external code review still running after every required
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "0.34.9",
3
+ "version": "0.34.10",
4
4
  "description": "A fast, language-aware repository factory for agent-ready workflows, testing, security, and release automation.",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-or-later",