mirror of
https://github.com/affaan-m/ECC.git
synced 2026-08-17 21:15:40 +02:00
feat(ito): derive safe CLI forwarding from capabilities
This commit is contained in:
@@ -375,11 +375,11 @@ Kimi Code discovers the installed `.kimi-code/AGENTS.md` instructions and `.kimi
|
|||||||
|
|
||||||
### Itô compute CLI bridge
|
### Itô compute CLI bridge
|
||||||
|
|
||||||
`ecc ito` delegates to the separately installed canonical Itô client; ECC does not maintain a second API client. `ecc ito login [--no-browser]` performs device authorization, opens the Itô verification page by default, and persists a device token in macOS Keychain; `--no-browser` suppresses the page handoff. ECC itself does no browser automation. `ecc ito auth` is validation-only and rejects `--no-browser`. The available operations are `ecc ito login`, `ecc ito auth`, `ecc ito find`, `ecc ito status`, and the separately gated `ecc ito evals`. The matching MCP tools remain `ito_auth`, `ito_find`, and `ito_status`; `ito_auth` validates existing credentials and node qualification is CLI-only.
|
`ecc ito` delegates to the separately installed canonical Itô client; ECC does not maintain a second API client. `ecc ito login [--no-browser]` performs device authorization, opens the Itô verification page by default, and persists a device token in macOS Keychain; `--no-browser` suppresses the page handoff. ECC itself does no browser automation. `ecc ito auth` is validation-only and rejects `--no-browser`. The bridge validates the installed local-only `ito.cli.capabilities.v1` contract before every operation. Available operations include `ecc ito capabilities`, `login`, `logout`, `auth`, `find`, `status`, the no-side-effect `workload-status`, and the separately gated `evals`. The matching MCP tools remain `ito_auth`, `ito_find`, and `ito_status`; `ito_auth` validates existing credentials and node qualification is CLI-only.
|
||||||
|
|
||||||
The `ito-compute-cli` package is currently unpublished. Build it locally from the Itô runtime repo (private while the desk hardens; design partners get access) under `cli/ito-compute-cli`, run `npm ci` and `npm run check`, then set `ECC_ITO_CLI_EXECUTABLE` to that build's absolute `dist/bin/ito.js` path. Login never inherits `ITO_API_KEY`; auth, find, and status forward `ITO_API_KEY` directly when configured, and `ITO_AUTH_MODE=legacy` is not required. `ecc ito logout` revokes the current device credential and retains its local copy if remote revocation cannot be confirmed. Device tokens use macOS Keychain by default; explicit file fallback must retain owner-only directory/file permissions. ECC does not discover this credential-bearing client through `PATH`. See the [`ito-compute` skill](skills/ito-compute/SKILL.md) for the full RFQ authority and MCP setup contract.
|
The `ito-compute-cli` package is currently unpublished. Build it locally from the Itô runtime repo (private while the desk hardens; design partners get access) under `cli/ito-compute-cli`, run `npm ci` and `npm run check`, then set `ECC_ITO_CLI_EXECUTABLE` to that build's absolute `dist/bin/ito.js` path. Login never inherits `ITO_API_KEY`; auth, find, status, and workload-status forward `ITO_API_KEY` directly when configured, and `ITO_AUTH_MODE=legacy` is not required. `ecc ito logout` revokes the current device credential and retains its local copy if remote revocation cannot be confirmed. Device tokens use macOS Keychain by default; explicit file fallback must retain owner-only directory/file permissions. ECC does not discover this credential-bearing client through `PATH`. See the [`ito-compute` skill](skills/ito-compute/SKILL.md) for the full RFQ authority and MCP setup contract.
|
||||||
|
|
||||||
`find` submits a live authenticated RFQ. It does not reserve capacity. `evals` requires both `ITO_ENABLE_SIXTYTWO_LIVE=1` and `--live-sixtytwo`, a separately installed `sixtytwo-cli==0.3.33`, an explicit node list, and an existing absolute configuration directory. It cannot rent, launch, recover, repair, or purchase. ECC exposes no quote lock, purchase, workload, or inference path, and it never replaces a missing client or failed live call with a local result.
|
`find` submits a live authenticated RFQ. It does not reserve capacity. `workload-status` can inspect an already existing entitled run, but ECC blocks workload start, cancel, cleanup, quote lock, purchase, and inference effects even if the canonical CLI advertises them. `evals` requires both `ITO_ENABLE_SIXTYTWO_LIVE=1` and `--live-sixtytwo`, a separately installed `sixtytwo-cli==0.3.33`, an explicit node list, and an existing absolute configuration directory. It cannot rent, launch, recover, repair, or purchase. ECC never replaces a missing client or failed live call with a local result.
|
||||||
|
|
||||||
## Advanced Install Options
|
## Advanced Install Options
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,15 @@ Itô platform. ECC adds no shadow store.
|
|||||||
|
|
||||||
## Unsupported in this slice
|
## Unsupported in this slice
|
||||||
|
|
||||||
ECC exposes no quote lock, purchase, workload execution, or inference command.
|
ECC validates the canonical CLI's local-only `ito.cli.capabilities.v1` manifest
|
||||||
|
before forwarding. Supported commands with `side_effect: none` and `authority:
|
||||||
|
none` are derived from that manifest; this currently
|
||||||
|
adds `capabilities` and read-only `workload-status` without a handwritten
|
||||||
|
allowlist update.
|
||||||
|
|
||||||
|
ECC exposes no quote lock, purchase, workload start, cancel, cleanup, or
|
||||||
|
inference command. Those advertised effects remain outside the explicit ECC
|
||||||
|
policy.
|
||||||
Node qualification is live-only through the separately gated canonical
|
Node qualification is live-only through the separately gated canonical
|
||||||
adapter; the ECC bridge does not expose its paper fixture mode.
|
adapter; the ECC bridge does not expose its paper fixture mode.
|
||||||
|
|
||||||
@@ -164,7 +172,7 @@ after review.
|
|||||||
|
|
||||||
The local contract suite proves:
|
The local contract suite proves:
|
||||||
|
|
||||||
- only the six supported operations spawn;
|
- capability discovery plus seven reviewed target operations spawn;
|
||||||
- RFQ arguments are forwarded without economic reinterpretation;
|
- RFQ arguments are forwarded without economic reinterpretation;
|
||||||
- only approved Itô runtime or isolated node-qualification variables cross the
|
- only approved Itô runtime or isolated node-qualification variables cross the
|
||||||
process boundary;
|
process boundary;
|
||||||
|
|||||||
@@ -197,7 +197,7 @@
|
|||||||
{
|
{
|
||||||
"id": "capability:ito-compute",
|
"id": "capability:ito-compute",
|
||||||
"family": "capability",
|
"family": "capability",
|
||||||
"description": "Authenticated Itô GPU inventory, RFQ, status, device revocation, and explicitly gated node-qualification workflows through the separately installed canonical CLI.",
|
"description": "Capability-validated Itô GPU inventory, RFQ, status, read-only workload inspection, device revocation, and explicitly gated node-qualification workflows through the separately installed canonical CLI.",
|
||||||
"modules": [
|
"modules": [
|
||||||
"ito-compute"
|
"ito-compute"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -275,6 +275,7 @@ function runCommand(commandName, args) {
|
|||||||
env: commandName === 'ito'
|
env: commandName === 'ito'
|
||||||
? {
|
? {
|
||||||
...createSafeItoInvocationEnvironment(process.env, args, {
|
...createSafeItoInvocationEnvironment(process.env, args, {
|
||||||
|
deferCapabilityPolicy: true,
|
||||||
includeControls: true,
|
includeControls: true,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-10
@@ -6,11 +6,15 @@ const fs = require("fs");
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
const { spawnSync } = require("child_process");
|
const { spawnSync } = require("child_process");
|
||||||
const {
|
const {
|
||||||
|
createSafeItoEnvironment,
|
||||||
createSafeItoInvocationEnvironment,
|
createSafeItoInvocationEnvironment,
|
||||||
getInvocationCommand,
|
getInvocationCommand,
|
||||||
} = require("./lib/ito-environment");
|
} = require("./lib/ito-environment");
|
||||||
|
const {
|
||||||
|
authorizeEccCapability,
|
||||||
|
parseItoCapabilities,
|
||||||
|
} = require("./lib/ito-capabilities");
|
||||||
|
|
||||||
const SUPPORTED_COMMANDS = Object.freeze(["login", "logout", "auth", "find", "status", "evals"]);
|
|
||||||
const CANONICAL_REPOSITORY = "https://github.com/Ito-Markets/ito-cloud-runtime.git";
|
const CANONICAL_REPOSITORY = "https://github.com/Ito-Markets/ito-cloud-runtime.git";
|
||||||
const CANONICAL_PACKAGE_PATH = "cli/ito-compute-cli";
|
const CANONICAL_PACKAGE_PATH = "cli/ito-compute-cli";
|
||||||
const CANONICAL_ENTRY_SEGMENTS = Object.freeze([
|
const CANONICAL_ENTRY_SEGMENTS = Object.freeze([
|
||||||
@@ -21,6 +25,7 @@ const CANONICAL_ENTRY_SEGMENTS = Object.freeze([
|
|||||||
]);
|
]);
|
||||||
const EXECUTABLE_OVERRIDE = "ECC_ITO_CLI_EXECUTABLE";
|
const EXECUTABLE_OVERRIDE = "ECC_ITO_CLI_EXECUTABLE";
|
||||||
const MAX_OUTPUT_BYTES = 10 * 1024 * 1024;
|
const MAX_OUTPUT_BYTES = 10 * 1024 * 1024;
|
||||||
|
const CAPABILITY_TIMEOUT_MS = 10 * 1000;
|
||||||
const NODE_QUALIFICATION_TIMEOUT_MS = 31 * 60 * 1000;
|
const NODE_QUALIFICATION_TIMEOUT_MS = 31 * 60 * 1000;
|
||||||
|
|
||||||
function showHelp() {
|
function showHelp() {
|
||||||
@@ -33,8 +38,10 @@ Usage:
|
|||||||
ecc ito auth
|
ecc ito auth
|
||||||
ecc ito find <all required RFQ options>
|
ecc ito find <all required RFQ options>
|
||||||
ecc ito status
|
ecc ito status
|
||||||
|
ecc ito workload-status <run-id>
|
||||||
|
ecc ito capabilities
|
||||||
ecc ito evals --cluster <id> --live-sixtytwo --nodes <list> --config-dir <dir>
|
ecc ito evals --cluster <id> --live-sixtytwo --nodes <list> --config-dir <dir>
|
||||||
ecc ito <login|logout|auth|find|status|evals> --json
|
ecc ito <command> --json
|
||||||
|
|
||||||
The bridge invokes the separately installed canonical Itô CLI and returns its
|
The bridge invokes the separately installed canonical Itô CLI and returns its
|
||||||
real stdout, stderr, and exit code unchanged. "ecc ito login" delegates to the
|
real stdout, stderr, and exit code unchanged. "ecc ito login" delegates to the
|
||||||
@@ -50,6 +57,10 @@ Important:
|
|||||||
- "find" reads live inventory and submits an authenticated RFQ.
|
- "find" reads live inventory and submits an authenticated RFQ.
|
||||||
- Obtain explicit buyer authority and every hard constraint before invoking it.
|
- Obtain explicit buyer authority and every hard constraint before invoking it.
|
||||||
- "status" reads live RFQ and procurement status.
|
- "status" reads live RFQ and procurement status.
|
||||||
|
- "workload-status" reads an existing entitled workload without changing it.
|
||||||
|
- The installed canonical CLI must advertise every command through the local-only
|
||||||
|
ito.cli.capabilities.v1 contract. ECC derives read-only forwarding from that
|
||||||
|
contract and blocks workload start, cancel, cleanup, purchase, and unknown effects.
|
||||||
- "evals" invokes only the canonical CLI's double-opt-in, pinned
|
- "evals" invokes only the canonical CLI's double-opt-in, pinned
|
||||||
sixtytwo-cli node-qualification adapter against explicit nodes.
|
sixtytwo-cli node-qualification adapter against explicit nodes.
|
||||||
- Node qualification cannot rent, launch, recover, repair, or purchase.
|
- Node qualification cannot rent, launch, recover, repair, or purchase.
|
||||||
@@ -162,10 +173,8 @@ function parseArgs(argv, environment = process.env) {
|
|||||||
}
|
}
|
||||||
const withoutJson = args.filter((value) => value !== "--json");
|
const withoutJson = args.filter((value) => value !== "--json");
|
||||||
const command = withoutJson.shift();
|
const command = withoutJson.shift();
|
||||||
if (!SUPPORTED_COMMANDS.includes(command)) {
|
if (typeof command !== "string" || !/^[a-z][a-z0-9-]{0,63}$/.test(command)) {
|
||||||
throw new Error(
|
throw new Error(`Invalid Itô command ${JSON.stringify(command || "(missing)")}.`);
|
||||||
`Unsupported Itô command "${command || "(missing)"}"; ECC permits only login, logout, auth, find, status, and evals.`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (command === "auth" && withoutJson.includes("--no-browser")) {
|
if (command === "auth" && withoutJson.includes("--no-browser")) {
|
||||||
throw new Error("--no-browser is valid only for ecc ito login; auth is validation-only.");
|
throw new Error("--no-browser is valid only for ecc ito login; auth is validation-only.");
|
||||||
@@ -176,6 +185,7 @@ function parseArgs(argv, environment = process.env) {
|
|||||||
|
|
||||||
return Object.freeze({
|
return Object.freeze({
|
||||||
help: false,
|
help: false,
|
||||||
|
command,
|
||||||
invocationArgs: Object.freeze([
|
invocationArgs: Object.freeze([
|
||||||
...(jsonIndexes.length === 1 ? ["--json"] : []),
|
...(jsonIndexes.length === 1 ? ["--json"] : []),
|
||||||
command,
|
command,
|
||||||
@@ -264,7 +274,28 @@ function buildInvocation(executable, args) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function invokeIto(executable, args, environment = process.env) {
|
function discoverItoCapabilities(executable, environment = process.env) {
|
||||||
|
const invocation = buildInvocation(executable, ["capabilities", "--json"]);
|
||||||
|
const result = spawnSync(invocation.executable, invocation.args, {
|
||||||
|
cwd: process.cwd(),
|
||||||
|
encoding: "utf8",
|
||||||
|
env: { ...createSafeItoEnvironment(environment) },
|
||||||
|
stdio: ["ignore", "pipe", "pipe"],
|
||||||
|
maxBuffer: MAX_OUTPUT_BYTES,
|
||||||
|
timeout: CAPABILITY_TIMEOUT_MS,
|
||||||
|
shell: false,
|
||||||
|
windowsHide: true,
|
||||||
|
});
|
||||||
|
if (result.error) {
|
||||||
|
throw new Error(`The local Itô capability contract could not be read: ${result.error.message}`);
|
||||||
|
}
|
||||||
|
if (result.status !== 0) {
|
||||||
|
throw new Error("The local Itô CLI rejected credential-free capability discovery.");
|
||||||
|
}
|
||||||
|
return parseItoCapabilities(result.stdout || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function invokeIto(executable, args, environment = process.env, capability) {
|
||||||
const invocation = buildInvocation(executable, args);
|
const invocation = buildInvocation(executable, args);
|
||||||
const command = getInvocationCommand(args);
|
const command = getInvocationCommand(args);
|
||||||
const isNodeQualification = command === "evals";
|
const isNodeQualification = command === "evals";
|
||||||
@@ -274,7 +305,9 @@ function invokeIto(executable, args, environment = process.env) {
|
|||||||
encoding: "utf8",
|
encoding: "utf8",
|
||||||
// Keep policy helpers immutable for callers, but give child-process
|
// Keep policy helpers immutable for callers, but give child-process
|
||||||
// instrumentation its own mutable copy (for example NODE_V8_COVERAGE).
|
// instrumentation its own mutable copy (for example NODE_V8_COVERAGE).
|
||||||
env: { ...createSafeItoInvocationEnvironment(environment, args) },
|
env: {
|
||||||
|
...createSafeItoInvocationEnvironment(environment, args, { capability }),
|
||||||
|
},
|
||||||
stdio: isDeviceLogin ? "inherit" : ["pipe", "pipe", "pipe"],
|
stdio: isDeviceLogin ? "inherit" : ["pipe", "pipe", "pipe"],
|
||||||
maxBuffer: MAX_OUTPUT_BYTES,
|
maxBuffer: MAX_OUTPUT_BYTES,
|
||||||
timeout: isNodeQualification ? NODE_QUALIFICATION_TIMEOUT_MS : undefined,
|
timeout: isNodeQualification ? NODE_QUALIFICATION_TIMEOUT_MS : undefined,
|
||||||
@@ -302,7 +335,9 @@ function main(argv = process.argv.slice(2), environment = process.env) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const executable = resolveItoExecutable(environment);
|
const executable = resolveItoExecutable(environment);
|
||||||
return invokeIto(executable, parsed.invocationArgs, environment);
|
const manifest = discoverItoCapabilities(executable, environment);
|
||||||
|
const capability = authorizeEccCapability(manifest, parsed.command);
|
||||||
|
return invokeIto(executable, parsed.invocationArgs, environment, capability);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error: ${error.message}`);
|
console.error(`Error: ${error.message}`);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -316,10 +351,11 @@ if (require.main === module) {
|
|||||||
module.exports = Object.freeze({
|
module.exports = Object.freeze({
|
||||||
CANONICAL_PACKAGE_PATH,
|
CANONICAL_PACKAGE_PATH,
|
||||||
CANONICAL_REPOSITORY,
|
CANONICAL_REPOSITORY,
|
||||||
|
CAPABILITY_TIMEOUT_MS,
|
||||||
EXECUTABLE_OVERRIDE,
|
EXECUTABLE_OVERRIDE,
|
||||||
NODE_QUALIFICATION_TIMEOUT_MS,
|
NODE_QUALIFICATION_TIMEOUT_MS,
|
||||||
SUPPORTED_COMMANDS,
|
|
||||||
buildInvocation,
|
buildInvocation,
|
||||||
|
discoverItoCapabilities,
|
||||||
invokeIto,
|
invokeIto,
|
||||||
main,
|
main,
|
||||||
parseArgs,
|
parseArgs,
|
||||||
|
|||||||
@@ -0,0 +1,209 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const CONTRACT_VERSION = "ito.cli.capabilities.v1";
|
||||||
|
const MAX_COMMANDS = 64;
|
||||||
|
const COMMAND_PATTERN = /^[a-z][a-z0-9-]{0,63}$/;
|
||||||
|
const ENUMS = Object.freeze({
|
||||||
|
availability: new Set(["supported", "unsupported"]),
|
||||||
|
auth: new Set(["none", "required", "device_bootstrap"]),
|
||||||
|
network: new Set(["none", "ito_api", "explicit_nodes"]),
|
||||||
|
side_effect: new Set([
|
||||||
|
"none",
|
||||||
|
"credential_write",
|
||||||
|
"credential_revoke",
|
||||||
|
"rfq_submit",
|
||||||
|
"workload_start",
|
||||||
|
"workload_cancel",
|
||||||
|
"workload_cleanup",
|
||||||
|
"provisioning_reconcile",
|
||||||
|
"node_qualification",
|
||||||
|
]),
|
||||||
|
authority: new Set([
|
||||||
|
"none",
|
||||||
|
"device_owner",
|
||||||
|
"buyer_rfq",
|
||||||
|
"entitled_workload",
|
||||||
|
"named_node_operator",
|
||||||
|
]),
|
||||||
|
});
|
||||||
|
const EXPLICIT_EFFECT_POLICY = Object.freeze({
|
||||||
|
login: Object.freeze({
|
||||||
|
auth: "device_bootstrap",
|
||||||
|
network: "ito_api",
|
||||||
|
side_effect: "credential_write",
|
||||||
|
authority: "device_owner",
|
||||||
|
}),
|
||||||
|
logout: Object.freeze({
|
||||||
|
auth: "none",
|
||||||
|
network: "ito_api",
|
||||||
|
side_effect: "credential_revoke",
|
||||||
|
authority: "device_owner",
|
||||||
|
}),
|
||||||
|
find: Object.freeze({
|
||||||
|
auth: "required",
|
||||||
|
network: "ito_api",
|
||||||
|
side_effect: "rfq_submit",
|
||||||
|
authority: "buyer_rfq",
|
||||||
|
}),
|
||||||
|
status: Object.freeze({
|
||||||
|
auth: "required",
|
||||||
|
network: "ito_api",
|
||||||
|
side_effect: "provisioning_reconcile",
|
||||||
|
authority: "buyer_rfq",
|
||||||
|
}),
|
||||||
|
evals: Object.freeze({
|
||||||
|
auth: "none",
|
||||||
|
network: "explicit_nodes",
|
||||||
|
side_effect: "node_qualification",
|
||||||
|
authority: "named_node_operator",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
function assertPlainObject(value, label) {
|
||||||
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||||
|
throw new Error(`Invalid Itô capability contract: ${label} must be an object.`);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertExactKeys(value, expected, label) {
|
||||||
|
const actual = Object.keys(value).sort();
|
||||||
|
const wanted = [...expected].sort();
|
||||||
|
if (actual.length !== wanted.length || actual.some((key, index) => key !== wanted[index])) {
|
||||||
|
throw new Error(`Invalid Itô capability contract: ${label} has unknown or missing fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertEnum(value, field) {
|
||||||
|
if (!ENUMS[field].has(value)) {
|
||||||
|
throw new Error(`Invalid Itô capability contract: unsupported ${field}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseItoCapabilities(stdout) {
|
||||||
|
let envelope;
|
||||||
|
try {
|
||||||
|
envelope = JSON.parse(stdout);
|
||||||
|
} catch {
|
||||||
|
throw new Error("Invalid Itô capability contract: canonical CLI did not emit JSON.");
|
||||||
|
}
|
||||||
|
assertPlainObject(envelope, "envelope");
|
||||||
|
assertExactKeys(envelope, ["ok", "live_api_contacted", "notice", "data"], "envelope");
|
||||||
|
if (
|
||||||
|
envelope.ok !== true
|
||||||
|
|| envelope.live_api_contacted !== false
|
||||||
|
|| typeof envelope.notice !== "string"
|
||||||
|
|| envelope.notice.length === 0
|
||||||
|
) {
|
||||||
|
throw new Error("Invalid Itô capability contract: discovery must be local-only success.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = assertPlainObject(envelope.data, "data");
|
||||||
|
assertExactKeys(
|
||||||
|
data,
|
||||||
|
["contract_version", "cli", "commands", "mcp_tools", "output_contract"],
|
||||||
|
"data",
|
||||||
|
);
|
||||||
|
if (data.contract_version !== CONTRACT_VERSION) {
|
||||||
|
throw new Error(`Unsupported Itô capability contract ${JSON.stringify(data.contract_version)}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const cli = assertPlainObject(data.cli, "cli");
|
||||||
|
assertExactKeys(cli, ["name", "version", "private"], "cli");
|
||||||
|
if (
|
||||||
|
cli.name !== "ito-compute-cli"
|
||||||
|
|| typeof cli.version !== "string"
|
||||||
|
|| !cli.version
|
||||||
|
|| cli.private !== true
|
||||||
|
) {
|
||||||
|
throw new Error("Invalid Itô capability contract: unexpected private CLI identity.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const outputContract = assertPlainObject(data.output_contract, "output_contract");
|
||||||
|
assertExactKeys(
|
||||||
|
outputContract,
|
||||||
|
["json_success_envelope", "errors_on_stderr", "unsupported_commands_contact_nothing"],
|
||||||
|
"output_contract",
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
outputContract.json_success_envelope !== true
|
||||||
|
|| outputContract.errors_on_stderr !== true
|
||||||
|
|| outputContract.unsupported_commands_contact_nothing !== true
|
||||||
|
) {
|
||||||
|
throw new Error("Invalid Itô capability contract: required output guarantees are absent.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!Array.isArray(data.mcp_tools)
|
||||||
|
|| data.mcp_tools.join("\n") !== "ito_auth\nito_find\nito_status"
|
||||||
|
) {
|
||||||
|
throw new Error("Invalid Itô capability contract: MCP tool surface changed.");
|
||||||
|
}
|
||||||
|
if (!Array.isArray(data.commands) || data.commands.length < 1 || data.commands.length > MAX_COMMANDS) {
|
||||||
|
throw new Error("Invalid Itô capability contract: commands must be a bounded non-empty array.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const seen = new Set();
|
||||||
|
const commands = data.commands.map((entry, index) => {
|
||||||
|
const command = assertPlainObject(entry, `commands[${index}]`);
|
||||||
|
assertExactKeys(
|
||||||
|
command,
|
||||||
|
["name", "availability", "auth", "network", "side_effect", "authority"],
|
||||||
|
`commands[${index}]`,
|
||||||
|
);
|
||||||
|
if (typeof command.name !== "string" || !COMMAND_PATTERN.test(command.name)) {
|
||||||
|
throw new Error("Invalid Itô capability contract: malformed command name.");
|
||||||
|
}
|
||||||
|
if (seen.has(command.name)) {
|
||||||
|
throw new Error(`Invalid Itô capability contract: duplicate command ${command.name}.`);
|
||||||
|
}
|
||||||
|
seen.add(command.name);
|
||||||
|
for (const field of ["availability", "auth", "network", "side_effect", "authority"]) {
|
||||||
|
assertEnum(command[field], field);
|
||||||
|
}
|
||||||
|
return Object.freeze({ ...command });
|
||||||
|
});
|
||||||
|
|
||||||
|
return Object.freeze({
|
||||||
|
contract_version: CONTRACT_VERSION,
|
||||||
|
cli: Object.freeze({ ...cli }),
|
||||||
|
commands: Object.freeze(commands),
|
||||||
|
mcp_tools: Object.freeze([...data.mcp_tools]),
|
||||||
|
output_contract: Object.freeze({ ...outputContract }),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function commandCapability(manifest, requestedCommand) {
|
||||||
|
const capability = manifest.commands.find(({ name }) => name === requestedCommand);
|
||||||
|
if (!capability || capability.availability !== "supported") {
|
||||||
|
throw new Error(
|
||||||
|
`The installed canonical Itô CLI does not advertise ${JSON.stringify(requestedCommand)} as supported.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return capability;
|
||||||
|
}
|
||||||
|
|
||||||
|
function authorizeEccCapability(manifest, requestedCommand) {
|
||||||
|
const capability = commandCapability(manifest, requestedCommand);
|
||||||
|
const policy = EXPLICIT_EFFECT_POLICY[requestedCommand];
|
||||||
|
if (policy) {
|
||||||
|
if (Object.entries(policy).every(([field, expected]) => capability[field] === expected)) {
|
||||||
|
return capability;
|
||||||
|
}
|
||||||
|
throw new Error(
|
||||||
|
`Itô command ${JSON.stringify(requestedCommand)} is outside ECC's safe policy: ${capability.side_effect}.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (capability.side_effect === "none" && capability.authority === "none") {
|
||||||
|
return capability;
|
||||||
|
}
|
||||||
|
throw new Error(
|
||||||
|
`Itô command ${JSON.stringify(requestedCommand)} is outside ECC's safe policy: ${capability.side_effect}.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Object.freeze({
|
||||||
|
CONTRACT_VERSION,
|
||||||
|
authorizeEccCapability,
|
||||||
|
parseItoCapabilities,
|
||||||
|
});
|
||||||
@@ -94,11 +94,27 @@ function createSafeItoInvocationEnvironment(
|
|||||||
options = {},
|
options = {},
|
||||||
) {
|
) {
|
||||||
const command = getInvocationCommand(args);
|
const command = getInvocationCommand(args);
|
||||||
|
const capability = options.capability;
|
||||||
|
const deferCapabilityPolicy = options.deferCapabilityPolicy === true;
|
||||||
|
const includeItoRuntime = deferCapabilityPolicy
|
||||||
|
? command !== "evals"
|
||||||
|
: capability
|
||||||
|
? capability.network === "ito_api"
|
||||||
|
: ITO_RUNTIME_COMMANDS.has(command);
|
||||||
|
const includeItoApiKey = deferCapabilityPolicy
|
||||||
|
? !["login", "logout", "evals"].includes(command)
|
||||||
|
: capability
|
||||||
|
? capability.auth === "required"
|
||||||
|
: ["auth", "find", "status"].includes(command);
|
||||||
return createSafeItoEnvironment(source, {
|
return createSafeItoEnvironment(source, {
|
||||||
includeControls: options.includeControls === true,
|
includeControls: options.includeControls === true,
|
||||||
includeItoRuntime: ITO_RUNTIME_COMMANDS.has(command),
|
includeItoRuntime,
|
||||||
includeItoApiKey: ["auth", "find", "status"].includes(command),
|
includeItoApiKey,
|
||||||
includeItoEvals: command === "evals",
|
includeItoEvals: deferCapabilityPolicy
|
||||||
|
? command === "evals"
|
||||||
|
: capability
|
||||||
|
? capability.network === "explicit_nodes"
|
||||||
|
: command === "evals",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: ito-compute
|
name: ito-compute
|
||||||
description: Query live GPU inventory, submit an authenticated Itô fixed-rate RFQ, inspect RFQ or procurement status, revoke device credentials, and run explicitly gated node qualification through the separately installed canonical CLI. Use when a user asks to find H100/H200 capacity, request a fixed compute rate, check Itô compute status, validate GPU nodes, revoke Itô access, or rent or purchase GPU compute and needs the supported boundary explained.
|
description: Query live GPU inventory, submit an authenticated Itô fixed-rate RFQ, inspect RFQ, procurement, or existing workload status, revoke device credentials, and run explicitly gated node qualification through the separately installed canonical CLI. Use when a user asks to find H100/H200 capacity, request a fixed compute rate, check Itô compute or workload status, validate GPU nodes, revoke Itô access, or rent or purchase GPU compute and needs the supported boundary explained.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Itô Compute
|
# Itô Compute
|
||||||
@@ -29,10 +29,17 @@ Set `ECC_ITO_CLI_EXECUTABLE` to the explicit absolute built entry:
|
|||||||
|
|
||||||
ECC never discovers this credential-bearing client through `PATH`.
|
ECC never discovers this credential-bearing client through `PATH`.
|
||||||
`ecc ito login` performs device authorization and never inherits `ITO_API_KEY`.
|
`ecc ito login` performs device authorization and never inherits `ITO_API_KEY`.
|
||||||
The validation-only `auth`, plus `find` and `status`, forward `ITO_API_KEY`
|
The validation-only `auth`, plus `find`, `status`, and `workload-status`, forward
|
||||||
directly when configured; `ITO_AUTH_MODE=legacy` is not required. Never put a
|
`ITO_API_KEY` directly when configured; `ITO_AUTH_MODE=legacy` is not required. Never put a
|
||||||
key or token in arguments, tracked files, MCP results, logs, or chat.
|
key or token in arguments, tracked files, MCP results, logs, or chat.
|
||||||
|
|
||||||
|
Before every forwarded operation, ECC invokes `capabilities --json` with a
|
||||||
|
credential-free environment and validates the closed `ito.cli.capabilities.v1`
|
||||||
|
contract. Run `ecc ito capabilities --json` to inspect that installed contract
|
||||||
|
directly. ECC automatically accepts supported no-side-effect commands and keeps
|
||||||
|
explicit policy only for login, logout, RFQ submission, and node qualification.
|
||||||
|
Workload start, cancel, and cleanup effects remain blocked.
|
||||||
|
|
||||||
## CLI workflow
|
## CLI workflow
|
||||||
|
|
||||||
1. Run `ecc ito login` before the first operation. ECC delegates this to the
|
1. Run `ecc ito login` before the first operation. ECC delegates this to the
|
||||||
@@ -73,7 +80,9 @@ key or token in arguments, tracked files, MCP results, logs, or chat.
|
|||||||
|
|
||||||
5. Run `ecc ito status` to inspect RFQs and procurement orders.
|
5. Run `ecc ito status` to inspect RFQs and procurement orders.
|
||||||
After an ambiguous transport failure, check status before repeating `find`.
|
After an ambiguous transport failure, check status before repeating `find`.
|
||||||
6. Run `ecc ito logout` when the user explicitly asks to revoke this device.
|
6. Run `ecc ito workload-status <run-id>` to inspect an already existing
|
||||||
|
entitled workload without starting, stopping, or cleaning it up.
|
||||||
|
7. Run `ecc ito logout` when the user explicitly asks to revoke this device.
|
||||||
The canonical CLI keeps the local credential when remote revocation fails so
|
The canonical CLI keeps the local credential when remote revocation fails so
|
||||||
the operator can retry; never delete the token manually as a substitute.
|
the operator can retry; never delete the token manually as a substitute.
|
||||||
|
|
||||||
@@ -144,8 +153,10 @@ operate it as a substitute for a missing CLI capability.
|
|||||||
|
|
||||||
## Unsupported operations
|
## Unsupported operations
|
||||||
|
|
||||||
The supported client surface cannot lock quotes, reserve capacity, execute
|
The ECC bridge cannot lock quotes, reserve capacity, start, cancel, or clean up
|
||||||
workloads, or serve inference. The MCP server does not expose qualification;
|
workloads, or serve inference. It may inspect an already existing workload when
|
||||||
|
the installed v1 capability contract advertises that no-side-effect command.
|
||||||
|
The MCP server does not expose qualification;
|
||||||
use the explicit CLI command above. Do not invent additional tools or a
|
use the explicit CLI command above. Do not invent additional tools or a
|
||||||
purchase path. Do not substitute a browser or fixture when the local CLI is
|
purchase path. Do not substitute a browser or fixture when the local CLI is
|
||||||
missing or a live operation fails. Report the missing capability and stop.
|
missing or a live operation fails. Report the missing capability and stop.
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ function main() {
|
|||||||
"ecc ito auth",
|
"ecc ito auth",
|
||||||
"ecc ito find",
|
"ecc ito find",
|
||||||
"ecc ito status",
|
"ecc ito status",
|
||||||
|
"ecc ito workload-status",
|
||||||
|
"ecc ito capabilities",
|
||||||
"ecc ito evals",
|
"ecc ito evals",
|
||||||
]) {
|
]) {
|
||||||
assert.match(skill, new RegExp(command.replace(" ", "\\s+")));
|
assert.match(skill, new RegExp(command.replace(" ", "\\s+")));
|
||||||
@@ -67,6 +69,8 @@ function main() {
|
|||||||
assert.match(skill, /--no-browser/);
|
assert.match(skill, /--no-browser/);
|
||||||
assert.match(skill, /macOS Keychain/i);
|
assert.match(skill, /macOS Keychain/i);
|
||||||
assert.match(skill, /(?:auth|find|status).*ITO_API_KEY/i);
|
assert.match(skill, /(?:auth|find|status).*ITO_API_KEY/i);
|
||||||
|
assert.match(skill, /ito\.cli\.capabilities\.v1/);
|
||||||
|
assert.match(skill, /workload start, cancel, and cleanup effects remain blocked/i);
|
||||||
assert.match(skill, /ITO_AUTH_MODE=legacy[^.]*not required/i);
|
assert.match(skill, /ITO_AUTH_MODE=legacy[^.]*not required/i);
|
||||||
assert.match(skill, /ECC (?:itself )?(?:does|performs) no browser automation/i);
|
assert.match(skill, /ECC (?:itself )?(?:does|performs) no browser automation/i);
|
||||||
assert.match(skill, /ITO_ENABLE_SIXTYTWO_LIVE/);
|
assert.match(skill, /ITO_ENABLE_SIXTYTWO_LIVE/);
|
||||||
@@ -93,6 +97,8 @@ function main() {
|
|||||||
assert.doesNotMatch(source, /ecc ito auth --no-browser/i, relativePath);
|
assert.doesNotMatch(source, /ecc ito auth --no-browser/i, relativePath);
|
||||||
assert.match(source, /ITO_API_KEY.*(?:auth|find|status)/is, relativePath);
|
assert.match(source, /ITO_API_KEY.*(?:auth|find|status)/is, relativePath);
|
||||||
assert.match(source, /ITO_AUTH_MODE=legacy[^.]*not required/i, relativePath);
|
assert.match(source, /ITO_AUTH_MODE=legacy[^.]*not required/i, relativePath);
|
||||||
|
assert.match(source, /ito\.cli\.capabilities\.v1/i, relativePath);
|
||||||
|
assert.match(source, /workload-status/i, relativePath);
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
["registers one opt-in install module and capability", () => {
|
["registers one opt-in install module and capability", () => {
|
||||||
@@ -117,7 +123,7 @@ function main() {
|
|||||||
{
|
{
|
||||||
id: "capability:ito-compute",
|
id: "capability:ito-compute",
|
||||||
family: "capability",
|
family: "capability",
|
||||||
description: "Authenticated Itô GPU inventory, RFQ, status, device revocation, and explicitly gated node-qualification workflows through the separately installed canonical CLI.",
|
description: "Capability-validated Itô GPU inventory, RFQ, status, read-only workload inspection, device revocation, and explicitly gated node-qualification workflows through the separately installed canonical CLI.",
|
||||||
modules: ["ito-compute"],
|
modules: ["ito-compute"],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,9 +4,8 @@
|
|||||||
|
|
||||||
const assert = require("assert");
|
const assert = require("assert");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const os = require("os");
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const { spawnSync } = require("child_process");
|
const { authorizeEccCapability } = require("../../scripts/lib/ito-capabilities");
|
||||||
|
|
||||||
const REPO_ROOT = path.join(__dirname, "..", "..");
|
const REPO_ROOT = path.join(__dirname, "..", "..");
|
||||||
|
|
||||||
@@ -64,32 +63,19 @@ const results = [
|
|||||||
assert.match(skill, /--confirmation-ref <opaque-non-authorizing-reference>/i);
|
assert.match(skill, /--confirmation-ref <opaque-non-authorizing-reference>/i);
|
||||||
assert.doesNotMatch(skill, /--confirmation-token|--api-key|--access-token/i);
|
assert.doesNotMatch(skill, /--confirmation-token|--api-key|--access-token/i);
|
||||||
}),
|
}),
|
||||||
test("keeps unsupported serving outside the executable bridge", () => {
|
test("keeps workload-serving effects outside the executable policy", () => {
|
||||||
const bridge = read("scripts/ito.js");
|
const capability = Object.freeze({
|
||||||
assert.match(bridge, /SUPPORTED_COMMANDS[^\n]+login[^\n]+auth[^\n]+find[^\n]+status[^\n]+evals/);
|
name: "serve",
|
||||||
assert.doesNotMatch(bridge, /SUPPORTED_COMMANDS[^\n]+serve/);
|
availability: "supported",
|
||||||
assert.match(bridge, /Unsupported Itô command/);
|
auth: "required",
|
||||||
|
network: "ito_api",
|
||||||
const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ecc-ito-serve-reject-"));
|
side_effect: "workload_start",
|
||||||
try {
|
authority: "entitled_workload",
|
||||||
const canonicalDir = path.join(fixtureRoot, "cli", "ito-compute-cli", "dist", "bin");
|
});
|
||||||
fs.mkdirSync(canonicalDir, { recursive: true });
|
assert.throws(
|
||||||
const marker = path.join(fixtureRoot, "spawned");
|
() => authorizeEccCapability({ commands: [capability] }, "serve"),
|
||||||
const executable = path.join(canonicalDir, "ito.js");
|
/outside ECC's safe policy: workload_start/,
|
||||||
fs.writeFileSync(executable, `require("fs").writeFileSync(${JSON.stringify(marker)}, "spawned");\n`);
|
);
|
||||||
const result = spawnSync(process.execPath, [
|
|
||||||
path.join(REPO_ROOT, "scripts", "ecc.js"), "ito", "serve",
|
|
||||||
"--booking", "booking_test", "--model", "model_test",
|
|
||||||
], {
|
|
||||||
encoding: "utf8",
|
|
||||||
env: { ...process.env, ECC_ITO_CLI_EXECUTABLE: executable },
|
|
||||||
});
|
|
||||||
assert.notStrictEqual(result.status, 0);
|
|
||||||
assert.match(result.stderr, /Unsupported Itô command "serve"/);
|
|
||||||
assert.ok(!fs.existsSync(marker), "unsupported serve spawned the canonical child");
|
|
||||||
} finally {
|
|
||||||
fs.rmSync(fixtureRoot, { recursive: true, force: true });
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
test("ships canonical inference through the existing opt-in compute module", () => {
|
test("ships canonical inference through the existing opt-in compute module", () => {
|
||||||
const modules = readJson("manifests/install-modules.json").modules;
|
const modules = readJson("manifests/install-modules.json").modules;
|
||||||
@@ -110,7 +96,7 @@ const results = [
|
|||||||
{
|
{
|
||||||
id: "capability:ito-compute",
|
id: "capability:ito-compute",
|
||||||
family: "capability",
|
family: "capability",
|
||||||
description: "Authenticated Itô GPU inventory, RFQ, status, device revocation, and explicitly gated node-qualification workflows through the separately installed canonical CLI.",
|
description: "Capability-validated Itô GPU inventory, RFQ, status, read-only workload inspection, device revocation, and explicitly gated node-qualification workflows through the separately installed canonical CLI.",
|
||||||
modules: ["ito-compute"],
|
modules: ["ito-compute"],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,9 +7,8 @@
|
|||||||
|
|
||||||
const assert = require("assert");
|
const assert = require("assert");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const os = require("os");
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const { spawnSync } = require("child_process");
|
const { authorizeEccCapability } = require("../../scripts/lib/ito-capabilities");
|
||||||
|
|
||||||
const REPO_ROOT = path.join(__dirname, "..", "..");
|
const REPO_ROOT = path.join(__dirname, "..", "..");
|
||||||
|
|
||||||
@@ -77,32 +76,19 @@ test("labels backend stages as future and keeps eval gates human-honest", () =>
|
|||||||
assert.match(skill, /Loss-spike restart is a proposed, human-gated action/i);
|
assert.match(skill, /Loss-spike restart is a proposed, human-gated action/i);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("keeps unsupported training outside the executable bridge", () => {
|
test("keeps workload-training effects outside the executable policy", () => {
|
||||||
const bridge = read("scripts/ito.js");
|
const capability = Object.freeze({
|
||||||
assert.match(bridge, /SUPPORTED_COMMANDS[^\n]+login[^\n]+auth[^\n]+find[^\n]+status[^\n]+evals/);
|
name: "train",
|
||||||
assert.doesNotMatch(bridge, /SUPPORTED_COMMANDS[^\n]+train/);
|
availability: "supported",
|
||||||
assert.match(bridge, /Unsupported Itô command/);
|
auth: "required",
|
||||||
|
network: "ito_api",
|
||||||
const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ecc-ito-train-reject-"));
|
side_effect: "workload_start",
|
||||||
try {
|
authority: "entitled_workload",
|
||||||
const canonicalDir = path.join(fixtureRoot, "cli", "ito-compute-cli", "dist", "bin");
|
});
|
||||||
fs.mkdirSync(canonicalDir, { recursive: true });
|
assert.throws(
|
||||||
const marker = path.join(fixtureRoot, "spawned");
|
() => authorizeEccCapability({ commands: [capability] }, "train"),
|
||||||
const executable = path.join(canonicalDir, "ito.js");
|
/outside ECC's safe policy: workload_start/,
|
||||||
fs.writeFileSync(executable, `require("fs").writeFileSync(${JSON.stringify(marker)}, "spawned");\n`);
|
);
|
||||||
const result = spawnSync(process.execPath, [
|
|
||||||
path.join(REPO_ROOT, "scripts", "ecc.js"), "ito", "train",
|
|
||||||
"--booking", "booking_test", "--model-size", "8B",
|
|
||||||
], {
|
|
||||||
encoding: "utf8",
|
|
||||||
env: { ...process.env, ECC_ITO_CLI_EXECUTABLE: executable },
|
|
||||||
});
|
|
||||||
assert.notStrictEqual(result.status, 0);
|
|
||||||
assert.match(result.stderr, /Unsupported Itô command "train"/);
|
|
||||||
assert.ok(!fs.existsSync(marker), "unsupported train spawned the canonical child");
|
|
||||||
} finally {
|
|
||||||
fs.rmSync(fixtureRoot, { recursive: true, force: true });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("ships through the existing opt-in compute module and npm package", () => {
|
test("ships through the existing opt-in compute module and npm package", () => {
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ const {
|
|||||||
getInvocationCommand,
|
getInvocationCommand,
|
||||||
ITO_RUNTIME_ENVIRONMENT_KEYS,
|
ITO_RUNTIME_ENVIRONMENT_KEYS,
|
||||||
} = require("../../scripts/lib/ito-environment");
|
} = require("../../scripts/lib/ito-environment");
|
||||||
|
const {
|
||||||
|
authorizeEccCapability,
|
||||||
|
parseItoCapabilities,
|
||||||
|
} = require("../../scripts/lib/ito-capabilities");
|
||||||
|
|
||||||
function runCli(args, environment = {}) {
|
function runCli(args, environment = {}) {
|
||||||
return spawnSync(process.execPath, [ECC_SCRIPT, ...args], {
|
return spawnSync(process.execPath, [ECC_SCRIPT, ...args], {
|
||||||
@@ -64,9 +68,44 @@ function runCliAndObserveFirstOutput(args, environment = {}) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeItoProbe(exitCode = 0) {
|
function capabilityEnvelope(commands) {
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
live_api_contacted: false,
|
||||||
|
notice: "Static CLI capability contract; no credential or network access occurred.",
|
||||||
|
data: {
|
||||||
|
contract_version: "ito.cli.capabilities.v1",
|
||||||
|
cli: { name: "ito-compute-cli", version: "0.1.1", private: true },
|
||||||
|
commands,
|
||||||
|
mcp_tools: ["ito_auth", "ito_find", "ito_status"],
|
||||||
|
output_contract: {
|
||||||
|
json_success_envelope: true,
|
||||||
|
errors_on_stderr: true,
|
||||||
|
unsupported_commands_contact_nothing: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_CAPABILITY_COMMANDS = Object.freeze([
|
||||||
|
{ name: "capabilities", availability: "supported", auth: "none", network: "none", side_effect: "none", authority: "none" },
|
||||||
|
{ name: "login", availability: "supported", auth: "device_bootstrap", network: "ito_api", side_effect: "credential_write", authority: "device_owner" },
|
||||||
|
{ name: "logout", availability: "supported", auth: "none", network: "ito_api", side_effect: "credential_revoke", authority: "device_owner" },
|
||||||
|
{ name: "auth", availability: "supported", auth: "required", network: "ito_api", side_effect: "none", authority: "none" },
|
||||||
|
{ name: "find", availability: "supported", auth: "required", network: "ito_api", side_effect: "rfq_submit", authority: "buyer_rfq" },
|
||||||
|
{ name: "status", availability: "supported", auth: "required", network: "ito_api", side_effect: "provisioning_reconcile", authority: "buyer_rfq" },
|
||||||
|
{ name: "serve", availability: "supported", auth: "required", network: "ito_api", side_effect: "workload_start", authority: "entitled_workload" },
|
||||||
|
{ name: "train", availability: "supported", auth: "required", network: "ito_api", side_effect: "workload_start", authority: "entitled_workload" },
|
||||||
|
{ name: "workload-status", availability: "supported", auth: "required", network: "ito_api", side_effect: "none", authority: "none" },
|
||||||
|
{ name: "workload-cancel", availability: "supported", auth: "required", network: "ito_api", side_effect: "workload_cancel", authority: "entitled_workload" },
|
||||||
|
{ name: "workload-cleanup", availability: "supported", auth: "required", network: "ito_api", side_effect: "workload_cleanup", authority: "entitled_workload" },
|
||||||
|
{ name: "evals", availability: "supported", auth: "none", network: "explicit_nodes", side_effect: "node_qualification", authority: "named_node_operator" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
function makeItoProbe(exitCode = 0, options = {}) {
|
||||||
const directory = fs.mkdtempSync(path.join(os.tmpdir(), "ecc-ito-cli-"));
|
const directory = fs.mkdtempSync(path.join(os.tmpdir(), "ecc-ito-cli-"));
|
||||||
const log = path.join(directory, "invocation.json");
|
const log = path.join(directory, "invocation.json");
|
||||||
|
const capabilityLog = path.join(directory, "capability-invocation.json");
|
||||||
const script = path.join(
|
const script = path.join(
|
||||||
directory,
|
directory,
|
||||||
"ito-cloud-runtime",
|
"ito-cloud-runtime",
|
||||||
@@ -84,6 +123,13 @@ function makeItoProbe(exitCode = 0) {
|
|||||||
`#!${process.execPath}`,
|
`#!${process.execPath}`,
|
||||||
'"use strict";',
|
'"use strict";',
|
||||||
'const fs = require("fs");',
|
'const fs = require("fs");',
|
||||||
|
'const argv = process.argv.slice(2);',
|
||||||
|
'const command = argv.filter((value) => value !== "--json")[0];',
|
||||||
|
'if (command === "capabilities") {',
|
||||||
|
` fs.writeFileSync(${JSON.stringify(capabilityLog)}, JSON.stringify({ argv, env: process.env }));`,
|
||||||
|
` process.stdout.write(${JSON.stringify(`${JSON.stringify(options.capabilityEnvelope ?? capabilityEnvelope(DEFAULT_CAPABILITY_COMMANDS))}\n`)});`,
|
||||||
|
' process.exit(0);',
|
||||||
|
'}',
|
||||||
`fs.writeFileSync(${JSON.stringify(log)}, JSON.stringify({ argv: process.argv.slice(2), env: process.env }));`,
|
`fs.writeFileSync(${JSON.stringify(log)}, JSON.stringify({ argv: process.argv.slice(2), env: process.env }));`,
|
||||||
'process.stdout.write(`ito-probe:${process.argv.slice(2).join("|")}\\n`);',
|
'process.stdout.write(`ito-probe:${process.argv.slice(2).join("|")}\\n`);',
|
||||||
'process.stderr.write("ito-probe-stderr\\n");',
|
'process.stderr.write("ito-probe-stderr\\n");',
|
||||||
@@ -94,7 +140,7 @@ function makeItoProbe(exitCode = 0) {
|
|||||||
if (process.platform !== "win32") {
|
if (process.platform !== "win32") {
|
||||||
fs.chmodSync(script, 0o755);
|
fs.chmodSync(script, 0o755);
|
||||||
}
|
}
|
||||||
return Object.freeze({ directory, executable, log });
|
return Object.freeze({ capabilityLog, directory, executable, log });
|
||||||
}
|
}
|
||||||
|
|
||||||
function readInvocation(probe) {
|
function readInvocation(probe) {
|
||||||
@@ -132,6 +178,92 @@ async function main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
|
["derives a newly supported read-only command from a credential-free capability probe", () => {
|
||||||
|
const probe = makeItoProbe();
|
||||||
|
try {
|
||||||
|
const result = runCli(["ito", "workload-status", "run_123", "--json"], {
|
||||||
|
ECC_ITO_CLI_EXECUTABLE: probe.executable,
|
||||||
|
ITO_API_KEY: "ito_test_key",
|
||||||
|
ITO_API_URL: "https://compute.example.test",
|
||||||
|
AWS_SECRET_ACCESS_KEY: "must-not-cross",
|
||||||
|
});
|
||||||
|
assert.strictEqual(result.status, 0, result.stderr);
|
||||||
|
const capabilityInvocation = JSON.parse(fs.readFileSync(probe.capabilityLog, "utf8"));
|
||||||
|
assert.deepStrictEqual(capabilityInvocation.argv, ["capabilities", "--json"]);
|
||||||
|
assert.strictEqual(capabilityInvocation.env.ITO_API_KEY, undefined);
|
||||||
|
assert.strictEqual(capabilityInvocation.env.ITO_API_URL, undefined);
|
||||||
|
assert.strictEqual(capabilityInvocation.env.AWS_SECRET_ACCESS_KEY, undefined);
|
||||||
|
assert.strictEqual(capabilityInvocation.env.ECC_ITO_CLI_EXECUTABLE, undefined);
|
||||||
|
const targetInvocation = readInvocation(probe);
|
||||||
|
assert.deepStrictEqual(targetInvocation.argv, ["--json", "workload-status", "run_123"]);
|
||||||
|
assert.strictEqual(targetInvocation.env.ITO_API_KEY, "ito_test_key");
|
||||||
|
assert.strictEqual(targetInvocation.env.ITO_API_URL, "https://compute.example.test");
|
||||||
|
} finally {
|
||||||
|
fs.rmSync(probe.directory, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
["blocks advertised workload mutations after capability discovery", () => {
|
||||||
|
const probe = makeItoProbe();
|
||||||
|
try {
|
||||||
|
const result = runCli([
|
||||||
|
"ito", "serve", "--model", "org/model", "--entitlement", "ent_123", "--confirm",
|
||||||
|
], { ECC_ITO_CLI_EXECUTABLE: probe.executable });
|
||||||
|
assert.notStrictEqual(result.status, 0);
|
||||||
|
assert.match(result.stderr, /workload_start|safe policy/i);
|
||||||
|
assert.ok(fs.existsSync(probe.capabilityLog), "capability discovery did not run");
|
||||||
|
assert.ok(!fs.existsSync(probe.log), "blocked workload command reached the target invocation");
|
||||||
|
} finally {
|
||||||
|
fs.rmSync(probe.directory, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
["requires exact tuples for every explicitly reviewed effectful command", () => {
|
||||||
|
for (const commandName of ["login", "logout", "find", "evals"]) {
|
||||||
|
const commands = DEFAULT_CAPABILITY_COMMANDS.map((command) => (
|
||||||
|
command.name === commandName
|
||||||
|
? { ...command, auth: "none", network: "none", side_effect: "none", authority: "none" }
|
||||||
|
: command
|
||||||
|
));
|
||||||
|
const manifest = parseItoCapabilities(JSON.stringify(capabilityEnvelope(commands)));
|
||||||
|
assert.throws(
|
||||||
|
() => authorizeEccCapability(manifest, commandName),
|
||||||
|
/outside ECC's safe policy/i,
|
||||||
|
commandName,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
["allows status only under the exact provisioning-reconcile tuple", () => {
|
||||||
|
const manifest = parseItoCapabilities(JSON.stringify(capabilityEnvelope(DEFAULT_CAPABILITY_COMMANDS)));
|
||||||
|
assert.strictEqual(authorizeEccCapability(manifest, "status").side_effect, "provisioning_reconcile");
|
||||||
|
const mislabeled = DEFAULT_CAPABILITY_COMMANDS.map((command) => (
|
||||||
|
command.name === "status"
|
||||||
|
? { ...command, side_effect: "none", authority: "none" }
|
||||||
|
: command
|
||||||
|
));
|
||||||
|
assert.throws(
|
||||||
|
() => authorizeEccCapability(
|
||||||
|
parseItoCapabilities(JSON.stringify(capabilityEnvelope(mislabeled))),
|
||||||
|
"status",
|
||||||
|
),
|
||||||
|
/outside ECC's safe policy/i,
|
||||||
|
);
|
||||||
|
}],
|
||||||
|
["fails closed on duplicate command records in the installed manifest", () => {
|
||||||
|
const duplicateAuth = DEFAULT_CAPABILITY_COMMANDS.find(({ name }) => name === "auth");
|
||||||
|
const probe = makeItoProbe(0, {
|
||||||
|
capabilityEnvelope: capabilityEnvelope([duplicateAuth, duplicateAuth]),
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
const result = runCli(["ito", "auth"], {
|
||||||
|
ECC_ITO_CLI_EXECUTABLE: probe.executable,
|
||||||
|
ITO_API_KEY: "must-not-cross-after-invalid-contract",
|
||||||
|
});
|
||||||
|
assert.notStrictEqual(result.status, 0);
|
||||||
|
assert.match(result.stderr, /duplicate|capabilit/i);
|
||||||
|
assert.ok(!fs.existsSync(probe.log), "invalid capability contract reached target invocation");
|
||||||
|
} finally {
|
||||||
|
fs.rmSync(probe.directory, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
}],
|
||||||
["forwards logout with device-token settings but never an API key", () => {
|
["forwards logout with device-token settings but never an API key", () => {
|
||||||
const probe = makeItoProbe();
|
const probe = makeItoProbe();
|
||||||
try {
|
try {
|
||||||
@@ -263,6 +395,11 @@ async function main() {
|
|||||||
probe.executable,
|
probe.executable,
|
||||||
[
|
[
|
||||||
'"use strict";',
|
'"use strict";',
|
||||||
|
'const argv = process.argv.slice(2);',
|
||||||
|
'if (argv.filter((value) => value !== "--json")[0] === "capabilities") {',
|
||||||
|
` process.stdout.write(${JSON.stringify(`${JSON.stringify(capabilityEnvelope(DEFAULT_CAPABILITY_COMMANDS))}\n`)});`,
|
||||||
|
' process.exit(0);',
|
||||||
|
'}',
|
||||||
'process.stdout.write("device-code-now\\n");',
|
'process.stdout.write("device-code-now\\n");',
|
||||||
'setTimeout(() => process.exit(7), 500);',
|
'setTimeout(() => process.exit(7), 500);',
|
||||||
"",
|
"",
|
||||||
@@ -472,7 +609,7 @@ async function main() {
|
|||||||
/timeout: isNodeQualification \? NODE_QUALIFICATION_TIMEOUT_MS : undefined/,
|
/timeout: isNodeQualification \? NODE_QUALIFICATION_TIMEOUT_MS : undefined/,
|
||||||
);
|
);
|
||||||
}],
|
}],
|
||||||
["rejects unsupported browser, paper, and execution operations before spawning", () => {
|
["rejects unsupported browser, paper, and execution operations after safe discovery", () => {
|
||||||
for (const command of ["rent", "lock", "purchase", "run", "inference", "mcp"]) {
|
for (const command of ["rent", "lock", "purchase", "run", "inference", "mcp"]) {
|
||||||
const probe = makeItoProbe();
|
const probe = makeItoProbe();
|
||||||
try {
|
try {
|
||||||
@@ -480,8 +617,9 @@ async function main() {
|
|||||||
ECC_ITO_CLI_EXECUTABLE: probe.executable,
|
ECC_ITO_CLI_EXECUTABLE: probe.executable,
|
||||||
});
|
});
|
||||||
assert.notStrictEqual(result.status, 0, command);
|
assert.notStrictEqual(result.status, 0, command);
|
||||||
assert.match(result.stderr, /only login, logout, auth, find, status, and evals/i);
|
assert.match(result.stderr, /does not advertise|safe policy/i);
|
||||||
assert.ok(!fs.existsSync(probe.log), `${command} must not spawn the Itô CLI`);
|
assert.ok(fs.existsSync(probe.capabilityLog), `${command} must inspect capabilities`);
|
||||||
|
assert.ok(!fs.existsSync(probe.log), `${command} must not reach target execution`);
|
||||||
} finally {
|
} finally {
|
||||||
fs.rmSync(probe.directory, { recursive: true, force: true });
|
fs.rmSync(probe.directory, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user