@red-hat-developer-hub/e2e-test-utils 2.1.13 → 2.1.15

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.
Files changed (59) hide show
  1. package/dist/deployment/rhdh/constants.d.ts +0 -1
  2. package/dist/deployment/rhdh/constants.d.ts.map +1 -1
  3. package/dist/deployment/rhdh/constants.js +0 -1
  4. package/dist/deployment/rhdh/deployment.d.ts.map +1 -1
  5. package/dist/deployment/rhdh/deployment.js +0 -3
  6. package/dist/playwright/global-setup.d.ts +5 -0
  7. package/dist/playwright/global-setup.d.ts.map +1 -1
  8. package/dist/playwright/global-setup.js +2 -4
  9. package/dist/playwright/helpers/github-session.test.js +1 -1
  10. package/dist/playwright/tests/global-setup.test.d.ts +2 -0
  11. package/dist/playwright/tests/global-setup.test.d.ts.map +1 -0
  12. package/dist/playwright/tests/global-setup.test.js +68 -0
  13. package/dist/secrets/bitwarden.d.ts +34 -0
  14. package/dist/secrets/bitwarden.d.ts.map +1 -0
  15. package/dist/secrets/bitwarden.js +193 -0
  16. package/dist/secrets/cli.d.ts +11 -0
  17. package/dist/secrets/cli.d.ts.map +1 -0
  18. package/dist/secrets/cli.js +98 -0
  19. package/dist/secrets/command.d.ts +15 -0
  20. package/dist/secrets/command.d.ts.map +1 -0
  21. package/dist/secrets/command.js +30 -0
  22. package/dist/secrets/config.d.ts +33 -0
  23. package/dist/secrets/config.d.ts.map +1 -0
  24. package/dist/secrets/config.js +156 -0
  25. package/dist/secrets/environment.d.ts +10 -0
  26. package/dist/secrets/environment.d.ts.map +1 -0
  27. package/dist/secrets/environment.js +53 -0
  28. package/dist/secrets/exec.d.ts +18 -0
  29. package/dist/secrets/exec.d.ts.map +1 -0
  30. package/dist/secrets/exec.js +50 -0
  31. package/dist/secrets/index.d.ts +5 -0
  32. package/dist/secrets/index.d.ts.map +1 -0
  33. package/dist/secrets/index.js +4 -0
  34. package/dist/secrets/tests/bitwarden.integration.test.d.ts +2 -0
  35. package/dist/secrets/tests/bitwarden.integration.test.d.ts.map +1 -0
  36. package/dist/secrets/tests/bitwarden.integration.test.js +50 -0
  37. package/dist/secrets/tests/bitwarden.test.d.ts +2 -0
  38. package/dist/secrets/tests/bitwarden.test.d.ts.map +1 -0
  39. package/dist/secrets/tests/bitwarden.test.js +418 -0
  40. package/dist/secrets/tests/cli.integration.test.d.ts +2 -0
  41. package/dist/secrets/tests/cli.integration.test.d.ts.map +1 -0
  42. package/dist/secrets/tests/cli.integration.test.js +70 -0
  43. package/dist/secrets/tests/cli.test.d.ts +2 -0
  44. package/dist/secrets/tests/cli.test.d.ts.map +1 -0
  45. package/dist/secrets/tests/cli.test.js +42 -0
  46. package/dist/secrets/tests/config.test.d.ts +2 -0
  47. package/dist/secrets/tests/config.test.d.ts.map +1 -0
  48. package/dist/secrets/tests/config.test.js +105 -0
  49. package/dist/secrets/tests/environment.test.d.ts +2 -0
  50. package/dist/secrets/tests/environment.test.d.ts.map +1 -0
  51. package/dist/secrets/tests/environment.test.js +119 -0
  52. package/dist/secrets/tests/exec.test.d.ts +2 -0
  53. package/dist/secrets/tests/exec.test.d.ts.map +1 -0
  54. package/dist/secrets/tests/exec.test.js +87 -0
  55. package/package.json +9 -2
  56. package/dist/deployment/rhdh/config/new-frontend-system/secrets.yaml +0 -8
  57. package/dist/utils/vault.d.ts +0 -16
  58. package/dist/utils/vault.d.ts.map +0 -1
  59. package/dist/utils/vault.js +0 -94
