@centient/secrets 0.9.0 → 0.11.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.
Files changed (152) hide show
  1. package/README.md +424 -8
  2. package/dist/audit/hmac-chain.d.ts +117 -0
  3. package/dist/audit/hmac-chain.d.ts.map +1 -0
  4. package/dist/audit/hmac-chain.js +811 -0
  5. package/dist/audit/hmac-chain.js.map +1 -0
  6. package/dist/audit/ocsf.d.ts +108 -0
  7. package/dist/audit/ocsf.d.ts.map +1 -0
  8. package/dist/audit/ocsf.js +204 -0
  9. package/dist/audit/ocsf.js.map +1 -0
  10. package/dist/cli/hidden-prompt.d.ts.map +1 -1
  11. package/dist/cli/hidden-prompt.js +55 -10
  12. package/dist/cli/hidden-prompt.js.map +1 -1
  13. package/dist/cli/messages.d.ts +40 -8
  14. package/dist/cli/messages.d.ts.map +1 -1
  15. package/dist/cli/messages.js +34 -8
  16. package/dist/cli/messages.js.map +1 -1
  17. package/dist/cli/secrets-cli.d.ts.map +1 -1
  18. package/dist/cli/secrets-cli.js +191 -32
  19. package/dist/cli/secrets-cli.js.map +1 -1
  20. package/dist/client.d.ts +26 -0
  21. package/dist/client.d.ts.map +1 -0
  22. package/dist/client.js +129 -0
  23. package/dist/client.js.map +1 -0
  24. package/dist/compatibility.d.ts +199 -0
  25. package/dist/compatibility.d.ts.map +1 -0
  26. package/dist/compatibility.js +419 -0
  27. package/dist/compatibility.js.map +1 -0
  28. package/dist/crypto/darwin-keychain.d.ts +394 -0
  29. package/dist/crypto/darwin-keychain.d.ts.map +1 -0
  30. package/dist/crypto/darwin-keychain.js +793 -0
  31. package/dist/crypto/darwin-keychain.js.map +1 -0
  32. package/dist/crypto/vault-common.d.ts +55 -12
  33. package/dist/crypto/vault-common.d.ts.map +1 -1
  34. package/dist/crypto/vault-common.js +74 -71
  35. package/dist/crypto/vault-common.js.map +1 -1
  36. package/dist/environment/EnvironmentManager.d.ts.map +1 -1
  37. package/dist/environment/EnvironmentManager.js +5 -10
  38. package/dist/environment/EnvironmentManager.js.map +1 -1
  39. package/dist/index.d.ts +37 -9
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +38 -6
  42. package/dist/index.js.map +1 -1
  43. package/dist/key-providers/keychain-provider.d.ts +30 -2
  44. package/dist/key-providers/keychain-provider.d.ts.map +1 -1
  45. package/dist/key-providers/keychain-provider.js +29 -5
  46. package/dist/key-providers/keychain-provider.js.map +1 -1
  47. package/dist/key-providers/onepassword-provider.d.ts +65 -5
  48. package/dist/key-providers/onepassword-provider.d.ts.map +1 -1
  49. package/dist/key-providers/onepassword-provider.js +159 -67
  50. package/dist/key-providers/onepassword-provider.js.map +1 -1
  51. package/dist/key-providers/op-cli.d.ts +78 -0
  52. package/dist/key-providers/op-cli.d.ts.map +1 -0
  53. package/dist/key-providers/op-cli.js +123 -0
  54. package/dist/key-providers/op-cli.js.map +1 -0
  55. package/dist/key-providers/passphrase-provider.d.ts +20 -0
  56. package/dist/key-providers/passphrase-provider.d.ts.map +1 -1
  57. package/dist/key-providers/passphrase-provider.js +49 -0
  58. package/dist/key-providers/passphrase-provider.js.map +1 -1
  59. package/dist/key-providers/probe.d.ts +46 -0
  60. package/dist/key-providers/probe.d.ts.map +1 -0
  61. package/dist/key-providers/probe.js +70 -0
  62. package/dist/key-providers/probe.js.map +1 -0
  63. package/dist/key-providers/types.d.ts +51 -1
  64. package/dist/key-providers/types.d.ts.map +1 -1
  65. package/dist/platform/agent-detect.d.ts +39 -3
  66. package/dist/platform/agent-detect.d.ts.map +1 -1
  67. package/dist/platform/agent-detect.js +55 -9
  68. package/dist/platform/agent-detect.js.map +1 -1
  69. package/dist/platform/session-context.d.ts +77 -0
  70. package/dist/platform/session-context.d.ts.map +1 -0
  71. package/dist/platform/session-context.js +83 -0
  72. package/dist/platform/session-context.js.map +1 -0
  73. package/dist/policies/audit-trail.d.ts +25 -0
  74. package/dist/policies/audit-trail.d.ts.map +1 -0
  75. package/dist/policies/audit-trail.js +31 -0
  76. package/dist/policies/audit-trail.js.map +1 -0
  77. package/dist/secret-state.d.ts +54 -0
  78. package/dist/secret-state.d.ts.map +1 -0
  79. package/dist/secret-state.js +2 -0
  80. package/dist/secret-state.js.map +1 -0
  81. package/dist/sinks/index.d.ts +9 -0
  82. package/dist/sinks/index.d.ts.map +1 -0
  83. package/dist/sinks/index.js +5 -0
  84. package/dist/sinks/index.js.map +1 -0
  85. package/dist/sinks/jsonl.d.ts +16 -0
  86. package/dist/sinks/jsonl.d.ts.map +1 -0
  87. package/dist/sinks/jsonl.js +51 -0
  88. package/dist/sinks/jsonl.js.map +1 -0
  89. package/dist/sinks/otel.d.ts +22 -0
  90. package/dist/sinks/otel.d.ts.map +1 -0
  91. package/dist/sinks/otel.js +155 -0
  92. package/dist/sinks/otel.js.map +1 -0
  93. package/dist/sinks/queue.d.ts +12 -0
  94. package/dist/sinks/queue.d.ts.map +1 -0
  95. package/dist/sinks/queue.js +89 -0
  96. package/dist/sinks/queue.js.map +1 -0
  97. package/dist/sinks/syslog.d.ts +17 -0
  98. package/dist/sinks/syslog.d.ts.map +1 -0
  99. package/dist/sinks/syslog.js +103 -0
  100. package/dist/sinks/syslog.js.map +1 -0
  101. package/dist/sinks/types.d.ts +27 -0
  102. package/dist/sinks/types.d.ts.map +1 -0
  103. package/dist/sinks/types.js +18 -0
  104. package/dist/sinks/types.js.map +1 -0
  105. package/dist/vault/policy.d.ts +64 -34
  106. package/dist/vault/policy.d.ts.map +1 -1
  107. package/dist/vault/policy.js +109 -67
  108. package/dist/vault/policy.js.map +1 -1
  109. package/dist/vault/session-vault-errors.d.ts +72 -4
  110. package/dist/vault/session-vault-errors.d.ts.map +1 -1
  111. package/dist/vault/session-vault-errors.js +95 -4
  112. package/dist/vault/session-vault-errors.js.map +1 -1
  113. package/dist/vault/session-vault.d.ts +145 -2
  114. package/dist/vault/session-vault.d.ts.map +1 -1
  115. package/dist/vault/session-vault.js +548 -72
  116. package/dist/vault/session-vault.js.map +1 -1
  117. package/dist/vault/sidecar.d.ts +9 -0
  118. package/dist/vault/sidecar.d.ts.map +1 -1
  119. package/dist/vault/sidecar.js +72 -3
  120. package/dist/vault/sidecar.js.map +1 -1
  121. package/dist/vault/types.d.ts +58 -10
  122. package/dist/vault/types.d.ts.map +1 -1
  123. package/dist/vault/types.js.map +1 -1
  124. package/dist/vault/vault-env.d.ts +43 -50
  125. package/dist/vault/vault-env.d.ts.map +1 -1
  126. package/dist/vault/vault-env.js +141 -62
  127. package/dist/vault/vault-env.js.map +1 -1
  128. package/dist/vault/vault-gpg.d.ts +6 -1
  129. package/dist/vault/vault-gpg.d.ts.map +1 -1
  130. package/dist/vault/vault-gpg.js +10 -8
  131. package/dist/vault/vault-gpg.js.map +1 -1
  132. package/dist/vault/vault-libsecret.d.ts +6 -1
  133. package/dist/vault/vault-libsecret.d.ts.map +1 -1
  134. package/dist/vault/vault-libsecret.js +16 -14
  135. package/dist/vault/vault-libsecret.js.map +1 -1
  136. package/dist/vault/vault-onepassword.d.ts +119 -0
  137. package/dist/vault/vault-onepassword.d.ts.map +1 -0
  138. package/dist/vault/vault-onepassword.js +271 -0
  139. package/dist/vault/vault-onepassword.js.map +1 -0
  140. package/dist/vault/vault-utils.d.ts +37 -3
  141. package/dist/vault/vault-utils.d.ts.map +1 -1
  142. package/dist/vault/vault-utils.js +65 -3
  143. package/dist/vault/vault-utils.js.map +1 -1
  144. package/dist/vault/vault-windows.d.ts +7 -2
  145. package/dist/vault/vault-windows.d.ts.map +1 -1
  146. package/dist/vault/vault-windows.js +21 -16
  147. package/dist/vault/vault-windows.js.map +1 -1
  148. package/dist/vault/vault.d.ts +120 -9
  149. package/dist/vault/vault.d.ts.map +1 -1
  150. package/dist/vault/vault.js +222 -139
  151. package/dist/vault/vault.js.map +1 -1
  152. package/package.json +8 -2
