@inetafrica/open-claudia 3.4.23 → 3.5.0

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.
@@ -8,7 +8,12 @@ const fs = require("fs");
8
8
  const os = require("os");
9
9
  const path = require("path");
10
10
 
11
+ // The CLI asks the running bot who it acts for; never let this suite (which
12
+ // may run inside a bot turn) reach that bot.
13
+ for (const key of Object.keys(process.env)) if (key.startsWith("OC_")) delete process.env[key];
14
+
11
15
  const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "tool-manifest-test-"));
16
+ process.env.OPEN_CLAUDIA_CONFIG_DIR = path.join(tmp, "config");
12
17
  process.env.TOOLS_DIR = path.join(tmp, "tools");
13
18
  process.env.KEYRING_FILE = path.join(tmp, "keyring.json");
14
19
  process.env.APPROVALS_DIR = path.join(tmp, "approvals");
@@ -142,6 +147,32 @@ const topLevelEnv = {};
142
147
  await toolCli.run(["run", "vaulted", "go", "--approval", b10rec.id]);
143
148
  assert.strictEqual(process.exitCode, 0, "the same token redeems once the key exists");
144
149
  assert.ok(approvals.read(b10rec.id).consumedAt, "token consumed exactly by the real run");
150
+
151
+ // ── an undeclared verb is refused at the CLI before anything else — even
152
+ // with an approved token for that exact command, which stays unconsumed
153
+ // (the smart-josephine `whatsapp chats` case used to reach the owner).
154
+ const chatsCmd = approvals.formatApprovedCommand(["open-claudia", "tool", "run", "fleet", "chats"]);
155
+ const chatsRec = approvals.create({ tool: "fleet", tier: "write", command: chatsCmd, channelId: "c1", adapter: "tg" });
156
+ approvals.decide(chatsRec.id, "approved", "c1");
157
+ errs.length = 0;
158
+ process.exitCode = 0;
159
+ await toolCli.run(["run", "fleet", "chats", "--approval", chatsRec.id]);
160
+ assert.strictEqual(process.exitCode, 3, "undeclared verb refused (exit 3)");
161
+ assert.ok(errs.some((l) => /no declared verb "chats" — its manifest allows: list, restart, purge/.test(l)), "the refusal lists the declared verbs");
162
+ assert.strictEqual(approvals.read(chatsRec.id).consumedAt, undefined, "the token is never redeemed for an undeclared verb");
163
+
164
+ // ── a redeemed approval exports exactly the approved tier to the tool (a
165
+ // write approval no longer hands nested tools destructive access) ──
166
+ const tierSrc = path.join(tmp, "tiered.sh");
167
+ fs.writeFileSync(tierSrc, `#!/usr/bin/env bash\necho "$OPEN_CLAUDIA_APPROVED_TIER" > ${JSON.stringify(path.join(tmp, "tier.out"))}\n`);
168
+ tools.addTool(tierSrc, { name: "tiered", description: "reports its approved tier", risk: "write" });
169
+ const tierCmd = approvals.formatApprovedCommand(["open-claudia", "tool", "run", "tiered", "go"]);
170
+ const tierRec = approvals.create({ tool: "tiered", tier: "write", command: tierCmd, channelId: "c1", adapter: "tg" });
171
+ approvals.decide(tierRec.id, "approved", "c1");
172
+ process.exitCode = 0;
173
+ await toolCli.run(["run", "tiered", "go", "--approval", tierRec.id]);
174
+ assert.strictEqual(process.exitCode, 0, "the write approval redeems");
175
+ assert.strictEqual(fs.readFileSync(path.join(tmp, "tier.out"), "utf-8").trim(), "write", "the run carries the approved tier, not destructive");
145
176
  } finally {
146
177
  for (const key of approvalKeys) {
147
178
  if (savedApprovalEnv[key] === undefined) delete process.env[key];