ci(workflows): scope GitHub Actions token permissions to jobs that need them#791
Conversation
…ed them Move write scopes off the workflow-level defaults in ci.yml and pr.yml so only the jobs that publish releases, push the changelog branch, or post PR comments run with write tokens; every compile, test, benchmark, compliance, and artifact job now runs read-only. - ci.yml default narrowed to `contents: read`; `nightly` gets `contents: write` (gh release delete/create) and `release` gets `contents: write` + `pull-requests: write` (release upload, git push, gh pr create). - pr.yml default narrowed to `contents: read`; the three PR-comment jobs get `pull-requests: write` (plus `contents: read` where they check out; `timing-comment` has no checkout, so it gets `pull-requests: write` only). - Add `persist-credentials: false` to every non-pushing checkout, matching the bump-workflow pattern; the `release` checkout keeps its credentials for the `git push --force-with-lease` of the changelog branch. The PR-comment jobs need only `pull-requests: write` (not `issues: write`): GitHub's create-issue-comment endpoint accepts either scope and these jobs only comment on pull requests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughWorkflow-level write permissions in ChangesGitHub Actions permissions hardening
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Benchmark Results430 benchmarks Interpreted: 🟢 7 improved · 🔴 225 regressed · 198 unchanged · avg -9.1% arraybuffer.js — Interp: 🔴 6, 8 unch. · avg -12.1% · Bytecode: 14 unch. · avg -0.3%
arrays.js — Interp: 🔴 12, 7 unch. · avg -12.2% · Bytecode: 🔴 1, 18 unch. · avg -1.9%
async-await.js — Interp: 🔴 5, 1 unch. · avg -22.4% · Bytecode: 6 unch. · avg +1.8%
async-generators.js — Interp: 🔴 1, 1 unch. · avg -32.4% · Bytecode: 2 unch. · avg -0.4%
atomics.js — Interp: 🔴 5, 1 unch. · avg -12.7% · Bytecode: 🟢 3, 3 unch. · avg +4.4%
base64.js — Interp: 🔴 6, 4 unch. · avg -10.7% · Bytecode: 🟢 4, 6 unch. · avg +2.2%
classes.js — Interp: 🔴 16, 15 unch. · avg -9.3% · Bytecode: 🟢 3, 28 unch. · avg -1.1%
closures.js — Interp: 🔴 7, 4 unch. · avg -9.3% · Bytecode: 11 unch. · avg -2.5%
collections.js — Interp: 🔴 9, 3 unch. · avg -13.9% · Bytecode: 12 unch. · avg +0.6%
csv.js — Interp: 🔴 8, 5 unch. · avg -12.8% · Bytecode: 🟢 1, 🔴 1, 11 unch. · avg +0.9%
destructuring.js — Interp: 🔴 16, 6 unch. · avg -11.2% · Bytecode: 🟢 6, 16 unch. · avg +1.6%
fibonacci.js — Interp: 🔴 3, 5 unch. · avg -10.3% · Bytecode: 8 unch. · avg -3.1%
float16array.js — Interp: 🔴 19, 13 unch. · avg -6.8% · Bytecode: 🟢 7, 🔴 2, 23 unch. · avg +2.1%
for-of.js — Interp: 🔴 6, 1 unch. · avg -12.8% · Bytecode: 🟢 1, 6 unch. · avg +1.2%
generators.js — Interp: 🔴 3, 1 unch. · avg -14.6% · Bytecode: 🔴 2, 2 unch. · avg -5.5%
intl.js — Interp: 🔴 5, 1 unch. · avg -17.9% · Bytecode: 🟢 1, 🔴 1, 4 unch. · avg +0.5%
iterators.js — Interp: 🟢 1, 🔴 16, 25 unch. · avg -8.8% · Bytecode: 🟢 4, 🔴 1, 37 unch. · avg +2.1%
json.js — Interp: 🔴 12, 8 unch. · avg -12.1% · Bytecode: 🟢 3, 🔴 2, 15 unch. · avg +1.9%
jsx.jsx — Interp: 🔴 8, 13 unch. · avg -9.1% · Bytecode: 🔴 4, 17 unch. · avg -3.2%
modules.js — Interp: 🔴 3, 6 unch. · avg -9.4% · Bytecode: 9 unch. · avg +2.0%
numbers.js — Interp: 🔴 5, 6 unch. · avg -9.9% · Bytecode: 🟢 1, 🔴 1, 9 unch. · avg +4.3%
objects.js — Interp: 🔴 2, 5 unch. · avg -8.2% · Bytecode: 7 unch. · avg -5.8%
promises.js — Interp: 🔴 4, 8 unch. · avg -3.6% · Bytecode: 12 unch. · avg -1.1%
property-access.js — Interp: 🔴 1, 4 unch. · avg -9.1% · Bytecode: 🔴 1, 4 unch. · avg -2.8%
regexp.js — Interp: 🔴 4, 7 unch. · avg -9.9% · Bytecode: 🔴 1, 10 unch. · avg +0.4%
strings.js — Interp: 🔴 6, 13 unch. · avg -10.7% · Bytecode: 🟢 2, 🔴 1, 16 unch. · avg +1.0%
temporal.js — Interp: 🔴 3, 3 unch. · avg -15.0% · Bytecode: 6 unch. · avg -0.8%
tsv.js — Interp: 🔴 4, 5 unch. · avg -12.3% · Bytecode: 🟢 1, 8 unch. · avg -2.1%
typed-arrays.js — Interp: 🟢 3, 🔴 12, 7 unch. · avg +3.7% · Bytecode: 🟢 2, 🔴 8, 12 unch. · avg -12.8%
uint8array-encoding.js — Interp: 🟢 3, 🔴 6, 9 unch. · avg +10.1% · Bytecode: 🟢 4, 14 unch. · avg +20.6%
weak-collections.js — Interp: 🔴 12, 3 unch. · avg -13.3% · Bytecode: 🟢 3, 🔴 1, 11 unch. · avg +27.0%
Deterministic profile diffDeterministic profile diff: no significant changes. Measured on ubuntu-latest x64. Benchmark ranges compare cached main-branch min/max ops/sec with the PR run; overlapping ranges are treated as unchanged noise. Percentage deltas are secondary context. |
Suite TimingTest Runner (interpreted: 10,799 passed; bytecode: 10,799 passed)
MemoryGC rows aggregate the main thread plus all worker thread-local GCs. Test runner worker shutdown frees thread-local heaps in bulk; that shutdown reclamation is not counted as GC collections or collected objects.
Benchmarks (interpreted: 430; bytecode: 430)
MemoryGC rows aggregate the main thread plus all worker thread-local GCs. Benchmark runner performs explicit between-file collections, so collection and collected-object counts can be much higher than the test runner.
Measured on ubuntu-latest x64. |
test262 Conformance
Areas closest to 100%
Per-test deltas (+37 / -2)Newly failing (2):
Newly passing (37):
Steady-state failures are non-blocking; regressions vs the cached main baseline (lower total pass count, or any PASS → non-PASS transition) fail the conformance gate. Measured on ubuntu-latest x64, bytecode mode. Areas grouped by the first two test262 path components; minimum 25 attempted tests, areas already at 100% excluded. Δ vs main compares against the most recent cached |
Summary
Tightens GitHub Actions
GITHUB_TOKENpermissions inci.ymlandpr.ymlso write scopes live only on the jobs that publish releases, push the changelog branch, or post PR comments. Every compile / test / benchmark / compliance / artifact job now runs read-only. This applies the least-privilege pattern already used by the four*-bump.ymlworkflows.Permission changes
ci.ymlworkflow defaultcontents: write+pull-requests: writecontents: readci.ymlnightlycontents: write(gh release delete/create)ci.ymlreleasecontents: write+pull-requests: write(release upload,git push,gh pr create)pr.ymlworkflow defaultpull-requests: writecontents: readpr.ymlbenchmark-comment,test262-commentcontents: read+pull-requests: writepr.ymltiming-commentpull-requests: writeonly (no checkout)Checkout hardening —
persist-credentials: falseadded to every non-pushing checkout (10 inci.yml, 9 inpr.yml), matching the bump-workflow pattern. Thereleasejob's checkout keepspersist-credentials: true(with an inline comment) because it runsgit push --force-with-leasefor the changelog branch.Key constraints / non-goals
pull-requests: write, notissues: write(the issue's open question): GitHub's "Create an issue comment" endpoint accepts either scope, and these jobs only ever comment on PRs.permissionsblocks replace (not merge with) the workflow default, so each checkout-bearing comment job explicitly keepscontents: read.actions/cache, same-run artifact upload/download, and the Vercel-Blob publish steps don't consumeGITHUB_TOKENwrite scopes (they use the runtime token /BLOB_READ_WRITE_TOKEN), so the affected jobs are safe read-only.*-bump.ymlworkflows and the reusabletoolchain.yml(which inherits the new read-only default) are intentionally untouched.Closes #785
Testing
GocciaTestRunner testsand--mode=bytecode→ 10,799 / 10,799 passed, 0 failed, 0 skipped in both modes. (A CI-config change cannot affect the engine; run per the project's "always run" gate.)grill-with-docssession).Workflow-specific verification
ruby -ryamlparse: both files load OK.actionlint ci.yml pr.yml: finding signatures byte-identical to theHEADbaseline — zero new findings. actionlint exits 1 solely because of the pre-existingSC2012/SC2044/SC2086shellcheck info/warnings inci.yml's buildrun:script (~line 64), which the issue documented and this PR deliberately leaves unchanged../format.pas --check: 366 files, all formatted correctly.persist-credentials: truecheckout is the only one that runs an authenticatedgit push.