diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ca11ea73..07800c3d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -56,6 +56,12 @@ pnpm install # Install all workspace dependencies CI installs with `pnpm install --frozen-lockfile`; commit an updated `pnpm-lock.yaml` when you change dependencies. +The workspace intentionally skips the optional `ssh2` and `cpu-features` native +install scripts. Scope uses `ssh2` only transitively through Docker test tooling, +and its supported JavaScript implementation preserves that behavior without a +Python/compiler toolchain. Keep required dependency build scripts allowlisted in +`pnpm-workspace.yaml`; do not replace this narrow policy with `--ignore-scripts`. + ## Local development Local authentication requires your browser to trust a development certificate. diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5bcac71d..425060e0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -34,11 +34,14 @@ packages: ignoredBuiltDependencies: - '@scarf/scarf' + # ssh2 works without these optional native accelerators. Scope reaches ssh2 + # only through Docker test tooling, so keep clean image installs on its + # supported JavaScript fallback instead of invoking node-gyp. + - cpu-features + - ssh2 onlyBuiltDependencies: - '@vscode/vsce-sign' - - cpu-features - esbuild - keytar - protobufjs - - ssh2 diff --git a/scripts/bootstrap-pnpm.test.ts b/scripts/bootstrap-pnpm.test.ts index f0307618..c86cd1ad 100644 --- a/scripts/bootstrap-pnpm.test.ts +++ b/scripts/bootstrap-pnpm.test.ts @@ -10,12 +10,16 @@ import { rmSync, writeFileSync, } from "node:fs"; +import { createRequire } from "node:module"; import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; const script = resolve("scripts/bootstrap-pnpm.sh"); const temporaryDirectories: string[] = []; +const { parse } = createRequire(resolve("packages/shared/package.json"))( + "yaml", +) as typeof import("yaml"); const nodeDockerfiles = [ "apps/api/Dockerfile", "apps/judge/Dockerfile", @@ -40,6 +44,12 @@ interface BootstrapFixture { env: NodeJS.ProcessEnv; } +interface PnpmWorkspaceConfig { + ignoredBuiltDependencies?: string[]; + onlyBuiltDependencies?: string[]; + ignoreDepScripts?: boolean; +} + /** * Creates fake Corepack and npm executables that capture registry configuration. */ @@ -231,6 +241,7 @@ describe("pnpm Docker bootstrap", () => { expect(contents, dockerfile).not.toMatch( /fetch[-_]retr(?:y|ies)|network-concurrency/i, ); + expect(contents, dockerfile).not.toContain("--ignore-scripts"); expect(packageInstallLines.length, dockerfile).toBeGreaterThan(0); for (const line of packageInstallLines) { expect(line, dockerfile).toContain( @@ -239,4 +250,22 @@ describe("pnpm Docker bootstrap", () => { } } }); + + it("uses ssh2's supported JavaScript fallback without suppressing other build scripts", () => { + const workspaceSource = readFileSync("pnpm-workspace.yaml", "utf8"); + const workspace = parse(workspaceSource) as PnpmWorkspaceConfig; + + expect(workspace.ignoredBuiltDependencies).toEqual( + expect.arrayContaining(["cpu-features", "ssh2"]), + ); + expect(workspace.onlyBuiltDependencies).not.toContain("cpu-features"); + expect(workspace.onlyBuiltDependencies).not.toContain("ssh2"); + expect(workspace.onlyBuiltDependencies).toEqual( + expect.arrayContaining(["esbuild", "keytar", "protobufjs"]), + ); + expect(workspace.ignoreDepScripts).not.toBe(true); + expect(readFileSync(".npmrc", "utf8")).not.toMatch( + /^\s*ignore-scripts\s*=\s*true\s*$/m, + ); + }); });