@red-hat-developer-hub/e2e-test-utils 2.1.15 → 2.1.16
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/dist/secrets/bitwarden.d.ts +43 -0
- package/dist/secrets/bitwarden.d.ts.map +1 -1
- package/dist/secrets/bitwarden.js +465 -53
- package/dist/secrets/cli.d.ts +48 -1
- package/dist/secrets/cli.d.ts.map +1 -1
- package/dist/secrets/cli.js +455 -28
- package/dist/secrets/command.d.ts +7 -0
- package/dist/secrets/command.d.ts.map +1 -1
- package/dist/secrets/command.js +103 -26
- package/dist/secrets/config.d.ts +11 -1
- package/dist/secrets/config.d.ts.map +1 -1
- package/dist/secrets/config.js +32 -1
- package/dist/secrets/environment-name.d.ts +2 -0
- package/dist/secrets/environment-name.d.ts.map +1 -0
- package/dist/secrets/environment-name.js +4 -0
- package/dist/secrets/environment.d.ts +10 -0
- package/dist/secrets/environment.d.ts.map +1 -1
- package/dist/secrets/environment.js +35 -4
- package/dist/secrets/exec.d.ts +9 -1
- package/dist/secrets/exec.d.ts.map +1 -1
- package/dist/secrets/exec.js +318 -38
- package/dist/secrets/gsm-wrapper.d.ts +42 -0
- package/dist/secrets/gsm-wrapper.d.ts.map +1 -0
- package/dist/secrets/gsm-wrapper.js +238 -0
- package/dist/secrets/gsm.d.ts +33 -0
- package/dist/secrets/gsm.d.ts.map +1 -0
- package/dist/secrets/gsm.js +172 -0
- package/dist/secrets/index.d.ts +9 -4
- package/dist/secrets/index.d.ts.map +1 -1
- package/dist/secrets/index.js +7 -2
- package/dist/secrets/lock.d.ts +3 -0
- package/dist/secrets/lock.d.ts.map +1 -0
- package/dist/secrets/lock.js +28 -0
- package/dist/secrets/mutation.d.ts +71 -0
- package/dist/secrets/mutation.d.ts.map +1 -0
- package/dist/secrets/mutation.js +210 -0
- package/dist/secrets/secret-input.d.ts +17 -0
- package/dist/secrets/secret-input.d.ts.map +1 -0
- package/dist/secrets/secret-input.js +40 -0
- package/dist/secrets/stream.d.ts +9 -0
- package/dist/secrets/stream.d.ts.map +1 -0
- package/dist/secrets/stream.js +211 -0
- package/dist/secrets/temporary-secret.d.ts +13 -0
- package/dist/secrets/temporary-secret.d.ts.map +1 -0
- package/dist/secrets/temporary-secret.js +87 -0
- package/dist/secrets/tests/bitwarden.test.js +640 -0
- package/dist/secrets/tests/cli.integration.test.js +131 -3
- package/dist/secrets/tests/cli.test.js +281 -6
- package/dist/secrets/tests/command.test.d.ts +2 -0
- package/dist/secrets/tests/command.test.d.ts.map +1 -0
- package/dist/secrets/tests/command.test.js +39 -0
- package/dist/secrets/tests/config.test.js +20 -1
- package/dist/secrets/tests/environment.test.js +145 -3
- package/dist/secrets/tests/exec.test.js +469 -2
- package/dist/secrets/tests/gsm-wrapper.test.d.ts +2 -0
- package/dist/secrets/tests/gsm-wrapper.test.d.ts.map +1 -0
- package/dist/secrets/tests/gsm-wrapper.test.js +166 -0
- package/dist/secrets/tests/gsm.test.d.ts +2 -0
- package/dist/secrets/tests/gsm.test.d.ts.map +1 -0
- package/dist/secrets/tests/gsm.test.js +181 -0
- package/dist/secrets/tests/mutation.test.d.ts +2 -0
- package/dist/secrets/tests/mutation.test.d.ts.map +1 -0
- package/dist/secrets/tests/mutation.test.js +390 -0
- package/dist/secrets/tests/secret-input.test.d.ts +2 -0
- package/dist/secrets/tests/secret-input.test.d.ts.map +1 -0
- package/dist/secrets/tests/secret-input.test.js +71 -0
- package/dist/secrets/tests/stream.test.d.ts +2 -0
- package/dist/secrets/tests/stream.test.d.ts.map +1 -0
- package/dist/secrets/tests/stream.test.js +88 -0
- package/dist/secrets/tests/temporary-secret.test.d.ts +2 -0
- package/dist/secrets/tests/temporary-secret.test.d.ts.map +1 -0
- package/dist/secrets/tests/temporary-secret.test.js +76 -0
- package/package.json +1 -1
|
@@ -141,6 +141,46 @@ test("syncs and reads only exact-prefix items from the selected collection", asy
|
|
|
141
141
|
assert.equal(calls[0]?.args[0], "--version");
|
|
142
142
|
assert.equal(calls.every((call) => call.env?.BW_SESSION === "synthetic-session"), true);
|
|
143
143
|
});
|
|
144
|
+
test("reads complete list results without fetching each note again", async () => {
|
|
145
|
+
const calls = [];
|
|
146
|
+
const runner = async (_command, args) => {
|
|
147
|
+
calls.push([...args]);
|
|
148
|
+
if (args[0] === "--version")
|
|
149
|
+
return result("2026.5.0");
|
|
150
|
+
if (args[0] === "status")
|
|
151
|
+
return result(JSON.stringify({ status: "unlocked" }));
|
|
152
|
+
if (args[0] === "sync")
|
|
153
|
+
return result();
|
|
154
|
+
if (args[1] === "collections") {
|
|
155
|
+
return result(JSON.stringify([
|
|
156
|
+
{
|
|
157
|
+
id: "collection-id",
|
|
158
|
+
name: "Rhdh Qe Ci Secrets",
|
|
159
|
+
organizationId: "org-id",
|
|
160
|
+
},
|
|
161
|
+
]));
|
|
162
|
+
}
|
|
163
|
+
if (args[1] === "items") {
|
|
164
|
+
return result(JSON.stringify([
|
|
165
|
+
{
|
|
166
|
+
id: "item-id",
|
|
167
|
+
name: "global/VAULT_TOKEN",
|
|
168
|
+
notes: "synthetic",
|
|
169
|
+
type: 2,
|
|
170
|
+
collectionIds: ["collection-id"],
|
|
171
|
+
organizationId: "org-id",
|
|
172
|
+
},
|
|
173
|
+
]));
|
|
174
|
+
}
|
|
175
|
+
throw new Error(`Unexpected command: ${args.join(" ")}`);
|
|
176
|
+
};
|
|
177
|
+
const secrets = await new BitwardenClient({
|
|
178
|
+
env: { BW_SESSION: "synthetic-session" },
|
|
179
|
+
runner,
|
|
180
|
+
}).read("rhdh-qe", [selectors[0]]);
|
|
181
|
+
assert.equal(secrets[0]?.value, "synthetic");
|
|
182
|
+
assert.equal(calls.some((args) => args[0] === "get" && args[1] === "item"), false);
|
|
183
|
+
});
|
|
144
184
|
test("rejects duplicate exact item names before returning secrets", async () => {
|
|
145
185
|
const runner = async (_command, args) => {
|
|
146
186
|
if (args[0] === "--version")
|
|
@@ -416,3 +456,603 @@ test("does not expose attachment command output when the command fails", async (
|
|
|
416
456
|
return true;
|
|
417
457
|
});
|
|
418
458
|
});
|
|
459
|
+
test("reads an exact rotation item with revision metadata", async () => {
|
|
460
|
+
const runner = async (_command, args) => {
|
|
461
|
+
if (args[0] === "--version")
|
|
462
|
+
return result("2026.5.0");
|
|
463
|
+
if (args[0] === "status")
|
|
464
|
+
return result(JSON.stringify({ status: "unlocked" }));
|
|
465
|
+
if (args[0] === "sync")
|
|
466
|
+
return result();
|
|
467
|
+
if (args[0] === "list" && args[1] === "collections") {
|
|
468
|
+
return result(JSON.stringify([
|
|
469
|
+
{
|
|
470
|
+
id: "collection-id",
|
|
471
|
+
name: "Rhdh Qe Ci Secrets",
|
|
472
|
+
organizationId: "org-id",
|
|
473
|
+
},
|
|
474
|
+
]));
|
|
475
|
+
}
|
|
476
|
+
if (args[0] === "list" && args[1] === "items") {
|
|
477
|
+
assert.deepEqual(args.slice(0, 4), [
|
|
478
|
+
"list",
|
|
479
|
+
"items",
|
|
480
|
+
"--collectionid",
|
|
481
|
+
"collection-id",
|
|
482
|
+
]);
|
|
483
|
+
return result(JSON.stringify([{ id: "item-id" }]));
|
|
484
|
+
}
|
|
485
|
+
if (args[0] === "get" && args[1] === "item") {
|
|
486
|
+
return result(JSON.stringify({
|
|
487
|
+
id: "item-id",
|
|
488
|
+
name: "rhdh/test",
|
|
489
|
+
notes: "old-value",
|
|
490
|
+
type: 2,
|
|
491
|
+
collectionIds: ["collection-id"],
|
|
492
|
+
organizationId: "org-id",
|
|
493
|
+
revisionDate: "2026-09-10T10:00:00.000Z",
|
|
494
|
+
}));
|
|
495
|
+
}
|
|
496
|
+
throw new Error(`Unexpected command: ${args.join(" ")}`);
|
|
497
|
+
};
|
|
498
|
+
const item = await new BitwardenClient({
|
|
499
|
+
env: { BW_SESSION: "synthetic-session" },
|
|
500
|
+
runner,
|
|
501
|
+
}).readItem("rhdh-qe", "rhdh/test");
|
|
502
|
+
assert.equal(item.value, "old-value");
|
|
503
|
+
assert.equal(item.storage, "note");
|
|
504
|
+
assert.equal(item.revisionDate, "2026-09-10T10:00:00.000Z");
|
|
505
|
+
});
|
|
506
|
+
test("does not treat deletion read errors as a missing item", async () => {
|
|
507
|
+
let deleted = false;
|
|
508
|
+
const runner = async (_command, args) => {
|
|
509
|
+
if (args[0] === "--version")
|
|
510
|
+
return result("2026.5.0");
|
|
511
|
+
if (args[0] === "status")
|
|
512
|
+
return result(JSON.stringify({ status: "unlocked" }));
|
|
513
|
+
if (args[0] === "sync")
|
|
514
|
+
return result();
|
|
515
|
+
if (args[0] === "list" && args[1] === "collections") {
|
|
516
|
+
return result(JSON.stringify([
|
|
517
|
+
{
|
|
518
|
+
id: "collection-id",
|
|
519
|
+
name: "Rhdh Qe Ci Secrets",
|
|
520
|
+
organizationId: "org-id",
|
|
521
|
+
},
|
|
522
|
+
]));
|
|
523
|
+
}
|
|
524
|
+
if (args[0] === "list" && args[1] === "items")
|
|
525
|
+
return result(JSON.stringify([{ id: "item-id" }]));
|
|
526
|
+
if (args[0] === "get" && args[1] === "item") {
|
|
527
|
+
if (deleted)
|
|
528
|
+
throw new Error("Bitwarden read failed after deletion");
|
|
529
|
+
return result(JSON.stringify({
|
|
530
|
+
id: "item-id",
|
|
531
|
+
name: "rhdh/test",
|
|
532
|
+
notes: "old-value",
|
|
533
|
+
type: 2,
|
|
534
|
+
collectionIds: ["collection-id"],
|
|
535
|
+
organizationId: "org-id",
|
|
536
|
+
revisionDate: "revision-1",
|
|
537
|
+
}));
|
|
538
|
+
}
|
|
539
|
+
if (args[0] === "delete" && args[1] === "item") {
|
|
540
|
+
deleted = true;
|
|
541
|
+
return result();
|
|
542
|
+
}
|
|
543
|
+
throw new Error(`Unexpected command: ${args.join(" ")}`);
|
|
544
|
+
};
|
|
545
|
+
const client = new BitwardenClient({
|
|
546
|
+
env: { BW_SESSION: "synthetic-session" },
|
|
547
|
+
runner,
|
|
548
|
+
});
|
|
549
|
+
const item = await client.readItem("rhdh-qe", "rhdh/test");
|
|
550
|
+
await assert.rejects(() => client.deleteItem(item), /item read failed/i);
|
|
551
|
+
});
|
|
552
|
+
test("filters fuzzy search results before reading the exact item", async () => {
|
|
553
|
+
const calls = [];
|
|
554
|
+
const runner = async (_command, args) => {
|
|
555
|
+
calls.push([...args]);
|
|
556
|
+
if (args[0] === "--version")
|
|
557
|
+
return result("2026.5.0");
|
|
558
|
+
if (args[0] === "status")
|
|
559
|
+
return result(JSON.stringify({ status: "unlocked" }));
|
|
560
|
+
if (args[0] === "sync")
|
|
561
|
+
return result();
|
|
562
|
+
if (args[1] === "collections") {
|
|
563
|
+
return result(JSON.stringify([
|
|
564
|
+
{
|
|
565
|
+
id: "collection-id",
|
|
566
|
+
name: "Rhdh Qe Ci Secrets",
|
|
567
|
+
organizationId: "org-id",
|
|
568
|
+
},
|
|
569
|
+
]));
|
|
570
|
+
}
|
|
571
|
+
if (args[1] === "items") {
|
|
572
|
+
return result(JSON.stringify([
|
|
573
|
+
{ id: "login-id", name: "rhdh/test-login", type: 1 },
|
|
574
|
+
{ id: "item-id", name: "rhdh/test" },
|
|
575
|
+
]));
|
|
576
|
+
}
|
|
577
|
+
if (args[0] === "get" && args[2] === "item-id") {
|
|
578
|
+
return result(JSON.stringify({
|
|
579
|
+
id: "item-id",
|
|
580
|
+
name: "rhdh/test",
|
|
581
|
+
notes: "old-value",
|
|
582
|
+
type: 2,
|
|
583
|
+
collectionIds: ["collection-id"],
|
|
584
|
+
organizationId: "org-id",
|
|
585
|
+
revisionDate: "revision-1",
|
|
586
|
+
}));
|
|
587
|
+
}
|
|
588
|
+
throw new Error(`Unexpected command: ${args.join(" ")}`);
|
|
589
|
+
};
|
|
590
|
+
const item = await new BitwardenClient({
|
|
591
|
+
env: { BW_SESSION: "synthetic-session" },
|
|
592
|
+
runner,
|
|
593
|
+
}).readItem("rhdh-qe", "rhdh/test");
|
|
594
|
+
assert.equal(item.id, "item-id");
|
|
595
|
+
assert.equal(calls.some((args) => args.includes("login-id")), false);
|
|
596
|
+
});
|
|
597
|
+
test("updates and verifies a note-backed rotation item without changing its metadata", async () => {
|
|
598
|
+
let value = "old-value";
|
|
599
|
+
let revision = "2026-09-10T10:00:00.000Z";
|
|
600
|
+
const editInputs = [];
|
|
601
|
+
const commands = [];
|
|
602
|
+
const runner = async (_command, args, options) => {
|
|
603
|
+
commands.push(args[0]);
|
|
604
|
+
if (args[0] === "--version")
|
|
605
|
+
return result("2026.5.0");
|
|
606
|
+
if (args[0] === "status")
|
|
607
|
+
return result(JSON.stringify({ status: "unlocked" }));
|
|
608
|
+
if (args[0] === "sync")
|
|
609
|
+
return result();
|
|
610
|
+
if (args[0] === "list" && args[1] === "collections") {
|
|
611
|
+
return result(JSON.stringify([
|
|
612
|
+
{
|
|
613
|
+
id: "collection-id",
|
|
614
|
+
name: "Rhdh Qe Ci Secrets",
|
|
615
|
+
organizationId: "org-id",
|
|
616
|
+
},
|
|
617
|
+
]));
|
|
618
|
+
}
|
|
619
|
+
if (args[0] === "list" && args[1] === "items")
|
|
620
|
+
return result(JSON.stringify([{ id: "item-id" }]));
|
|
621
|
+
if (args[0] === "get" && args[1] === "item") {
|
|
622
|
+
return result(JSON.stringify({
|
|
623
|
+
id: "item-id",
|
|
624
|
+
name: "rhdh/test",
|
|
625
|
+
notes: value,
|
|
626
|
+
type: 2,
|
|
627
|
+
collectionIds: ["collection-id"],
|
|
628
|
+
organizationId: "org-id",
|
|
629
|
+
revisionDate: revision,
|
|
630
|
+
}));
|
|
631
|
+
}
|
|
632
|
+
if (args[0] === "edit") {
|
|
633
|
+
assert.equal(args[1], "item");
|
|
634
|
+
assert.equal(args[2], "item-id");
|
|
635
|
+
const payload = JSON.parse(Buffer.from(options?.input ?? "", "base64").toString("utf8"));
|
|
636
|
+
assert.equal(payload.notes, "new-value");
|
|
637
|
+
assert.deepEqual(payload.collectionIds, ["collection-id"]);
|
|
638
|
+
assert.equal(commands.includes("encode"), false);
|
|
639
|
+
editInputs.push(options?.input ?? "");
|
|
640
|
+
value = "new-value";
|
|
641
|
+
revision = "2026-09-10T11:00:00.000Z";
|
|
642
|
+
return result(JSON.stringify({
|
|
643
|
+
id: "item-id",
|
|
644
|
+
name: "rhdh/test",
|
|
645
|
+
notes: value,
|
|
646
|
+
type: 2,
|
|
647
|
+
collectionIds: ["collection-id"],
|
|
648
|
+
organizationId: "org-id",
|
|
649
|
+
revisionDate: revision,
|
|
650
|
+
}));
|
|
651
|
+
}
|
|
652
|
+
throw new Error(`Unexpected command: ${args.join(" ")}`);
|
|
653
|
+
};
|
|
654
|
+
const client = new BitwardenClient({
|
|
655
|
+
env: { BW_SESSION: "synthetic-session" },
|
|
656
|
+
runner,
|
|
657
|
+
});
|
|
658
|
+
const item = await client.readItem("rhdh-qe", "rhdh/test");
|
|
659
|
+
const updated = await client.updateItem(item, "new-value");
|
|
660
|
+
assert.equal(editInputs.length, 1);
|
|
661
|
+
assert.equal(updated.value, "new-value");
|
|
662
|
+
assert.equal(updated.revisionDate, "2026-09-10T11:00:00.000Z");
|
|
663
|
+
});
|
|
664
|
+
test("rejects a note update whose mutation response contains the old value", async () => {
|
|
665
|
+
let reads = 0;
|
|
666
|
+
const runner = async (_command, args) => {
|
|
667
|
+
if (args[0] === "--version")
|
|
668
|
+
return result("2026.5.0");
|
|
669
|
+
if (args[0] === "status")
|
|
670
|
+
return result(JSON.stringify({ status: "unlocked" }));
|
|
671
|
+
if (args[0] === "sync")
|
|
672
|
+
return result();
|
|
673
|
+
if (args[1] === "collections") {
|
|
674
|
+
return result(JSON.stringify([
|
|
675
|
+
{
|
|
676
|
+
id: "collection-id",
|
|
677
|
+
name: "Rhdh Qe Ci Secrets",
|
|
678
|
+
organizationId: "org-id",
|
|
679
|
+
},
|
|
680
|
+
]));
|
|
681
|
+
}
|
|
682
|
+
if (args[1] === "items")
|
|
683
|
+
return result(JSON.stringify([{ id: "item-id" }]));
|
|
684
|
+
if (args[0] === "get") {
|
|
685
|
+
reads++;
|
|
686
|
+
return result(JSON.stringify({
|
|
687
|
+
id: "item-id",
|
|
688
|
+
name: "rhdh/test",
|
|
689
|
+
notes: reads > 2 ? "new-value" : "old-value",
|
|
690
|
+
type: 2,
|
|
691
|
+
collectionIds: ["collection-id"],
|
|
692
|
+
organizationId: "org-id",
|
|
693
|
+
revisionDate: reads > 2 ? "revision-3" : "revision-1",
|
|
694
|
+
}));
|
|
695
|
+
}
|
|
696
|
+
if (args[0] === "encode")
|
|
697
|
+
return result("encoded");
|
|
698
|
+
if (args[0] === "edit") {
|
|
699
|
+
return result(JSON.stringify({
|
|
700
|
+
id: "item-id",
|
|
701
|
+
name: "rhdh/test",
|
|
702
|
+
notes: "old-value",
|
|
703
|
+
type: 2,
|
|
704
|
+
collectionIds: ["collection-id"],
|
|
705
|
+
organizationId: "org-id",
|
|
706
|
+
revisionDate: "revision-3",
|
|
707
|
+
}));
|
|
708
|
+
}
|
|
709
|
+
throw new Error(`Unexpected command: ${args.join(" ")}`);
|
|
710
|
+
};
|
|
711
|
+
const client = new BitwardenClient({
|
|
712
|
+
env: { BW_SESSION: "synthetic-session" },
|
|
713
|
+
runner,
|
|
714
|
+
});
|
|
715
|
+
const existing = await client.readItem("rhdh-qe", "rhdh/test");
|
|
716
|
+
await assert.rejects(() => client.updateItem(existing, "new-value"), /read-back verification failed/i);
|
|
717
|
+
});
|
|
718
|
+
test("updates and verifies an attachment-backed rotation item", async () => {
|
|
719
|
+
let attachmentPresent = true;
|
|
720
|
+
let attachmentValue = "old-certificate";
|
|
721
|
+
let revision = "2026-09-10T10:00:00.000Z";
|
|
722
|
+
const runner = async (_command, args) => {
|
|
723
|
+
if (args[0] === "--version")
|
|
724
|
+
return result("2026.5.0");
|
|
725
|
+
if (args[0] === "status")
|
|
726
|
+
return result(JSON.stringify({ status: "unlocked" }));
|
|
727
|
+
if (args[0] === "sync")
|
|
728
|
+
return result();
|
|
729
|
+
if (args[0] === "list" && args[1] === "collections") {
|
|
730
|
+
return result(JSON.stringify([
|
|
731
|
+
{
|
|
732
|
+
id: "collection-id",
|
|
733
|
+
name: "Rhdh Qe Ci Secrets",
|
|
734
|
+
organizationId: "org-id",
|
|
735
|
+
},
|
|
736
|
+
]));
|
|
737
|
+
}
|
|
738
|
+
if (args[0] === "list" && args[1] === "items") {
|
|
739
|
+
return result(JSON.stringify([{ id: "item-id" }]));
|
|
740
|
+
}
|
|
741
|
+
if (args[0] === "get" && args[1] === "item") {
|
|
742
|
+
return result(JSON.stringify({
|
|
743
|
+
id: "item-id",
|
|
744
|
+
name: "rhdh/certificate.pem",
|
|
745
|
+
notes: null,
|
|
746
|
+
type: 2,
|
|
747
|
+
collectionIds: ["collection-id"],
|
|
748
|
+
organizationId: "org-id",
|
|
749
|
+
revisionDate: revision,
|
|
750
|
+
attachments: attachmentPresent
|
|
751
|
+
? [{ id: "attachment-id", fileName: "certificate.pem" }]
|
|
752
|
+
: [],
|
|
753
|
+
}));
|
|
754
|
+
}
|
|
755
|
+
if (args[0] === "get" && args[1] === "attachment") {
|
|
756
|
+
return result(attachmentValue);
|
|
757
|
+
}
|
|
758
|
+
if (args[0] === "delete" && args[1] === "attachment") {
|
|
759
|
+
attachmentPresent = false;
|
|
760
|
+
return result();
|
|
761
|
+
}
|
|
762
|
+
if (args[0] === "create" && args[1] === "attachment") {
|
|
763
|
+
attachmentPresent = true;
|
|
764
|
+
attachmentValue = "new-certificate";
|
|
765
|
+
revision = "2026-09-10T11:00:00.000Z";
|
|
766
|
+
return result();
|
|
767
|
+
}
|
|
768
|
+
throw new Error(`Unexpected command: ${args.join(" ")}`);
|
|
769
|
+
};
|
|
770
|
+
const client = new BitwardenClient({
|
|
771
|
+
env: { BW_SESSION: "synthetic-session" },
|
|
772
|
+
runner,
|
|
773
|
+
});
|
|
774
|
+
const item = await client.readItem("rhdh-qe", "rhdh/certificate.pem");
|
|
775
|
+
const updated = await client.updateItem(item, "new-certificate");
|
|
776
|
+
assert.equal(updated.storage, "attachment");
|
|
777
|
+
assert.equal(updated.value, "new-certificate");
|
|
778
|
+
});
|
|
779
|
+
test("creates a note-backed item and verifies it without putting the value in arguments", async () => {
|
|
780
|
+
const storedValue = "new-value";
|
|
781
|
+
const calls = [];
|
|
782
|
+
const runner = async (_command, args, options) => {
|
|
783
|
+
calls.push({ args, input: options?.input });
|
|
784
|
+
if (args[0] === "--version")
|
|
785
|
+
return result("2026.5.0");
|
|
786
|
+
if (args[0] === "status")
|
|
787
|
+
return result(JSON.stringify({ status: "unlocked" }));
|
|
788
|
+
if (args[0] === "sync")
|
|
789
|
+
return result();
|
|
790
|
+
if (args[0] === "list" && args[1] === "collections") {
|
|
791
|
+
return result(JSON.stringify([
|
|
792
|
+
{
|
|
793
|
+
id: "collection-id",
|
|
794
|
+
name: "Rhdh Qe Ci Secrets",
|
|
795
|
+
organizationId: "org-id",
|
|
796
|
+
},
|
|
797
|
+
]));
|
|
798
|
+
}
|
|
799
|
+
if (args[0] === "create" && args[1] === "item") {
|
|
800
|
+
const payload = JSON.parse(Buffer.from(options?.input ?? "", "base64").toString("utf8"));
|
|
801
|
+
assert.equal(payload.notes, storedValue);
|
|
802
|
+
return result(JSON.stringify({
|
|
803
|
+
...payload,
|
|
804
|
+
id: "created-item-id",
|
|
805
|
+
revisionDate: "revision-1",
|
|
806
|
+
}));
|
|
807
|
+
}
|
|
808
|
+
if (args[0] === "get" && args[1] === "item") {
|
|
809
|
+
return result(JSON.stringify({
|
|
810
|
+
id: "created-item-id",
|
|
811
|
+
name: "rhdh/test",
|
|
812
|
+
notes: storedValue,
|
|
813
|
+
type: 2,
|
|
814
|
+
collectionIds: ["collection-id"],
|
|
815
|
+
organizationId: "org-id",
|
|
816
|
+
revisionDate: "revision-1",
|
|
817
|
+
}));
|
|
818
|
+
}
|
|
819
|
+
throw new Error(`Unexpected command: ${args.join(" ")}`);
|
|
820
|
+
};
|
|
821
|
+
const created = await new BitwardenClient({
|
|
822
|
+
env: { BW_SESSION: "synthetic-session" },
|
|
823
|
+
runner,
|
|
824
|
+
}).createItem("rhdh-qe", "rhdh/test", storedValue, "note");
|
|
825
|
+
assert.equal(created.value, storedValue);
|
|
826
|
+
assert.equal(created.storage, "note");
|
|
827
|
+
assert.equal(calls.every(({ args }) => !args.includes(storedValue)), true);
|
|
828
|
+
assert.equal(calls.some(({ args, input }) => args[0] === "create" && input !== undefined), true);
|
|
829
|
+
});
|
|
830
|
+
test("does not hide attachment cleanup failure after a provider write", async () => {
|
|
831
|
+
const runner = async (_command, args, options) => {
|
|
832
|
+
if (args[0] === "--version")
|
|
833
|
+
return result("2026.5.0");
|
|
834
|
+
if (args[0] === "status")
|
|
835
|
+
return result(JSON.stringify({ status: "unlocked" }));
|
|
836
|
+
if (args[0] === "sync")
|
|
837
|
+
return result();
|
|
838
|
+
if (args[0] === "list" && args[1] === "collections") {
|
|
839
|
+
return result(JSON.stringify([
|
|
840
|
+
{
|
|
841
|
+
id: "collection-id",
|
|
842
|
+
name: "Rhdh Qe Ci Secrets",
|
|
843
|
+
organizationId: "org-id",
|
|
844
|
+
},
|
|
845
|
+
]));
|
|
846
|
+
}
|
|
847
|
+
if (args[0] === "create" && args[1] === "item") {
|
|
848
|
+
assert.match(options?.input ?? "", /^[A-Za-z0-9+/]+=*$/);
|
|
849
|
+
return result(JSON.stringify({ id: "created-item-id" }));
|
|
850
|
+
}
|
|
851
|
+
if (args[0] === "create" && args[1] === "attachment")
|
|
852
|
+
return result();
|
|
853
|
+
if (args[0] === "delete" && args[1] === "item")
|
|
854
|
+
return result();
|
|
855
|
+
throw new Error(`Unexpected command: ${args.join(" ")}`);
|
|
856
|
+
};
|
|
857
|
+
await assert.rejects(() => new BitwardenClient({
|
|
858
|
+
env: { BW_SESSION: "synthetic-session" },
|
|
859
|
+
runner,
|
|
860
|
+
removeTemporaryDirectory: async () => {
|
|
861
|
+
throw new Error("temporary cleanup failed");
|
|
862
|
+
},
|
|
863
|
+
}).createItem("rhdh-qe", "rhdh/cert.pem", "certificate", "attachment"), /temporary cleanup failed/i);
|
|
864
|
+
});
|
|
865
|
+
test("converts a note-backed item to an attachment-backed item", async () => {
|
|
866
|
+
let storage = "note";
|
|
867
|
+
let value = "old-value";
|
|
868
|
+
const runner = async (_command, args, options) => {
|
|
869
|
+
if (args[0] === "--version")
|
|
870
|
+
return result("2026.5.0");
|
|
871
|
+
if (args[0] === "status")
|
|
872
|
+
return result(JSON.stringify({ status: "unlocked" }));
|
|
873
|
+
if (args[0] === "sync")
|
|
874
|
+
return result();
|
|
875
|
+
if (args[0] === "list" && args[1] === "collections") {
|
|
876
|
+
return result(JSON.stringify([
|
|
877
|
+
{
|
|
878
|
+
id: "collection-id",
|
|
879
|
+
name: "Rhdh Qe Ci Secrets",
|
|
880
|
+
organizationId: "org-id",
|
|
881
|
+
},
|
|
882
|
+
]));
|
|
883
|
+
}
|
|
884
|
+
if (args[0] === "list" && args[1] === "items") {
|
|
885
|
+
return result(JSON.stringify([{ id: "item-id" }]));
|
|
886
|
+
}
|
|
887
|
+
if (args[0] === "get" && args[1] === "item") {
|
|
888
|
+
return result(JSON.stringify({
|
|
889
|
+
id: "item-id",
|
|
890
|
+
name: "rhdh/test",
|
|
891
|
+
notes: storage === "note" ? value : null,
|
|
892
|
+
type: 2,
|
|
893
|
+
collectionIds: ["collection-id"],
|
|
894
|
+
organizationId: "org-id",
|
|
895
|
+
revisionDate: storage === "note" ? "revision-1" : "revision-2",
|
|
896
|
+
...(storage === "attachment"
|
|
897
|
+
? { attachments: [{ id: "attachment-id", fileName: "test" }] }
|
|
898
|
+
: {}),
|
|
899
|
+
}));
|
|
900
|
+
}
|
|
901
|
+
if (args[0] === "edit" && args[1] === "item") {
|
|
902
|
+
const payload = JSON.parse(Buffer.from(options?.input ?? "", "base64").toString("utf8"));
|
|
903
|
+
assert.equal(payload.notes, null);
|
|
904
|
+
return result();
|
|
905
|
+
}
|
|
906
|
+
if (args[0] === "create" && args[1] === "attachment") {
|
|
907
|
+
storage = "attachment";
|
|
908
|
+
value = "new-value";
|
|
909
|
+
return result();
|
|
910
|
+
}
|
|
911
|
+
if (args[0] === "get" && args[1] === "attachment") {
|
|
912
|
+
return result(value);
|
|
913
|
+
}
|
|
914
|
+
throw new Error(`Unexpected command: ${args.join(" ")}`);
|
|
915
|
+
};
|
|
916
|
+
const client = new BitwardenClient({
|
|
917
|
+
env: { BW_SESSION: "synthetic-session" },
|
|
918
|
+
runner,
|
|
919
|
+
});
|
|
920
|
+
const existing = await client.readItem("rhdh-qe", "rhdh/test");
|
|
921
|
+
const updated = await client.updateItem(existing, "new-value", "attachment");
|
|
922
|
+
assert.equal(updated.storage, "attachment");
|
|
923
|
+
assert.equal(updated.value, "new-value");
|
|
924
|
+
});
|
|
925
|
+
test("restores a note when note-to-attachment edit loses its response", async () => {
|
|
926
|
+
let storage = "note";
|
|
927
|
+
let value = "old-value";
|
|
928
|
+
let edits = 0;
|
|
929
|
+
const runner = async (_command, args, options) => {
|
|
930
|
+
if (args[0] === "--version")
|
|
931
|
+
return result("2026.5.0");
|
|
932
|
+
if (args[0] === "status")
|
|
933
|
+
return result(JSON.stringify({ status: "unlocked" }));
|
|
934
|
+
if (args[0] === "sync")
|
|
935
|
+
return result();
|
|
936
|
+
if (args[0] === "list" && args[1] === "collections") {
|
|
937
|
+
return result(JSON.stringify([
|
|
938
|
+
{
|
|
939
|
+
id: "collection-id",
|
|
940
|
+
name: "Rhdh Qe Ci Secrets",
|
|
941
|
+
organizationId: "org-id",
|
|
942
|
+
},
|
|
943
|
+
]));
|
|
944
|
+
}
|
|
945
|
+
if (args[0] === "list" && args[1] === "items")
|
|
946
|
+
return result(JSON.stringify([{ id: "item-id" }]));
|
|
947
|
+
if (args[0] === "get" && args[1] === "item") {
|
|
948
|
+
return result(JSON.stringify({
|
|
949
|
+
id: "item-id",
|
|
950
|
+
name: "rhdh/test",
|
|
951
|
+
notes: storage === "note" ? value : null,
|
|
952
|
+
type: 2,
|
|
953
|
+
collectionIds: ["collection-id"],
|
|
954
|
+
organizationId: "org-id",
|
|
955
|
+
revisionDate: storage === "note" ? "revision-1" : "revision-2",
|
|
956
|
+
...(storage === "attachment"
|
|
957
|
+
? { attachments: [{ id: "attachment-id", fileName: "test" }] }
|
|
958
|
+
: {}),
|
|
959
|
+
}));
|
|
960
|
+
}
|
|
961
|
+
if (args[0] === "edit" && args[1] === "item") {
|
|
962
|
+
edits++;
|
|
963
|
+
const payload = JSON.parse(Buffer.from(options?.input ?? "", "base64").toString("utf8"));
|
|
964
|
+
storage = payload.notes === null ? "attachment" : "note";
|
|
965
|
+
value = typeof payload.notes === "string" ? payload.notes : value;
|
|
966
|
+
if (edits === 1)
|
|
967
|
+
throw new Error("response lost after edit");
|
|
968
|
+
return result();
|
|
969
|
+
}
|
|
970
|
+
throw new Error(`Unexpected command: ${args.join(" ")}`);
|
|
971
|
+
};
|
|
972
|
+
const client = new BitwardenClient({
|
|
973
|
+
env: { BW_SESSION: "synthetic-session" },
|
|
974
|
+
runner,
|
|
975
|
+
});
|
|
976
|
+
const existing = await client.readItem("rhdh-qe", "rhdh/test");
|
|
977
|
+
await assert.rejects(() => client.updateItem(existing, "new-value", "attachment"), /update failed/i);
|
|
978
|
+
assert.equal(edits, 2);
|
|
979
|
+
assert.equal(storage, "note");
|
|
980
|
+
assert.equal(value, "old-value");
|
|
981
|
+
});
|
|
982
|
+
test("deletes an uploaded attachment before restoring a note after read-back failure", async () => {
|
|
983
|
+
let storage = "note";
|
|
984
|
+
let value = "old-value";
|
|
985
|
+
let uploaded = false;
|
|
986
|
+
let verificationReadFailed = false;
|
|
987
|
+
const commands = [];
|
|
988
|
+
const runner = async (_command, args, options) => {
|
|
989
|
+
commands.push(args.join(" "));
|
|
990
|
+
if (args[0] === "--version")
|
|
991
|
+
return result("2026.5.0");
|
|
992
|
+
if (args[0] === "status")
|
|
993
|
+
return result(JSON.stringify({ status: "unlocked" }));
|
|
994
|
+
if (args[0] === "sync")
|
|
995
|
+
return result();
|
|
996
|
+
if (args[0] === "list" && args[1] === "collections") {
|
|
997
|
+
return result(JSON.stringify([
|
|
998
|
+
{
|
|
999
|
+
id: "collection-id",
|
|
1000
|
+
name: "Rhdh Qe Ci Secrets",
|
|
1001
|
+
organizationId: "org-id",
|
|
1002
|
+
},
|
|
1003
|
+
]));
|
|
1004
|
+
}
|
|
1005
|
+
if (args[0] === "list" && args[1] === "items")
|
|
1006
|
+
return result(JSON.stringify([{ id: "item-id" }]));
|
|
1007
|
+
if (args[0] === "get" && args[1] === "item") {
|
|
1008
|
+
if (uploaded && !verificationReadFailed) {
|
|
1009
|
+
verificationReadFailed = true;
|
|
1010
|
+
throw new Error("post-upload read failed");
|
|
1011
|
+
}
|
|
1012
|
+
return result(JSON.stringify({
|
|
1013
|
+
id: "item-id",
|
|
1014
|
+
name: "rhdh/test",
|
|
1015
|
+
notes: storage === "note" ? value : null,
|
|
1016
|
+
type: 2,
|
|
1017
|
+
collectionIds: ["collection-id"],
|
|
1018
|
+
organizationId: "org-id",
|
|
1019
|
+
revisionDate: storage === "note" ? "revision-1" : "revision-2",
|
|
1020
|
+
...(uploaded
|
|
1021
|
+
? {
|
|
1022
|
+
attachments: [
|
|
1023
|
+
{ id: "uploaded-attachment-id", fileName: "test" },
|
|
1024
|
+
],
|
|
1025
|
+
}
|
|
1026
|
+
: {}),
|
|
1027
|
+
}));
|
|
1028
|
+
}
|
|
1029
|
+
if (args[0] === "edit" && args[1] === "item") {
|
|
1030
|
+
const payload = JSON.parse(Buffer.from(options?.input ?? "", "base64").toString("utf8"));
|
|
1031
|
+
storage = payload.notes === null ? "attachment" : "note";
|
|
1032
|
+
value = typeof payload.notes === "string" ? payload.notes : value;
|
|
1033
|
+
return result();
|
|
1034
|
+
}
|
|
1035
|
+
if (args[0] === "create" && args[1] === "attachment") {
|
|
1036
|
+
uploaded = true;
|
|
1037
|
+
return result();
|
|
1038
|
+
}
|
|
1039
|
+
if (args[0] === "delete" && args[1] === "attachment") {
|
|
1040
|
+
assert.equal(args[2], "uploaded-attachment-id");
|
|
1041
|
+
uploaded = false;
|
|
1042
|
+
return result();
|
|
1043
|
+
}
|
|
1044
|
+
throw new Error(`Unexpected command: ${args.join(" ")}`);
|
|
1045
|
+
};
|
|
1046
|
+
const client = new BitwardenClient({
|
|
1047
|
+
env: { BW_SESSION: "synthetic-session" },
|
|
1048
|
+
runner,
|
|
1049
|
+
});
|
|
1050
|
+
const existing = await client.readItem("rhdh-qe", "rhdh/test");
|
|
1051
|
+
await assert.rejects(() => client.updateItem(existing, "new-value", "attachment"), /item read failed/i);
|
|
1052
|
+
assert.equal(storage, "note");
|
|
1053
|
+
assert.equal(value, "old-value");
|
|
1054
|
+
assert.equal(uploaded, false);
|
|
1055
|
+
assert.ok(commands.indexOf("delete attachment uploaded-attachment-id") > -1);
|
|
1056
|
+
assert.ok(commands.indexOf("delete attachment uploaded-attachment-id") <
|
|
1057
|
+
commands.lastIndexOf("edit item item-id"));
|
|
1058
|
+
});
|