@@ -0,0 +1,156 @@
1
+ const COLLECTIONS = [
2
+ {
3
+ id: "rhdh-qe",
4
+ bitwardenCollection: "Rhdh Qe Ci Secrets",
5
+ },
6
+ {
7
+ id: "rhdh-test-instance",
8
+ bitwardenCollection: "Rhdh Test Instance Ci Secrets",
9
+ },
10
+ {
11
+ id: "rhdh-plugin-export-overlays",
12
+ bitwardenCollection: "Rhdh Plugin Export Overlays Ci Secrets",
13
+ },
14
+ ];
15
+ const DENIED_COLLECTION = "rhdh-aws-credentials";
16
+ const WORKSPACE_TOKEN = "${workspace}";
17
+ const WORKSPACE_NAME = /^[a-z0-9][a-z0-9-]*$/;
18
+ export function getCollectionMapping(collection) {
19
+ if (collection === DENIED_COLLECTION) {
20
+ throw new Error(`Collection ${DENIED_COLLECTION} is GSM-only and cannot be read from Bitwarden`);
21
+ }
22
+ if (!isReadableCollectionId(collection)) {
23
+ throw new Error(`Unknown Bitwarden collection: ${collection}`);
24
+ }
25
+ return COLLECTIONS.find((mapping) => mapping.id === collection);
26
+ }
27
+ export function parseProfile(value) {
28
+ if (!isRecord(value) || value.schemaVersion !== 1) {
29
+ throw new Error("Invalid secret profile: schemaVersion must be 1");
30
+ }
31
+ if (typeof value.collection !== "string") {
32
+ throw new Error("Invalid secret profile: collection is required");
33
+ }
34
+ const collection = getCollectionMapping(value.collection).id;
35
+ if (!Array.isArray(value.selectors) || value.selectors.length === 0) {
36
+ throw new Error("Invalid secret profile: selectors must not be empty");
37
+ }
38
+ const selectors = value.selectors.map((selector, index) => parseSelector(selector, index));
39
+ const selectorKeys = selectors.map((selector) => selector.prefix);
40
+ if (new Set(selectorKeys).size !== selectorKeys.length) {
41
+ throw new Error("Invalid secret profile: duplicate selector");
42
+ }
43
+ return { schemaVersion: 1, collection, selectors };
44
+ }
45
+ export function expandProfile(profile, workspaces = []) {
46
+ const hasWorkspaceToken = profile.selectors.some((selector) => selector.prefix.includes(WORKSPACE_TOKEN));
47
+ if (!hasWorkspaceToken && workspaces.length > 0) {
48
+ throw new Error("Secret profile does not accept workspace arguments");
49
+ }
50
+ if (hasWorkspaceToken && workspaces.length === 0) {
51
+ throw new Error("Secret profile requires at least one workspace argument");
52
+ }
53
+ for (const workspace of workspaces) {
54
+ if (!WORKSPACE_NAME.test(workspace)) {
55
+ throw new Error(`Invalid workspace name: ${workspace}`);
56
+ }
57
+ }
58
+ if (new Set(workspaces).size !== workspaces.length) {
59
+ throw new Error("Duplicate workspace argument");
60
+ }
61
+ const selectors = [];
62
+ for (const selector of profile.selectors) {
63
+ const values = selector.prefix.includes(WORKSPACE_TOKEN)
64
+ ? workspaces
65
+ : [undefined];
66
+ for (const workspace of values) {
67
+ selectors.push({
68
+ ...selector,
69
+ prefix: expandToken(selector.prefix, workspace),
70
+ destination: {
71
+ ...selector.destination,
72
+ stripPrefix: expandToken(selector.destination.stripPrefix, workspace),
73
+ },
74
+ optional: selector.optional === true,
75
+ });
76
+ }
77
+ }
78
+ return {
79
+ schemaVersion: 1,
80
+ collection: profile.collection,
81
+ selectors,
82
+ };
83
+ }
84
+ function parseSelector(value, index) {
85
+ if (!isRecord(value)) {
86
+ throw new Error(`Invalid secret selector at index ${index}`);
87
+ }
88
+ if (typeof value.prefix !== "string" || value.prefix.length === 0) {
89
+ throw new Error(`Invalid secret selector at index ${index}: prefix is required`);
90
+ }
91
+ validateTokenCount(value.prefix, `selector ${index} prefix`);
92
+ if (!value.prefix.endsWith("/")) {
93
+ throw new Error(`Invalid secret selector at index ${index}: prefix must end with /`);
94
+ }
95
+ if (!isRecord(value.destination) ||
96
+ value.destination.kind !== "environment") {
97
+ throw new Error(`Invalid secret selector at index ${index}: destination must be an environment`);
98
+ }
99
+ const destination = value.destination;
100
+ if (typeof destination.stripPrefix !== "string" ||
101
+ destination.stripPrefix.length === 0) {
102
+ throw new Error(`Invalid secret selector at index ${index}: stripPrefix is required`);
103
+ }
104
+ validateTokenCount(destination.stripPrefix, `selector ${index} stripPrefix`);
105
+ if (!destination.stripPrefix.endsWith("/")) {
106
+ throw new Error(`Invalid secret selector at index ${index}: stripPrefix must end with /`);
107
+ }
108
+ if (!value.prefix.startsWith(destination.stripPrefix)) {
109
+ throw new Error(`Invalid secret selector at index ${index}: stripPrefix must be a prefix of prefix`);
110
+ }
111
+ if (typeof destination.requirePrefix !== "undefined" &&
112
+ (typeof destination.requirePrefix !== "string" ||
113
+ destination.requirePrefix.length === 0)) {
114
+ throw new Error(`Invalid secret selector at index ${index}: requirePrefix must be non-empty`);
115
+ }
116
+ if (destination.keyTransform !== "identity" &&
117
+ destination.keyTransform !== "legacy-env") {
118
+ throw new Error(`Invalid secret selector at index ${index}: unsupported keyTransform`);
119
+ }
120
+ if (typeof value.optional !== "undefined" &&
121
+ typeof value.optional !== "boolean") {
122
+ throw new Error(`Invalid secret selector at index ${index}: optional must be boolean`);
123
+ }
124
+ return {
125
+ prefix: value.prefix,
126
+ optional: value.optional === true,
127
+ destination: {
128
+ kind: "environment",
129
+ stripPrefix: destination.stripPrefix,
130
+ ...(typeof destination.requirePrefix === "string"
131
+ ? { requirePrefix: destination.requirePrefix }
132
+ : {}),
133
+ keyTransform: destination.keyTransform,
134
+ },
135
+ };
136
+ }
137
+ function expandToken(value, workspace) {
138
+ if (!value.includes(WORKSPACE_TOKEN))
139
+ return value;
140
+ if (workspace === undefined) {
141
+ throw new Error(`Missing workspace for selector: ${value}`);
142
+ }
143
+ return value.replace(WORKSPACE_TOKEN, workspace);
144
+ }
145
+ function validateTokenCount(value, label) {
146
+ const count = value.split(WORKSPACE_TOKEN).length - 1;
147
+ if (count > 1) {
148
+ throw new Error(`${label} may contain ${WORKSPACE_TOKEN} at most once`);
149
+ }
150
+ }
151
+ function isReadableCollectionId(value) {
152
+ return COLLECTIONS.some((mapping) => mapping.id === value);
153
+ }
154
+ function isRecord(value) {
155
+ return typeof value === "object" && value !== null && !Array.isArray(value);
156
+ }
@@ -0,0 +1,10 @@
1
+ import type { ExpandedSecretSelector } from "./config.js";
2
+ export interface EnvironmentSecret {
3
+ id: string;
4
+ name: string;
5
+ value: string;
6
+ selector: ExpandedSecretSelector;
7
+ }
8
+ export declare function removeProviderEnvironmentVariables(environment: NodeJS.ProcessEnv): void;
9
+ export declare function materializeEnvironment(secrets: readonly EnvironmentSecret[], selectors: readonly ExpandedSecretSelector[], parent?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
10
+ //# sourceMappingURL=environment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../src/secrets/environment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,sBAAsB,CAAC;CAClC;AAUD,wBAAgB,kCAAkC,CAChD,WAAW,EAAE,MAAM,CAAC,UAAU,GAC7B,IAAI,CAMN;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,SAAS,iBAAiB,EAAE,EACrC,SAAS,EAAE,SAAS,sBAAsB,EAAE,EAC5C,MAAM,GAAE,MAAM,CAAC,UAAwB,GACtC,MAAM,CAAC,UAAU,CAwCnB"}
@@ -0,0 +1,53 @@
1
+ const ENVIRONMENT_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
2
+ const PROVIDER_ENVIRONMENT_KEYS = new Set([
3
+ "VAULT",
4
+ "VAULT_TOKEN",
5
+ "VAULT_ADDR",
6
+ "VAULT_BASE_PATH",
7
+ ]);
8
+ export function removeProviderEnvironmentVariables(environment) {
9
+ for (const key of Object.keys(environment)) {
10
+ if (key.startsWith("BW_") || PROVIDER_ENVIRONMENT_KEYS.has(key)) {
11
+ delete environment[key];
12
+ }
13
+ }
14
+ }
15
+ export function materializeEnvironment(secrets, selectors, parent = process.env) {
16
+ const child = { ...parent };
17
+ removeProviderEnvironmentVariables(child);
18
+ const mapped = new Map();
19
+ for (const secret of secrets) {
20
+ const selector = selectors.find((candidate) => sameSelector(candidate, secret.selector));
21
+ if (!selector) {
22
+ throw new Error(`Secret ${secret.name} does not match selector`);
23
+ }
24
+ if (!secret.name.startsWith(selector.prefix)) {
25
+ throw new Error(`Secret ${secret.name} does not match selector ${selector.prefix}`);
26
+ }
27
+ const relativeName = secret.name.slice(selector.destination.stripPrefix.length);
28
+ if (selector.destination.requirePrefix !== undefined) {
29
+ if (!relativeName.startsWith(selector.destination.requirePrefix))
30
+ continue;
31
+ }
32
+ const key = transformEnvironmentName(relativeName, selector.destination.keyTransform);
33
+ if (!ENVIRONMENT_NAME.test(key)) {
34
+ throw new Error(`Invalid environment variable name: ${key}`);
35
+ }
36
+ if (mapped.has(key)) {
37
+ throw new Error(`Environment variable collision: ${key}`);
38
+ }
39
+ mapped.set(key, secret.value);
40
+ }
41
+ for (const [key, value] of mapped)
42
+ child[key] = value;
43
+ return child;
44
+ }
45
+ function transformEnvironmentName(value, transform) {
46
+ return transform === "legacy-env" ? value.replace(/[.\-/]/g, "_") : value;
47
+ }
48
+ function sameSelector(left, right) {
49
+ return (left.prefix === right.prefix &&
50
+ left.destination.stripPrefix === right.destination.stripPrefix &&
51
+ left.destination.requirePrefix === right.destination.requirePrefix &&
52
+ left.destination.keyTransform === right.destination.keyTransform);
53
+ }
@@ -0,0 +1,18 @@
1
+ import { type BitwardenSecret } from "./bitwarden.js";
2
+ import { type ExpandedSecretSelector, type SecretProfile } from "./config.js";
3
+ export interface SecretReader {
4
+ read(collection: SecretProfile["collection"], selectors: readonly ExpandedSecretSelector[]): Promise<BitwardenSecret[]>;
5
+ }
6
+ export type ChildRunner = (command: string, args: readonly string[], env: NodeJS.ProcessEnv) => Promise<number>;
7
+ export interface ExecuteCommandOptions {
8
+ profile: SecretProfile;
9
+ workspaces: readonly string[];
10
+ command: string;
11
+ args: readonly string[];
12
+ env?: NodeJS.ProcessEnv;
13
+ client?: SecretReader;
14
+ childRunner?: ChildRunner;
15
+ }
16
+ export declare function executeCommand(options: ExecuteCommandOptions): Promise<number>;
17
+ export declare const runChild: ChildRunner;
18
+ //# sourceMappingURL=exec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/secrets/exec.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAEL,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,YAAY;IAC3B,IAAI,CACF,UAAU,EAAE,aAAa,CAAC,YAAY,CAAC,EACvC,SAAS,EAAE,SAAS,sBAAsB,EAAE,GAC3C,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;CAC/B;AAED,MAAM,MAAM,WAAW,GAAG,CACxB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC;AAErB,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,aAAa,CAAC;IACvB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,MAAM,CAAC,CAejB;AAED,eAAO,MAAM,QAAQ,EAAE,WAqCnB,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { spawn } from "node:child_process";
2
+ import { BitwardenClient } from "./bitwarden.js";
3
+ import { expandProfile, } from "./config.js";
4
+ import { materializeEnvironment } from "./environment.js";
5
+ export async function executeCommand(options) {
6
+ const expanded = expandProfile(options.profile, options.workspaces);
7
+ const client = options.client ?? new BitwardenClient({ env: options.env ?? process.env });
8
+ const secrets = await client.read(options.profile.collection, expanded.selectors);
9
+ const childEnvironment = materializeEnvironment(secrets, expanded.selectors, options.env ?? process.env);
10
+ const childRunner = options.childRunner ?? runChild;
11
+ return childRunner(options.command, options.args, childEnvironment);
12
+ }
13
+ export const runChild = (command, args, env) => new Promise((resolve, reject) => {
14
+ const child = spawn(command, args, { env, stdio: "inherit" });
15
+ let settled = false;
16
+ const signals = ["SIGINT", "SIGTERM", "SIGHUP"];
17
+ const signalExitCodes = new Map([
18
+ ["SIGINT", 130],
19
+ ["SIGTERM", 143],
20
+ ["SIGHUP", 129],
21
+ ]);
22
+ const forwarders = new Map();
23
+ for (const signal of signals) {
24
+ const forwardSignal = () => child.kill(signal);
25
+ forwarders.set(signal, forwardSignal);
26
+ process.on(signal, forwardSignal);
27
+ }
28
+ const cleanup = () => {
29
+ for (const [signal, forwardSignal] of forwarders) {
30
+ process.removeListener(signal, forwardSignal);
31
+ }
32
+ };
33
+ child.once("error", () => {
34
+ if (settled)
35
+ return;
36
+ settled = true;
37
+ cleanup();
38
+ reject(new Error(`Unable to start command: ${command}`));
39
+ });
40
+ child.once("close", (code, signal) => {
41
+ if (settled)
42
+ return;
43
+ settled = true;
44
+ cleanup();
45
+ const signalExitCode = signal
46
+ ? signalExitCodes.get(signal)
47
+ : undefined;
48
+ resolve(code ?? signalExitCode ?? 1);
49
+ });
50
+ });
@@ -0,0 +1,5 @@
1
+ export { expandProfile, getCollectionMapping, parseProfile, type CollectionMapping, type EnvironmentDestination, type ExpandedSecretProfile, type ExpandedSecretSelector, type ReadableCollectionId, type SecretProfile, type SecretSelector, } from "./config.js";
2
+ export { BitwardenClient, type BitwardenClientOptions, type BitwardenAttachment, type BitwardenSecret, } from "./bitwarden.js";
3
+ export { executeCommand, runChild, type ChildRunner, type ExecuteCommandOptions, type SecretReader, } from "./exec.js";
4
+ export { materializeEnvironment, removeProviderEnvironmentVariables, type EnvironmentSecret, } from "./environment.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/secrets/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,cAAc,EACd,QAAQ,EACR,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,KAAK,YAAY,GAClB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,sBAAsB,EACtB,kCAAkC,EAClC,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { expandProfile, getCollectionMapping, parseProfile, } from "./config.js";
2
+ export { BitwardenClient, } from "./bitwarden.js";
3
+ export { executeCommand, runChild, } from "./exec.js";
4
+ export { materializeEnvironment, removeProviderEnvironmentVariables, } from "./environment.js";
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bitwarden.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bitwarden.integration.test.d.ts","sourceRoot":"","sources":["../../../src/secrets/tests/bitwarden.integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,50 @@
1
+ /* eslint-disable @typescript-eslint/naming-convention, playwright/expect-expect -- node:test fixture models CLI environment keys */
2
+ import assert from "node:assert/strict";
3
+ import { chmod, mkdtemp, rm, writeFile } from "node:fs/promises";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import test from "node:test";
7
+ import { BitwardenClient } from "../bitwarden.js";
8
+ const selector = {
9
+ prefix: "global/",
10
+ optional: false,
11
+ destination: {
12
+ kind: "environment",
13
+ stripPrefix: "global/",
14
+ requirePrefix: "VAULT_",
15
+ keyTransform: "legacy-env",
16
+ },
17
+ };
18
+ test("reads secure notes and attachments through a fake bw executable", async () => {
19
+ const directory = await mkdtemp(path.join(os.tmpdir(), "bitwarden-cli-test-"));
20
+ const command = path.join(directory, "bw");
21
+ await writeFile(command, `#!/usr/bin/env node
22
+ const args = process.argv.slice(2);
23
+ if (args[0] === "--version") process.stdout.write("2026.5.0\\n");
24
+ else if (args[0] === "status") process.stdout.write(JSON.stringify({ status: "unlocked" }));
25
+ else if (args[0] === "sync") {}
26
+ else if (args[0] === "list" && args[1] === "collections") process.stdout.write(JSON.stringify([{ id: "collection-id", name: "Rhdh Qe Ci Secrets", organizationId: "organization-id" }]));
27
+ else if (args[0] === "list" && args[1] === "items") process.stdout.write(JSON.stringify([{ id: "note-item-id" }, { id: "attachment-item-id" }]));
28
+ else if (args[0] === "get" && args[1] === "item" && args[2] === "note-item-id") process.stdout.write(JSON.stringify({ id: "note-item-id", name: "global/VAULT_TOKEN", notes: "synthetic-note-value", type: 2, collectionIds: ["collection-id"], organizationId: "organization-id" }));
29
+ else if (args[0] === "get" && args[1] === "item" && args[2] === "attachment-item-id") process.stdout.write(JSON.stringify({ id: "attachment-item-id", name: "global/VAULT_CERT_PEM", notes: null, type: 2, collectionIds: ["collection-id"], organizationId: "organization-id", attachments: [{ id: "attachment-id", fileName: "VAULT_CERT_PEM" }] }));
30
+ else if (args[0] === "get" && args[1] === "attachment" && args[2] === "VAULT_CERT_PEM" && args[3] === "--itemid" && args[4] === "attachment-item-id" && args[5] === "--raw") process.stdout.write("synthetic-attachment-value");
31
+ else process.exitCode = 1;
32
+ `);
33
+ await chmod(command, 0o755);
34
+ try {
35
+ const secrets = await new BitwardenClient({
36
+ command,
37
+ env: { BW_SESSION: "synthetic-session" },
38
+ }).read("rhdh-qe", [selector]);
39
+ assert.deepEqual(secrets.map(({ name, value }) => ({ name, value })), [
40
+ { name: "global/VAULT_TOKEN", value: "synthetic-note-value" },
41
+ {
42
+ name: "global/VAULT_CERT_PEM",
43
+ value: "synthetic-attachment-value",
44
+ },
45
+ ]);
46
+ }
47
+ finally {
48
+ await rm(directory, { recursive: true, force: true });
49
+ }
50
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bitwarden.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bitwarden.test.d.ts","sourceRoot":"","sources":["../../../src/secrets/tests/bitwarden.test.ts"],"names":[],"mappings":""}