@withone/cli 2.9.1 → 2.9.2

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/README.md CHANGED
@@ -50,10 +50,14 @@ one logout # Clear credentials (with scope picker and confirmation)
50
50
 
51
51
  The browser consent page names the key and tags it with where this CLI is installed (scope, project path, machine, OS user, CLI version, chosen harnesses, and the per-install device id unless telemetry is off) so you can find and revoke it from Settings → API keys. The terminal prints exactly what will be sent before the browser opens.
52
52
 
53
- Requires Node.js 18+. `one sync` additionally needs Node 20+, because its
54
- local SQLite engine (`better-sqlite3`, an optional dependency) ships prebuilt
55
- binaries only for Node 20 and above. On Node 18 every other command works
56
- normally; `one sync` reports that the engine isn't installed.
53
+ Requires Node.js 22.23.4+, 24.22.1+ or 26.12.1+. Older Node versions trust the
54
+ compromised eMudhra intermediate CA certificates (October 2026), so a network
55
+ attacker could intercept the CLI's traffic and your API key. On them the CLI
56
+ refuses to run and prints the command that updates Node for how you installed
57
+ it. Node 18, 20, 23 and 25 are end-of-life and never got the fix.
58
+
59
+ If you can't update Node yet, `ONE_ALLOW_UNPATCHED_NODE=1` runs the CLI anyway,
60
+ with a security warning on every run. You remain exposed while it is set.
57
61
 
58
62
  ## Quick start
59
63
 
package/bin/cli.js CHANGED
@@ -1,5 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { program } from '../dist/index.js';
3
+ import { requirePatchedNode } from '../dist/node-check.js';
4
+
5
+ // eMudhra CA compromise: refuse to run before any connection opens on a Node
6
+ // that still trusts the leaked intermediates (see src/node-check.ts).
7
+ requirePatchedNode();
8
+
9
+ const { program } = await import('../dist/index.js');
4
10
 
5
11
  program.parse();
