@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
@@ -0,0 +1,394 @@
1
+ /**
2
+ * Hardened macOS Keychain core (#188).
3
+ *
4
+ * ## The defect this module exists to end
5
+ *
6
+ * Every `security` invocation in this package used to be wrong in the same two
7
+ * ways, and both ways only bite in a context that cannot complain:
8
+ *
9
+ * 1. **Writes preauthorized nothing.** `add-generic-password … -T ""` trusts
10
+ * *no* application. An item written that way is readable only by granting
11
+ * consent through a dialog — and a launchd daemon or an SSH login has no
12
+ * UI in which such a dialog can render. The item is therefore unreadable
13
+ * in exactly the contexts a credential store is for.
14
+ * 2. **Reads consulted the search list.** `find-generic-password` with no
15
+ * keychain argument walks the session search list, which leads with the
16
+ * login keychain. In a sessionless context that keychain is locked, and a
17
+ * locked copy *shadows* a readable System-keychain copy — so the read
18
+ * fails even though the credential is right there.
19
+ *
20
+ * Combined with the old accessors' habit of collapsing every failure into
21
+ * `null`, the result was a store that silently reported "nothing configured"
22
+ * to a headless reader. See issue #188 and `docs/threat-model.md`.
23
+ *
24
+ * ## The posture
25
+ *
26
+ * 1. **Session-aware reads.** An interactive session keeps its existing
27
+ * search-list read (so vaults that open today keep opening unchanged). A
28
+ * *sessionless* context reads the System keychain by **explicit
29
+ * positional target** first — no search list, so nothing can shadow it —
30
+ * and only consults the search list when the System keychain genuinely
31
+ * has no copy. That ordering is what makes a misclassified context
32
+ * harmless: the fallback can only ever add a result, never lose one.
33
+ * 2. **Preauthorized writes.** `-T /usr/bin/security` grants the reader path
34
+ * at write time, on every write, everywhere in this package. Never
35
+ * `-T ""`.
36
+ * 3. **`-U` replace-in-place.** A rotation is one command and never leaves
37
+ * two generations of the same account. The old delete-then-add left a
38
+ * window in which the credential existed nowhere.
39
+ * 4. **Discriminated results.** Reads, probes, writes, deletes and the
40
+ * migration all answer with a discriminated union. `absent` and `locked`
41
+ * are never merged (see {@link ../secret-state.js}).
42
+ *
43
+ * ## Never logs a value
44
+ *
45
+ * No function here logs or formats a credential into a diagnostic. Every
46
+ * `detail`/`reason`/`command` string is value-free by construction — the
47
+ * operator command reads the secret with `read -s` into a shell variable, so
48
+ * it appears in neither the printed text nor the shell history.
49
+ *
50
+ * ## Residual, stated rather than hidden
51
+ *
52
+ * A programmatic write passes the value in `argv` (`-w <value>`), briefly
53
+ * visible to a local `ps`. That is unchanged from this package's previous
54
+ * write path, so it is not a regression — but it is why the OPERATOR-facing
55
+ * command printed by {@link privilegedWriteCommand} keeps the value out of the
56
+ * command text entirely. `docs/threat-model.md` §4.3 tracks the argv exposure.
57
+ */
58
+ import type { SecretState } from "../secret-state.js";
59
+ /** The macOS system keychain — readable from the launchd system domain. */
60
+ export declare const SYSTEM_KEYCHAIN_PATH = "/Library/Keychains/System.keychain";
61
+ /**
62
+ * The reader path preauthorized on write (`-T`), and the binary this module
63
+ * spawns. Absolute deliberately: the `-T` argument names a path, so the two
64
+ * must be the same path or the grant does not describe the reader.
65
+ */
66
+ export declare const SECURITY_BINARY = "/usr/bin/security";
67
+ export interface KeychainRunResult {
68
+ status: number;
69
+ stderr: string;
70
+ stdout: string;
71
+ }
72
+ /**
73
+ * The one seam every `security` invocation in this package passes through.
74
+ * Tests inject `runSecurity` and `platform`, so no test touches a real
75
+ * keychain and the exact argv is assertable — the argv *is* the contract here.
76
+ */
77
+ export interface KeychainDeps {
78
+ runSecurity: (args: readonly string[], options?: {
79
+ maxBuffer?: number;
80
+ }) => KeychainRunResult;
81
+ platform: NodeJS.Platform;
82
+ env: NodeJS.ProcessEnv;
83
+ }
84
+ /**
85
+ * A read outcome. The only variant carrying secret material — probes use the
86
+ * value-free {@link SecretState} instead.
87
+ */
88
+ export type KeychainReadResult = {
89
+ kind: "found";
90
+ value: string;
91
+ } | {
92
+ kind: "absent";
93
+ } | {
94
+ kind: "locked";
95
+ } | {
96
+ kind: "not-applicable";
97
+ reason: string;
98
+ } | {
99
+ kind: "failed";
100
+ detail: string;
101
+ };
102
+ export type KeychainWriteResult = {
103
+ kind: "stored";
104
+ /**
105
+ * Where the item actually landed — the System keychain path, or
106
+ * `"default"` for the session's default (login) keychain. Present only
107
+ * on the session-aware write, which is the one that can choose. A caller
108
+ * comparing this against the reader's context learns whether the write
109
+ * is reachable from there; leaving it out would be exactly the silent
110
+ * degradation this ticket is about.
111
+ */
112
+ keychain?: string;
113
+ /**
114
+ * Set when the item landed somewhere other than the System keychain
115
+ * *because* the System write needed privileges. Value-free; running it
116
+ * promotes the credential to the daemon-readable copy.
117
+ */
118
+ privilegedCommand?: string;
119
+ }
120
+ /** The write needs root. Carries the exact VALUE-FREE operator command. */
121
+ | {
122
+ kind: "needs-privilege";
123
+ command: string;
124
+ } | {
125
+ kind: "not-applicable";
126
+ reason: string;
127
+ } | {
128
+ kind: "failed";
129
+ detail: string;
130
+ };
131
+ export type KeychainDeleteResult = {
132
+ kind: "deleted";
133
+ }
134
+ /** Nothing to delete. Distinct from `deleted`, and never an error. */
135
+ | {
136
+ kind: "absent";
137
+ } | {
138
+ kind: "not-applicable";
139
+ reason: string;
140
+ } | {
141
+ kind: "failed";
142
+ detail: string;
143
+ };
144
+ export type KeychainMigrationResult =
145
+ /** The System copy was written from the login copy. */
146
+ {
147
+ kind: "migrated";
148
+ loginCopyDeleted: boolean;
149
+ }
150
+ /** A System copy already existed — nothing moved. */
151
+ | {
152
+ kind: "already-resident";
153
+ loginCopyDeleted: boolean;
154
+ }
155
+ /** No login copy to move (and no System copy) — nothing to do. */
156
+ | {
157
+ kind: "nothing-to-migrate";
158
+ }
159
+ /** Could not complete. The PREVIOUS read path is untouched. */
160
+ | {
161
+ kind: "blocked";
162
+ reason: string;
163
+ command?: string;
164
+ };
165
+ /**
166
+ * Classify a `security` outcome.
167
+ *
168
+ * Stderr patterns are checked BEFORE exit codes on purpose: Apple has shifted
169
+ * `security` exit codes between releases while the user-facing strings have
170
+ * stayed stable, so pinning on the code alone silently reclassifies an
171
+ * unreadable item as a missing one on the next OS bump — the very collapse
172
+ * this module exists to prevent.
173
+ */
174
+ export declare function classifyKeychainRead(status: number, stderr: string, stdout: string): KeychainReadResult;
175
+ /** Drop the value from a read outcome, yielding the value-free state. */
176
+ export declare function toSecretState(read: KeychainReadResult): SecretState;
177
+ /**
178
+ * Shell-quote one argument for the copy/paste operator command.
179
+ *
180
+ * The service and account reach this from caller-supplied strings, so an
181
+ * unquoted interpolation turns a remediation command into a DIFFERENT command
182
+ * the moment one of them carries a shell metacharacter. Single-quote wrapping
183
+ * is the only form that neutralizes every metacharacter; an embedded single
184
+ * quote is closed, escaped and reopened (the POSIX `'\''` idiom).
185
+ */
186
+ export declare function shellQuote(value: string): string;
187
+ /**
188
+ * The operator command for a privileged System-keychain write.
189
+ *
190
+ * The command TEXT is value-free: the secret is read by `read -s` (silent, and
191
+ * present in both zsh and bash) into a shell variable, so it never appears in
192
+ * the printed command, in a log line, or in shell history — history records
193
+ * the literal `"$PW"`, not its expansion.
194
+ *
195
+ * Why not a `security` prompt form: `-w` consumes any following token as the
196
+ * password, so a trailing keychain path would silently BECOME the stored
197
+ * value, and the bare dangling `-w` form is not a reliable terminal prompt.
198
+ * The `read -s` flow sidesteps `security`'s prompt semantics entirely and
199
+ * RESTORES the explicit System-keychain positional target, so the write cannot
200
+ * land in the wrong keychain.
201
+ */
202
+ export declare function privilegedWriteCommand(service: string, account: string): string;
203
+ /**
204
+ * Read one credential from the System keychain, addressing it EXPLICITLY.
205
+ *
206
+ * The trailing keychain path is the whole point: without it `security` walks
207
+ * the session search list, which in a sessionless context leads with the
208
+ * locked login keychain — so a stale login copy shadows the readable System
209
+ * one and the read fails in exactly the context that has no way to prompt.
210
+ */
211
+ export declare function readSystemKeychainCredential(service: string, account: string, deps?: Partial<KeychainDeps>): KeychainReadResult;
212
+ /**
213
+ * Read one credential through the session search list — the historical path,
214
+ * and still the right one in an interactive session where the login keychain
215
+ * is unlocked and is where the item lives.
216
+ */
217
+ export declare function readSearchListCredential(service: string, account: string, deps?: Partial<KeychainDeps>): KeychainReadResult;
218
+ /**
219
+ * Read a credential using the path appropriate to THIS execution context.
220
+ *
221
+ * - Interactive session: the search-list read, byte-for-byte what this package
222
+ * did before #188. Vaults that open today keep opening.
223
+ * - Sessionless (launchd system domain, SSH): the explicit System-keychain
224
+ * read first, so no login copy can shadow it — then, only if the System
225
+ * keychain genuinely has no such item, the search-list read.
226
+ *
227
+ * The fallback ordering is deliberate and load-bearing. Session detection is a
228
+ * heuristic (see `../platform/session-context.ts`); with System consulted
229
+ * first, a *false* sessionless verdict cannot lose a credential that used to
230
+ * be readable, and a false interactive verdict is no worse than today. The
231
+ * shadowing bug cannot come back either way, because the search list is only
232
+ * ever reached after the System keychain has answered `absent`.
233
+ */
234
+ export declare function readKeychainCredential(service: string, account: string, deps?: Partial<KeychainDeps>): KeychainReadResult;
235
+ /**
236
+ * **Presence, not readability.** Metadata-only existence probe against the
237
+ * System keychain.
238
+ *
239
+ * No `-w`, so `security` prints no value on any stream. That is also its
240
+ * limit: a `found` here means only that an item with these coordinates exists.
241
+ * An item can exist and still be unreadable — locked keychain, an ACL that
242
+ * does not preauthorize the reader, a partially written item — so this must
243
+ * NOT be used to answer "what is the state of this credential?". Reporting
244
+ * `found` for an item the reader cannot open is the exact failure mode #188
245
+ * exists to end.
246
+ *
247
+ * Its correct use is the non-destructive residency question inside
248
+ * {@link migrateLoginCredentialToSystem} ("is a copy already here, so that I
249
+ * need not move one?"), which is deliberately answered without reading the
250
+ * secret. Credential STATE is {@link probeKeychainCredentialState}.
251
+ */
252
+ export declare function probeSystemKeychainEntry(service: string, account: string, deps?: Partial<KeychainDeps>): SecretState;
253
+ /**
254
+ * **Presence, not readability.** Metadata-only existence probe through the
255
+ * session search list. Same caveat as {@link probeSystemKeychainEntry}: use
256
+ * {@link probeKeychainCredentialState} for credential state.
257
+ */
258
+ export declare function probeSearchListEntry(service: string, account: string, deps?: Partial<KeychainDeps>): SecretState;
259
+ /**
260
+ * **Presence, not readability.** Metadata-only probe along the same keychain
261
+ * the reader would consult in this context.
262
+ *
263
+ * Same caveat as the two functions above, and for the same reason: a status-0
264
+ * metadata hit says an item exists, not that opening it yields bytes. Use
265
+ * {@link probeKeychainCredentialState} for credential state.
266
+ */
267
+ export declare function probeKeychainEntry(service: string, account: string, deps?: Partial<KeychainDeps>): SecretState;
268
+ /**
269
+ * The credential STATE probe: what will the reader in THIS context actually
270
+ * get?
271
+ *
272
+ * Runs the real read — {@link readKeychainCredential}, the same path, the same
273
+ * explicit target, the same `-w` — and then **discards the value**, returning
274
+ * only the value-free {@link SecretState}. So `found` here means "the reader
275
+ * will get bytes", which is the claim a caller needs and the claim a metadata
276
+ * probe cannot make.
277
+ *
278
+ * Presence is not readability, and the gap between them is not hypothetical:
279
+ * an item whose ACL does not preauthorize the reader, or that sits in a locked
280
+ * keychain, or that was written empty, is *present* and *unreadable*. A probe
281
+ * that answered `found` for those would hand a caller trusted state that is
282
+ * wrong in precisely the direction #188 exists to fix — a reader told the
283
+ * credential is there, failing anyway, with no signal that says why.
284
+ *
285
+ * The trade is deliberate: this reads secret material into the process to
286
+ * answer, where {@link probeKeychainEntry} does not. Nothing leaves — the
287
+ * value never reaches a return value, a log, or a stream. Callers that must
288
+ * not read the secret at all (the migration's residency check) use the
289
+ * metadata probe under its own name, and accept that it answers a narrower
290
+ * question.
291
+ */
292
+ export declare function probeKeychainCredentialState(service: string, account: string, deps?: Partial<KeychainDeps>): SecretState;
293
+ /**
294
+ * Store a credential in the System keychain, preauthorized for the reader path.
295
+ *
296
+ * `-U` replaces an existing item in place (the rotation path, and the reason
297
+ * there is no delete-then-add window here); `-T` grants
298
+ * `/usr/bin/security` up front because no consent prompt can render in the
299
+ * launchd or SSH contexts that have to read it.
300
+ */
301
+ export declare function writeSystemKeychainCredential(service: string, account: string, value: string, deps?: Partial<KeychainDeps>): KeychainWriteResult;
302
+ /**
303
+ * Store a credential in the session's default (login) keychain — the
304
+ * historical destination — but with the two flags that were missing: `-U` so a
305
+ * rotation replaces in place, and `-T /usr/bin/security` so the item is
306
+ * readable without a consent dialog.
307
+ *
308
+ * A permission failure here is reported as `failed`, not `needs-privilege`:
309
+ * `sudo` is the wrong remedy for a login keychain (it would write root's), and
310
+ * offering it would send an operator down a path that cannot work.
311
+ */
312
+ export declare function writeDefaultKeychainCredential(service: string, account: string, value: string, deps?: Partial<KeychainDeps>): KeychainWriteResult;
313
+ /**
314
+ * Store a credential using the destination appropriate to THIS context.
315
+ *
316
+ * - Interactive: the default (login) keychain, unchanged destination, now with
317
+ * `-U` and `-T`.
318
+ * - Sessionless: the System keychain, so the reader that has no session can
319
+ * actually open it. If that write needs privileges the credential is still
320
+ * written to the default keychain rather than failing outright — but the
321
+ * result says so (`keychain`) and carries the value-free command that
322
+ * promotes it (`privilegedCommand`). Reporting the lesser destination is
323
+ * what keeps this from being a silent downgrade.
324
+ */
325
+ export declare function writeKeychainCredential(service: string, account: string, value: string, deps?: Partial<KeychainDeps>): KeychainWriteResult;
326
+ /**
327
+ * Did a write land where THIS context's reader will look for it?
328
+ *
329
+ * `kind: "stored"` alone does not answer that. In a sessionless context a
330
+ * System-keychain write that needs privileges falls back to the default
331
+ * keychain — the value is stored, and the result says so and carries the
332
+ * command that promotes it, but a launchd or SSH reader will not find it
333
+ * there. A boolean caller that treated that as success would record a write
334
+ * the reader cannot see: a silent downgrade, which is the same class of lie as
335
+ * the read-side collapse this module exists to fix.
336
+ *
337
+ * So: interactive → the default keychain IS where the reader looks, so any
338
+ * `stored` is reachable. Sessionless → only the System keychain is.
339
+ *
340
+ * Callers that want the nuance rather than the boolean use the discriminated
341
+ * {@link KeychainWriteResult} directly; it carries both the destination and
342
+ * the value-free promotion command.
343
+ */
344
+ export declare function storedWithinReaderReach(result: KeychainWriteResult, deps?: Partial<KeychainDeps>): boolean;
345
+ /**
346
+ * Delete a credential from wherever this context can read it.
347
+ *
348
+ * Interactive: the historical default-destination delete, unchanged.
349
+ *
350
+ * Sessionless: both copies the read path can see — the System copy (explicit
351
+ * target) and the login copy (targeted through `login-keychain`, skipped when
352
+ * unresolvable). Deleting only one would leave the other to be resurrected by
353
+ * the very fallback that makes sessionless reads work.
354
+ */
355
+ export declare function deleteKeychainCredential(service: string, account: string, deps?: Partial<KeychainDeps>): KeychainDeleteResult;
356
+ /**
357
+ * Move one credential from the login keychain to the System keychain, ONCE,
358
+ * then remove the login copy so nothing can shadow it.
359
+ *
360
+ * Idempotent: a System copy that already exists short-circuits to
361
+ * `already-resident` (and still sweeps a login shadow if one is left).
362
+ *
363
+ * Fail-loud-but-SAFE ordering — the login copy is deleted LAST, and only after
364
+ * the System copy is verified readable through the explicit-target read. Every
365
+ * earlier failure returns `blocked` with the login copy intact, so the previous
366
+ * read path keeps working: a failed migration can never produce "reader up with
367
+ * no credential".
368
+ */
369
+ export declare function migrateLoginCredentialToSystem(service: string, account: string, deps?: Partial<KeychainDeps>): KeychainMigrationResult;
370
+ /**
371
+ * The keychain search list, for diagnostics. Names only — a search list
372
+ * carries no secret material, and knowing that the login keychain leads it is
373
+ * exactly what explains a shadowed read.
374
+ */
375
+ export declare function keychainSearchList(deps?: Partial<KeychainDeps>): readonly string[];
376
+ /**
377
+ * Raw `security dump-keychain` output, for the enumeration path in
378
+ * `vault-common.ts`.
379
+ *
380
+ * Deliberately NOT platform-guarded: enumeration is only reachable when the
381
+ * Keychain backend is the active one, and guarding here would change a
382
+ * spawn-and-fail into a silent empty answer on a host whose platform string
383
+ * has been adjusted (several suites in this package do exactly that).
384
+ *
385
+ * `-d` is deliberately omitted, so no password data is in the output.
386
+ */
387
+ export declare function dumpKeychain(deps?: Partial<KeychainDeps>): {
388
+ kind: "ok";
389
+ output: string;
390
+ } | {
391
+ kind: "failed";
392
+ detail: string;
393
+ };
394
+ //# sourceMappingURL=darwin-keychain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"darwin-keychain.d.ts","sourceRoot":"","sources":["../../src/crypto/darwin-keychain.ts"],"names":[],"mappings":"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"}