Files
pastilhasandClaude Opus 5 f2052fbdaa freeze installs: bun resolves from the lockfile or fails
bunfig.toml sets [install] frozenLockfile = true, so `bun install` resolves from
bun.lock and nothing else — it fails rather than quietly picking up a newer
version, including a transitive one nobody chose.

Config rather than a documented habit, because a supply-chain compromise does not
wait for the one time somebody forgets a flag. On 2026-08-04 eleven cache
packages — keyv, flat-cache, file-entry-cache, cacheable-request, cache-manager,
the @cacheable/* scope and ecto — were published with a preinstall dropper that
harvested npm and GitHub tokens, AWS and Kubernetes credentials, SSH and PEM
keys, .env files and .claude/settings.json, then republished itself through any
npm token it found, reaching 434 further packages across 1381 versions. This
machine was unaffected only because nothing had installed since 2026-08-02.

Verified on bun 1.3.10 rather than assumed, and the first result was wrong: with
NO lockfile present, neither the flag nor the config refuses — bun simply creates
one, so an initial test made the setting look ignored. Against a lockfile that no
longer satisfies package.json, both exit 1 with "lockfile had changes, but
lockfile is frozen". The config is honoured; the earlier reading was a bad test.
`bun install` in this repo still reports 1058 installs, no changes.

Applied to monorepo-mobile too, where flat-cache, file-entry-cache and keyv are
present as eslint/got transitive deps — at versions old enough to be unaffected,
which was luck rather than design.

Documented in platform/CLAUDE.md and the workspace root, including the part that
matters most: do NOT add --no-frozen-lockfile to a script, a Dockerfile or CI to
make the error go away. The error means the lockfile and package.json disagree,
and an unexplained lockfile change in a diff is precisely the signal this exists
to produce.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 17:58:07 +00:00

26 lines
1.2 KiB
TOML

# Every install resolves from bun.lock and nothing else. `bun install` fails rather than quietly
# resolving a new version — including a transitive one nobody asked for.
#
# This is here rather than in a habit or a README because a supply-chain compromise does not wait for
# the one time somebody forgets the flag. On 2026-08-04 eleven cache packages (keyv, flat-cache,
# file-entry-cache, cacheable-request and friends) were published with a `preinstall` dropper that
# harvested npm and GitHub tokens, cloud credentials, SSH keys, .env files and .claude/settings.json,
# then republished itself through any token it found. It spread to 434 more packages. A floating
# transitive range is all it takes; a frozen lockfile is the difference between "we were not affected"
# and "we ran `bun install` on the wrong afternoon".
#
# When a dependency genuinely needs to change: edit package.json, run `bun install --no-frozen-lockfile`
# deliberately, READ the lockfile diff, and commit it. The friction is the point.
[install]
frozenLockfile = true
[serve.static]
plugins = ["bun-plugin-tailwind"]
env = "BUN_PUBLIC_*"
[test]
coverage = true
coverageDir = "coverage"
preload = ["./test-setup.ts"]
root = "./src"