Unverified 提交 61c49948 authored 作者: keppo-bot[bot]'s avatar keppo-bot[bot] 提交者: GitHub

fix: pin socket firewall npx invocation (#3163)

## Summary - run Socket Firewall through `npx sfw@2.0.4` instead of relying on a global install - keep the socket firewall command path reproducible and avoid Windows global path issues - update command-shape assertions in the related IPC tests ## Test plan - npm run fmt - npm run lint:fix - npm run ts - npm test <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/dyad-sh/dyad/pull/3163" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> --------- Co-authored-by: 's avatarWill Chen <7344640+wwwillchen@users.noreply.github.com> Co-authored-by: 's avatarClaude Opus 4.5 <noreply@anthropic.com>
上级 7b74c5f2
......@@ -102,7 +102,7 @@ describe("processFullResponseActions add dependency errors", () => {
new ExecuteAddDependencyError({
error: new CommandExecutionError({
message:
"Command 'sfw npm install --legacy-peer-deps react' exited with code 1",
"Command 'npx sfw@2.0.4 npm install --legacy-peer-deps react' exited with code 1",
stderr:
"Socket Firewall blocked react<malware>\nPolicy: malware package",
exitCode: 1,
......
......@@ -31,13 +31,37 @@ describe("detectPreferredPackageManager", () => {
describe("buildAddDependencyCommand", () => {
it.each<[PackageManager, boolean, { command: string; args: string[] }]>([
["pnpm", true, { command: "sfw", args: ["pnpm", "add", "react", "zod"] }],
[
"pnpm",
true,
{
command: "npx",
args: [
"--prefer-offline",
"--yes",
"sfw@2.0.4",
"pnpm",
"add",
"react",
"zod",
],
},
],
[
"npm",
true,
{
command: "sfw",
args: ["npm", "install", "--legacy-peer-deps", "react", "zod"],
command: "npx",
args: [
"--prefer-offline",
"--yes",
"sfw@2.0.4",
"npm",
"install",
"--legacy-peer-deps",
"react",
"zod",
],
},
],
["pnpm", false, { command: "pnpm", args: ["add", "react", "zod"] }],
......@@ -69,34 +93,30 @@ describe("ensureSocketFirewallInstalled", () => {
available: true,
});
expect(runner).toHaveBeenCalledTimes(1);
expect(runner).toHaveBeenCalledWith("sfw", ["--help"]);
expect(runner).toHaveBeenCalledWith("npx", [
"--prefer-offline",
"--yes",
"sfw@2.0.4",
"--help",
]);
});
it("installs sfw when missing and returns available", async () => {
it("returns a warning when sfw cannot be run through npx", async () => {
const runner = vi
.fn<CommandRunner>()
.mockRejectedValueOnce(new Error("sfw missing"))
.mockResolvedValueOnce({ stdout: "installed", stderr: "" })
.mockResolvedValueOnce({ stdout: "", stderr: "" });
await expect(ensureSocketFirewallInstalled(runner)).resolves.toEqual({
available: true,
});
expect(runner).toHaveBeenNthCalledWith(1, "sfw", ["--help"]);
expect(runner).toHaveBeenNthCalledWith(2, "npm", ["install", "-g", "sfw"]);
expect(runner).toHaveBeenNthCalledWith(3, "sfw", ["--help"]);
});
it("returns a warning when sfw cannot be installed", async () => {
const runner = vi
.fn<CommandRunner>()
.mockRejectedValueOnce(new Error("sfw missing"))
.mockRejectedValueOnce(new Error("npm install failed"));
.mockRejectedValueOnce(new Error("npx sfw failed"));
await expect(ensureSocketFirewallInstalled(runner)).resolves.toEqual({
available: false,
warningMessage: SOCKET_FIREWALL_WARNING_MESSAGE,
});
expect(runner).toHaveBeenCalledTimes(1);
expect(runner).toHaveBeenCalledWith("npx", [
"--prefer-offline",
"--yes",
"sfw@2.0.4",
"--help",
]);
});
});
......
......@@ -2,6 +2,12 @@ import { spawn } from "node:child_process";
export const SOCKET_FIREWALL_WARNING_MESSAGE =
"the npm firewall could not be installed. Warning: can not check if npm packages are safe";
const SOCKET_FIREWALL_PACKAGE = "sfw@2.0.4";
const SOCKET_FIREWALL_NPX_ARGS = [
"--prefer-offline",
"--yes",
SOCKET_FIREWALL_PACKAGE,
];
export interface CommandExecutionOptions {
cwd?: string;
......@@ -137,12 +143,7 @@ export async function ensureSocketFirewallInstalled(
warningMessage?: string;
}> {
try {
await runner("sfw", ["--help"]);
return { available: true };
} catch {
try {
await runner("npm", ["install", "-g", "sfw"]);
await runner("sfw", ["--help"]);
await runner("npx", [...SOCKET_FIREWALL_NPX_ARGS, "--help"]);
return { available: true };
} catch {
return {
......@@ -150,7 +151,6 @@ export async function ensureSocketFirewallInstalled(
warningMessage: SOCKET_FIREWALL_WARNING_MESSAGE,
};
}
}
}
export async function detectPreferredPackageManager(
......@@ -176,8 +176,13 @@ export function buildAddDependencyCommand(
if (useSocketFirewall) {
return {
command: "sfw",
args: [packageManager, ...packageManagerArgs],
// Use a pinned npx package so sfw stays reproducible and avoids global path issues on Windows.
command: "npx",
args: [
...SOCKET_FIREWALL_NPX_ARGS,
packageManager,
...packageManagerArgs,
],
};
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论