fallow-similar-code 3.22.0 → 3.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fallow-similar-code",
3
- "version": "3.22.0",
3
+ "version": "3.23.0",
4
4
  "description": "First-party local embedding sidecar for Fallow similar-code analysis",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -26,13 +26,13 @@
26
26
  "detect-libc": "2.1.2"
27
27
  },
28
28
  "optionalDependencies": {
29
- "@fallow-cli/fallow-similar-code-darwin-arm64": "3.22.0",
30
- "@fallow-cli/fallow-similar-code-darwin-x64": "3.22.0",
31
- "@fallow-cli/fallow-similar-code-linux-x64-gnu": "3.22.0",
32
- "@fallow-cli/fallow-similar-code-linux-arm64-gnu": "3.22.0",
33
- "@fallow-cli/fallow-similar-code-linux-x64-musl": "3.22.0",
34
- "@fallow-cli/fallow-similar-code-linux-arm64-musl": "3.22.0",
35
- "@fallow-cli/fallow-similar-code-win32-x64-msvc": "3.22.0",
36
- "@fallow-cli/fallow-similar-code-win32-arm64-msvc": "3.22.0"
29
+ "@fallow-cli/fallow-similar-code-darwin-arm64": "3.23.0",
30
+ "@fallow-cli/fallow-similar-code-darwin-x64": "3.23.0",
31
+ "@fallow-cli/fallow-similar-code-linux-x64-gnu": "3.23.0",
32
+ "@fallow-cli/fallow-similar-code-linux-arm64-gnu": "3.23.0",
33
+ "@fallow-cli/fallow-similar-code-linux-x64-musl": "3.23.0",
34
+ "@fallow-cli/fallow-similar-code-linux-arm64-musl": "3.23.0",
35
+ "@fallow-cli/fallow-similar-code-win32-x64-msvc": "3.23.0",
36
+ "@fallow-cli/fallow-similar-code-win32-arm64-msvc": "3.23.0"
37
37
  }
38
38
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  const fs = require("node:fs");
4
4
  const path = require("node:path");
5
+ const os = require("node:os");
5
6
  const { spawn, spawnSync } = require("node:child_process");
6
7
  const { once } = require("node:events");
7
8
  const { getPlatformPackage, isPlatformPackage } = require("./platform-package");
@@ -72,8 +73,6 @@ const resolveBinaryArtifact = (
72
73
  });
73
74
  };
74
75
 
75
- const resolveBinary = (...args) => resolveBinaryArtifact(...args).binaryPath;
76
-
77
76
  const setupTimeoutFor = (args) => (args[0] === "setup" ? SETUP_PROCESS_TIMEOUT_MS : null);
78
77
 
