fix(ito-compute): complete device auth lifecycle

This commit is contained in:
Affaan Mustafa
2026-08-07 14:50:39 -04:00
parent f16a6ff2a6
commit f41ba2f949
12 changed files with 73 additions and 18 deletions
+1 -1
View File
@@ -566,7 +566,7 @@ Kimi Code discovers the installed `.kimi-code/AGENTS.md` instructions and `.kimi
`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.
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. 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, 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.
`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.
</details>
+6 -2
View File
@@ -24,10 +24,11 @@ ECC delegates to the canonical Itô package in
`Ito-Markets/ito-cloud-runtime/cli/ito-compute-cli`. ECC does not maintain a
second API client or response schema.
The wrapper exposes only the canonical CLI's `login`, `auth`, `find`, `status`, and `evals`
The wrapper exposes only the canonical CLI's `login`, `logout`, `auth`, `find`, `status`, and `evals`
operations:
ecc ito login [--no-browser]
ecc ito logout
ecc ito auth
ecc ito find <all required RFQ constraints>
ecc ito status
@@ -76,6 +77,9 @@ directory and 0600 token-file permissions. ECC does not inspect or log secrets.
- `login` starts canonical device authorization, with `--no-browser` available
when the operator does not want the CLI to open the verification page.
- `logout` revokes the current device credential and removes the local copy only
after confirmed remote revocation; a failed revocation keeps the local copy
for retry.
- `auth` validates existing credentials only.
- `find` reads live inventory and submits a live authenticated RFQ. An operator
or agent must gather every hard topology/economic constraint and obtain
@@ -132,7 +136,7 @@ after review.
The local contract suite proves:
- only the four supported operations spawn;
- only the six supported operations spawn;
- RFQ arguments are forwarded without economic reinterpretation;
- only approved Itô runtime or isolated node-qualification variables cross the
process boundary;
+3 -2
View File
@@ -8,7 +8,8 @@ handoff. No external plan file was executed.
## User journeys
1. As an ECC operator, I can explicitly invoke streaming device `login`, then
use validation-only `auth`, `find`, and `status` without a duplicate client.
use validation-only `auth`, `find`, and `status`, or revoke the device with
`logout`, without a duplicate client.
2. As a security reviewer, I can prove unsupported operations, missing local
installs, and ECC dry-run requests fail before any child process or network
operation.
@@ -56,7 +57,7 @@ module. No dependency installation was performed.
| Guarantee | Test | Type | Result |
|---|---|---|---|
| `login`, `auth`, `find`, and `status` forward only their reviewed surfaces | `tests/scripts/ito-cli-bridge.test.js` | end-to-end process contract | PASS |
| `login`, `logout`, `auth`, `find`, and `status` forward only their reviewed surfaces | `tests/scripts/ito-cli-bridge.test.js` | end-to-end process contract | PASS |
| Login output streams before completion and its exit status propagates | `tests/scripts/ito-cli-bridge.test.js` | async process contract | PASS |
| `auth --no-browser` fails before spawn | `tests/scripts/ito-cli-bridge.test.js` | negative process contract | PASS |
| Full RFQ arguments cross unchanged | `tests/scripts/ito-cli-bridge.test.js` | integration | PASS |
+1 -1
View File
@@ -197,7 +197,7 @@
{
"id": "capability:ito-compute",
"family": "capability",
"description": "Authenticated Itô GPU inventory, RFQ, status, and explicitly gated node-qualification workflows through the separately installed canonical CLI.",
"description": "Authenticated Itô GPU inventory, RFQ, status, device revocation, and explicitly gated node-qualification workflows through the separately installed canonical CLI.",
"modules": [
"ito-compute"
]
+1 -1
View File
@@ -605,7 +605,7 @@
{
"id": "ito-compute",
"kind": "skills",
"description": "Authenticated Itô GPU inventory, RFQ, status, and explicitly gated node-qualification workflows through the separately installed canonical CLI.",
"description": "Authenticated Itô GPU inventory, RFQ, status, device revocation, and explicitly gated node-qualification workflows through the separately installed canonical CLI.",
"paths": [
"skills/ito-compute",
"skills/ito-inference",
+1
View File
@@ -164,6 +164,7 @@ Examples:
ecc consult "security reviews"
ecc control-pane --port 8765
ecc ito login [--no-browser]
ecc ito logout
ecc ito auth
ecc ito find --gpu h200 --count 8 --nodes 1 --gpus-per-node 8 --days 30 --storage-tb 1 --start-window 2099-08-15 --max-rate 3.00 --form-factor bare_metal --contract-type reservation --fabric infiniband --region us-east-1
ecc ito status --json
+6 -3
View File
@@ -10,7 +10,7 @@ const {
getInvocationCommand,
} = require("./lib/ito-environment");
const SUPPORTED_COMMANDS = Object.freeze(["login", "auth", "find", "status", "evals"]);
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_PACKAGE_PATH = "cli/ito-compute-cli";
const CANONICAL_ENTRY_SEGMENTS = Object.freeze([
@@ -29,11 +29,12 @@ ECC × Itô local CLI bridge
Usage:
ecc ito login [--no-browser]
ecc ito logout
ecc ito auth
ecc ito find <all required RFQ options>
ecc ito status
ecc ito evals --cluster <id> --live-sixtytwo --nodes <list> --config-dir <dir>
ecc ito <login|auth|find|status|evals> --json
ecc ito <login|logout|auth|find|status|evals> --json
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
@@ -42,6 +43,8 @@ and persists its device token in macOS Keychain. Pass --no-browser to
suppress that handoff. ECC itself performs no browser automation and adds no
lock, workload, inference, or purchase path.
"ecc ito auth" is validation-only and never starts device login.
"ecc ito logout" asks the canonical CLI to revoke the current device credential
and remove its local copy only after remote revocation is confirmed.
Important:
- "find" reads live inventory and submits an authenticated RFQ.
@@ -161,7 +164,7 @@ function parseArgs(argv, environment = process.env) {
const command = withoutJson.shift();
if (!SUPPORTED_COMMANDS.includes(command)) {
throw new Error(
`Unsupported Itô command "${command || "(missing)"}"; ECC permits only login, auth, find, status, and evals.`
`Unsupported Itô command "${command || "(missing)"}"; ECC permits only login, logout, auth, find, status, and evals.`
);
}
if (command === "auth" && withoutJson.includes("--no-browser")) {
+1 -1
View File
@@ -45,7 +45,7 @@ const ECC_ITO_CONTROL_KEYS = Object.freeze([
"ECC_ITO_CLI_EXECUTABLE",
"NODE_ENV",
]);
const ITO_RUNTIME_COMMANDS = new Set(["login", "auth", "find", "status"]);
const ITO_RUNTIME_COMMANDS = new Set(["login", "logout", "auth", "find", "status"]);
function copyDefined(source, target, key) {
if (typeof source[key] === "string") {
+15 -4
View File
@@ -1,8 +1,6 @@
---
name: ito-compute
description: Query live GPU inventory, submit an authenticated Itô fixed-rate RFQ, inspect RFQ or procurement status, 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, or validate GPU nodes.
metadata:
origin: ECC
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.
---
# Itô Compute
@@ -41,7 +39,9 @@ key or token in arguments, tracked files, MCP results, logs, or chat.
canonical CLI's device authorization, which opens the Itô verification page
by default and persists a device token in macOS Keychain. Use
`ecc ito login --no-browser` to suppress the page handoff. ECC itself does no
browser automation.
browser automation. If the originating agent cannot complete the signed-in
browser step, hand the exact command to the user; after approval finishes,
return to the originating task and continue with `ecc ito auth`.
Device tokens use macOS Keychain by default. File-token fallback is explicit
and its directory and token file must remain owner-only (0700 and 0600).
2. Run `ecc ito auth` to validate existing credentials; it never starts login
@@ -73,6 +73,9 @@ key or token in arguments, tracked files, MCP results, logs, or chat.
5. Run `ecc ito status` to inspect RFQs and procurement orders.
After an ambiguous transport failure, check status before repeating `find`.
6. 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 operator can retry; never delete the token manually as a substitute.
Inventory prices are indicative. An RFQ is not reserved capacity. Treat a rate
as fixed only when the canonical result contains a non-null firm quote.
@@ -131,6 +134,14 @@ The server exposes only:
`ito_auth`, gather explicit buyer authority and every hard constraint, call
`ito_find`, then poll with `ito_status` when needed.
## Rent or purchase semantics
`find` submits an RFQ and may return a firm quote, but it does not rent,
purchase, reserve, provision, or move funds. `status` is read-oriented, though
the provider endpoint may reconcile an existing procurement order. The passive
dashboard link in ECC help is a separate user-operated web route; do not open or
operate it as a substitute for a missing CLI capability.
## Unsupported operations
The supported client surface cannot lock quotes, reserve capacity, execute
+4
View File
@@ -0,0 +1,4 @@
interface:
display_name: "Itô Compute"
short_description: "GPU inventory, RFQs, status, and revocation"
default_prompt: "Use $ito-compute to request a live GPU RFQ, inspect status, or revoke this device safely."
+10 -1
View File
@@ -36,6 +36,7 @@ function main() {
const skill = read("skills/ito-compute/SKILL.md");
for (const command of [
"ecc ito login",
"ecc ito logout",
"ecc ito auth",
"ecc ito find",
"ecc ito status",
@@ -59,6 +60,9 @@ function main() {
assert.match(skill, /explicit absolute built entry/);
assert.match(skill, /never discovers[^\n]*through `PATH`/);
assert.match(skill, /ecc ito login --no-browser/);
assert.match(skill, /return to the originating (?:agent|task)/i);
assert.match(skill, /revok/i);
assert.match(skill, /rent or purchase/i);
assert.match(skill, /auth.*validat/i);
assert.match(skill, /--no-browser/);
assert.match(skill, /macOS Keychain/i);
@@ -70,6 +74,11 @@ function main() {
assert.match(skill, /explicit node/i);
assert.match(skill, /cannot (?:rent|launch|recover|repair)/i);
assert.doesNotMatch(skill, /npm link/);
const frontmatter = skill.match(/^---\n([\s\S]*?)\n---/)[1];
assert.doesNotMatch(frontmatter, /^metadata:/m);
const interfaceMetadata = read("skills/ito-compute/agents/openai.yaml");
assert.match(interfaceMetadata, /display_name: "Itô Compute"/);
assert.match(interfaceMetadata, /default_prompt: .*\$ito-compute/);
}],
["keeps README and integration docs aligned with the separated auth contract", () => {
for (const relativePath of [
@@ -108,7 +117,7 @@ function main() {
{
id: "capability:ito-compute",
family: "capability",
description: "Authenticated Itô GPU inventory, RFQ, status, and explicitly gated node-qualification workflows through the separately installed canonical CLI.",
description: "Authenticated Itô GPU inventory, RFQ, status, device revocation, and explicitly gated node-qualification workflows through the separately installed canonical CLI.",
modules: ["ito-compute"],
}
);
+24 -2
View File
@@ -118,7 +118,7 @@ async function main() {
const tests = [
["forwards only the reviewed RFQ CLI surface to an explicit local executable", () => {
for (const command of ["login", "auth", "find", "status"]) {
for (const command of ["login", "logout", "auth", "find", "status"]) {
const probe = makeItoProbe();
try {
const result = runCli(["ito", command], {
@@ -132,6 +132,27 @@ async function main() {
}
}
}],
["forwards logout with device-token settings but never an API key", () => {
const probe = makeItoProbe();
try {
const result = runCli(["ito", "logout", "--json"], {
ECC_ITO_CLI_EXECUTABLE: probe.executable,
ITO_API_KEY: "must-not-cross-into-device-revocation",
ITO_ALLOW_FILE_TOKEN: "1",
ITO_TOKEN_FILE: "/tmp/ito-device-token",
ITO_API_URL: "https://compute.example.test",
});
assert.strictEqual(result.status, 0, result.stderr);
const invocation = readInvocation(probe);
assert.deepStrictEqual(invocation.argv, ["--json", "logout"]);
assert.strictEqual(invocation.env.ITO_API_KEY, undefined);
assert.strictEqual(invocation.env.ITO_ALLOW_FILE_TOKEN, "1");
assert.strictEqual(invocation.env.ITO_TOKEN_FILE, "/tmp/ito-device-token");
assert.strictEqual(invocation.env.ITO_API_URL, "https://compute.example.test");
} finally {
fs.rmSync(probe.directory, { recursive: true, force: true });
}
}],
["forwards the canonical login browser opt-out without performing browser automation", () => {
const probe = makeItoProbe();
try {
@@ -459,7 +480,7 @@ async function main() {
ECC_ITO_CLI_EXECUTABLE: probe.executable,
});
assert.notStrictEqual(result.status, 0, command);
assert.match(result.stderr, /only login, auth, find, status, and evals/i);
assert.match(result.stderr, /only login, logout, auth, find, status, and evals/i);
assert.ok(!fs.existsSync(probe.log), `${command} must not spawn the Itô CLI`);
} finally {
fs.rmSync(probe.directory, { recursive: true, force: true });
@@ -632,6 +653,7 @@ async function main() {
});
assert.strictEqual(result.status, 0, result.stderr);
assert.match(result.stdout, /ecc ito login \[--no-browser\]/);
assert.match(result.stdout, /ecc ito logout/);
assert.match(result.stdout, /ecc ito auth/);
assert.match(result.stdout, /ecc ito find/);
assert.match(result.stdout, /ecc ito status/);