Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions apps/server/src/cloud/pinnedRuntime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,67 @@ it.layer(NodeServices.layer)("ensurePinnedRuntimeInstalled", (it) => {
}),
);

it.effect("drops every spelling of the inherited allow-scripts policy from the installer", () =>
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const baseDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-pinned-runtime-env-" });
// npx exports the lowercase name and npm reads the uppercase one just the
// same. Unrelated npm configuration must still reach the child.
const stubbed = {
npm_config_allow_scripts: "true",
NPM_CONFIG_ALLOW_SCRIPTS: "true",
npm_config_registry: "https://registry.example.test/",
};
const previous = Object.fromEntries(
Object.keys(stubbed).map((key) => [key, process.env[key]]),
);
Object.assign(process.env, stubbed);
yield* Effect.addFinalizer(() =>
Effect.sync(() => {
for (const [key, value] of Object.entries(previous)) {
if (value === undefined) delete process.env[key];
else process.env[key] = value;
}
}),
);

// Spawn a real child with exactly what the installer hands npm, so the
// assertion covers the environment the child sees rather than the input.
const real = yield* Effect.service(ProcessRunner.ProcessRunner).pipe(
Effect.provide(ProcessRunner.layer),
);
const inner = successfulRunner(fs, path);
let childEnv: Record<string, string | undefined> | undefined;
const runner = ProcessRunner.ProcessRunner.of({
run: (input) =>
Effect.gen(function* () {
const probe = yield* real.run({
...input,
command: process.execPath,
args: ["-e", "process.stdout.write(JSON.stringify(process.env))"],
});
childEnv = JSON.parse(probe.stdout) as Record<string, string | undefined>;
return yield* inner.run(input);
}),
});

yield* ensurePinnedRuntimeInstalled({
baseDir,
version: "1.2.3",
fs,
path,
runner,
validate: () => Effect.void,
});

assert.isDefined(childEnv);
assert.notProperty(childEnv, "npm_config_allow_scripts");
assert.notProperty(childEnv, "NPM_CONFIG_ALLOW_SCRIPTS");
assert.equal(childEnv.npm_config_registry, "https://registry.example.test/");
}),
);

it.effect("removes staging when installation is interrupted", () =>
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
Expand Down
14 changes: 14 additions & 0 deletions apps/server/src/cloud/pinnedRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as PlatformError from "effect/PlatformError";
import * as Schema from "effect/Schema";
import * as Option from "effect/Option";
import * as Semaphore from "effect/Semaphore";
import { HostProcessEnvironment } from "@t3tools/shared/hostProcess";

import * as ProcessRunner from "../processRunner.ts";

Expand Down Expand Up @@ -161,10 +162,22 @@ const installPinnedRuntime = Effect.fn("cloud.pinned_runtime.ensure_installed")(
"--no-audit",
`t3@${input.version}`,
];
// npx exports its resolved allow-scripts policy as npm_config_allow_scripts,
// which npm 12 reads as a project-scoped --allow-scripts and refuses with
// EALLOWSCRIPTS. npm matches config variable names case-insensitively, so
// unset every spelling the child would inherit (Node drops undefined
// entries) and leave the rest of the npm configuration alone.
const hostEnvironment = yield* HostProcessEnvironment;
const installEnv = Object.fromEntries(
Object.keys(hostEnvironment)
.filter((key) => /^npm_config_allow[-_]scripts$/i.test(key))
.map((key) => [key, undefined]),
);
yield* runner
.run({
command: "npm",
args: installArgs,
env: installEnv,
// Native dependencies may compile from source on slower machines.
timeout: PINNED_RUNTIME_INSTALL_TIMEOUT,
})
Expand All @@ -178,6 +191,7 @@ const installPinnedRuntime = Effect.fn("cloud.pinned_runtime.ensure_installed")(
runner.run({
command: "pnpm",
args: ["--package=npm@11", "dlx", "npm", ...installArgs],
env: installEnv,
timeout: PINNED_RUNTIME_INSTALL_TIMEOUT,
})
: Effect.fail(error),
Expand Down
Loading