@@ -0,0 +1,79 @@
1
+ // src/node-check.ts
2
+ var FIXED_IN = {
3
+ 22: [23, 4],
4
+ 24: [22, 1],
5
+ 26: [12, 1]
6
+ };
7
+ var FIRST_LINE_WITH_FIX = 27;
8
+ var RECOMMENDED_LINE = 24;
9
+ var REQUIRED_NODE = "22.23.4+, 24.22.1+ or 26.12.1+";
10
+ var REQUIRED_NODE_RANGE = "^22.23.4 || ^24.22.1 || >=26.12.1";
11
+ var ALLOW_UNPATCHED_ENV = "ONE_ALLOW_UNPATCHED_NODE";
12
+ function parseVersion(version) {
13
+ const [major, minor, patch] = version.split(".").map((part) => Number.parseInt(part, 10));
14
+ return [major, minor, patch ?? 0];
15
+ }
16
+ function nodeHasTlsFix(version = process.versions.node) {
17
+ const [major, minor, patch] = parseVersion(version);
18
+ if (!Number.isFinite(major)) return false;
19
+ if (major >= FIRST_LINE_WITH_FIX) return true;
20
+ const fixed = FIXED_IN[major];
21
+ if (!fixed) return false;
22
+ const [fixedMinor, fixedPatch] = fixed;
23
+ return minor > fixedMinor || minor === fixedMinor && patch >= fixedPatch;
24
+ }
25
+ function upgradeCommand(version = process.versions.node, execPath = process.execPath) {
26
+ const [major] = parseVersion(version);
27
+ const line = FIXED_IN[major] ? major : RECOMMENDED_LINE;
28
+ const path = execPath.replace(/\\/g, "/");
29
+ if (/\/\.nvm\/versions\/node\//.test(path)) return `nvm install ${line} && nvm alias default ${line}`;
30
+ if (/\/AppData\/(Roaming|Local)\/nvm\//i.test(path)) return `nvm install ${line} && nvm use ${line}`;
31
+ if (/\/\.?volta\//i.test(path)) return `volta install node@${line}`;
32
+ if (/fnm/i.test(path)) return `fnm install ${line} && fnm default ${line}`;
33
+ const brew = path.match(/\/Cellar\/(node(?:@\d+)?)\//);
34
+ if (brew) {
35
+ const formula = brew[1] === "node" || FIXED_IN[major] ? brew[1] : `node@${line}`;
36
+ return formula === brew[1] ? `brew upgrade ${formula}` : `brew install ${formula}`;
37
+ }
38
+ return `download Node.js ${line} from https://nodejs.org`;
39
+ }
40
+ function unpatchedNodeMessage(version = process.versions.node) {
41
+ return `Node.js v${version} trusts the compromised eMudhra certificates, so a network attacker could intercept One's traffic and your API key. The One CLI requires Node.js ${REQUIRED_NODE} (Node 18, 20, 23 and 25 never got the fix).`;
42
+ }
43
+ function requirePatchedNode() {
44
+ if (nodeHasTlsFix()) return;
45
+ const message = unpatchedNodeMessage();
46
+ const upgrade = upgradeCommand();
47
+ const agent = process.argv.includes("--agent") || process.env.ONE_AGENT === "1";
48
+ if (process.env[ALLOW_UNPATCHED_ENV] === "1") {
49
+ if (!agent) process.stderr.write(`Warning: ${message} Running anyway because ${ALLOW_UNPATCHED_ENV}=1.
50
+ `);
51
+ return;
52
+ }
53
+ if (agent) {
54
+ const error = {
55
+ error: `${message} Ask the user to update Node.js: ${upgrade}`,
56
+ code: "NODE_UPGRADE_REQUIRED",
57
+ currentNode: process.versions.node,
58
+ requiredNode: REQUIRED_NODE_RANGE,
59
+ upgrade
60
+ };
61
+ process.stdout.write(`${JSON.stringify(error)}
62
+ `);
63
+ } else {
64
+ process.stderr.write(`Error: ${message}
65
+ To update: ${upgrade}
66
+ `);
67
+ }
68
+ process.exit(1);
69
+ }
70
+
71
+ export {
72
+ REQUIRED_NODE,
73
+ REQUIRED_NODE_RANGE,
74
+ ALLOW_UNPATCHED_ENV,
75
+ nodeHasTlsFix,
76
+ upgradeCommand,
77
+ unpatchedNodeMessage,
78
+ requirePatchedNode
79
+ };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Command } from 'commander';
2
+ export { nodeHasTlsFix } from './node-check.js';
2
3
 
3
4
  declare const program: Command;
4
5
 
package/dist/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ import {
2
+ nodeHasTlsFix
3
+ } from "./chunk-FYTWXGPJ.js";
1
4
  import {
2
5
  ApiError,
3
6
  FLOW_SCHEMA,
@@ -10917,6 +10920,7 @@ Request specific sections:
10917
10920
  - **Always use \`--agent\` flag** for structured JSON output
10918
10921
  - Platform names are **lowercase**; multi-word names use dashes (e.g., \`hubspot\`, \`google-calendar\`)
10919
10922
  - Always use the **exact action ID** from a find answer \u2014 don't guess
10923
+ - Requires Node.js 22.23.4+, 24.22.1+ or 26.12.1+. Older Node trusts the compromised eMudhra CA certificates, so every command exits 1 there with \`"code": "NODE_UPGRADE_REQUIRED"\` and an \`upgrade\` field holding the command for the user's setup. Don't retry: show the user that command and ask them to update Node.js
10920
10924
  - Always read **knowledge** before executing any action
10921
10925
  - Connection keys come from \`one connection list\` \u2014 don't hardcode them
10922
10926
  - \`connection list\` also reports an \`access\` field per connection (\`full\` / \`methods\` / \`actions\`, plus a \`level\`: full, read-write, read-only, custom, none) \u2014 what One enforces for this key, narrowed by \`one config\`. Read it before planning so you don't propose an action that will be refused. \`accessSource: "local"\` means One did not report it, so it is unverified
@@ -13441,5 +13445,6 @@ program.command("list").alias("ls").description("Shortcut for: connection list")
13441
13445
  await connectionListCommand(options);
13442
13446
  });
13443
13447
  export {
13448
+ nodeHasTlsFix,
13444
13449
  program
13445
13450
  };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Refuses to run on a Node.js that still trusts the compromised eMudhra
3
+ * intermediate CAs (October 2026, RUSTSEC-2026-0381).
4
+ *
5
+ * Eight eMudhra/emSign intermediates were created with 8-bit private keys, so
6
+ * anyone can compute them and sign a certificate for any domain, including
7
+ * api.withone.ai. Node.js blocks them inside the TLS handshake from 22.23.4,
8
+ * 24.22.1 and 26.12.1 (nodejs/node#66871). On any older Node, a network
9
+ * attacker can intercept the CLI's traffic and the user's API key, and nothing
10
+ * in userland can block the intermediates the way Node's fix does.
11
+ *
12
+ * Built as its own entry so bin/cli.js can run it before loading the rest of
13
+ * the CLI, and before any connection opens.
14
+ */
15
+ declare const REQUIRED_NODE = "22.23.4+, 24.22.1+ or 26.12.1+";
16
+ declare const REQUIRED_NODE_RANGE = "^22.23.4 || ^24.22.1 || >=26.12.1";
17
+ /** Set to 1 to run on an unpatched Node anyway, with a warning on every run. */
18
+ declare const ALLOW_UNPATCHED_ENV = "ONE_ALLOW_UNPATCHED_NODE";
19
+ /** True when this Node version rejects chains through the compromised eMudhra intermediates. */
20
+ declare function nodeHasTlsFix(version?: string): boolean;
21
+ /**
22
+ * The command that updates Node for however it was installed, judged from the
23
+ * path of the running binary. A line that got the fix stays on its line; any
24
+ * other moves to the recommended one.
25
+ */
26
+ declare function upgradeCommand(version?: string, execPath?: string): string;
27
+ declare function unpatchedNodeMessage(version?: string): string;
28
+ /**
29
+ * Exits with an error on an unpatched Node; returns on a patched one. In agent
30
+ * mode the error is JSON on stdout with a code agents can act on. With
31
+ * ONE_ALLOW_UNPATCHED_NODE=1 it warns and returns instead (silently in agent
32
+ * mode, where stderr would corrupt the JSON for harnesses that merge streams).
33
+ */
34
+ declare function requirePatchedNode(): void;
35
+
36
+ export { ALLOW_UNPATCHED_ENV, REQUIRED_NODE, REQUIRED_NODE_RANGE, nodeHasTlsFix, requirePatchedNode, unpatchedNodeMessage, upgradeCommand };
@@ -0,0 +1,18 @@
1
+ import {
2
+ ALLOW_UNPATCHED_ENV,
3
+ REQUIRED_NODE,
4
+ REQUIRED_NODE_RANGE,
5
+ nodeHasTlsFix,
6
+ requirePatchedNode,
7
+ unpatchedNodeMessage,
8
+ upgradeCommand
9
+ } from "./chunk-FYTWXGPJ.js";
10
+ export {
11
+ ALLOW_UNPATCHED_ENV,
12
+ REQUIRED_NODE,
13
+ REQUIRED_NODE_RANGE,
14
+ nodeHasTlsFix,
15
+ requirePatchedNode,
16
+ unpatchedNodeMessage,
17
+ upgradeCommand
18
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withone/cli",
3
- "version": "2.9.1",
3
+ "version": "2.9.2",
4
4
  "description": "CLI for managing One",
5
5
  "type": "module",
6
6
  "files": [
@@ -52,6 +52,6 @@
52
52
  "url": "https://github.com/withoneai/cli"
53
53
  },
54
54
  "engines": {
55
- "node": ">=18"
55
+ "node": "^22.23.4 || ^24.22.1 || >=26.12.1"
56
56
  }
57
57
  }
@@ -171,6 +171,8 @@ All segments are validated before any execution. Failed actions don't block othe
171
171
 
172
172
  All errors return JSON: `{"error": "message"}`. Parse output as JSON and check for the `error` key.
173
173
 
174
+ The CLI requires Node.js 22.23.4+, 24.22.1+ or 26.12.1+ (older Node trusts the compromised eMudhra CA certificates). On an older Node every command exits 1 with `"code": "NODE_UPGRADE_REQUIRED"` and an `upgrade` field holding the command for the user's setup. Don't retry: show the user that command and ask them to update Node.js.
175
+
174
176
  ## Important Rules
175
177
 
176
178
  - Always use `--agent` flag for structured JSON output