From 8045aecdf902229a0ab345b4c63ceb5c6ad55cad Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Thu, 23 Jul 2026 23:53:17 -0400 Subject: [PATCH] fix: require canonical Ito CLI entry path --- scripts/ito.js | 25 +++++++++++++++-- tests/scripts/ito-cli-bridge.test.js | 41 +++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/scripts/ito.js b/scripts/ito.js index bfd44c1d4..85f541b03 100755 --- a/scripts/ito.js +++ b/scripts/ito.js @@ -10,6 +10,12 @@ const { createSafeItoEnvironment } = require("./lib/ito-environment"); const SUPPORTED_COMMANDS = Object.freeze(["auth", "find", "status"]); const CANONICAL_REPOSITORY = "https://github.com/Ito-Markets/ito-cloud-runtime.git"; const CANONICAL_PACKAGE_PATH = "cli/ito-compute-cli"; +const CANONICAL_ENTRY_SEGMENTS = Object.freeze([ + ...CANONICAL_PACKAGE_PATH.split("/"), + "dist", + "bin", + "ito.js", +]); const EXECUTABLE_OVERRIDE = "ECC_ITO_CLI_EXECUTABLE"; const MAX_OUTPUT_BYTES = 10 * 1024 * 1024; @@ -127,7 +133,7 @@ function assertUsableExecutable(candidate) { `${EXECUTABLE_OVERRIDE} does not point to a readable local Itô CLI file.` ); } - if (path.extname(canonicalCandidate).toLowerCase() !== ".js") { + if (!isCanonicalItoEntry(canonicalCandidate)) { throw new Error( `${EXECUTABLE_OVERRIDE} must point to the canonical dist/bin/ito.js entry.` ); @@ -140,6 +146,21 @@ function assertUsableExecutable(candidate) { return canonicalCandidate; } +function isCanonicalItoEntry(candidate) { + const pathSegments = path + .normalize(candidate) + .split(path.sep) + .filter(Boolean); + if (pathSegments.length < CANONICAL_ENTRY_SEGMENTS.length) return false; + const candidateTail = pathSegments.slice(-CANONICAL_ENTRY_SEGMENTS.length); + return candidateTail.every((segment, index) => { + const expected = CANONICAL_ENTRY_SEGMENTS[index]; + return process.platform === "win32" + ? segment.toLowerCase() === expected.toLowerCase() + : segment === expected; + }); +} + function isUsableExecutable(candidate) { try { const info = fs.statSync(candidate); @@ -152,7 +173,7 @@ function isUsableExecutable(candidate) { } function buildInvocation(executable, args) { - if (path.extname(executable).toLowerCase() !== ".js") { + if (!isCanonicalItoEntry(executable)) { throw new Error( `Refusing to invoke an Itô CLI shim. Set ${EXECUTABLE_OVERRIDE} to the absolute dist/bin/ito.js path.` ); diff --git a/tests/scripts/ito-cli-bridge.test.js b/tests/scripts/ito-cli-bridge.test.js index 41a8a80d7..ef896290e 100644 --- a/tests/scripts/ito-cli-bridge.test.js +++ b/tests/scripts/ito-cli-bridge.test.js @@ -30,8 +30,17 @@ function runCli(args, environment = {}) { function makeItoProbe(exitCode = 0) { const directory = fs.mkdtempSync(path.join(os.tmpdir(), "ecc-ito-cli-")); const log = path.join(directory, "invocation.json"); - const script = path.join(directory, "ito-probe.js"); + const script = path.join( + directory, + "ito-cloud-runtime", + "cli", + "ito-compute-cli", + "dist", + "bin", + "ito.js" + ); const executable = script; + fs.mkdirSync(path.dirname(script), { recursive: true }); fs.writeFileSync( script, [ @@ -265,6 +274,36 @@ function main() { fs.rmSync(directory, { recursive: true, force: true }); } }], + ["rejects a readable JavaScript decoy outside the canonical package entry", () => { + const directory = fs.mkdtempSync(path.join(os.tmpdir(), "ecc-hostile-ito-js-")); + const decoy = path.join(directory, "ito.js"); + const stolenEnvironment = path.join(directory, "stolen.json"); + try { + fs.writeFileSync( + decoy, + [ + '"use strict";', + 'const fs = require("fs");', + `fs.writeFileSync(${JSON.stringify(stolenEnvironment)}, JSON.stringify(process.env));`, + "", + ].join("\n") + ); + + const result = runCli(["ito", "auth"], { + ECC_ITO_CLI_EXECUTABLE: decoy, + ITO_API_KEY: "must-never-reach-js-decoy", + }); + + assert.notStrictEqual(result.status, 0); + assert.match(result.stderr, /canonical dist\/bin\/ito\.js/i); + assert.ok( + !fs.existsSync(stolenEnvironment), + "an arbitrary JavaScript file must never receive the Itô credential" + ); + } finally { + fs.rmSync(directory, { recursive: true, force: true }); + } + }], ["rejects a relative executable override instead of searching or guessing", () => { const result = runCli(["ito", "status"], { ECC_ITO_CLI_EXECUTABLE: "ito",