From d7c936a078cfa8062a3a43ffc8ee1e441fd689f6 Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Fri, 7 Aug 2026 15:20:06 -0400 Subject: [PATCH] fix(ito): require verified npm provenance --- scripts/ito.js | 25 +++++++++++-------------- skills/ito-compute/SKILL.md | 19 +++++++++---------- tests/ci/ito-compute-skill.test.js | 7 ++++--- tests/scripts/ito-cli-bridge.test.js | 9 +++++---- 4 files changed, 29 insertions(+), 31 deletions(-) diff --git a/scripts/ito.js b/scripts/ito.js index 1e0c83846..9f489c265 100755 --- a/scripts/ito.js +++ b/scripts/ito.js @@ -14,7 +14,6 @@ const SUPPORTED_COMMANDS = Object.freeze([ "login", "logout", "auth", "find", "status", "evals", "serve", "train", "workload-status", "workload-cancel", "workload-cleanup", ]); -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("/"), @@ -65,15 +64,14 @@ Important: - Workload cancellation and cleanup never terminate the paid entitlement. - Inventory and RFQs are not reservations; only a returned firm quote is firm. -The canonical package is currently unpublished. Install it locally: - Canonical source: Ito-Markets/ito-cloud-runtime/${CANONICAL_PACKAGE_PATH} - git clone ${CANONICAL_REPOSITORY} - cd ito-cloud-runtime/${CANONICAL_PACKAGE_PATH} - npm ci - npm run check +The canonical package is currently unpublished. Do not clone a private source +repository as an installation requirement. After an official Itô release record +identifies the npm publisher, provenance, and expected integrity, verify those +values and then install the recorded version: + npm install --global ito-compute-cli@0.1.0 Then set ${EXECUTABLE_OVERRIDE} to the explicit absolute built entry: - /absolute/path/to/ito-cloud-runtime/${CANONICAL_PACKAGE_PATH}/dist/bin/ito.js + /absolute/npm/root/ito-compute-cli/dist/bin/ito.js For safety, ECC never discovers this credential-bearing client through PATH. @@ -83,7 +81,7 @@ The same package's MCP server exposes only: ito_status Configure the MCP command as "node" with this absolute argument: - /absolute/path/to/ito-cloud-runtime/${CANONICAL_PACKAGE_PATH}/dist/bin/ito-mcp.js + /absolute/npm/root/ito-compute-cli/dist/bin/ito-mcp.js Device login never inherits ITO_API_KEY. The auth, find, and status commands forward ITO_API_KEY directly when configured; ITO_AUTH_MODE=legacy is not @@ -240,10 +238,10 @@ function resolveItoExecutable(environment = process.env) { if (!configured) { throw new Error([ "The canonical ito-compute-cli is unpublished and ECC will not resolve", - `a credential-bearing "ito" executable from PATH. Build it from`, - `${CANONICAL_REPOSITORY.replace(/\.git$/, "")}/${CANONICAL_PACKAGE_PATH},`, - "run npm ci and npm run check, then set", - `${EXECUTABLE_OVERRIDE} to the explicit absolute dist/bin/ito.js path.`, + `a credential-bearing "ito" executable from PATH. Do not clone a private`, + "repository. Wait for an official Itô release record with verified npm", + "publisher, provenance, and integrity; install that artifact, then set", + `${EXECUTABLE_OVERRIDE} to its explicit absolute dist/bin/ito.js path.`, ].join(" ")); } @@ -366,7 +364,6 @@ if (require.main === module) { module.exports = Object.freeze({ CANONICAL_PACKAGE_PATH, - CANONICAL_REPOSITORY, EXECUTABLE_OVERRIDE, NODE_QUALIFICATION_TIMEOUT_MS, SUPPORTED_COMMANDS, diff --git a/skills/ito-compute/SKILL.md b/skills/ito-compute/SKILL.md index 5d97e1bf2..2ea249fef 100644 --- a/skills/ito-compute/SKILL.md +++ b/skills/ito-compute/SKILL.md @@ -11,20 +11,19 @@ server. ECC itself does no browser automation. ## Install the canonical local package -`ito-compute-cli` is currently unpublished. Build it from its canonical -repository instead of using `npx`, `npm exec`, or an unverified package: +`ito-compute-cli` is currently unpublished. Do not clone a private repository +as an installation requirement. Install only after an official Itô release +record identifies the npm publisher, provenance, and expected integrity and +those values match the registry artifact: ```sh -git clone https://github.com/Ito-Markets/ito-cloud-runtime.git -cd ito-cloud-runtime/cli/ito-compute-cli -npm ci -npm run check +npm install --global ito-compute-cli@0.1.0 ``` Set `ECC_ITO_CLI_EXECUTABLE` to the explicit absolute built entry: ```text -/absolute/path/to/ito-cloud-runtime/cli/ito-compute-cli/dist/bin/ito.js +/absolute/npm/root/ito-compute-cli/dist/bin/ito.js ``` ECC never discovers this credential-bearing client through `PATH`. @@ -132,8 +131,8 @@ recover, repair, reset, purchase, or order resources. ECC does not forward ## MCP workflow -Build the canonical package, then configure the stdio server with an absolute -path: +After installing the verified canonical npm artifact, configure its stdio +server with an absolute path: ```json { @@ -141,7 +140,7 @@ path: "ito-compute": { "command": "node", "args": [ - "/absolute/path/to/ito-cloud-runtime/cli/ito-compute-cli/dist/bin/ito-mcp.js" + "/absolute/npm/root/ito-compute-cli/dist/bin/ito-mcp.js" ] } } diff --git a/tests/ci/ito-compute-skill.test.js b/tests/ci/ito-compute-skill.test.js index 58ccfa155..393cbbd33 100644 --- a/tests/ci/ito-compute-skill.test.js +++ b/tests/ci/ito-compute-skill.test.js @@ -53,9 +53,10 @@ function main() { /ito_lock|ito_run|ITO_CLI_DEMO|paper mode|simulated|live on the registry|publishing soon/i ); assert.match(skill, /unpublished/i); - assert.match(skill, /Ito-Markets\/ito-cloud-runtime/); - assert.match(skill, /cli\/ito-compute-cli/); - assert.match(skill, /npm run check/); + assert.match(skill, /official Itô release\s+record/i); + assert.match(skill, /publisher, provenance, and expected integrity/i); + assert.match(skill, /npm install --global ito-compute-cli@0\.1\.0/); + assert.doesNotMatch(skill, /git clone|npm ci/i); assert.match(skill, /ECC_ITO_CLI_EXECUTABLE/); assert.match(skill, /explicit absolute built entry/); assert.match(skill, /never discovers[^\n]*through `PATH`/); diff --git a/tests/scripts/ito-cli-bridge.test.js b/tests/scripts/ito-cli-bridge.test.js index d657b9d82..f9536289c 100644 --- a/tests/scripts/ito-cli-bridge.test.js +++ b/tests/scripts/ito-cli-bridge.test.js @@ -14,7 +14,6 @@ const { spawn, spawnSync } = require("child_process"); const REPO_ROOT = path.join(__dirname, "..", ".."); const ECC_SCRIPT = path.join(REPO_ROOT, "scripts", "ecc.js"); const ITO_SCRIPT = path.join(REPO_ROOT, "scripts", "ito.js"); -const CANONICAL_PACKAGE = "Ito-Markets/ito-cloud-runtime/cli/ito-compute-cli"; const { NODE_QUALIFICATION_TIMEOUT_MS, } = require("../../scripts/ito"); @@ -620,8 +619,8 @@ async function main() { }); assert.notStrictEqual(result.status, 0); assert.match(result.stderr, /canonical ito-compute-cli is unpublished/i); - assert.match(result.stderr, new RegExp(CANONICAL_PACKAGE.replaceAll("/", "\\/"))); - assert.match(result.stderr, /npm run check/); + assert.match(result.stderr, /official Itô release record/i); + assert.match(result.stderr, /publisher, provenance, and integrity/i); assert.match(result.stderr, /ECC_ITO_CLI_EXECUTABLE/); assert.match(result.stderr, /explicit absolute/i); assert.match(result.stderr, /unpublished/i); @@ -773,7 +772,9 @@ async function main() { assert.match(result.stdout, /ito_auth/); assert.match(result.stdout, /ito_find/); assert.match(result.stdout, /ito_status/); - assert.match(result.stdout, new RegExp(CANONICAL_PACKAGE.replaceAll("/", "\\/"))); + assert.match(result.stdout, /npm install --global ito-compute-cli@0\.1\.0/); + assert.match(result.stdout, /publisher, provenance, and expected integrity/i); + assert.doesNotMatch(result.stdout, /git clone/i); assert.match(result.stdout, /unpublished/i); assert.match(result.stdout, /never discovers[^\n]*through PATH/i); assert.match(result.stdout, /device authorization/i);