79
78
  const spawnNative = (binaryPath, args, spawnProcess = spawnSync) => {
@@ -177,7 +176,8 @@ const run = async (args) => {
177
176
  }
178
177
  if (result.signal) {
179
178
  process.stderr.write(`fallow-similar-code terminated by signal ${result.signal}\n`);
180
- process.exit(1);
179
+ const signalNumber = os.constants.signals[result.signal];
180
+ process.exit(result.status ?? (signalNumber ? 128 + signalNumber : 1));
181
181
  }
182
182
  process.exit(result.status ?? 1);
183
183
  } catch (error) {
@@ -191,7 +191,6 @@ module.exports = {
191
191
  SETUP_PROCESS_TIMEOUT_MS,
192
192
  SETUP_TIMEOUT_EXIT_CODE,
193
193
  SETUP_TIMEOUT_MESSAGE,
194
- resolveBinary,
195
194
  resolveBinaryArtifact,
196
195
  resolvePlatformPackage,
197
196
  run,
@@ -3,12 +3,17 @@
3
3
  const assert = require("node:assert/strict");
4
4
  const test = require("node:test");
5
5
  const path = require("node:path");
6
+ const crypto = require("node:crypto");
7
+ const fs = require("node:fs");
8
+ const os = require("node:os");
9
+ const { spawn } = require("node:child_process");
10
+ const { once } = require("node:events");
11
+ const { resolvePlatformPackage } = require("./run-binary");
6
12
  const ownManifest = require("../package.json");
7
13
  const {
8
14
  SETUP_PROCESS_TIMEOUT_MS,
9
15
  SETUP_TIMEOUT_EXIT_CODE,
10
16
  SETUP_TIMEOUT_MESSAGE,
11
- resolveBinary,
12
17
  resolveBinaryArtifact,
13
18
  setupTimeoutFor,
14
19
  spawnNative,
@@ -21,19 +26,19 @@ const manifest = (overrides = {}) =>
21
26
 
22
27
  test("resolves an exact-version regular native binary", () => {
23
28
  const manifestPath = path.join("/packages", "native", "package.json");
24
- const resolved = resolveBinary(
29
+ const resolved = resolveBinaryArtifact(
25
30
  PACKAGE_NAME,
26
31
  () => manifestPath,
27
32
  () => manifest(),
28
33
  () => ({ isFile: () => true, isSymbolicLink: () => false }),
29
34
  );
30
- assert.equal(resolved, path.join("/packages", "native", "fallow-similar-code"));
35
+ assert.equal(resolved.binaryPath, path.join("/packages", "native", "fallow-similar-code"));
31
36
  });
32
37
 
33
38
  test("rejects a platform package from another release", () => {
34
39
  assert.throws(
35
40
  () =>
36
- resolveBinary(
41
+ resolveBinaryArtifact(
37
42
  PACKAGE_NAME,
38
43
  () => "/native/package.json",
39
44
  () => manifest({ version: "0.0.0" }),
@@ -46,7 +51,7 @@ test("rejects a platform package from another release", () => {
46
51
  test("rejects symlinked binaries", () => {
47
52
  assert.throws(
48
53
  () =>
49
- resolveBinary(
54
+ resolveBinaryArtifact(
50
55
  PACKAGE_NAME,
51
56
  () => "/native/package.json",
52
57
  () => manifest(),
@@ -163,3 +168,65 @@ test("spawns non-setup commands without a wrapper timeout", () => {
163
168
  assert.deepEqual(captured.args, ["status", "--json"]);
164
169
  assert.deepEqual(captured.options, { env: process.env, stdio: "inherit" });
165
170
  });
171
+
172
+ test(
173
+ "the signed setup launcher preserves forwarded SIGTERM as exit 143",
174
+ { skip: process.platform === "win32", timeout: 10_000 },
175
+ async (t) => {
176
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "fallow-setup-signal-"));
177
+ t.after(() => fs.rmSync(root, { recursive: true, force: true }));
178
+ const packageName = resolvePlatformPackage();
179
+ const packageDir = path.join(root, "node_modules", packageName);
180
+ fs.mkdirSync(packageDir, { recursive: true });
181
+ const binaryName = "fallow-similar-code";
182
+ const binaryPath = path.join(packageDir, binaryName);
183
+ const binary = Buffer.from(
184
+ "#!/usr/bin/env node\nprocess.on('SIGTERM', () => process.exit(0)); process.stdout.write('READY\\n'); setInterval(() => {}, 1000);\n",
185
+ );
186
+ const { privateKey, publicKey } = crypto.generateKeyPairSync("ed25519");
187
+ fs.writeFileSync(binaryPath, binary, { mode: 0o755 });
188
+ fs.writeFileSync(`${binaryPath}.sig`, crypto.sign(null, binary, privateKey));
189
+ fs.writeFileSync(
190
+ path.join(packageDir, "package.json"),
191
+ JSON.stringify({
192
+ name: packageName,
193
+ version: ownManifest.version,
194
+ fallowDigests: {
195
+ [binaryName]: `sha256:${crypto.createHash("sha256").update(binary).digest("hex")}`,
196
+ },
197
+ }),
198
+ );
199
+ // The real verifier checks a signed fixture using an ephemeral trust key.
200
+ // Package resolution, digest verification, spawning and signal forwarding all run.
201
+ const driver = `
202
+ const crypto = require("node:crypto");
203
+ const verifier = require(${JSON.stringify(require.resolve("./verify-binary"))});
204
+ const verify = verifier.verifyBinary;
205
+ const publicKey = crypto.createPublicKey(${JSON.stringify(publicKey.export({ type: "spki", format: "pem" }))});
206
+ verifier.verifyBinary = artifact => verify(artifact, { createPublicKey: () => publicKey });
207
+ require(${JSON.stringify(require.resolve("./run-binary"))}).run(["setup"]);
208
+ `;
209
+ const child = spawn(process.execPath, ["-e", driver], {
210
+ env: { ...process.env, NODE_PATH: path.join(root, "node_modules") },
211
+ stdio: ["ignore", "pipe", "pipe"],
212
+ });
213
+ t.after(() => child.kill("SIGKILL"));
214
+ let ready = false;
215
+ let stdout = "";
216
+ let stderr = "";
217
+ child.stdout.on("data", (chunk) => {
218
+ stdout += chunk.toString();
219
+ if (!ready && stdout.includes("READY")) {
220
+ ready = true;
221
+ child.kill("SIGTERM");
222
+ }
223
+ });
224
+ child.stderr.on("data", (chunk) => {
225
+ stderr += chunk.toString();
226
+ });
227
+ const [status, signal] = await once(child, "close");
228
+ assert.equal(ready, true, stderr);
229
+ assert.equal(signal, null);
230
+ assert.equal(status, 143, stderr);
231
+ },
232
+ );