ci: run publish build under Node's permission model (experiment)#22465
Open
GirlBossRush wants to merge 1 commit into
Open
ci: run publish build under Node's permission model (experiment)#22465GirlBossRush wants to merge 1 commit into
GirlBossRush wants to merge 1 commit into
Conversation
❌ 7 Tests Failed:
View the top 3 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
✅ Deploy Preview for authentik-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Wraps the build phase of the npm publish workflow (`tsc -p .`, plus
`typedoc` for `packages/esbuild-plugin-live-reload`) in Node 24's
permission model.
Configuration:
node --permission \
--allow-fs-read="$PWD" \
--allow-fs-write="$PWD" \
./node_modules/typescript/bin/tsc -p .
`--permission` with no other `--allow` flags denies by default:
- network (--allow-net)
- child_process (--allow-child-process)
- worker_threads (--allow-worker)
- native addons
- WASI
fs reads and writes are scoped to the package working tree. The
threat model addressed: a malicious devDep (direct or transitive)
that wakes up during `tsc` and tries to exfil credentials. It can
still read process.env, but with no network, no subprocess, and no
fs write outside `$PWD`, it has no channel to send anything out.
`npm ci` and `npm publish` keep their full capability set — both
legitimately need network and subprocess access, and `npm publish`'s
defense lives at the runner egress layer (step-security/harden-runner,
added in #22463).
This is the smallest tractable surface for the permission model in
this repo: all six publishable packages build via `tsc` (one also
runs `typedoc`), with no native addons and no in-build child
processes. If a future package needs broader permissions, the
allow-list can be widened per-step rather than discarded.
The Node permission model is still in active development (stability
1.1 in v24); the API surface is stable enough to commit to but the
"experiment" framing is intentional — if a downstream tsc/typedoc
revision starts touching paths outside `$PWD`, revert is one-line.
Co-authored-by: Agent <279763771+playpen-agent@users.noreply.github.com>
c4d8daf to
d29a2d0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Wraps the build phase of
.github/workflows/packages-npm-publish.yml(tsc -p ., plustypedocforpackages/esbuild-plugin-live-reload) in Node 24's permission model.node --permission \ --allow-fs-read="$PWD" \ --allow-fs-write="$PWD" \ ./node_modules/typescript/bin/tsc -p .--permissionwith no other--allowflags denies by default:--allow-netunset)--allow-child-processunset)--allow-workerunset)fs reads and writes are explicitly scoped to the package working tree.
Threat model
A malicious devDep (direct or transitive) of one of the six publishable packages that wakes up during
tscand tries to do anything beyond compile TypeScript. With this in place it can still readprocess.env(the permission model doesn't gate env vars), but it has no channel to send anything anywhere:fetchan exfil endpointcurl/nc/ssh$PWD→ can't drop a payload into~/.ssh,/var/tmp, etc.npm ciandnpm publishkeep their full capability set. Both legitimately need network and subprocess access, and the runner-level egress defense fornpm publishlives in #22463 (step-security/harden-runner).Why this is the right surface
All six publishable packages have build scripts that are either
tsc -p .ortsc -p . && typedoc— pure JS tools with no native addons and no in-build subprocess spawning. The permission allow-list is uniform and the failure mode (build fails noisily) is much preferable to a quiet exfil.Caveats
--permission,--allow-fs-read,--allow-fs-write,--allow-net) is settled, but minor semantics can shift across Node minors.worker_threads, e.g.), the allow-list widens per-step; the wrapper does not need to be discarded.tscortypedocupstream starts touching paths outside$PWD, the build will fail with a permission error; revert is a one-line removal.Test plan
workflow_dispatchagainst this branch — all six matrix entries' build phase completes under--permission.npm publishstill succeeds end-to-end (capability boundary preserved between phases).ERR_ACCESS_DENIEDwith the path that wasn't allowed; we widen the list precisely.