Skip to content

Commit d29a2d0

Browse files
ci: run publish build under Node's permission model (experiment)
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>
1 parent f992754 commit d29a2d0

1 file changed

Lines changed: 27 additions & 1 deletion

File tree

.github/workflows/packages-npm-publish.yml

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,33 @@ jobs:
4747
- name: Publish package
4848
if: steps.changed-files.outputs.any_changed == 'true'
4949
working-directory: ${{ matrix.package }}
50+
# Experimental: the build (tsc, plus typedoc for one package) runs
51+
# under Node's permission model. fs reads/writes are scoped to the
52+
# package working tree; --permission with no other --allow flags
53+
# blocks network, child_process, worker_threads, native addons,
54+
# and WASI by default.
55+
#
56+
# Trade-off: env vars are still readable (the permission model
57+
# does not gate them), but with no exfil channel — no network,
58+
# no subprocess, no write outside $PWD — they cannot leave the
59+
# build sandbox. The npm ci and npm publish phases keep their
60+
# full capability set since they legitimately need network and
61+
# subprocess access.
5062
run: |
5163
corepack npm ci
52-
corepack npm run build
64+
65+
WORK="$PWD"
66+
node \
67+
--permission \
68+
--allow-fs-read="$WORK" \
69+
--allow-fs-write="$WORK" \
70+
./node_modules/typescript/bin/tsc -p .
71+
if [ -x ./node_modules/typedoc/bin/typedoc ]; then
72+
node \
73+
--permission \
74+
--allow-fs-read="$WORK" \
75+
--allow-fs-write="$WORK" \
76+
./node_modules/typedoc/bin/typedoc
77+
fi
78+
5379
corepack npm publish

0 commit comments

Comments
 (0)