@ouro.bot/cli 0.1.0-alpha.400 → 0.1.0-alpha.401

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/changelog.json CHANGED
@@ -1,6 +1,16 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.401",
6
+ "changes": [
7
+ "Bitwarden-backed credential writes now prove success by reading the saved item back immediately and verifying its name, username, password, and notes before returning success.",
8
+ "Post-save verification now prefers `bw get item <id>` when create/edit returns a usable id, falls back cleanly when stdout is malformed or id-less, and retries once when the local Bitwarden session expires mid-verification.",
9
+ "Malformed or invalid `bw get item` responses now fail with short sanitized errors instead of leaving auth and vault save flows in an ambiguous half-success state.",
10
+ "Runtime auth's Bitwarden harness coverage now exercises the same post-save readback path as the real vault store, and the store test suite covers missing items, malformed responses, field-by-field mismatches, and multi-field mismatch guidance.",
11
+ "`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the vault write readback verification release."
12
+ ]
13
+ },
4
14
  {
5
15
  "version": "0.1.0-alpha.400",
6
16
  "changes": [
@@ -184,6 +184,34 @@ function parseBwItems(stdout, context) {
184
184
  throw new Error(`bw CLI error: invalid JSON from ${context}`);
185
185
  }
186
186
  }
187
+ function parseBwItem(stdout, context) {
188
+ let parsed;
189
+ try {
190
+ parsed = JSON.parse(stdout);
191
+ if (!isBwLoginItem(parsed)) {
192
+ throw new Error("expected login item");
193
+ }
194
+ return parsed;
195
+ }
196
+ catch {
197
+ if (parsed !== undefined) {
198
+ throw new Error(`bw CLI error: invalid item from ${context}`);
199
+ }
200
+ throw new Error(`bw CLI error: invalid JSON from ${context}`);
201
+ }
202
+ }
203
+ function parseBwItemId(stdout) {
204
+ try {
205
+ const parsed = JSON.parse(stdout);
206
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
207
+ return null;
208
+ const id = parsed.id;
209
+ return typeof id === "string" && id.trim().length > 0 ? id : null;
210
+ }
211
+ catch {
212
+ return null;
213
+ }
214
+ }
187
215
  // ---------------------------------------------------------------------------
188
216
  // BitwardenCredentialStore
189
217
  // ---------------------------------------------------------------------------
@@ -387,12 +415,20 @@ class BitwardenCredentialStore {
387
415
  notes: data.notes ?? null,
388
416
  };
389
417
  const encoded = Buffer.from(JSON.stringify(item)).toString("base64");
418
+ let savedItem;
390
419
  if (existing) {
391
- await execBw(["edit", "item", existing.id], session, this.appDataDir, encoded);
420
+ const stdout = await execBw(["edit", "item", existing.id], session, this.appDataDir, encoded);
421
+ const savedItemId = parseBwItemId(stdout) ?? existing.id;
422
+ savedItem = await this.findItemById(savedItemId, session);
392
423
  }
393
424
  else {
394
- await execBw(["create", "item"], session, this.appDataDir, encoded);
425
+ const stdout = await execBw(["create", "item"], session, this.appDataDir, encoded);
426
+ const savedItemId = parseBwItemId(stdout);
427
+ savedItem = savedItemId
428
+ ? await this.findItemById(savedItemId, session)
429
+ : await this.findItemByDomain(domain, session);
395
430
  }
431
+ this.assertStoredCredentialMatches(domain, data, savedItem);
396
432
  });
397
433
  (0, runtime_1.emitNervesEvent)({
398
434
  event: "repertoire.bw_credential_store_end",
@@ -457,5 +493,27 @@ class BitwardenCredentialStore {
457
493
  // Find exact match by name
458
494
  return items.find((item) => item.name === domain) ?? null;
459
495
  }
496
+ async findItemById(id, session) {
497
+ const stdout = await execBw(["get", "item", id], session, this.appDataDir);
498
+ return parseBwItem(stdout, "bw get item");
499
+ }
500
+ assertStoredCredentialMatches(domain, data, item) {
501
+ if (!item) {
502
+ throw new Error(`bw CLI error: credential save verification failed for ${domain}: saved item could not be read back after write`);
503
+ }
504
+ const mismatches = [];
505
+ if (item.name !== domain)
506
+ mismatches.push("name");
507
+ if ((item.login?.username ?? "") !== (data.username ?? ""))
508
+ mismatches.push("username");
509
+ if ((item.login?.password ?? "") !== data.password)
510
+ mismatches.push("password");
511
+ if ((item.notes ?? null) !== (data.notes ?? null))
512
+ mismatches.push("notes");
513
+ if (mismatches.length > 0) {
514
+ const label = mismatches.length === 1 ? "field" : "fields";
515
+ throw new Error(`bw CLI error: credential save verification failed for ${domain}: saved item did not match requested ${label} ${mismatches.join(", ")}`);
516
+ }
517
+ }
460
518
  }
461
519
  exports.BitwardenCredentialStore = BitwardenCredentialStore;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.400",
3
+ "version": "0.1.0-alpha.401",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",