@@ -1,20 +1,19 @@
1
1
  /**
2
2
  * SecretsPolicy — Middleware layer for credential operations.
3
3
  *
4
- * Policies are cross-cutting concerns (audit, rate limiting, access
5
- * control, attestation) applied to every credential operation via
6
- * `setSecretsPolicies([...])`. In 0.5.0 only the audit policy is
7
- * shipped; the API shape is designed to grow into the full policy
8
- * stack described in ADR-002.
4
+ * Policies are cross-cutting concerns (audit, rate limiting, access control,
5
+ * attestation) applied to every credential operation. Explicit clients own an
6
+ * isolated stack supplied to `createSecretsClient`; `setSecretsPolicies`
7
+ * remains as the deprecated configuration path for the module-level shims and
8
+ * SessionVault. The API shape is designed for the full stack in ADR-002.
9
9
  *
10
10
  * Execution model:
11
11
  * 1. `before` hooks run top-to-bottom. If one throws, the operation
12
12
  * is aborted and the error propagates to the caller — but the
13
- * `after` hooks of already-entered policies (those whose `before`
14
- * hook already completed) still fire with a `*_rejected` event, so
13
+ * rejecting policy and already-entered policies still fire their
14
+ * `after` hooks with a `*_rejected` event, so
15
15
  * a policy-denied operation is audited rather than vanishing
16
- * (ADR-002 §1.0.0). The rejecting policy's own `after` hook does
17
- * not fire — its `before` hook did not complete.
16
+ * (issue #98). Policies not yet reached do not fire.
18
17
  * 2. The backend operation executes.
19
18
  * 3. `after` hooks run bottom-to-top with a structured event
20
19
  * describing the outcome. Exceptions in `after` hooks are
@@ -44,59 +43,57 @@ export function rejectedEventType(op) {
44
43
  }
45
44
  }
46
45
  }
47
- // =============================================================================
48
- // Policy registry
49
- // =============================================================================
50
- let activePolicies = [];
51
- let afterWarningEmitted = false;
52
- export function setSecretsPolicies(policies) {
53
- activePolicies = [...policies];
54
- afterWarningEmitted = false;
55
- }
56
- export function getActivePolicies() {
57
- return activePolicies;
58
- }
59
- /**
60
- * Run `before` hooks top-to-bottom. If a hook throws, the operation is
61
- * rejected: the `after` hooks of the already-entered policies (indices
62
- * `0..i-1`, bottom-to-top) fire with the event built by
63
- * `makeRejectionEvent` so the denied operation is still audited, then the
64
- * original error is re-thrown to abort the operation. The rejecting
65
- * policy's own `after` hook is intentionally skipped — its `before` hook
66
- * did not complete, so the policy was not fully entered. See ADR-002
67
- * §1.0.0.
68
- */
69
- export async function runBeforeHooks(op, makeRejectionEvent) {
70
- for (let i = 0; i < activePolicies.length; i++) {
71
- const policy = activePolicies[i];
72
- if (!policy.before)
73
- continue;
74
- try {
75
- await policy.before(op);
46
+ function snapshotPolicies(configured) {
47
+ const snapshot = configured.map((policy) => {
48
+ // Capture the complete callable shape, not just the containing array.
49
+ // Otherwise a caller could add or replace a before hook after ordering
50
+ // validation and make a rejection observer silently miss denials.
51
+ const name = policy.name;
52
+ const observesPolicyRejections = policy.observesPolicyRejections;
53
+ const configuredBefore = policy.before;
54
+ const configuredAfter = policy.after;
55
+ // ADR-002 permits a policy object to retain mutable internal state. Bind
56
+ // the captured hooks to that original receiver while freezing only the
57
+ // validated public wrapper and its hook identities.
58
+ const before = configuredBefore?.bind(policy);
59
+ const after = configuredAfter?.bind(policy);
60
+ return Object.freeze({
61
+ name,
62
+ ...(observesPolicyRejections === true
63
+ ? { observesPolicyRejections: true }
64
+ : {}),
65
+ ...(before !== undefined ? { before } : {}),
66
+ ...(after !== undefined ? { after } : {}),
67
+ });
68
+ });
69
+ let precedingBeforePolicy;
70
+ for (const policy of snapshot) {
71
+ if (policy.observesPolicyRejections === true &&
72
+ precedingBeforePolicy !== undefined) {
73
+ throw new TypeError(`policy "${policy.name}" observes policy rejections and must precede ` +
74
+ `policy "${precedingBeforePolicy.name}" (and every other policy with a before hook)`);
76
75
  }
77
- catch (err) {
78
- const msg = err instanceof Error ? err.message : String(err);
79
- runAfterHooksForRange(makeRejectionEvent(msg), i - 1);
80
- throw err;
76
+ if (policy.before !== undefined && precedingBeforePolicy === undefined) {
77
+ precedingBeforePolicy = policy;
81
78
  }
82
79
  }
83
- }
84
- export function runAfterHooks(event) {
85
- runAfterHooksForRange(event, activePolicies.length - 1);
80
+ // The registry's public inspection API returns this same value. Freeze the
81
+ // array so a cast to a mutable type cannot bypass replacement validation.
82
+ return Object.freeze(snapshot);
86
83
  }
87
84
  /**
88
- * Run `after` hooks for policies `fromIndex..0` (bottom-to-top). A
89
- * negative `fromIndex` is a no-op (no policy was entered). Synchronous
90
- * hook exceptions are swallowed best-effort with a one-time stderr
91
- * warning — audit-infrastructure failures must never break credential
92
- * operations. `after` hooks are synchronous by contract (see
93
- * `SecretsPolicy.after`); a hook that returns a rejected `Promise` is
94
- * not awaited here, so it would surface as an unhandled rejection.
85
+ * Build an isolated policy runner. Its input is snapshotted immediately, and
86
+ * every operation captures the current immutable frame so replacement cannot
87
+ * splice two different stacks across an await boundary.
95
88
  */
96
- function runAfterHooksForRange(event, fromIndex) {
97
- for (let i = fromIndex; i >= 0; i--) {
98
- const policy = activePolicies[i];
99
- if (policy.after) {
89
+ export function createPolicyRunner(initialPolicies = []) {
90
+ let policies = snapshotPolicies(initialPolicies);
91
+ let afterWarningEmitted = false;
92
+ const runAfterForFrame = (event, frame) => {
93
+ for (let i = frame.length - 1; i >= 0; i--) {
94
+ const policy = frame[i];
95
+ if (!policy.after)
96
+ continue;
100
97
  try {
101
98
  policy.after(event);
102
99
  }
@@ -108,20 +105,65 @@ function runAfterHooksForRange(event, fromIndex) {
108
105
  }
109
106
  }
110
107
  }
111
- }
112
- }
113
- export function auditTrail(opts) {
114
- const includeReads = opts.includeReads ?? true;
108
+ };
115
109
  return {
116
- name: "auditTrail",
117
- after(event) {
118
- if (!includeReads &&
119
- (event.type === "credential_read" ||
120
- event.type === "credential_read_missing")) {
121
- return;
110
+ async runBefore(op, makeRejectionEvent) {
111
+ const frame = policies;
112
+ for (let i = 0; i < frame.length; i++) {
113
+ const policy = frame[i];
114
+ try {
115
+ await policy.before?.(op);
116
+ }
117
+ catch (err) {
118
+ const msg = err instanceof Error ? err.message : String(err);
119
+ // Issue #98 is authoritative: the rejecting policy is part of the
120
+ // unwind, followed by already-entered outer policies.
121
+ runAfterForFrame(makeRejectionEvent(msg), frame.slice(0, i + 1));
122
+ throw err;
123
+ }
122
124
  }
123
- opts.sink(event);
125
+ return frame;
126
+ },
127
+ runAfter(event, frame = policies) {
128
+ runAfterForFrame(event, frame);
129
+ },
130
+ getPolicies() {
131
+ return policies;
132
+ },
133
+ replacePolicies(nextPolicies) {
134
+ policies = snapshotPolicies(nextPolicies);
135
+ afterWarningEmitted = false;
124
136
  },
125
137
  };
126
138
  }
139
+ /** Global runner retained only for legacy module APIs and SessionVault. */
140
+ export const defaultPolicyRunner = createPolicyRunner();
141
+ /**
142
+ * @deprecated Configure policies on an isolated client created with
143
+ * `createSecretsClient`. This setter remains for module-level shims and
144
+ * SessionVault compatibility through the 1.x deprecation window.
145
+ */
146
+ export function setSecretsPolicies(policies) {
147
+ defaultPolicyRunner.replacePolicies(policies);
148
+ }
149
+ /** @deprecated Inspect the policy list owned by the legacy default client. */
150
+ export function getActivePolicies() {
151
+ return defaultPolicyRunner.getPolicies();
152
+ }
153
+ /**
154
+ * Run `before` hooks top-to-bottom. If a hook throws, the operation is
155
+ * rejected: the rejecting policy and already-entered policies (indices
156
+ * `0..i`, bottom-to-top) fire `after` with the event built by
157
+ * `makeRejectionEvent` so the denied operation is still audited, then the
158
+ * original error is re-thrown to abort the operation. This follows issue
159
+ * #98's acceptance contract; policies after the rejector are never entered.
160
+ */
161
+ export async function runBeforeHooks(op, makeRejectionEvent) {
162
+ return defaultPolicyRunner.runBefore(op, makeRejectionEvent);
163
+ }
164
+ export function runAfterHooks(event, frame) {
165
+ defaultPolicyRunner.runAfter(event, frame);
166
+ }
167
+ // Compatibility re-export: the built-in now lives with the other policies.
168
+ export { auditTrail } from "../policies/audit-trail.js";
127
169
  //# sourceMappingURL=policy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/vault/policy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/vault/policy.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,23 @@
1
1
  /**
2
- * SessionVault error classesextracted so helper modules (file-lock,
3
- * sidecar) can throw them without creating an import cycle back into
4
- * session-vault.ts.
2
+ * Vault error taxonomythe package's one `VaultError` hierarchy, extracted
3
+ * so helper modules (file-lock, sidecar, vault-utils) can throw these without
4
+ * creating an import cycle back into session-vault.ts.
5
+ *
6
+ * Most members are SessionVault-specific; `InvalidCredentialKeyError` is
7
+ * raised by the credential cascade (`vault.ts`) and its backends. They share a
8
+ * base class deliberately — a caller wrapping vault work in
9
+ * `catch (e) { if (e instanceof VaultError) … }` should not have to know which
10
+ * storage path produced the failure.
11
+ *
12
+ * This module has no imports on purpose; keep it that way so any vault module
13
+ * can depend on it.
5
14
  *
6
15
  * Each subclass restores the prototype chain with `Object.setPrototypeOf`
7
16
  * so `instanceof VaultError` etc. remains robust when the class is consumed
8
17
  * across an ES transpile boundary (L2 — matches the EngramError pattern in
9
18
  * `packages/sdk/src/errors.ts`).
10
19
  */
11
- /** Base class for SessionVault errors. */
20
+ /** Base class for vault errors. */
12
21
  export declare class VaultError extends Error {
13
22
  readonly code: string;
14
23
  constructor(code: string, message: string);
@@ -31,6 +40,65 @@ export declare class VaultRollbackError extends VaultError {
31
40
  export declare class VaultClosedError extends VaultError {
32
41
  constructor();
33
42
  }
43
+ /**
44
+ * Thrown when a rekey's external commit failed AND restoring the prior
45
+ * ciphertext then failed too.
46
+ *
47
+ * This is the one indeterminate state the rekey path can reach: the vault file
48
+ * may still hold the ciphertext written under the NEW key, so neither key can
49
+ * be assumed to be the right one — and, critically, **no key material for
50
+ * either may be discarded**. Callers that clean up on failure (e.g. deleting
51
+ * freshly written passphrase metadata) must special-case this error; deleting
52
+ * the new key's material here can leave the vault permanently unopenable.
53
+ */
54
+ export declare class VaultRestoreError extends VaultError {
55
+ /** Absolute path of the vault whose state is indeterminate. */
56
+ readonly path: string;
57
+ /** Version the new ciphertext carries, if it is the one on disk. */
58
+ readonly attemptedVersion: number;
59
+ /** The `commit` failure that triggered the rollback attempt. */
60
+ readonly commitCause: unknown;
61
+ /** The failure of the rollback write itself. */
62
+ readonly restoreCause: unknown;
63
+ constructor(
64
+ /** Absolute path of the vault whose state is indeterminate. */
65
+ path: string,
66
+ /** Version the new ciphertext carries, if it is the one on disk. */
67
+ attemptedVersion: number,
68
+ /** The `commit` failure that triggered the rollback attempt. */
69
+ commitCause: unknown,
70
+ /** The failure of the rollback write itself. */
71
+ restoreCause: unknown);
72
+ }
73
+ /**
74
+ * Thrown when a credential key (or a `listCredentials` prefix) does not match
75
+ * the key grammar every vault backend is required to accept.
76
+ *
77
+ * **Why this throws rather than returning a falsy value (#168).** The backends
78
+ * disagree about non-conforming keys: macOS Keychain and the env fallback
79
+ * store anything, while the 1Password, GPG, libsecret and Windows backends
80
+ * cannot address such a key at all. A key that violates the grammar therefore
81
+ * writes successfully on a Mac and is unreadable everywhere else — a silent
82
+ * write/read asymmetry (P2). Returning `false`/`null` would express that as
83
+ * "the write failed" or, worse on the read path, as "no such credential",
84
+ * which is indistinguishable from a genuine miss. The key is malformed, not
85
+ * missing, and only a distinguishable failure says so.
86
+ */
87
+ export declare class InvalidCredentialKeyError extends VaultError {
88
+ /** The offending key or prefix. A key name, never credential material. */
89
+ readonly key: string;
90
+ /** The operation that was refused — "read", "write", "delete", "enumerate". */
91
+ readonly operation: string;
92
+ /** Whether `key` was supplied as a full key or as a `listCredentials` prefix. */
93
+ readonly kind: "key" | "prefix";
94
+ constructor(
95
+ /** The offending key or prefix. A key name, never credential material. */
96
+ key: string,
97
+ /** The operation that was refused — "read", "write", "delete", "enumerate". */
98
+ operation: string,
99
+ /** Whether `key` was supplied as a full key or as a `listCredentials` prefix. */
100
+ kind?: "key" | "prefix");
101
+ }
34
102
  /** Thrown when the write-path file lock can't be acquired within the timeout. */
35
103
  export declare class VaultLockError extends VaultError {
36
104
  constructor(message: string);
@@ -1 +1 @@
1
- {"version":3,"file":"session-vault-errors.d.ts","sourceRoot":"","sources":["../../src/vault/session-vault-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,0CAA0C;AAC1C,qBAAa,UAAW,SAAQ,KAAK;aACP,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1D;AAED,kFAAkF;AAClF,qBAAa,gBAAiB,SAAQ,UAAU;gBAClC,OAAO,EAAE,MAAM;CAK5B;AAED,iFAAiF;AACjF,qBAAa,iBAAkB,SAAQ,UAAU;gBACnC,OAAO,EAAE,MAAM;CAK5B;AAED,oEAAoE;AACpE,qBAAa,kBAAmB,SAAQ,UAAU;aAE9B,QAAQ,EAAE,MAAM;aAChB,MAAM,EAAE,MAAM;gBADd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM;CAWjC;AAED,8DAA8D;AAC9D,qBAAa,gBAAiB,SAAQ,UAAU;;CAM/C;AAED,iFAAiF;AACjF,qBAAa,cAAe,SAAQ,UAAU;gBAChC,OAAO,EAAE,MAAM;CAK5B"}
1
+ {"version":3,"file":"session-vault-errors.d.ts","sourceRoot":"","sources":["../../src/vault/session-vault-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,mCAAmC;AACnC,qBAAa,UAAW,SAAQ,KAAK;aACP,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1D;AAED,kFAAkF;AAClF,qBAAa,gBAAiB,SAAQ,UAAU;gBAClC,OAAO,EAAE,MAAM;CAK5B;AAED,iFAAiF;AACjF,qBAAa,iBAAkB,SAAQ,UAAU;gBACnC,OAAO,EAAE,MAAM;CAK5B;AAED,oEAAoE;AACpE,qBAAa,kBAAmB,SAAQ,UAAU;aAE9B,QAAQ,EAAE,MAAM;aAChB,MAAM,EAAE,MAAM;gBADd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM;CAWjC;AAED,8DAA8D;AAC9D,qBAAa,gBAAiB,SAAQ,UAAU;;CAM/C;AAED;;;;;;;;;;GAUG;AACH,qBAAa,iBAAkB,SAAQ,UAAU;IAE7C,+DAA+D;aAC/C,IAAI,EAAE,MAAM;IAC5B,oEAAoE;aACpD,gBAAgB,EAAE,MAAM;IACxC,gEAAgE;aAChD,WAAW,EAAE,OAAO;IACpC,gDAAgD;aAChC,YAAY,EAAE,OAAO;;IAPrC,+DAA+D;IAC/C,IAAI,EAAE,MAAM;IAC5B,oEAAoE;IACpD,gBAAgB,EAAE,MAAM;IACxC,gEAAgE;IAChD,WAAW,EAAE,OAAO;IACpC,gDAAgD;IAChC,YAAY,EAAE,OAAO;CAexC;AAMD;;;;;;;;;;;;;GAaG;AACH,qBAAa,yBAA0B,SAAQ,UAAU;IAErD,0EAA0E;aAC1D,GAAG,EAAE,MAAM;IAC3B,+EAA+E;aAC/D,SAAS,EAAE,MAAM;IACjC,iFAAiF;aACjE,IAAI,EAAE,KAAK,GAAG,QAAQ;;IALtC,0EAA0E;IAC1D,GAAG,EAAE,MAAM;IAC3B,+EAA+E;IAC/D,SAAS,EAAE,MAAM;IACjC,iFAAiF;IACjE,IAAI,GAAE,KAAK,GAAG,QAAgB;CAejD;AAED,iFAAiF;AACjF,qBAAa,cAAe,SAAQ,UAAU;gBAChC,OAAO,EAAE,MAAM;CAK5B"}
@@ -1,14 +1,23 @@
1
1
  /**
2
- * SessionVault error classesextracted so helper modules (file-lock,
3
- * sidecar) can throw them without creating an import cycle back into
4
- * session-vault.ts.
2
+ * Vault error taxonomythe package's one `VaultError` hierarchy, extracted
3
+ * so helper modules (file-lock, sidecar, vault-utils) can throw these without
4
+ * creating an import cycle back into session-vault.ts.
5
+ *
6
+ * Most members are SessionVault-specific; `InvalidCredentialKeyError` is
7
+ * raised by the credential cascade (`vault.ts`) and its backends. They share a
8
+ * base class deliberately — a caller wrapping vault work in
9
+ * `catch (e) { if (e instanceof VaultError) … }` should not have to know which
10
+ * storage path produced the failure.
11
+ *
12
+ * This module has no imports on purpose; keep it that way so any vault module
13
+ * can depend on it.
5
14
  *
6
15
  * Each subclass restores the prototype chain with `Object.setPrototypeOf`
7
16
  * so `instanceof VaultError` etc. remains robust when the class is consumed
8
17
  * across an ES transpile boundary (L2 — matches the EngramError pattern in
9
18
  * `packages/sdk/src/errors.ts`).
10
19
  */
11
- /** Base class for SessionVault errors. */
20
+ /** Base class for vault errors. */
12
21
  export class VaultError extends Error {
13
22
  code;
14
23
  constructor(code, message) {
@@ -56,6 +65,88 @@ export class VaultClosedError extends VaultError {
56
65
  Object.setPrototypeOf(this, new.target.prototype);
57
66
  }
58
67
  }
68
+ /**
69
+ * Thrown when a rekey's external commit failed AND restoring the prior
70
+ * ciphertext then failed too.
71
+ *
72
+ * This is the one indeterminate state the rekey path can reach: the vault file
73
+ * may still hold the ciphertext written under the NEW key, so neither key can
74
+ * be assumed to be the right one — and, critically, **no key material for
75
+ * either may be discarded**. Callers that clean up on failure (e.g. deleting
76
+ * freshly written passphrase metadata) must special-case this error; deleting
77
+ * the new key's material here can leave the vault permanently unopenable.
78
+ */
79
+ export class VaultRestoreError extends VaultError {
80
+ path;
81
+ attemptedVersion;
82
+ commitCause;
83
+ restoreCause;
84
+ constructor(
85
+ /** Absolute path of the vault whose state is indeterminate. */
86
+ path,
87
+ /** Version the new ciphertext carries, if it is the one on disk. */
88
+ attemptedVersion,
89
+ /** The `commit` failure that triggered the rollback attempt. */
90
+ commitCause,
91
+ /** The failure of the rollback write itself. */
92
+ restoreCause) {
93
+ super("VAULT_RESTORE_FAILED", `Rekey of ${path} could not be completed OR undone. The caller's commit ` +
94
+ `failed (${describeCause(commitCause)}) and restoring the prior ` +
95
+ `ciphertext then failed (${describeCause(restoreCause)}). The vault ` +
96
+ `file may still hold the ciphertext written under the NEW key at ` +
97
+ `version ${attemptedVersion}. Do NOT discard either key: try the new ` +
98
+ `key first, then the old one. If neither opens it, restore a backup of ` +
99
+ `the vault file and its sidecar.`);
100
+ this.path = path;
101
+ this.attemptedVersion = attemptedVersion;
102
+ this.commitCause = commitCause;
103
+ this.restoreCause = restoreCause;
104
+ this.name = "VaultRestoreError";
105
+ Object.setPrototypeOf(this, new.target.prototype);
106
+ }
107
+ }
108
+ function describeCause(cause) {
109
+ return cause instanceof Error ? cause.message : String(cause);
110
+ }
111
+ /**
112
+ * Thrown when a credential key (or a `listCredentials` prefix) does not match
113
+ * the key grammar every vault backend is required to accept.
114
+ *
115
+ * **Why this throws rather than returning a falsy value (#168).** The backends
116
+ * disagree about non-conforming keys: macOS Keychain and the env fallback
117
+ * store anything, while the 1Password, GPG, libsecret and Windows backends
118
+ * cannot address such a key at all. A key that violates the grammar therefore
119
+ * writes successfully on a Mac and is unreadable everywhere else — a silent
120
+ * write/read asymmetry (P2). Returning `false`/`null` would express that as
121
+ * "the write failed" or, worse on the read path, as "no such credential",
122
+ * which is indistinguishable from a genuine miss. The key is malformed, not
123
+ * missing, and only a distinguishable failure says so.
124
+ */
125
+ export class InvalidCredentialKeyError extends VaultError {
126
+ key;
127
+ operation;
128
+ kind;
129
+ constructor(
130
+ /** The offending key or prefix. A key name, never credential material. */
131
+ key,
132
+ /** The operation that was refused — "read", "write", "delete", "enumerate". */
133
+ operation,
134
+ /** Whether `key` was supplied as a full key or as a `listCredentials` prefix. */
135
+ kind = "key") {
136
+ super("VAULT_INVALID_CREDENTIAL_KEY", `Vault ${operation} refused: credential ${kind} ${JSON.stringify(key)} ` +
137
+ `does not match the required key grammar. Keys must be 2-64 characters ` +
138
+ `of lowercase alphanumerics with '-' or '.' as separators, beginning ` +
139
+ `and ending with an alphanumeric` +
140
+ (kind === "prefix" ? " (a prefix may end with a separator)" : "") +
141
+ `. Non-conforming keys store on some backends and are unaddressable on ` +
142
+ `others, so the value would be written and never read back.`);
143
+ this.key = key;
144
+ this.operation = operation;
145
+ this.kind = kind;
146
+ this.name = "InvalidCredentialKeyError";
147
+ Object.setPrototypeOf(this, new.target.prototype);
148
+ }
149
+ }
59
150
  /** Thrown when the write-path file lock can't be acquired within the timeout. */
60
151
  export class VaultLockError extends VaultError {
61
152
  constructor(message) {
@@ -1 +1 @@
1
- {"version":3,"file":"session-vault-errors.js","sourceRoot":"","sources":["../../src/vault/session-vault-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,0CAA0C;AAC1C,MAAM,OAAO,UAAW,SAAQ,KAAK;IACP;IAA5B,YAA4B,IAAY,EAAE,OAAe;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QADW,SAAI,GAAJ,IAAI,CAAQ;QAEtC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAED,kFAAkF;AAClF,MAAM,OAAO,gBAAiB,SAAQ,UAAU;IAC9C,YAAY,OAAe;QACzB,KAAK,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAED,iFAAiF;AACjF,MAAM,OAAO,iBAAkB,SAAQ,UAAU;IAC/C,YAAY,OAAe;QACzB,KAAK,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAED,oEAAoE;AACpE,MAAM,OAAO,kBAAmB,SAAQ,UAAU;IAE9B;IACA;IAFlB,YACkB,QAAgB,EAChB,MAAc;QAE9B,KAAK,CACH,iCAAiC,EACjC,+DAA+D,QAAQ,IAAI;YACzE,kCAAkC,MAAM,8BAA8B;YACtE,wDAAwD,CAC3D,CAAC;QARc,aAAQ,GAAR,QAAQ,CAAQ;QAChB,WAAM,GAAN,MAAM,CAAQ;QAQ9B,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAED,8DAA8D;AAC9D,MAAM,OAAO,gBAAiB,SAAQ,UAAU;IAC9C;QACE,KAAK,CAAC,cAAc,EAAE,6DAA6D,CAAC,CAAC;QACrF,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAED,iFAAiF;AACjF,MAAM,OAAO,cAAe,SAAQ,UAAU;IAC5C,YAAY,OAAe;QACzB,KAAK,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF"}
1
+ {"version":3,"file":"session-vault-errors.js","sourceRoot":"","sources":["../../src/vault/session-vault-errors.ts"],"names":[],"mappings":"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"}
@@ -39,8 +39,8 @@
39
39
  */
40
40
  import type { KeychainProviderOptions } from "../key-providers/keychain-provider.js";
41
41
  import type { KeyProvider, KeyProviderType } from "../key-providers/types.js";
42
- import { VaultError, VaultUnlockError, VaultDecryptError, VaultRollbackError, VaultClosedError, VaultLockError } from "./session-vault-errors.js";
43
- export { VaultError, VaultUnlockError, VaultDecryptError, VaultRollbackError, VaultClosedError, VaultLockError, };
42
+ import { VaultError, VaultUnlockError, VaultDecryptError, VaultRollbackError, VaultClosedError, VaultLockError, VaultRestoreError, InvalidCredentialKeyError } from "./session-vault-errors.js";
43
+ export { VaultError, VaultUnlockError, VaultDecryptError, VaultRollbackError, VaultClosedError, VaultLockError, VaultRestoreError, InvalidCredentialKeyError, };
44
44
  /** Current payload schema version — bump requires a compat migration. */
45
45
  export declare const VAULT_SCHEMA_VERSION = 1;
46
46
  /** Default vault file location — same path the CLI uses, so they share state. */
@@ -123,6 +123,29 @@ export interface OpenVaultOptions {
123
123
  */
124
124
  keychain?: KeychainProviderOptions;
125
125
  }
126
+ /** Options for {@link createVault}. */
127
+ export interface CreateVaultOptions {
128
+ /** Alternate vault file path. Defaults to the same path the CLI uses. */
129
+ path?: string;
130
+ /** Alternate sidecar path. Defaults to vault directory + `vault.seen-version`. */
131
+ sidecarPath?: string;
132
+ /**
133
+ * Caller-owned AES-256 key used to encrypt the empty vault.
134
+ *
135
+ * This function neither stores nor zeroes the key. Key-provider setup is a
136
+ * separate, potentially irreversible transaction; keeping it outside this
137
+ * filesystem primitive prevents a failed create from deleting or replacing
138
+ * a key that another vault may share.
139
+ */
140
+ key: Buffer;
141
+ }
142
+ /** Result of an idempotent {@link createVault} call. */
143
+ export interface CreateVaultResult {
144
+ /** True when this call created the vault/sidecar pair; false when both existed. */
145
+ created: boolean;
146
+ /** Canonical absolute vault path used for AAD binding. */
147
+ path: string;
148
+ }
126
149
  /**
127
150
  * A long-lived handle to an unlocked vault. Construct with {@link openVault};
128
151
  * close with {@link SessionVault.close}. Operations are async so policy
@@ -148,6 +171,26 @@ export interface SessionVault {
148
171
  /** Diagnostic — the current in-memory vault version. */
149
172
  readonly vaultVersion: number;
150
173
  }
174
+ /**
175
+ * Create an empty, AAD-bound session vault and its rollback sidecar.
176
+ *
177
+ * Creation is idempotent only for a complete pair: if both files already
178
+ * exist they are left byte-for-byte untouched and `created` is false. A
179
+ * vault-only or sidecar-only state is refused rather than "repaired" because
180
+ * replacing either half could erase rollback evidence or make existing
181
+ * ciphertext permanently unreadable.
182
+ *
183
+ * Both destinations use no-clobber publication: the completed vault temp is
184
+ * linked into place first, then the sidecar is the logical commit point. A
185
+ * successful return therefore means both public paths exist, and a competing
186
+ * destination is never replaced. This is temp-file/link crash safety, not an
187
+ * fsync or power-loss durability guarantee.
188
+ *
189
+ * The caller retains ownership of `opts.key`; this function snapshots it for
190
+ * the duration of the call, zeroes that private copy, and never mutates,
191
+ * zeroes, or stores the caller's buffer.
192
+ */
193
+ export declare function createVault(opts: CreateVaultOptions): Promise<CreateVaultResult>;
151
194
  /**
152
195
  * Open an encrypted session vault.
153
196
  *
@@ -174,4 +217,104 @@ export interface SessionVault {
174
217
  * ```
175
218
  */
176
219
  export declare function openVault(opts?: OpenVaultOptions): Promise<SessionVault>;
220
+ /** Options for {@link rekeyVault}. */
221
+ export interface RekeyVaultOptions {
222
+ /** Vault file path. Defaults to the same path the CLI uses. */
223
+ path?: string;
224
+ /** Sidecar path. Defaults to vault directory + `vault.seen-version`. */
225
+ sidecarPath?: string;
226
+ /** The key the vault is currently encrypted under. */
227
+ currentKey: Buffer;
228
+ /** The key the vault should be re-encrypted under. */
229
+ nextKey: Buffer;
230
+ /**
231
+ * Opt-in acceptance of a detected rollback (sidecar version > vault
232
+ * version), mirroring {@link OpenVaultOptions.acceptRollback}. Unlike
233
+ * `openVault`, the sidecar is never lowered to match — the rekeyed vault
234
+ * lands above the recorded high-water mark either way, so accepting a
235
+ * rollback here does not also discard the mark.
236
+ */
237
+ acceptRollback?: boolean;
238
+ /**
239
+ * Opt-in acceptance of a missing sidecar, mirroring
240
+ * {@link OpenVaultOptions.acceptMissingSidecar}. Legacy (pre-`openVault`,
241
+ * AAD-less) vaults never had a sidecar by construction and are exempt.
242
+ */
243
+ acceptMissingSidecar?: boolean;
244
+ /**
245
+ * Invoked once the re-encrypted vault has landed on disk, while the write
246
+ * lock is still held and before the sidecar high-water mark is published.
247
+ *
248
+ * This is the seam that makes an *external* commitment part of the same
249
+ * all-or-nothing step. `migrate --to passphrase` uses it to write
250
+ * `secrets.provider` — a config that names a provider which cannot open the
251
+ * vault (or a vault no configured provider can open) is exactly the
252
+ * half-migrated state this exists to prevent. Throwing restores the prior
253
+ * ciphertext byte-for-byte and rethrows; the sidecar is never advanced on
254
+ * that path, so the restored vault opens cleanly.
255
+ */
256
+ commit?: () => void | Promise<void>;
257
+ }
258
+ /** Outcome of a successful {@link rekeyVault}. */
259
+ export interface RekeyVaultResult {
260
+ /** Number of secrets carried across to the new ciphertext. */
261
+ secretCount: number;
262
+ /** The vault version after the rekey. */
263
+ vaultVersion: number;
264
+ /** True when the source vault was in the pre-`openVault` AAD-less shape. */
265
+ upgradedFromLegacy: boolean;
266
+ /**
267
+ * False when the rekey committed but the sidecar version bump could not be
268
+ * written (warned on stderr). The rekey still succeeded — see the note on
269
+ * the sidecar write in {@link rekeyVault} — but rollback protection is
270
+ * degraded until the next successful vault write catches the sidecar up.
271
+ */
272
+ sidecarPublished: boolean;
273
+ }
274
+ /**
275
+ * Re-encrypt a vault in place under a different master key.
276
+ *
277
+ * Needed whenever the new key cannot be *chosen* — a `PassphraseProvider`
278
+ * derives its key from what the operator types and cannot store a
279
+ * caller-supplied one, so moving a vault to it means rewriting the ciphertext
280
+ * rather than copying the key to a new home. Provider-to-provider moves that
281
+ * only relocate the same key do not need this.
282
+ *
283
+ * The AAD binds the vault's resolved real path and schema, not the key, so the
284
+ * rekeyed ciphertext stays bound to the same file identity. Legacy AAD-less
285
+ * vaults are upgraded to schema 1 in the same step. The new version is one
286
+ * above both the payload's version and the sidecar's high-water mark, so a
287
+ * rekeyed vault can never land below a version already seen.
288
+ *
289
+ * Any process holding this vault open under the old key will fail its next
290
+ * decrypt with {@link VaultDecryptError} — an honest failure, by design: the
291
+ * old key genuinely no longer opens this vault.
292
+ *
293
+ * **Post-commit guarantee.** With one named exception, a throw means `commit`
294
+ * did not succeed and the prior ciphertext is back in place — nothing after a
295
+ * successful `commit` can throw, because the only step that follows it (the
296
+ * sidecar bump) is reported via {@link RekeyVaultResult.sidecarPublished}
297
+ * rather than thrown. Callers may therefore treat a throw as "nothing was
298
+ * committed" and clean up accordingly; that is what makes it safe for the CLI
299
+ * to delete freshly written passphrase metadata on failure.
300
+ *
301
+ * **The exception: {@link VaultRestoreError}.** If `commit` throws *and* the
302
+ * rollback write then fails, the file on disk may still be the new ciphertext.
303
+ * That state is neither committed nor undone, so it gets its own error type —
304
+ * callers MUST special-case it and must NOT discard key material for either
305
+ * key. Every other throw keeps the plain guarantee.
306
+ *
307
+ * @param opts - {@link RekeyVaultOptions}. `currentKey`/`nextKey` are required;
308
+ * both remain owned by the caller and are never zeroed here.
309
+ * @returns {@link RekeyVaultResult}.
310
+ * @throws {@link VaultError} `VAULT_NOT_FOUND` when the vault file is absent.
311
+ * @throws {@link VaultDecryptError} when `currentKey` does not open the vault.
312
+ * @throws {@link VaultError} `VAULT_SIDECAR_MISSING` when the sidecar is absent
313
+ * and neither `acceptMissingSidecar` nor the legacy exemption applies.
314
+ * @throws {@link VaultRollbackError} when the vault version trails the sidecar
315
+ * and `acceptRollback` is not set.
316
+ * @throws {@link VaultError} `VAULT_ENCRYPT_FAILED` when re-encryption fails.
317
+ * @throws Whatever `commit` throws, after restoring the prior ciphertext.
318
+ */
319
+ export declare function rekeyVault(opts: RekeyVaultOptions): Promise<RekeyVaultResult>;
177
320
  //# sourceMappingURL=session-vault.d.ts.map