@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
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* delete(key): boolean — always returns true (no-op; nothing to delete)
|
|
12
12
|
* static detect(): boolean — always returns true (last-resort fallback)
|
|
13
13
|
*/
|
|
14
|
+
import type { SecretState } from "../secret-state.js";
|
|
14
15
|
import type { VaultBackend } from "./types.js";
|
|
15
16
|
/**
|
|
16
17
|
* Environment-variable-only vault backend.
|
|
@@ -46,6 +47,19 @@ export declare class EnvVault implements VaultBackend {
|
|
|
46
47
|
* @returns The credential value, or null if unavailable
|
|
47
48
|
*/
|
|
48
49
|
retrieve(key: string): string | null;
|
|
50
|
+
/**
|
|
51
|
+
* Probe one credential's state (#188).
|
|
52
|
+
*
|
|
53
|
+
* Environment variables have no lock concept and no ACL: a variable is
|
|
54
|
+
* either set in this process or it is not, and there is no third state in
|
|
55
|
+
* which it exists but cannot be read. So this backend answers exactly
|
|
56
|
+
* `found`/`absent` and never `locked` — inventing one would be as dishonest
|
|
57
|
+
* as the collapse the probe exists to prevent, in the other direction.
|
|
58
|
+
*
|
|
59
|
+
* Value-free: the variable is read only to test it against `null`, and the
|
|
60
|
+
* value is discarded.
|
|
61
|
+
*/
|
|
62
|
+
probe(key: string): SecretState;
|
|
49
63
|
/**
|
|
50
64
|
* Delete a credential.
|
|
51
65
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vault-env.d.ts","sourceRoot":"","sources":["../../src/vault/vault-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C;;;;;;GAMG;AACH,qBAAa,QAAS,YAAW,YAAY;IAC3C;;;OAGG;IACH,MAAM,CAAC,MAAM,IAAI,OAAO;IAIxB;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAK5C;;;;;;;;;OASG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOpC;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI7B;;;;;;;;;OASG;IACG,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAKnD"}
|
|
1
|
+
{"version":3,"file":"vault-env.d.ts","sourceRoot":"","sources":["../../src/vault/vault-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C;;;;;;GAMG;AACH,qBAAa,QAAS,YAAW,YAAY;IAC3C;;;OAGG;IACH,MAAM,CAAC,MAAM,IAAI,OAAO;IAIxB;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAK5C;;;;;;;;;OASG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOpC;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW;IAI/B;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI7B;;;;;;;;;OASG;IACG,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAKnD"}
|
package/dist/vault/vault-env.js
CHANGED
|
@@ -59,6 +59,21 @@ export class EnvVault {
|
|
|
59
59
|
}
|
|
60
60
|
return null;
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Probe one credential's state (#188).
|
|
64
|
+
*
|
|
65
|
+
* Environment variables have no lock concept and no ACL: a variable is
|
|
66
|
+
* either set in this process or it is not, and there is no third state in
|
|
67
|
+
* which it exists but cannot be read. So this backend answers exactly
|
|
68
|
+
* `found`/`absent` and never `locked` — inventing one would be as dishonest
|
|
69
|
+
* as the collapse the probe exists to prevent, in the other direction.
|
|
70
|
+
*
|
|
71
|
+
* Value-free: the variable is read only to test it against `null`, and the
|
|
72
|
+
* value is discarded.
|
|
73
|
+
*/
|
|
74
|
+
probe(key) {
|
|
75
|
+
return this.retrieve(key) !== null ? { kind: "found" } : { kind: "absent" };
|
|
76
|
+
}
|
|
62
77
|
/**
|
|
63
78
|
* Delete a credential.
|
|
64
79
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vault-env.js","sourceRoot":"","sources":["../../src/vault/vault-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"vault-env.js","sourceRoot":"","sources":["../../src/vault/vault-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAInD,gFAAgF;AAChF,0BAA0B;AAC1B,gFAAgF;AAEhF;;;;;;GAMG;AACH,MAAM,OAAO,QAAQ;IACnB;;;OAGG;IACH,MAAM,CAAC,MAAM;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAY,EAAE,MAAc;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;QACrE,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;;;OASG;IACH,QAAQ,CAAC,GAAW;QAClB,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YACzB,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,IAAI,CAAC;QAC/C,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,GAAW;QACf,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC9E,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,IAAY;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,QAAQ,CAAC,MAAe;QAC5B,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,KAAK,SAAS;YAAE,OAAO,EAAE,CAAC;QAC3D,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QACxE,OAAO,CAAC,YAAY,CAAC,CAAC;IACxB,CAAC;CACF"}
|
|
@@ -5,7 +5,11 @@
|
|
|
5
5
|
* ~/.centient/auth/credentials-<key>.gpg. Falls back gracefully when GPG is
|
|
6
6
|
* not installed or no keys are configured.
|
|
7
7
|
*
|
|
8
|
-
* Error handling:
|
|
8
|
+
* Error handling: a storage failure returns false/null — this backend never
|
|
9
|
+
* throws for that. A credential key that violates the shared key grammar is
|
|
10
|
+
* NOT a storage failure and throws `InvalidCredentialKeyError` (#168): such a
|
|
11
|
+
* key is unaddressable here, and reporting it as a failed write or an absent
|
|
12
|
+
* credential would be indistinguishable from the ordinary miss.
|
|
9
13
|
*/
|
|
10
14
|
import type { VaultBackend } from "./types.js";
|
|
11
15
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vault-gpg.d.ts","sourceRoot":"","sources":["../../src/vault/vault-gpg.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"vault-gpg.d.ts","sourceRoot":"","sources":["../../src/vault/vault-gpg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA4D/C;;;;GAIG;AACH,qBAAa,QAAS,YAAW,YAAY;IAC3C;;OAEG;IACH,MAAM,CAAC,MAAM,IAAI,OAAO;IASxB;;;;OAIG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAuB1C;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAkBpC;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAmB5B;;;;;;;OAOG;IACG,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CA0BnD"}
|
package/dist/vault/vault-gpg.js
CHANGED
|
@@ -5,13 +5,17 @@
|
|
|
5
5
|
* ~/.centient/auth/credentials-<key>.gpg. Falls back gracefully when GPG is
|
|
6
6
|
* not installed or no keys are configured.
|
|
7
7
|
*
|
|
8
|
-
* Error handling:
|
|
8
|
+
* Error handling: a storage failure returns false/null — this backend never
|
|
9
|
+
* throws for that. A credential key that violates the shared key grammar is
|
|
10
|
+
* NOT a storage failure and throws `InvalidCredentialKeyError` (#168): such a
|
|
11
|
+
* key is unaddressable here, and reporting it as a failed write or an absent
|
|
12
|
+
* credential would be indistinguishable from the ordinary miss.
|
|
9
13
|
*/
|
|
10
14
|
import { execFileSync } from "child_process";
|
|
11
15
|
import { mkdirSync, readdirSync, unlinkSync } from "fs";
|
|
12
16
|
import { homedir } from "os";
|
|
13
17
|
import { join } from "path";
|
|
14
|
-
import {
|
|
18
|
+
import { assertValidKey } from "./vault-utils.js";
|
|
15
19
|
// =============================================================================
|
|
16
20
|
// Constants
|
|
17
21
|
// =============================================================================
|
|
@@ -84,8 +88,7 @@ export class GpgVault {
|
|
|
84
88
|
* @returns true on success, false if GPG is unavailable or encryption fails
|
|
85
89
|
*/
|
|
86
90
|
store(key, value) {
|
|
87
|
-
|
|
88
|
-
return false;
|
|
91
|
+
assertValidKey(key, "write");
|
|
89
92
|
try {
|
|
90
93
|
const keyId = getFirstGpgKeyId();
|
|
91
94
|
if (keyId === null)
|
|
@@ -108,8 +111,7 @@ export class GpgVault {
|
|
|
108
111
|
* @returns the plaintext credential, or null if not found / decryption fails
|
|
109
112
|
*/
|
|
110
113
|
retrieve(key) {
|
|
111
|
-
|
|
112
|
-
return null;
|
|
114
|
+
assertValidKey(key, "read");
|
|
113
115
|
try {
|
|
114
116
|
const filePath = credentialPath(key);
|
|
115
117
|
const result = execFileSync("gpg", ["--batch", "--quiet", "-d", filePath], {
|
|
@@ -128,8 +130,7 @@ export class GpgVault {
|
|
|
128
130
|
* @returns true if the file was deleted or did not exist, false on unexpected error
|
|
129
131
|
*/
|
|
130
132
|
delete(key) {
|
|
131
|
-
|
|
132
|
-
return false;
|
|
133
|
+
assertValidKey(key, "delete");
|
|
133
134
|
try {
|
|
134
135
|
unlinkSync(credentialPath(key));
|
|
135
136
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vault-gpg.js","sourceRoot":"","sources":["../../src/vault/vault-gpg.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"vault-gpg.js","sourceRoot":"","sources":["../../src/vault/vault-gpg.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
* stored under a fixed service attribute (`centient`) and a per-key
|
|
7
7
|
* attribute (`key`).
|
|
8
8
|
*
|
|
9
|
-
* Error handling:
|
|
9
|
+
* Error handling: a storage failure returns false/null — this backend never
|
|
10
|
+
* throws for that. A credential key that violates the shared key grammar is
|
|
11
|
+
* NOT a storage failure and throws `InvalidCredentialKeyError` (#168): such a
|
|
12
|
+
* key is unaddressable here, and reporting it as a failed write or an absent
|
|
13
|
+
* credential would be indistinguishable from the ordinary miss.
|
|
10
14
|
*/
|
|
11
15
|
import type { VaultBackend } from "./types.js";
|
|
12
16
|
/**
|
|
@@ -62,12 +66,30 @@ export declare class LibsecretVault implements VaultBackend {
|
|
|
62
66
|
* `secret-tool search --all` and parses `attribute.key` lines.
|
|
63
67
|
* The fallback still briefly materializes secret values on stdout;
|
|
64
68
|
* the JSDoc on the `secret-tool` path in the fallback documents
|
|
65
|
-
* this trade-off.
|
|
69
|
+
* this trade-off. Because that fallback is a security-relevant
|
|
70
|
+
* degradation, a host that advertises a session bus yet still fails
|
|
71
|
+
* the D-Bus path emits a one-time stderr warning
|
|
72
|
+
* (`warnOnDbusDegradation`); a genuinely bus-less host stays quiet
|
|
73
|
+
* since the fallback is the documented, expected behavior there.
|
|
66
74
|
*
|
|
67
75
|
* No results -> empty list. A transient failure from both paths is
|
|
68
76
|
* propagated per the VaultBackend contract so the caller can retry.
|
|
69
77
|
*/
|
|
70
78
|
listKeys(prefix?: string): Promise<string[]>;
|
|
79
|
+
/**
|
|
80
|
+
* The secret-tool fallback briefly materializes secret values on
|
|
81
|
+
* stdout (see `listKeysViaSecretTool`), so reverting to it from the
|
|
82
|
+
* secure D-Bus path is a security-relevant degradation that must not
|
|
83
|
+
* be silent (DESIGN-PHILOSOPHY: no silent degradation).
|
|
84
|
+
*
|
|
85
|
+
* But a host with no session bus at all — an SSH session or headless
|
|
86
|
+
* server with no `DBUS_SESSION_BUS_ADDRESS` — is the *documented,
|
|
87
|
+
* expected* fallback case, not a degradation, so warning there would
|
|
88
|
+
* be noise. We therefore warn (once per process) only when a session
|
|
89
|
+
* bus is advertised yet the D-Bus enumeration still failed: that is an
|
|
90
|
+
* unexpected failure of the path that was supposed to work.
|
|
91
|
+
*/
|
|
92
|
+
private warnOnDbusDegradation;
|
|
71
93
|
/**
|
|
72
94
|
* D-Bus primary path for listKeys — no secret values cross process
|
|
73
95
|
* memory. Uses dynamic import so `dbus-next` is only loaded on
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vault-libsecret.d.ts","sourceRoot":"","sources":["../../src/vault/vault-libsecret.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"vault-libsecret.d.ts","sourceRoot":"","sources":["../../src/vault/vault-libsecret.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAsB/C;;;;;;;;;GASG;AACH,qBAAa,cAAe,YAAW,YAAY;IACjD;;;OAGG;IACH,MAAM,CAAC,MAAM,IAAI,OAAO;IAYxB;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAiB1C;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAiBpC;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAmB5B;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAelD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,qBAAqB;IAa7B;;;;OAIG;YACW,eAAe;IAyD7B;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;CA2B9B"}
|
|
@@ -6,15 +6,26 @@
|
|
|
6
6
|
* stored under a fixed service attribute (`centient`) and a per-key
|
|
7
7
|
* attribute (`key`).
|
|
8
8
|
*
|
|
9
|
-
* Error handling:
|
|
9
|
+
* Error handling: a storage failure returns false/null — this backend never
|
|
10
|
+
* throws for that. A credential key that violates the shared key grammar is
|
|
11
|
+
* NOT a storage failure and throws `InvalidCredentialKeyError` (#168): such a
|
|
12
|
+
* key is unaddressable here, and reporting it as a failed write or an absent
|
|
13
|
+
* credential would be indistinguishable from the ordinary miss.
|
|
10
14
|
*/
|
|
11
15
|
import { execSync } from "child_process";
|
|
12
|
-
import {
|
|
16
|
+
import { assertValidKey } from "./vault-utils.js";
|
|
13
17
|
// =============================================================================
|
|
14
18
|
// Constants
|
|
15
19
|
// =============================================================================
|
|
16
20
|
const SERVICE_ATTR = "centient";
|
|
17
21
|
const LABEL = "centient-auth";
|
|
22
|
+
/**
|
|
23
|
+
* One-time guard so a "secure D-Bus enumeration degraded to secret-tool"
|
|
24
|
+
* warning is emitted at most once per process (mirrors the audit-policy
|
|
25
|
+
* warning idiom in policy.ts), avoiding a log flood when enumeration is
|
|
26
|
+
* called in a loop.
|
|
27
|
+
*/
|
|
28
|
+
let dbusFallbackWarned = false;
|
|
18
29
|
// =============================================================================
|
|
19
30
|
// LibsecretVault
|
|
20
31
|
// =============================================================================
|
|
@@ -53,8 +64,7 @@ export class LibsecretVault {
|
|
|
53
64
|
* @returns true on success, false if the write fails
|
|
54
65
|
*/
|
|
55
66
|
store(key, value) {
|
|
56
|
-
|
|
57
|
-
return false;
|
|
67
|
+
assertValidKey(key, "write");
|
|
58
68
|
try {
|
|
59
69
|
execSync(`secret-tool store --label "${LABEL}" service ${SERVICE_ATTR} key "${key}"`, {
|
|
60
70
|
encoding: "utf8",
|
|
@@ -74,8 +84,7 @@ export class LibsecretVault {
|
|
|
74
84
|
* @returns The stored value, or null if not found / lookup fails
|
|
75
85
|
*/
|
|
76
86
|
retrieve(key) {
|
|
77
|
-
|
|
78
|
-
return null;
|
|
87
|
+
assertValidKey(key, "read");
|
|
79
88
|
try {
|
|
80
89
|
const result = execSync(`secret-tool lookup service ${SERVICE_ATTR} key "${key}"`, {
|
|
81
90
|
encoding: "utf8",
|
|
@@ -95,8 +104,7 @@ export class LibsecretVault {
|
|
|
95
104
|
* @returns true on success (including "already deleted"), false on unexpected error
|
|
96
105
|
*/
|
|
97
106
|
delete(key) {
|
|
98
|
-
|
|
99
|
-
return false;
|
|
107
|
+
assertValidKey(key, "delete");
|
|
100
108
|
try {
|
|
101
109
|
execSync(`secret-tool clear service ${SERVICE_ATTR} key "${key}"`, {
|
|
102
110
|
encoding: "utf8",
|
|
@@ -126,7 +134,11 @@ export class LibsecretVault {
|
|
|
126
134
|
* `secret-tool search --all` and parses `attribute.key` lines.
|
|
127
135
|
* The fallback still briefly materializes secret values on stdout;
|
|
128
136
|
* the JSDoc on the `secret-tool` path in the fallback documents
|
|
129
|
-
* this trade-off.
|
|
137
|
+
* this trade-off. Because that fallback is a security-relevant
|
|
138
|
+
* degradation, a host that advertises a session bus yet still fails
|
|
139
|
+
* the D-Bus path emits a one-time stderr warning
|
|
140
|
+
* (`warnOnDbusDegradation`); a genuinely bus-less host stays quiet
|
|
141
|
+
* since the fallback is the documented, expected behavior there.
|
|
130
142
|
*
|
|
131
143
|
* No results -> empty list. A transient failure from both paths is
|
|
132
144
|
* propagated per the VaultBackend contract so the caller can retry.
|
|
@@ -135,10 +147,42 @@ export class LibsecretVault {
|
|
|
135
147
|
try {
|
|
136
148
|
return await this.listKeysViaDbus(prefix);
|
|
137
149
|
}
|
|
138
|
-
catch {
|
|
150
|
+
catch (err) {
|
|
151
|
+
// Intentionally broad: the contract is "if the secure D-Bus path
|
|
152
|
+
// cannot enumerate for ANY reason, degrade to secret-tool" — the
|
|
153
|
+
// dominant cause is a bus-less host, but a protocol/variant error
|
|
154
|
+
// should fall back too rather than fail the read. The degradation
|
|
155
|
+
// is never silent (warnOnDbusDegradation surfaces an unexpected
|
|
156
|
+
// failure once), so a swallowed cause is still observable.
|
|
157
|
+
this.warnOnDbusDegradation(err);
|
|
139
158
|
return this.listKeysViaSecretTool(prefix);
|
|
140
159
|
}
|
|
141
160
|
}
|
|
161
|
+
/**
|
|
162
|
+
* The secret-tool fallback briefly materializes secret values on
|
|
163
|
+
* stdout (see `listKeysViaSecretTool`), so reverting to it from the
|
|
164
|
+
* secure D-Bus path is a security-relevant degradation that must not
|
|
165
|
+
* be silent (DESIGN-PHILOSOPHY: no silent degradation).
|
|
166
|
+
*
|
|
167
|
+
* But a host with no session bus at all — an SSH session or headless
|
|
168
|
+
* server with no `DBUS_SESSION_BUS_ADDRESS` — is the *documented,
|
|
169
|
+
* expected* fallback case, not a degradation, so warning there would
|
|
170
|
+
* be noise. We therefore warn (once per process) only when a session
|
|
171
|
+
* bus is advertised yet the D-Bus enumeration still failed: that is an
|
|
172
|
+
* unexpected failure of the path that was supposed to work.
|
|
173
|
+
*/
|
|
174
|
+
warnOnDbusDegradation(err) {
|
|
175
|
+
if (dbusFallbackWarned)
|
|
176
|
+
return;
|
|
177
|
+
const sessionBus = process.env.DBUS_SESSION_BUS_ADDRESS;
|
|
178
|
+
if (sessionBus === undefined || sessionBus.length === 0)
|
|
179
|
+
return;
|
|
180
|
+
dbusFallbackWarned = true;
|
|
181
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
182
|
+
process.stderr.write(`[secrets] libsecret D-Bus enumeration failed despite an active session ` +
|
|
183
|
+
`bus; falling back to \`secret-tool search\`, which briefly materializes ` +
|
|
184
|
+
`secret values on stdout. Cause: ${msg}\n`);
|
|
185
|
+
}
|
|
142
186
|
/**
|
|
143
187
|
* D-Bus primary path for listKeys — no secret values cross process
|
|
144
188
|
* memory. Uses dynamic import so `dbus-next` is only loaded on
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vault-libsecret.js","sourceRoot":"","sources":["../../src/vault/vault-libsecret.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"vault-libsecret.js","sourceRoot":"","sources":["../../src/vault/vault-libsecret.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault backend — 1Password credential storage (ADR-004).
|
|
3
|
+
*
|
|
4
|
+
* Stores credential **values** in a dedicated 1Password vault via the `op` CLI.
|
|
5
|
+
* This is a different layer from ADR-001's `OnePasswordProvider`, which stores
|
|
6
|
+
* the vault *encryption key*: an operator may keep the key in the Keychain and
|
|
7
|
+
* the credentials in 1Password, or the reverse. The two carry separate config
|
|
8
|
+
* blocks for exactly that reason (ADR-004 §1).
|
|
9
|
+
*
|
|
10
|
+
* ## Two properties this backend exists to hold
|
|
11
|
+
*
|
|
12
|
+
* 1. **Never auto-selected.** `op` being installed must not silently route
|
|
13
|
+
* credentials into someone's personal vault — surprising secret placement is
|
|
14
|
+
* a security defect (P15/P2). Selection is explicit opt-in, and
|
|
15
|
+
* {@link OnePasswordVault.detect} refuses without it.
|
|
16
|
+
* 2. **Secret values never touch argv.** Writes build the item JSON in-process
|
|
17
|
+
* and pipe it to `op item create -`, so nothing readable in `ps` ever carries
|
|
18
|
+
* a secret. This is the pattern issue #102 retrofitted to the key provider,
|
|
19
|
+
* which now writes through the same `op item create -` stdin seam. Its
|
|
20
|
+
* replace ordering differs — create first, delete the superseded item last —
|
|
21
|
+
* because losing the vault *master key* between two calls would be
|
|
22
|
+
* unrecoverable, where a credential value can be re-fetched from its source.
|
|
23
|
+
*/
|
|
24
|
+
import type { VaultBackend } from "./types.js";
|
|
25
|
+
import type { OnePasswordBackendConfig } from "../key-providers/types.js";
|
|
26
|
+
/** Default tag applied to every item this backend writes. */
|
|
27
|
+
export declare const DEFAULT_OP_TAG = "centient";
|
|
28
|
+
/**
|
|
29
|
+
* List-cache TTL, mirroring `KEYCHAIN_LIST_CACHE_TTL_MS` (ADR-004 §8).
|
|
30
|
+
*
|
|
31
|
+
* Only key **names** are cached, never values: a cached value would both extend
|
|
32
|
+
* how long plaintext sits in the heap and serve a rotated or revoked credential
|
|
33
|
+
* until expiry. 1Password stays the source of truth for values.
|
|
34
|
+
*/
|
|
35
|
+
export declare const OP_LIST_CACHE_TTL_MS = 5000;
|
|
36
|
+
/** Options for {@link OnePasswordVault}. */
|
|
37
|
+
export interface OnePasswordVaultOptions extends OnePasswordBackendConfig {
|
|
38
|
+
/**
|
|
39
|
+
* Injectable clock for the list cache, so tests can drive expiry without
|
|
40
|
+
* sleeping. Defaults to `Date.now`.
|
|
41
|
+
*/
|
|
42
|
+
now?: () => number;
|
|
43
|
+
}
|
|
44
|
+
export declare class OnePasswordVault implements VaultBackend {
|
|
45
|
+
private readonly vault;
|
|
46
|
+
private readonly tag;
|
|
47
|
+
private readonly now;
|
|
48
|
+
private listCache;
|
|
49
|
+
private warned;
|
|
50
|
+
/**
|
|
51
|
+
* @param config - must carry a `vault`; there is deliberately no default
|
|
52
|
+
* (ADR-004 §1 — guessing a vault name risks writing credentials somewhere
|
|
53
|
+
* the operator did not intend).
|
|
54
|
+
* @throws {Error} when `vault` is missing or blank.
|
|
55
|
+
*/
|
|
56
|
+
constructor(config: OnePasswordVaultOptions);
|
|
57
|
+
/**
|
|
58
|
+
* Whether this backend may be used.
|
|
59
|
+
*
|
|
60
|
+
* Requires **both** an explicit opt-in and a usable `op`. The opt-in half is
|
|
61
|
+
* what keeps 1Password out of the auto-cascade: without it this returns false
|
|
62
|
+
* even on a machine where `op` is installed and signed in.
|
|
63
|
+
*
|
|
64
|
+
* @param optedIn - true when config or env explicitly selected this backend.
|
|
65
|
+
*/
|
|
66
|
+
static detect(optedIn: boolean): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Write a credential. The value travels on stdin and never appears in argv.
|
|
69
|
+
*
|
|
70
|
+
* Update is modeled as replace (delete-then-create) so create and update share
|
|
71
|
+
* one argv-safe path rather than needing a separate `op item edit` form.
|
|
72
|
+
*/
|
|
73
|
+
store(key: string, value: string): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Read a credential value. Returns null when absent or on failure.
|
|
76
|
+
*
|
|
77
|
+
* @throws {InvalidCredentialKeyError} for a key this backend could never
|
|
78
|
+
* have written — building an `op://` reference from it is exactly the
|
|
79
|
+
* misparse the key grammar exists to prevent, and `null` would report the
|
|
80
|
+
* impossible key as a merely absent one.
|
|
81
|
+
*/
|
|
82
|
+
retrieve(key: string): string | null;
|
|
83
|
+
/**
|
|
84
|
+
* Delete a credential. Idempotent — a missing item is success.
|
|
85
|
+
*
|
|
86
|
+
* @throws {InvalidCredentialKeyError} — deliberately NOT folded into the
|
|
87
|
+
* idempotent-success path. "Missing" and "impossible" are different
|
|
88
|
+
* answers: such a key was never storable here, so reporting success would
|
|
89
|
+
* assert something about a key this backend does not accept.
|
|
90
|
+
*/
|
|
91
|
+
delete(key: string): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Enumerate credential keys, optionally prefix-filtered.
|
|
94
|
+
*
|
|
95
|
+
* Per the {@link VaultBackend} contract this returns `[]` for a genuinely
|
|
96
|
+
* empty vault but **throws** on a transient failure, so a caller can tell
|
|
97
|
+
* "nothing stored" from "1Password did not answer" and retry the latter.
|
|
98
|
+
* The `--tags` filter keeps unrelated items in a shared vault out of the
|
|
99
|
+
* result; no secret values appear in `op item list` output.
|
|
100
|
+
*/
|
|
101
|
+
listKeys(prefix?: string): Promise<string[]>;
|
|
102
|
+
private fetchKeys;
|
|
103
|
+
private deleteItem;
|
|
104
|
+
private readListCache;
|
|
105
|
+
private invalidateListCache;
|
|
106
|
+
/**
|
|
107
|
+
* Surface an unexpected `op` failure once per instance (ADR-004 §7, the
|
|
108
|
+
* libsecret lesson from #121).
|
|
109
|
+
*
|
|
110
|
+
* A not-found is normal and stays quiet. Anything else means we are
|
|
111
|
+
* authenticated but the call still failed — a misconfiguration the operator
|
|
112
|
+
* needs to see, since the non-throwing backend contract would otherwise
|
|
113
|
+
* swallow it entirely. Once per instance keeps a hot loop from flooding
|
|
114
|
+
* stderr while still making the first occurrence visible.
|
|
115
|
+
*/
|
|
116
|
+
private warnOnce;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=vault-onepassword.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vault-onepassword.d.ts","sourceRoot":"","sources":["../../src/vault/vault-onepassword.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAa1E,6DAA6D;AAC7D,eAAO,MAAM,cAAc,aAAa,CAAC;AAKzC;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,OAAQ,CAAC;AAM1C,4CAA4C;AAC5C,MAAM,WAAW,uBAAwB,SAAQ,wBAAwB;IACvE;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAMD,qBAAa,gBAAiB,YAAW,YAAY;IACnD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IAEnC,OAAO,CAAC,SAAS,CAAsD;IACvE,OAAO,CAAC,MAAM,CAAS;IAEvB;;;;;OAKG;gBACS,MAAM,EAAE,uBAAuB;IAa3C;;;;;;;;OAQG;IACH,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO;IAKxC;;;;;OAKG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IA2B1C;;;;;;;OAOG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAepC;;;;;;;OAOG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAa5B;;;;;;;;OAQG;IACG,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAgBlD,OAAO,CAAC,SAAS;IAsDjB,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,mBAAmB;IAI3B;;;;;;;;;OASG;IACH,OAAO,CAAC,QAAQ;CAWjB"}
|