Final-review fixes: stale env toggles, zip-slip, Windows exe, test env - #27
Merged
arcaputo3 merged 1 commit intoAug 27, 2026
Merged
Conversation
bunUseSystem and bunRequireLockfile read Task.env inside plain cached Tasks, so the documented workflows — toggling MILL_BUN_USE_SYSTEM, or MIGRATING-0.3's mid-migration MILL_BUN_REQUIRE_LOCKFILE=false — were silently ignored on a warm out/ until a manual clean. Both are Task.Input now, with a forked-eval integration test that toggles the requirement between runs on one warm out/ tree (confirmed failing with plain Task). mergeFromJar accepted `..` segments from jar entries: a dependency jar carrying the vendored marker could write arbitrary files during bunInstall without executing any code (zip-slip). Entries are backslash-normalized and refused when they climb out of the bundle root; a unit test builds a hostile jar and asserts refusal plus zero leakage. compileExecutable on Windows recorded a PathRef without the .exe bun actually appends — CreateProcess masked it in CI while downstream copies would fail and a missing path's constant signature broke invalidation. Both module kinds record the .exe name on Windows, and both integration tests now assert the recorded file exists. The TypeScript test trait gains bunTestEnv (default: outer bunRuntimeEnv), the test-side env lever mirroring bunTestJsEnv — overriding forkEnv on a test object compiles and does nothing. All six test-execution commands use it; the typescript-tests fixture asserts the variable reaches bun test. Generated member manifests now carry bunWorkspacePackageName (user packageJson.name still wins on TypeScript): overriding the name — the documented fix for colliding module names — previously satisfied Mill's duplicate guard while bun still saw the colliding defaults. The mixed-workspace fixture renames a member and asserts directory, manifest name, and vendor staging all follow. bunPublishedRuntimeInstall declared its .npmrc read as a Task.Source; the raw workspace read tripped Mill's filesystem checker the moment the file existed and never invalidated on change. Docs and CI: the README Scala.js quick start compiles now (missing scalalib import and utest dependency); the workspace snippet's imports are complete; the examples-CI version grep survives prerelease pins; RELEASING.md records why the release integration step deliberately omits PUBLISH_VERSION; MIGRATING-0.3 documents that deterministic conflict failure applies to every install, with npmOverrides as the escape hatch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
arcaputo3
merged commit Aug 27, 2026
6147ca7
into
agent/idiomatic-scalajs-mill-workflows
7 checks passed
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.
Final-review fixes for #13, from a four-reviewer adversarial pass over the complete
104-file diff against main. Targets
agent/idiomatic-scalajs-mill-workflows.Blocker
bunUseSystemandbunRequireLockfilereadTask.envinside plain cachedTask {}— thefirst-seen value was served until a manual
clean, so the documented workflows (togglingMILL_BUN_USE_SYSTEM; MIGRATING-0.3's mid-migrationMILL_BUN_REQUIRE_LOCKFILE=false) weresilently ignored on a warm
out/. Both areTask.Inputnow — the same fixpublishVersionandbunDownloadCacheDiralready had. New forked-eval integration test toggles the requirementbetween runs on one warm out/ tree; confirmed failing with plain
Task.Security
Zip-slip in
BunVendoredNodeModules.mergeFromJar. A dependency jar carrying the vendoredmarker plus an entry like
META-INF/bun/node_modules/../../../xproduced an arbitrary filewrite during
bunInstallof any module with that jar on its classpath — no dependency codeexecution required. Entries are now backslash-normalized and rejected when they climb out of
the bundle root. Unit test builds a hostile jar and asserts refusal plus zero leakage; confirmed
failing without the guard.
Majors
compileExecutablerecorded aPathRefto a file that doesn't exist (bun appends.exe; Win32 CreateProcess masked it by appending.exeat launch, so CI stayed green whiledownstream copies would fail and caching never invalidated). Both module kinds now record the
.exename on Windows, and both integration tests assert the recorded file exists.override def forkEnvon a testobject compiles and does nothing (only upstream's Node runners read it). New
bunTestEnvonthe test trait (default: outer
bunRuntimeEnv), used by all six test-execution commands,mirroring the Scala.js
bunTestJsEnv. The typescript-tests fixture overrides it and a buntest asserts the variable arrives.
bunWorkspacePackageNamewas ignored by generated member manifests — overriding it (thedocumented fix for colliding module names) satisfied Mill's duplicate guard while bun still
saw the colliding defaults. Both module kinds now emit it as the manifest
name(userpackageJson.namestill wins on TypeScript). The mixed-workspace fixture now renames a memberand asserts directory, manifest name, and vendor staging all follow.
bunPublishedRuntimeInstall— the raw.npmrcread trippedMill's filesystem checker the moment the file existed (exactly the private-registry case
vendored publishing serves), and never invalidated on change. Declared as a
Task.Source.import mill.scalalib.*and the utest dependency); the workspace snippet was missing two imports.
Minors
0.4.0-RC1).PUBLISH_VERSION(fixtures pin0.0.0-NIGHTLY) so nobody "fixes" it into breaking releases.publishing, with the
npmOverridesescape hatch.Reviewed and deliberately deferred (fast-follow candidates, not regressions)
System-mode Bun resolution caches PATH lookup and version verification until clean (needs a
design decision on re-probe cost); vendored publishing frozen-installs a reduced manifest
against the full lock (vendoring is opt-in and stub-covered — needs its own lock story); a
publish module's
unmanagedDepsare invisible to local moduleDeps consumers; dev-server syncthread resilience; error-message polish (raw ujson/HTTP/permission errors on exotic paths);
upstream
runTypeCheckignored; test-declared version of an outer package silently shadowed.