@centient/secrets 0.8.0 → 0.10.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.
- package/README.md +70 -2
- package/dist/cli/secrets-cli.d.ts.map +1 -1
- package/dist/cli/secrets-cli.js +191 -32
- package/dist/cli/secrets-cli.js.map +1 -1
- package/dist/crypto/darwin-keychain.d.ts +394 -0
- package/dist/crypto/darwin-keychain.d.ts.map +1 -0
- package/dist/crypto/darwin-keychain.js +793 -0
- package/dist/crypto/darwin-keychain.js.map +1 -0
- package/dist/crypto/vault-common.d.ts +55 -12
- package/dist/crypto/vault-common.d.ts.map +1 -1
- package/dist/crypto/vault-common.js +74 -71
- package/dist/crypto/vault-common.js.map +1 -1
- package/dist/environment/EnvironmentManager.d.ts.map +1 -1
- package/dist/environment/EnvironmentManager.js +5 -10
- package/dist/environment/EnvironmentManager.js.map +1 -1
- package/dist/index.d.ts +21 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -6
- package/dist/index.js.map +1 -1
- package/dist/key-providers/keychain-provider.d.ts +30 -2
- package/dist/key-providers/keychain-provider.d.ts.map +1 -1
- package/dist/key-providers/keychain-provider.js +29 -5
- package/dist/key-providers/keychain-provider.js.map +1 -1
- package/dist/key-providers/onepassword-provider.d.ts +65 -5
- package/dist/key-providers/onepassword-provider.d.ts.map +1 -1
- package/dist/key-providers/onepassword-provider.js +159 -67
- package/dist/key-providers/onepassword-provider.js.map +1 -1
- package/dist/key-providers/op-cli.d.ts +78 -0
- package/dist/key-providers/op-cli.d.ts.map +1 -0
- package/dist/key-providers/op-cli.js +123 -0
- package/dist/key-providers/op-cli.js.map +1 -0
- package/dist/key-providers/passphrase-provider.d.ts +20 -0
- package/dist/key-providers/passphrase-provider.d.ts.map +1 -1
- package/dist/key-providers/passphrase-provider.js +49 -0
- package/dist/key-providers/passphrase-provider.js.map +1 -1
- package/dist/key-providers/probe.d.ts +46 -0
- package/dist/key-providers/probe.d.ts.map +1 -0
- package/dist/key-providers/probe.js +70 -0
- package/dist/key-providers/probe.js.map +1 -0
- package/dist/key-providers/types.d.ts +51 -1
- package/dist/key-providers/types.d.ts.map +1 -1
- package/dist/platform/agent-detect.d.ts +39 -3
- package/dist/platform/agent-detect.d.ts.map +1 -1
- package/dist/platform/agent-detect.js +55 -9
- package/dist/platform/agent-detect.js.map +1 -1
- package/dist/platform/session-context.d.ts +77 -0
- package/dist/platform/session-context.d.ts.map +1 -0
- package/dist/platform/session-context.js +83 -0
- package/dist/platform/session-context.js.map +1 -0
- package/dist/secret-state.d.ts +54 -0
- package/dist/secret-state.d.ts.map +1 -0
- package/dist/secret-state.js +2 -0
- package/dist/secret-state.js.map +1 -0
- package/dist/vault/policy.d.ts +35 -4
- package/dist/vault/policy.d.ts.map +1 -1
- package/dist/vault/policy.js +65 -6
- package/dist/vault/policy.js.map +1 -1
- package/dist/vault/session-vault-errors.d.ts +72 -4
- package/dist/vault/session-vault-errors.d.ts.map +1 -1
- package/dist/vault/session-vault-errors.js +95 -4
- package/dist/vault/session-vault-errors.js.map +1 -1
- package/dist/vault/session-vault.d.ts +102 -2
- package/dist/vault/session-vault.d.ts.map +1 -1
- package/dist/vault/session-vault.js +236 -38
- package/dist/vault/session-vault.js.map +1 -1
- package/dist/vault/types.d.ts +42 -1
- package/dist/vault/types.d.ts.map +1 -1
- package/dist/vault/types.js.map +1 -1
- package/dist/vault/vault-env.d.ts +14 -0
- package/dist/vault/vault-env.d.ts.map +1 -1
- package/dist/vault/vault-env.js +15 -0
- package/dist/vault/vault-env.js.map +1 -1
- package/dist/vault/vault-gpg.d.ts +5 -1
- package/dist/vault/vault-gpg.d.ts.map +1 -1
- package/dist/vault/vault-gpg.js +9 -8
- package/dist/vault/vault-gpg.js.map +1 -1
- package/dist/vault/vault-libsecret.d.ts +24 -2
- package/dist/vault/vault-libsecret.d.ts.map +1 -1
- package/dist/vault/vault-libsecret.js +54 -10
- package/dist/vault/vault-libsecret.js.map +1 -1
- package/dist/vault/vault-onepassword.d.ts +118 -0
- package/dist/vault/vault-onepassword.d.ts.map +1 -0
- package/dist/vault/vault-onepassword.js +270 -0
- package/dist/vault/vault-onepassword.js.map +1 -0
- package/dist/vault/vault-utils.d.ts +33 -0
- package/dist/vault/vault-utils.d.ts.map +1 -1
- package/dist/vault/vault-utils.js +61 -0
- package/dist/vault/vault-utils.js.map +1 -1
- package/dist/vault/vault-windows.d.ts +5 -1
- package/dist/vault/vault-windows.d.ts.map +1 -1
- package/dist/vault/vault-windows.js +9 -8
- package/dist/vault/vault-windows.js.map +1 -1
- package/dist/vault/vault.d.ts +116 -4
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +288 -22
- package/dist/vault/vault.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC1F,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE7F,mBAAmB;AACnB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Key Provider — macOS Keychain
|
|
3
3
|
*
|
|
4
|
-
* Wraps the
|
|
5
|
-
*
|
|
4
|
+
* Wraps the getKeyFromKeychain / storeKeyInKeychain functions from
|
|
5
|
+
* vault-common.ts as a KeyProvider implementation. Those in turn delegate to
|
|
6
|
+
* the hardened `security` core in `crypto/darwin-keychain.ts` (#188), so the
|
|
7
|
+
* vault MASTER KEY inherits the same posture as credential values: explicit
|
|
8
|
+
* System-keychain reads in a sessionless context, `-U` replace-in-place
|
|
9
|
+
* writes, and `-T /usr/bin/security` reader preauthorization.
|
|
10
|
+
*
|
|
11
|
+
* Fixing only the value layer would have been half a fix — the master key
|
|
12
|
+
* would have become unreadable in exactly the contexts the values had just
|
|
13
|
+
* become readable in.
|
|
6
14
|
*
|
|
7
15
|
* Only available on macOS (darwin). Uses the `security` CLI to interact
|
|
8
16
|
* with the system Keychain, which prompts for Touch ID or system password.
|
|
9
17
|
*/
|
|
18
|
+
import type { KeychainDeps } from "../crypto/darwin-keychain.js";
|
|
19
|
+
import type { SecretState } from "../secret-state.js";
|
|
10
20
|
import type { KeyProvider, KeyProviderType } from "./types.js";
|
|
11
21
|
/**
|
|
12
22
|
* Default Keychain item coordinates. These are the historical values every
|
|
@@ -29,11 +39,18 @@ export interface KeychainProviderOptions {
|
|
|
29
39
|
service?: string;
|
|
30
40
|
/** Keychain account name. Defaults to {@link DEFAULT_KEYCHAIN_ACCOUNT}. */
|
|
31
41
|
account?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Injection seam for the `security` CLI and the platform/environment that
|
|
44
|
+
* decide the read path (#188). Omitted in production; supplied by tests so
|
|
45
|
+
* the exact argv is assertable without touching a real keychain.
|
|
46
|
+
*/
|
|
47
|
+
deps?: Partial<KeychainDeps>;
|
|
32
48
|
}
|
|
33
49
|
export declare class KeychainProvider implements KeyProvider {
|
|
34
50
|
readonly name: KeyProviderType;
|
|
35
51
|
private readonly service;
|
|
36
52
|
private readonly account;
|
|
53
|
+
private readonly deps;
|
|
37
54
|
/**
|
|
38
55
|
* @param options - Optional per-consumer Keychain item coordinates. With no
|
|
39
56
|
* options the provider targets the historical `centient-vault`/`vault-key`
|
|
@@ -45,5 +62,16 @@ export declare class KeychainProvider implements KeyProvider {
|
|
|
45
62
|
getKey(): Buffer | null;
|
|
46
63
|
storeKey(key: Buffer): boolean;
|
|
47
64
|
deleteKey(): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* The five-way state of the vault master key, value-free (#188).
|
|
67
|
+
*
|
|
68
|
+
* Runs the SAME read {@link getKey} would run in this context, then discards
|
|
69
|
+
* the key and returns only the value-free {@link SecretState}. A
|
|
70
|
+
* metadata-only lookup would answer presence, not readability — and a key
|
|
71
|
+
* that is present but sits behind an ACL this context cannot satisfy is
|
|
72
|
+
* exactly the case a caller needs told apart from "no key stored". `found`
|
|
73
|
+
* here means the reader will get bytes.
|
|
74
|
+
*/
|
|
75
|
+
probeKey(): SecretState;
|
|
48
76
|
}
|
|
49
77
|
//# sourceMappingURL=keychain-provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keychain-provider.d.ts","sourceRoot":"","sources":["../../src/key-providers/keychain-provider.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"keychain-provider.d.ts","sourceRoot":"","sources":["../../src/key-providers/keychain-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAQH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAM/D;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,mBAAmB,CAAC;AACzD,eAAO,MAAM,wBAAwB,cAAc,CAAC;AAMpD;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAuB;IACtC,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CAC9B;AAMD,qBAAa,gBAAiB,YAAW,WAAW;IAClD,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAc;IAE5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;IAE7C;;;;OAIG;gBACS,OAAO,GAAE,uBAA4B;IAMjD,wCAAwC;IACxC,MAAM,CAAC,MAAM,IAAI,OAAO;IAIxB,MAAM,IAAI,MAAM,GAAG,IAAI;IAIvB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI9B,SAAS,IAAI,OAAO;IAIpB;;;;;;;;;OASG;IACH,QAAQ,IAAI,WAAW;CAGxB"}
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Key Provider — macOS Keychain
|
|
3
3
|
*
|
|
4
|
-
* Wraps the
|
|
5
|
-
*
|
|
4
|
+
* Wraps the getKeyFromKeychain / storeKeyInKeychain functions from
|
|
5
|
+
* vault-common.ts as a KeyProvider implementation. Those in turn delegate to
|
|
6
|
+
* the hardened `security` core in `crypto/darwin-keychain.ts` (#188), so the
|
|
7
|
+
* vault MASTER KEY inherits the same posture as credential values: explicit
|
|
8
|
+
* System-keychain reads in a sessionless context, `-U` replace-in-place
|
|
9
|
+
* writes, and `-T /usr/bin/security` reader preauthorization.
|
|
10
|
+
*
|
|
11
|
+
* Fixing only the value layer would have been half a fix — the master key
|
|
12
|
+
* would have become unreadable in exactly the contexts the values had just
|
|
13
|
+
* become readable in.
|
|
6
14
|
*
|
|
7
15
|
* Only available on macOS (darwin). Uses the `security` CLI to interact
|
|
8
16
|
* with the system Keychain, which prompts for Touch ID or system password.
|
|
9
17
|
*/
|
|
10
18
|
import { getKeyFromKeychain, storeKeyInKeychain, deleteFromKeychain, } from "../crypto/vault-common.js";
|
|
19
|
+
import { probeKeychainCredentialState } from "../crypto/darwin-keychain.js";
|
|
11
20
|
// =============================================================================
|
|
12
21
|
// Constants
|
|
13
22
|
// =============================================================================
|
|
@@ -25,6 +34,7 @@ export class KeychainProvider {
|
|
|
25
34
|
name = "keychain";
|
|
26
35
|
service;
|
|
27
36
|
account;
|
|
37
|
+
deps;
|
|
28
38
|
/**
|
|
29
39
|
* @param options - Optional per-consumer Keychain item coordinates. With no
|
|
30
40
|
* options the provider targets the historical `centient-vault`/`vault-key`
|
|
@@ -33,19 +43,33 @@ export class KeychainProvider {
|
|
|
33
43
|
constructor(options = {}) {
|
|
34
44
|
this.service = options.service ?? DEFAULT_KEYCHAIN_SERVICE;
|
|
35
45
|
this.account = options.account ?? DEFAULT_KEYCHAIN_ACCOUNT;
|
|
46
|
+
this.deps = options.deps ?? {};
|
|
36
47
|
}
|
|
37
48
|
/** Returns true if running on macOS. */
|
|
38
49
|
static detect() {
|
|
39
50
|
return process.platform === "darwin";
|
|
40
51
|
}
|
|
41
52
|
getKey() {
|
|
42
|
-
return getKeyFromKeychain(this.service, this.account);
|
|
53
|
+
return getKeyFromKeychain(this.service, this.account, this.deps);
|
|
43
54
|
}
|
|
44
55
|
storeKey(key) {
|
|
45
|
-
return storeKeyInKeychain(this.service, this.account, key);
|
|
56
|
+
return storeKeyInKeychain(this.service, this.account, key, this.deps);
|
|
46
57
|
}
|
|
47
58
|
deleteKey() {
|
|
48
|
-
return deleteFromKeychain(this.service, this.account);
|
|
59
|
+
return deleteFromKeychain(this.service, this.account, this.deps);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The five-way state of the vault master key, value-free (#188).
|
|
63
|
+
*
|
|
64
|
+
* Runs the SAME read {@link getKey} would run in this context, then discards
|
|
65
|
+
* the key and returns only the value-free {@link SecretState}. A
|
|
66
|
+
* metadata-only lookup would answer presence, not readability — and a key
|
|
67
|
+
* that is present but sits behind an ACL this context cannot satisfy is
|
|
68
|
+
* exactly the case a caller needs told apart from "no key stored". `found`
|
|
69
|
+
* here means the reader will get bytes.
|
|
70
|
+
*/
|
|
71
|
+
probeKey() {
|
|
72
|
+
return probeKeychainCredentialState(this.service, this.account, this.deps);
|
|
49
73
|
}
|
|
50
74
|
}
|
|
51
75
|
//# sourceMappingURL=keychain-provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keychain-provider.js","sourceRoot":"","sources":["../../src/key-providers/keychain-provider.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"keychain-provider.js","sourceRoot":"","sources":["../../src/key-providers/keychain-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AAK5E,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,gBAAgB,CAAC;AACzD,MAAM,CAAC,MAAM,wBAAwB,GAAG,WAAW,CAAC;AA4BpD,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF,MAAM,OAAO,gBAAgB;IAClB,IAAI,GAAoB,UAAU,CAAC;IAE3B,OAAO,CAAS;IAChB,OAAO,CAAS;IAChB,IAAI,CAAwB;IAE7C;;;;OAIG;IACH,YAAY,UAAmC,EAAE;QAC/C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,wBAAwB,CAAC;QAC3D,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,wBAAwB,CAAC;QAC3D,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;IACjC,CAAC;IAED,wCAAwC;IACxC,MAAM,CAAC,MAAM;QACX,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC;IACvC,CAAC;IAED,MAAM;QACJ,OAAO,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACnE,CAAC;IAED,QAAQ,CAAC,GAAW;QAClB,OAAO,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACxE,CAAC;IAED,SAAS;QACP,OAAO,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACnE,CAAC;IAED;;;;;;;;;OASG;IACH,QAAQ;QACN,OAAO,4BAA4B,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7E,CAAC;CACF"}
|
|
@@ -9,9 +9,21 @@
|
|
|
9
9
|
* 3. CLI session — user ran `op signin` (OP_SESSION_* env var)
|
|
10
10
|
*
|
|
11
11
|
* The `op` CLI handles auth selection internally; this provider just
|
|
12
|
-
* shells out to `op read` / `op item create`
|
|
12
|
+
* shells out to `op read` / `op item create` through the shared `op-cli.ts`
|
|
13
|
+
* helper (ADR-004 §6), which it co-owns with the credential-value backend
|
|
14
|
+
* `OnePasswordVault`.
|
|
13
15
|
*
|
|
14
|
-
* No dependency on @1password/sdk —
|
|
16
|
+
* No dependency on @1password/sdk — `execFileSync` only.
|
|
17
|
+
*
|
|
18
|
+
* **Key material never reaches argv (#102).** `storeKey` builds the item JSON
|
|
19
|
+
* in-process and pipes it to `op item create -` via `runOp`'s `input` option —
|
|
20
|
+
* the argv-safe seam ADR-004 §4 specifies and `OnePasswordVault.store` already
|
|
21
|
+
* uses. Nothing readable in `ps` / `/proc/<pid>/cmdline` carries the key. This
|
|
22
|
+
* closes ADR-001's "Process argument visibility" negative, which had the hex
|
|
23
|
+
* key in a `password=<hex>` argv element for the life of the call.
|
|
24
|
+
*
|
|
25
|
+
* `getKey` uses `op read`, whose only argv is a non-secret `op://` reference —
|
|
26
|
+
* the value comes back on stdout, so that path was never exposed.
|
|
15
27
|
*/
|
|
16
28
|
import type { KeyProvider, KeyProviderType, OnePasswordConfig } from "./types.js";
|
|
17
29
|
export declare class OnePasswordProvider implements KeyProvider {
|
|
@@ -29,10 +41,58 @@ export declare class OnePasswordProvider implements KeyProvider {
|
|
|
29
41
|
*/
|
|
30
42
|
static detect(): boolean;
|
|
31
43
|
getKey(): Buffer | null;
|
|
44
|
+
/**
|
|
45
|
+
* Store the vault key. Overwrites any existing item.
|
|
46
|
+
*
|
|
47
|
+
* The hex travels on **stdin** inside an item template and never appears in
|
|
48
|
+
* argv (#102): the template goes to `op item create -` through `runOp`'s
|
|
49
|
+
* `input` option, the argv-safe seam ADR-004 §4 specifies. Item ids, titles
|
|
50
|
+
* and vault names are not secret and stay on the command line.
|
|
51
|
+
*
|
|
52
|
+
* ## Ordering: create first, delete the old item last
|
|
53
|
+
*
|
|
54
|
+
* `op item edit` has no stdin template form, so the overwrite cannot be an
|
|
55
|
+
* edit-in-place without putting `password=<hex>` back in argv. The write is
|
|
56
|
+
* therefore a replace — but a **non-destructive** one, sequenced so no window
|
|
57
|
+
* exists in which the master key is absent from 1Password:
|
|
58
|
+
*
|
|
59
|
+
* 1. Resolve the existing item's id (absent ⇒ plain create, no step 3).
|
|
60
|
+
* 2. Create the replacement under the **same canonical title** — `op`
|
|
61
|
+
* permits duplicate titles — and capture the new item's id.
|
|
62
|
+
* Create fails ⇒ the old item is untouched and this returns false.
|
|
63
|
+
* 3. Delete the **old** item by id. Delete fails ⇒ roll back by deleting
|
|
64
|
+
* the **new** item by id, leaving the old one in place, and return false.
|
|
65
|
+
*
|
|
66
|
+
* The key is only ever removed from 1Password after its replacement durably
|
|
67
|
+
* exists. Nothing here renames, so there is no window where a rename failure
|
|
68
|
+
* strands the item under a title `getKey` cannot read.
|
|
69
|
+
*
|
|
70
|
+
* **Residual window (double failure).** If step 3's delete fails *and* the
|
|
71
|
+
* rollback delete of the new item also fails, both items remain and this
|
|
72
|
+
* returns false. That is not a loss: no key is destroyed, and {@link getKey}
|
|
73
|
+
* does not silently pick one — `op read` on an ambiguous title fails, so the
|
|
74
|
+
* caller gets a loud failure rather than a wrong key. The operator resolves
|
|
75
|
+
* it by deleting whichever item is stale.
|
|
76
|
+
*/
|
|
32
77
|
storeKey(key: Buffer): boolean;
|
|
33
78
|
deleteKey(): boolean;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
79
|
+
/**
|
|
80
|
+
* The id of the existing key item, or null when there is none.
|
|
81
|
+
*
|
|
82
|
+
* @throws when 1Password cannot be asked, or answers with an item whose id
|
|
83
|
+
* we cannot read. Both are "unknown", not "absent" — and {@link storeKey}
|
|
84
|
+
* must not treat unknown as absent, or a transient read failure would end
|
|
85
|
+
* with two items under one title.
|
|
86
|
+
*/
|
|
87
|
+
private findItemId;
|
|
88
|
+
/**
|
|
89
|
+
* Delete an item by id or title, treating "no such item" as the desired end
|
|
90
|
+
* state.
|
|
91
|
+
*
|
|
92
|
+
* Unlike {@link deleteKey}, an auth or network failure is **rethrown** — the
|
|
93
|
+
* {@link storeKey} path needs to distinguish "the old item is gone" from
|
|
94
|
+
* "we could not remove it", because only the second case must roll back.
|
|
95
|
+
*/
|
|
96
|
+
private deleteItem;
|
|
37
97
|
}
|
|
38
98
|
//# sourceMappingURL=onepassword-provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onepassword-provider.d.ts","sourceRoot":"","sources":["../../src/key-providers/onepassword-provider.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"onepassword-provider.d.ts","sourceRoot":"","sources":["../../src/key-providers/onepassword-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAqBlF,qBAAa,mBAAoB,YAAW,WAAW;IACrD,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,MAAM,CAAC,EAAE,iBAAiB;IAKtC;;;;;;;OAOG;IACH,MAAM,CAAC,MAAM,IAAI,OAAO;IAIxB,MAAM,IAAI,MAAM,GAAG,IAAI;IAcvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAsD9B,SAAS,IAAI,OAAO;IAcpB;;;;;;;OAOG;IACH,OAAO,CAAC,UAAU;IAsBlB;;;;;;;OAOG;IACH,OAAO,CAAC,UAAU;CAUnB"}
|
|
@@ -9,11 +9,23 @@
|
|
|
9
9
|
* 3. CLI session — user ran `op signin` (OP_SESSION_* env var)
|
|
10
10
|
*
|
|
11
11
|
* The `op` CLI handles auth selection internally; this provider just
|
|
12
|
-
* shells out to `op read` / `op item create`
|
|
12
|
+
* shells out to `op read` / `op item create` through the shared `op-cli.ts`
|
|
13
|
+
* helper (ADR-004 §6), which it co-owns with the credential-value backend
|
|
14
|
+
* `OnePasswordVault`.
|
|
13
15
|
*
|
|
14
|
-
* No dependency on @1password/sdk —
|
|
16
|
+
* No dependency on @1password/sdk — `execFileSync` only.
|
|
17
|
+
*
|
|
18
|
+
* **Key material never reaches argv (#102).** `storeKey` builds the item JSON
|
|
19
|
+
* in-process and pipes it to `op item create -` via `runOp`'s `input` option —
|
|
20
|
+
* the argv-safe seam ADR-004 §4 specifies and `OnePasswordVault.store` already
|
|
21
|
+
* uses. Nothing readable in `ps` / `/proc/<pid>/cmdline` carries the key. This
|
|
22
|
+
* closes ADR-001's "Process argument visibility" negative, which had the hex
|
|
23
|
+
* key in a `password=<hex>` argv element for the life of the call.
|
|
24
|
+
*
|
|
25
|
+
* `getKey` uses `op read`, whose only argv is a non-secret `op://` reference —
|
|
26
|
+
* the value comes back on stdout, so that path was never exposed.
|
|
15
27
|
*/
|
|
16
|
-
import {
|
|
28
|
+
import { detectOpCli, runOp, OpCliError, OP_READ_TIMEOUT_MS, OP_WRITE_TIMEOUT_MS, } from "./op-cli.js";
|
|
17
29
|
// =============================================================================
|
|
18
30
|
// Defaults
|
|
19
31
|
// =============================================================================
|
|
@@ -40,38 +52,12 @@ export class OnePasswordProvider {
|
|
|
40
52
|
* is configured (desktop app / prior sign-in).
|
|
41
53
|
*/
|
|
42
54
|
static detect() {
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
execFileSync("op", ["--version"], {
|
|
46
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
47
|
-
timeout: 5000,
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
catch {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
// Service account mode — no further checks needed
|
|
54
|
-
if (process.env.OP_SERVICE_ACCOUNT_TOKEN) {
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
// Interactive mode — check for configured accounts
|
|
58
|
-
try {
|
|
59
|
-
const output = execFileSync("op", ["account", "list", "--format=json"], { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }).trim();
|
|
60
|
-
// Returns "[]" when no accounts are configured
|
|
61
|
-
return output !== "[]" && output.length > 2;
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
55
|
+
return detectOpCli();
|
|
66
56
|
}
|
|
67
57
|
getKey() {
|
|
68
58
|
try {
|
|
69
59
|
const ref = `op://${this.vault}/${this.item}/${FIELD_NAME}`;
|
|
70
|
-
const result =
|
|
71
|
-
encoding: "utf8",
|
|
72
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
73
|
-
timeout: 30000,
|
|
74
|
-
}).trim();
|
|
60
|
+
const result = runOp(["read", ref], { timeoutMs: OP_WRITE_TIMEOUT_MS });
|
|
75
61
|
if (!result)
|
|
76
62
|
return null;
|
|
77
63
|
const buf = Buffer.from(result, "hex");
|
|
@@ -84,63 +70,169 @@ export class OnePasswordProvider {
|
|
|
84
70
|
return null;
|
|
85
71
|
}
|
|
86
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Store the vault key. Overwrites any existing item.
|
|
75
|
+
*
|
|
76
|
+
* The hex travels on **stdin** inside an item template and never appears in
|
|
77
|
+
* argv (#102): the template goes to `op item create -` through `runOp`'s
|
|
78
|
+
* `input` option, the argv-safe seam ADR-004 §4 specifies. Item ids, titles
|
|
79
|
+
* and vault names are not secret and stay on the command line.
|
|
80
|
+
*
|
|
81
|
+
* ## Ordering: create first, delete the old item last
|
|
82
|
+
*
|
|
83
|
+
* `op item edit` has no stdin template form, so the overwrite cannot be an
|
|
84
|
+
* edit-in-place without putting `password=<hex>` back in argv. The write is
|
|
85
|
+
* therefore a replace — but a **non-destructive** one, sequenced so no window
|
|
86
|
+
* exists in which the master key is absent from 1Password:
|
|
87
|
+
*
|
|
88
|
+
* 1. Resolve the existing item's id (absent ⇒ plain create, no step 3).
|
|
89
|
+
* 2. Create the replacement under the **same canonical title** — `op`
|
|
90
|
+
* permits duplicate titles — and capture the new item's id.
|
|
91
|
+
* Create fails ⇒ the old item is untouched and this returns false.
|
|
92
|
+
* 3. Delete the **old** item by id. Delete fails ⇒ roll back by deleting
|
|
93
|
+
* the **new** item by id, leaving the old one in place, and return false.
|
|
94
|
+
*
|
|
95
|
+
* The key is only ever removed from 1Password after its replacement durably
|
|
96
|
+
* exists. Nothing here renames, so there is no window where a rename failure
|
|
97
|
+
* strands the item under a title `getKey` cannot read.
|
|
98
|
+
*
|
|
99
|
+
* **Residual window (double failure).** If step 3's delete fails *and* the
|
|
100
|
+
* rollback delete of the new item also fails, both items remain and this
|
|
101
|
+
* returns false. That is not a loss: no key is destroyed, and {@link getKey}
|
|
102
|
+
* does not silently pick one — `op read` on an ambiguous title fails, so the
|
|
103
|
+
* caller gets a loud failure rather than a wrong key. The operator resolves
|
|
104
|
+
* it by deleting whichever item is stale.
|
|
105
|
+
*/
|
|
87
106
|
storeKey(key) {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
107
|
+
const item = {
|
|
108
|
+
title: this.item,
|
|
109
|
+
category: "PASSWORD",
|
|
110
|
+
vault: { name: this.vault },
|
|
111
|
+
fields: [
|
|
112
|
+
{ id: FIELD_NAME, type: "CONCEALED", value: key.toString("hex") },
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
// Step 1. What is already there? A failure to answer that is a failure to
|
|
116
|
+
// store: creating blind would risk leaving two items under one title.
|
|
117
|
+
let oldId;
|
|
96
118
|
try {
|
|
97
|
-
|
|
98
|
-
return true;
|
|
119
|
+
oldId = this.findItemId();
|
|
99
120
|
}
|
|
100
121
|
catch {
|
|
101
|
-
|
|
102
|
-
return true;
|
|
122
|
+
return false;
|
|
103
123
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// Private helpers
|
|
107
|
-
// ---------------------------------------------------------------------------
|
|
108
|
-
itemExists() {
|
|
124
|
+
// Step 2. Write the replacement. Until this succeeds nothing is removed.
|
|
125
|
+
let newId;
|
|
109
126
|
try {
|
|
110
|
-
|
|
111
|
-
|
|
127
|
+
const created = runOp(["item", "create", "--format=json", "-"], {
|
|
128
|
+
input: JSON.stringify(item),
|
|
129
|
+
timeoutMs: OP_WRITE_TIMEOUT_MS,
|
|
130
|
+
});
|
|
131
|
+
newId = parseItemId(created);
|
|
112
132
|
}
|
|
113
133
|
catch {
|
|
114
134
|
return false;
|
|
115
135
|
}
|
|
116
|
-
|
|
117
|
-
|
|
136
|
+
if (oldId === null)
|
|
137
|
+
return true;
|
|
138
|
+
// Step 3. Retire the superseded item, by id so the duplicate title cannot
|
|
139
|
+
// make the delete ambiguous.
|
|
118
140
|
try {
|
|
119
|
-
|
|
120
|
-
"item", "create",
|
|
121
|
-
"--category", "Password",
|
|
122
|
-
"--title", this.item,
|
|
123
|
-
"--vault", this.vault,
|
|
124
|
-
`${FIELD_NAME}=${keyHex}`,
|
|
125
|
-
], { stdio: ["pipe", "pipe", "pipe"], timeout: 30000 });
|
|
141
|
+
this.deleteItem(oldId);
|
|
126
142
|
return true;
|
|
127
143
|
}
|
|
128
144
|
catch {
|
|
145
|
+
// Roll back: the store did not complete, so the vault should look as it
|
|
146
|
+
// did before. Deleting the new item leaves the old key readable.
|
|
147
|
+
if (newId !== null) {
|
|
148
|
+
try {
|
|
149
|
+
this.deleteItem(newId);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// Double failure — see "Residual window" above. Both items remain;
|
|
153
|
+
// getKey fails loudly on the ambiguous title rather than returning a
|
|
154
|
+
// key that may be the wrong one, and neither key is lost.
|
|
155
|
+
}
|
|
156
|
+
}
|
|
129
157
|
return false;
|
|
130
158
|
}
|
|
131
159
|
}
|
|
132
|
-
|
|
160
|
+
deleteKey() {
|
|
133
161
|
try {
|
|
134
|
-
|
|
135
|
-
"item", "edit", this.item,
|
|
136
|
-
"--vault", this.vault,
|
|
137
|
-
`${FIELD_NAME}=${keyHex}`,
|
|
138
|
-
], { stdio: ["pipe", "pipe", "pipe"], timeout: 30000 });
|
|
139
|
-
return true;
|
|
162
|
+
this.deleteItem(this.item);
|
|
140
163
|
}
|
|
141
164
|
catch {
|
|
142
|
-
|
|
165
|
+
// Unchanged from before #102: this entry point reports success for any
|
|
166
|
+
// failure, not just a missing item.
|
|
167
|
+
}
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
// Private helpers
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
/**
|
|
174
|
+
* The id of the existing key item, or null when there is none.
|
|
175
|
+
*
|
|
176
|
+
* @throws when 1Password cannot be asked, or answers with an item whose id
|
|
177
|
+
* we cannot read. Both are "unknown", not "absent" — and {@link storeKey}
|
|
178
|
+
* must not treat unknown as absent, or a transient read failure would end
|
|
179
|
+
* with two items under one title.
|
|
180
|
+
*/
|
|
181
|
+
findItemId() {
|
|
182
|
+
let raw;
|
|
183
|
+
try {
|
|
184
|
+
raw = runOp(["item", "get", this.item, "--vault", this.vault, "--format=json"], { timeoutMs: OP_READ_TIMEOUT_MS });
|
|
143
185
|
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
if (err instanceof OpCliError && err.isNotFound)
|
|
188
|
+
return null;
|
|
189
|
+
throw err;
|
|
190
|
+
}
|
|
191
|
+
const id = parseItemId(raw);
|
|
192
|
+
if (id === null) {
|
|
193
|
+
throw new Error(`op item get ${this.item} returned no readable item id — refusing to ` +
|
|
194
|
+
"create a second item under the same title");
|
|
195
|
+
}
|
|
196
|
+
return id;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Delete an item by id or title, treating "no such item" as the desired end
|
|
200
|
+
* state.
|
|
201
|
+
*
|
|
202
|
+
* Unlike {@link deleteKey}, an auth or network failure is **rethrown** — the
|
|
203
|
+
* {@link storeKey} path needs to distinguish "the old item is gone" from
|
|
204
|
+
* "we could not remove it", because only the second case must roll back.
|
|
205
|
+
*/
|
|
206
|
+
deleteItem(ref) {
|
|
207
|
+
try {
|
|
208
|
+
runOp(["item", "delete", ref, "--vault", this.vault], {
|
|
209
|
+
timeoutMs: OP_WRITE_TIMEOUT_MS,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
if (err instanceof OpCliError && err.isNotFound)
|
|
214
|
+
return;
|
|
215
|
+
throw err;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// =============================================================================
|
|
220
|
+
// Helpers
|
|
221
|
+
// =============================================================================
|
|
222
|
+
/** The `id` of an item in `op … --format=json` output, or null if unreadable. */
|
|
223
|
+
function parseItemId(raw) {
|
|
224
|
+
if (raw === "")
|
|
225
|
+
return null;
|
|
226
|
+
let parsed;
|
|
227
|
+
try {
|
|
228
|
+
parsed = JSON.parse(raw);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return null;
|
|
144
232
|
}
|
|
233
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
234
|
+
return null;
|
|
235
|
+
const id = parsed.id;
|
|
236
|
+
return typeof id === "string" && id.length > 0 ? id : null;
|
|
145
237
|
}
|
|
146
238
|
//# sourceMappingURL=onepassword-provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onepassword-provider.js","sourceRoot":"","sources":["../../src/key-providers/onepassword-provider.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"onepassword-provider.js","sourceRoot":"","sources":["../../src/key-providers/onepassword-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EACL,WAAW,EACX,KAAK,EACL,UAAU,EACV,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAErB,gFAAgF;AAChF,WAAW;AACX,gFAAgF;AAEhF,MAAM,aAAa,GAAG,SAAS,CAAC;AAChC,MAAM,YAAY,GAAG,oBAAoB,CAAC;AAC1C,MAAM,UAAU,GAAG,UAAU,CAAC;AAE9B,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF,MAAM,OAAO,mBAAmB;IACrB,IAAI,GAAoB,WAAW,CAAC;IAC5B,KAAK,CAAS;IACd,IAAI,CAAS;IAE9B,YAAY,MAA0B;QACpC,IAAI,CAAC,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,aAAa,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,MAAM,EAAE,IAAI,IAAI,YAAY,CAAC;IAC3C,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,MAAM;QACX,OAAO,WAAW,EAAE,CAAC;IACvB,CAAC;IAED,MAAM;QACJ,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,IAAI,UAAU,EAAE,CAAC;YAC5D,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC;YACxE,IAAI,CAAC,MAAM;gBAAE,OAAO,IAAI,CAAC;YACzB,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YACvC,mDAAmD;YACnD,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE;gBAAE,OAAO,IAAI,CAAC;YACnC,OAAO,GAAG,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,QAAQ,CAAC,GAAW;QAClB,MAAM,IAAI,GAAG;YACX,KAAK,EAAE,IAAI,CAAC,IAAI;YAChB,QAAQ,EAAE,UAAU;YACpB,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE;YAC3B,MAAM,EAAE;gBACN,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;aAClE;SACF,CAAC;QAEF,0EAA0E;QAC1E,sEAAsE;QACtE,IAAI,KAAoB,CAAC;QACzB,IAAI,CAAC;YACH,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;QAED,yEAAyE;QACzE,IAAI,KAAoB,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,CAAC,EAAE;gBAC9D,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;gBAC3B,SAAS,EAAE,mBAAmB;aAC/B,CAAC,CAAC;YACH,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAEhC,0EAA0E;QAC1E,6BAA6B;QAC7B,IAAI,CAAC;YACH,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,wEAAwE;YACxE,iEAAiE;YACjE,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,IAAI,CAAC;oBACH,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;gBACzB,CAAC;gBAAC,MAAM,CAAC;oBACP,mEAAmE;oBACnE,qEAAqE;oBACrE,0DAA0D;gBAC5D,CAAC;YACH,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,SAAS;QACP,IAAI,CAAC;YACH,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,uEAAuE;YACvE,oCAAoC;QACtC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,8EAA8E;IAC9E,kBAAkB;IAClB,8EAA8E;IAE9E;;;;;;;OAOG;IACK,UAAU;QAChB,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,KAAK,CACT,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,eAAe,CAAC,EAClE,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAClC,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,UAAU,IAAI,GAAG,CAAC,UAAU;gBAAE,OAAO,IAAI,CAAC;YAC7D,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CACb,eAAe,IAAI,CAAC,IAAI,8CAA8C;gBACpE,2CAA2C,CAC9C,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED;;;;;;;OAOG;IACK,UAAU,CAAC,GAAW;QAC5B,IAAI,CAAC;YACH,KAAK,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE;gBACpD,SAAS,EAAE,mBAAmB;aAC/B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,UAAU,IAAI,GAAG,CAAC,UAAU;gBAAE,OAAO;YACxD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CACF;AAED,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF,iFAAiF;AACjF,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAC5B,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/D,MAAM,EAAE,GAAI,MAA2B,CAAC,EAAE,CAAC;IAC3C,OAAO,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared 1Password `op` CLI helper (ADR-004 §6).
|
|
3
|
+
*
|
|
4
|
+
* Two independent layers call `op` for different purposes — `OnePasswordProvider`
|
|
5
|
+
* for the vault *encryption key* (ADR-001) and `OnePasswordVault` for credential
|
|
6
|
+
* *values* (ADR-004) — and before this module each carried its own copy of the
|
|
7
|
+
* availability probe and its own `execFileSync` invocation. One source of truth
|
|
8
|
+
* for how `op` is invoked, how long it may take, and what "available and
|
|
9
|
+
* authenticated" means (P6).
|
|
10
|
+
*
|
|
11
|
+
* No dependency on `@1password/sdk` — `execFileSync` only, matching ADR-001's
|
|
12
|
+
* zero-new-runtime-deps position.
|
|
13
|
+
*/
|
|
14
|
+
/** Probe calls (`--version`, `account list`) — fast or the CLI is unusable. */
|
|
15
|
+
export declare const OP_PROBE_TIMEOUT_MS = 5000;
|
|
16
|
+
/** Metadata reads (`item get`, `item list`) — a network round-trip. */
|
|
17
|
+
export declare const OP_READ_TIMEOUT_MS = 15000;
|
|
18
|
+
/** Mutations and secret reads — desktop-app approval may sit in front of these. */
|
|
19
|
+
export declare const OP_WRITE_TIMEOUT_MS = 30000;
|
|
20
|
+
/** Options for {@link runOp}. */
|
|
21
|
+
export interface RunOpOptions {
|
|
22
|
+
/**
|
|
23
|
+
* Data piped to `op` on **stdin**. This is the argv-safe path for secret
|
|
24
|
+
* values (ADR-004 §4): anything passed here is invisible to `ps`, unlike an
|
|
25
|
+
* `field=value` argv element.
|
|
26
|
+
*/
|
|
27
|
+
input?: string;
|
|
28
|
+
/** Wall-clock timeout. Defaults to {@link OP_READ_TIMEOUT_MS}. */
|
|
29
|
+
timeoutMs?: number;
|
|
30
|
+
}
|
|
31
|
+
/** A failed `op` invocation, with whatever the CLI wrote to stderr. */
|
|
32
|
+
export declare class OpCliError extends Error {
|
|
33
|
+
/** The argv `op` was called with — never contains secret values. */
|
|
34
|
+
readonly args: readonly string[];
|
|
35
|
+
/** `op`'s stderr, trimmed; empty when the process produced none. */
|
|
36
|
+
readonly stderr: string;
|
|
37
|
+
/** The underlying spawn/exit error. Narrows `Error.cause` to this value. */
|
|
38
|
+
readonly cause: unknown;
|
|
39
|
+
constructor(
|
|
40
|
+
/** The argv `op` was called with — never contains secret values. */
|
|
41
|
+
args: readonly string[],
|
|
42
|
+
/** `op`'s stderr, trimmed; empty when the process produced none. */
|
|
43
|
+
stderr: string,
|
|
44
|
+
/** The underlying spawn/exit error. Narrows `Error.cause` to this value. */
|
|
45
|
+
cause: unknown);
|
|
46
|
+
/**
|
|
47
|
+
* True when the failure is 1Password reporting the item simply is not there,
|
|
48
|
+
* as opposed to an auth, network, or configuration problem.
|
|
49
|
+
*
|
|
50
|
+
* The distinction is load-bearing for ADR-004 §7: a not-found is a normal
|
|
51
|
+
* `null`/`false` return, while an unexpected failure additionally warrants a
|
|
52
|
+
* one-time stderr warning so a misconfiguration cannot stay silent (P2).
|
|
53
|
+
* `op` has no stable exit code for this, so the message is the only signal.
|
|
54
|
+
*/
|
|
55
|
+
get isNotFound(): boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Invoke `op` and return its stdout, trimmed.
|
|
59
|
+
*
|
|
60
|
+
* @param args - argv after the binary. **Never** put a secret value here — pass
|
|
61
|
+
* it via {@link RunOpOptions.input} instead (ADR-004 §4).
|
|
62
|
+
* @throws {@link OpCliError} on spawn failure, non-zero exit, or timeout.
|
|
63
|
+
*/
|
|
64
|
+
export declare function runOp(args: readonly string[], opts?: RunOpOptions): string;
|
|
65
|
+
/**
|
|
66
|
+
* Whether the `op` CLI is present **and** authenticated.
|
|
67
|
+
*
|
|
68
|
+
* True when the binary is on `PATH` and either `OP_SERVICE_ACCOUNT_TOKEN` is
|
|
69
|
+
* set (headless/CI mode, which needs no further check) or at least one account
|
|
70
|
+
* is configured (desktop app or a prior `op signin`).
|
|
71
|
+
*
|
|
72
|
+
* This answers only "can we talk to 1Password?" — it says nothing about whether
|
|
73
|
+
* a caller *should*. ADR-004's credential backend is opt-in precisely because
|
|
74
|
+
* `op` being installed must never by itself route secrets into 1Password (§1);
|
|
75
|
+
* that selection decision belongs to the caller, not here.
|
|
76
|
+
*/
|
|
77
|
+
export declare function detectOpCli(): boolean;
|
|
78
|
+
//# sourceMappingURL=op-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"op-cli.d.ts","sourceRoot":"","sources":["../../src/key-providers/op-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAQH,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,OAAQ,CAAC;AAEzC,uEAAuE;AACvE,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAEzC,mFAAmF;AACnF,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAM1C,iCAAiC;AACjC,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,uEAAuE;AACvE,qBAAa,UAAW,SAAQ,KAAK;IAEjC,oEAAoE;aACpD,IAAI,EAAE,SAAS,MAAM,EAAE;IACvC,oEAAoE;aACpD,MAAM,EAAE,MAAM;IAC9B,4EAA4E;aACnD,KAAK,EAAE,OAAO;;IALvC,oEAAoE;IACpD,IAAI,EAAE,SAAS,MAAM,EAAE;IACvC,oEAAoE;IACpD,MAAM,EAAE,MAAM;IAC9B,4EAA4E;IACnD,KAAK,EAAE,OAAO;IASzC;;;;;;;;OAQG;IACH,IAAI,UAAU,IAAI,OAAO,CAIxB;CACF;AAED;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,GAAE,YAAiB,GAAG,MAAM,CAY9E;AAeD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAkBrC"}
|