Files
scriptc/tests/harness/sandbox-config.test.ts
Chris Tate cc75597869 Shorten the CI critical path (#605)
* Shorten the CI critical path

* Bound Effect runner memory and avoid repeated type checks
2026-10-01 22:18:40 -05:00

319 lines
11 KiB
TypeScript

import { readFileSync } from "node:fs";
import { expect, test } from "vitest";
import {
defaultSandboxImage,
sandboxBootstrapCommand,
sandboxEffectWorkerAllocation,
sandboxImageConfig,
sandboxRunnerConfig,
sandboxTestSourceConfig,
sandboxTestWorkerAllocation,
sandboxVcrConfig,
sandboxVercelConfig,
sandboxVercelEnvironment,
} from "../../scripts/sandbox-config.mjs";
const oidcToken = (claims: object) =>
["header", Buffer.from(JSON.stringify(claims)).toString("base64url"), "signature"].join(".");
test("runner settings are read after loading the sandbox environment", () => {
expect(
sandboxRunnerConfig({
SCRIPTC_SANDBOX_VCPUS: "16",
SCRIPTC_TEST_WORKERS: "7",
SCRIPTC_LOCAL_TEST_WORKERS: "3",
SCRIPTC_LOCAL_CASE_SHARDS: "4",
SCRIPTC_SANDBOX_TIMEOUT: "90m",
}),
).toEqual({
vcpus: "16",
testWorkers: "7",
localTestWorkers: "3",
localCaseShards: "4",
sandboxTimeout: "90m",
sandboxTimeoutMs: 5_400_000,
});
});
test("runner settings retain their documented defaults", () => {
expect(sandboxRunnerConfig({})).toEqual({
vcpus: "8",
testWorkers: "4",
localTestWorkers: "2",
localCaseShards: "2",
sandboxTimeout: "45m",
sandboxTimeoutMs: 2_700_000,
});
});
test("the local command deadline follows the configured Sandbox duration", () => {
for (const [duration, milliseconds] of [["120m", 7_200_000], ["2h", 7_200_000], ["30 s", 30_000], ["500ms", 500]] as const) {
expect(sandboxRunnerConfig({ SCRIPTC_SANDBOX_TIMEOUT: duration }).sandboxTimeoutMs).toBe(milliseconds);
}
for (const duration of ["0m", "-1h", "forever", "1.5m", "999999999h"]) {
expect(() => sandboxRunnerConfig({ SCRIPTC_SANDBOX_TIMEOUT: duration })).toThrow("positive duration");
}
});
test("the managed Sandbox image is the default", () => {
expect(sandboxImageConfig({})).toEqual({
custom: false,
reference: defaultSandboxImage,
sandboxImage: "vercel/sandbox/universal",
});
});
test("the managed image bootstraps the ScriptC native toolchain and workspace", () => {
const bootstrap = sandboxBootstrapCommand(false);
expect(bootstrap?.prepareWorkspace).toMatchObject({ command: "sh", workdir: "/vercel" });
expect(bootstrap?.prepareWorkspace.args.join(" ")).toContain("mkdir -p /workspace");
expect(bootstrap?.install).toEqual({
args: ["scripts/sandbox-bootstrap.sh"],
command: "sh",
workdir: "/workspace",
});
expect(sandboxBootstrapCommand(true)).toBeUndefined();
});
test("the managed-image bootstrap pins the custom image's Node, pnpm, and LLVM", () => {
const bootstrap = readFileSync(new URL("../../scripts/sandbox-bootstrap.sh", import.meta.url), "utf8");
expect(bootstrap).toContain("< .node-version");
expect(bootstrap).toContain("ARG PNPM_VERSION=");
expect(bootstrap).toContain("llvm-toolchain-${llvm_distro}-22");
expect(bootstrap).toContain("install -D -m 0644");
expect(bootstrap).toContain("clang-22");
expect(bootstrap).toContain("libclang-rt-22-dev");
expect(bootstrap).toContain("llvm-22-dev");
expect(bootstrap).toContain("ninja-build");
});
test("a custom image does not select the Sandbox team or project", () => {
expect(
sandboxImageConfig({
SCRIPTC_SANDBOX_IMAGE: "vcr.vercel.com/image-team/image-project/scriptc-tests:node24",
}),
).toEqual({
custom: true,
reference: "vcr.vercel.com/image-team/image-project/scriptc-tests:node24",
repository: "scriptc-tests",
sandboxImage: "vcr.vercel.com/image-team/image-project/scriptc-tests:node24",
tag: "node24",
});
});
test("custom images must be fully qualified VCR references", () => {
expect(() => sandboxImageConfig({ SCRIPTC_SANDBOX_IMAGE: "scriptc-tests:node24" })).toThrow(
"fully qualified VCR image",
);
});
test("prepared snapshots select the snapshot CLI source without changing project scope", () => {
const config = sandboxTestSourceConfig({ SCRIPTC_SANDBOX_SNAPSHOT: " snap_ABC123 " });
expect(config).toEqual({
prepared: true, reference: "snap_ABC123", description: "prepared snapshot", createArgs: ["--snapshot", "snap_ABC123"],
});
expect(sandboxBootstrapCommand(config.prepared)).toBeUndefined();
});
test("test sources retain managed and custom image preparation", () => {
expect(sandboxTestSourceConfig({})).toMatchObject({ prepared: false, createArgs: ["--image", defaultSandboxImage] });
const image = "vcr.vercel.com/team/project/tests:node24";
expect(sandboxTestSourceConfig({ SCRIPTC_SANDBOX_IMAGE: image })).toMatchObject({ prepared: true, createArgs: ["--image", image] });
});
test("ambiguous or malformed snapshot sources fail before creating workers", () => {
expect(() => sandboxTestSourceConfig({ SCRIPTC_SANDBOX_SNAPSHOT: "snap_ABC123", SCRIPTC_SANDBOX_IMAGE: "image" })).toThrow("Set only one");
expect(() => sandboxTestSourceConfig({ SCRIPTC_SANDBOX_SNAPSHOT: "wrong-id" })).toThrow("snapshot ID");
});
test("OIDC authentication wins and supplies its own Sandbox scope", () => {
const config = sandboxVercelConfig({
VERCEL_OIDC_TOKEN: "header.payload.signature",
VERCEL_TOKEN: "legacy-token",
});
expect(config).toMatchObject({
authSource: "VERCEL_OIDC_TOKEN",
authToken: "header.payload.signature",
oidc: true,
scopeArgs: [],
scopeSource: "VERCEL_OIDC_TOKEN claims",
});
expect(
sandboxVercelEnvironment(config, {
VERCEL_OIDC_TOKEN: "header.payload.signature",
VERCEL_TOKEN: "legacy-token",
}),
).toEqual({
VERCEL_AUTH_TOKEN: "header.payload.signature",
VERCEL_OIDC_TOKEN: "header.payload.signature",
});
});
test("OIDC scope wins over complete or partial legacy environment scope", () => {
for (const legacyScope of [
{ VERCEL_PROJECT_ID: "stale-project", VERCEL_TEAM_ID: "stale-team" },
{ VERCEL_TEAM_ID: "stale-team" },
]) {
expect(
sandboxVercelConfig({
...legacyScope,
VERCEL_OIDC_TOKEN: "header.payload.signature",
}),
).toMatchObject({
authSource: "VERCEL_OIDC_TOKEN",
oidc: true,
project: undefined,
scopeArgs: [],
scopeSource: "VERCEL_OIDC_TOKEN claims",
team: undefined,
});
}
});
test("access-token authentication uses explicit environment scope", () => {
expect(
sandboxVercelConfig({
VERCEL_PROJECT_ID: "prj_example",
VERCEL_TEAM_ID: "team_example",
VERCEL_TOKEN: "legacy-token",
}),
).toMatchObject({
authSource: "VERCEL_TOKEN",
authToken: "legacy-token",
oidc: false,
project: "prj_example",
scopeArgs: ["--scope", "team_example", "--project", "prj_example"],
scopeSource: "VERCEL_TEAM_ID + VERCEL_PROJECT_ID",
team: "team_example",
});
});
test("VCR uses an access-token fallback with scope decoded from OIDC claims", () => {
const token = oidcToken({ owner_id: "team_oidc", project_id: "prj_oidc" });
const config = sandboxVercelConfig({
VERCEL_OIDC_TOKEN: token,
VERCEL_PROJECT_ID: "stale-project",
VERCEL_TEAM_ID: "stale-team",
VERCEL_TOKEN: "registryaccesstoken",
});
expect(
sandboxVcrConfig(config, {
VERCEL_AUTH_TOKEN: "stale-auth-token",
VERCEL_OIDC_TOKEN: token,
VERCEL_TOKEN: "registryaccesstoken",
}),
).toEqual({
authSource: "VERCEL_TOKEN",
env: {
VERCEL_OIDC_TOKEN: token,
VERCEL_TOKEN: "registryaccesstoken",
},
scopeArgs: ["--scope", "team_oidc", "--project", "prj_oidc"],
scopeSource: "VERCEL_OIDC_TOKEN claims",
});
});
test("VCR never passes an OIDC JWT through VERCEL_TOKEN", () => {
const token = oidcToken({ owner_id: "team_oidc", project_id: "prj_oidc" });
const config = sandboxVercelConfig({
VERCEL_OIDC_TOKEN: token,
VERCEL_TOKEN: token,
});
expect(
sandboxVcrConfig(config, {
VERCEL_AUTH_TOKEN: token,
VERCEL_OIDC_TOKEN: token,
VERCEL_TOKEN: token,
}),
).toEqual({
authSource: "Vercel CLI login",
env: { VERCEL_OIDC_TOKEN: token },
scopeArgs: ["--scope", "team_oidc", "--project", "prj_oidc"],
scopeSource: "VERCEL_OIDC_TOKEN claims",
});
});
test("VCR uses the selected access token and explicit environment scope", () => {
const config = sandboxVercelConfig({
VERCEL_AUTH_TOKEN: "accesstoken",
VERCEL_PROJECT_ID: "prj_example",
VERCEL_TEAM_ID: "team_example",
});
expect(sandboxVcrConfig(config, { VERCEL_AUTH_TOKEN: "accesstoken" })).toEqual({
authSource: "VERCEL_AUTH_TOKEN",
env: { VERCEL_TOKEN: "accesstoken" },
scopeArgs: ["--scope", "team_example", "--project", "prj_example"],
scopeSource: "VERCEL_TEAM_ID + VERCEL_PROJECT_ID",
});
});
test("VCR rejects JWT-shaped access tokens when OIDC is not selected", () => {
const token = oidcToken({ owner_id: "team_example", project_id: "prj_example" });
const config = sandboxVercelConfig({
VERCEL_AUTH_TOKEN: token,
VERCEL_PROJECT_ID: "prj_example",
VERCEL_TEAM_ID: "team_example",
});
expect(() => sandboxVcrConfig(config, { VERCEL_AUTH_TOKEN: token })).toThrow(
"is not a VCR-compatible access token",
);
});
test("VCR rejects OIDC tokens without usable project claims", () => {
const token = oidcToken({ owner_id: "team_oidc" });
const config = sandboxVercelConfig({ VERCEL_OIDC_TOKEN: token });
expect(() => sandboxVcrConfig(config, { VERCEL_OIDC_TOKEN: token })).toThrow(
"owner_id and project_id claims",
);
});
test("access-token scope failures explain every required variable", () => {
expect(() => sandboxVercelConfig({ VERCEL_TOKEN: "legacy-token" })).toThrow(
"VERCEL_TOKEN requires VERCEL_TEAM_ID and VERCEL_PROJECT_ID",
);
expect(() => sandboxVercelConfig({ VERCEL_TEAM_ID: "team_example" })).toThrow(
"VERCEL_TEAM_ID and VERCEL_PROJECT_ID must be set together",
);
});
test("test processes stay within the per-Sandbox worker budget", () => {
expect(sandboxTestWorkerAllocation(4, 1)).toEqual({
caseWorkers: 3,
sideConcurrency: 1,
});
expect(sandboxTestWorkerAllocation(4, 2)).toEqual({
caseWorkers: 2,
sideConcurrency: 2,
});
expect(sandboxTestWorkerAllocation(2, 2)).toEqual({
caseWorkers: 1,
sideConcurrency: 1,
});
expect(sandboxTestWorkerAllocation(1, 2)).toEqual({
caseWorkers: 1,
sideConcurrency: 0,
});
});
test("isolated Effect concurrency stays within the budget and only uses large Sandboxes", () => {
for (const vcpus of [2, 8, 16, 30, 32]) {
for (const workers of [1, 2, 4, 8]) {
for (const sideTasks of [0, 1, 2, 3]) {
const plan = sandboxEffectWorkerAllocation(workers, sideTasks, vcpus);
expect(plan.caseWorkers).toBeGreaterThanOrEqual(1);
const extraCompilers = Math.min(2, plan.caseWorkers) * (plan.effectConcurrency - 1);
expect(plan.caseWorkers + plan.sideConcurrency + extraCompilers).toBeLessThanOrEqual(workers);
expect(plan.sideConcurrency).toBeLessThanOrEqual(sideTasks);
expect(plan.effectConcurrency === 2).toBe(vcpus === 32 && workers >= 4);
}
}
}
expect(() => sandboxEffectWorkerAllocation(0, 1, 32)).toThrow();
expect(() => sandboxEffectWorkerAllocation(4, -1, 32)).toThrow();
});