@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
@@ -2,21 +2,67 @@
2
2
  * Agent Environment Detection
3
3
  *
4
4
  * Detects whether the process is running inside an AI agent session
5
- * (Claude Code, MCP context, etc.). Auth commands that require human
6
- * interaction are blocked in these environments.
5
+ * (Claude Code, MCP subprocess, etc.) by testing the environment markers such
6
+ * a session sets.
7
7
  *
8
- * Shared by: vault.ts, cli, secrets-cli.ts
8
+ * **What this gates (the whole list).** This is the single implementation; the
9
+ * only call sites are:
10
+ *
11
+ * - `cli/secrets-cli.ts` — `runSecrets()` refuses every `centient secrets`
12
+ * subcommand when it returns true, and
13
+ * - `environment/EnvironmentManager.ts` — the environment mutation commands
14
+ * (create / switch / delete-style auth operations).
15
+ *
16
+ * It does **not** gate the programmatic API: `openVault()`, `getCredential()`,
17
+ * `storeCredential()`, and `SessionVault.get()` contain no agent check, and
18
+ * `vault.ts` does not call this function. (An earlier version of this comment
19
+ * claimed it was "shared by vault.ts" — it never was.)
20
+ *
21
+ * **This is a UX guardrail, not a security boundary.** It reads environment
22
+ * variables the calling process itself controls, so any agent can clear them
23
+ * (`env -u CLAUDECODE …`) and walk straight through. Its job is to stop an
24
+ * agent from *accidentally* driving the operator CLI, nothing more. See
25
+ * `docs/threat-model.md` §4.4 and ADR-005 §3, which demotes this check
26
+ * explicitly; repairing the marker names (#189) does not re-promote it.
27
+ *
28
+ * **Marker accuracy matters** precisely because the check is cheap: before
29
+ * #189 it tested `CLAUDE_CODE_ENTRY_POINT` (a misspelling of the real
30
+ * `CLAUDE_CODE_ENTRYPOINT`) and leaned on `CLAUDE_PROJECT_DIR`, which
31
+ * hook-spawned subprocesses get but live interactive sessions do not — so the
32
+ * gate never fired for the sessions it was written for. `tests/agent-detect.test.ts`
33
+ * pins each marker individually so a rename cannot silently disable it again.
9
34
  */
35
+ /**
36
+ * Environment variables whose presence marks an AI agent session.
37
+ *
38
+ * Package-internal (not re-exported from `index.ts`) — exported so tests and
39
+ * the CLI test harnesses clear exactly this set rather than a hand-copied one
40
+ * that can drift.
41
+ */
42
+ export const AGENT_ENV_MARKERS = [
43
+ /** Set by every live Claude Code session (interactive and headless). */
44
+ "CLAUDECODE",
45
+ /** Set by Claude Code to name how the session was launched (cli, vscode, …). */
46
+ "CLAUDE_CODE_ENTRYPOINT",
47
+ /** Set in Claude Code hook-spawned subprocesses; absent in live sessions. */
48
+ "CLAUDE_PROJECT_DIR",
49
+ /** Session identifier exposed by some Claude Code integrations. */
50
+ "CLAUDE_CODE_SESSION",
51
+ /** Set by MCP hosts for servers running under a model context. */
52
+ "MCP_CONTEXT",
53
+ /** Set by MCP hosts to name the server being run. */
54
+ "MCP_SERVER_NAME",
55
+ /** Legacy marker retained from the pre-#189 set; harmless if unset. */
56
+ "ANTHROPIC_API_KEY_SOURCE",
57
+ ];
10
58
  /**
11
59
  * Returns true if the current process appears to be running inside an
12
60
  * AI agent environment (Claude Code, MCP subprocess, etc.).
61
+ *
62
+ * Advisory only — see the module docstring. A false result does not mean "a
63
+ * human is at the keyboard", it means "no marker was found".
13
64
  */
14
65
  export function isAgentEnvironment() {
15
- return !!(process.env["CLAUDE_PROJECT_DIR"] ||
16
- process.env["MCP_CONTEXT"] ||
17
- process.env["CLAUDE_CODE_SESSION"] ||
18
- process.env["CLAUDE_CODE_ENTRY_POINT"] ||
19
- process.env["ANTHROPIC_API_KEY_SOURCE"] ||
20
- process.env["MCP_SERVER_NAME"]);
66
+ return AGENT_ENV_MARKERS.some((name) => !!process.env[name]);
21
67
  }
22
68
  //# sourceMappingURL=agent-detect.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-detect.js","sourceRoot":"","sources":["../../src/platform/agent-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,CAAC,CAAC,CACP,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAC/B,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"agent-detect.js","sourceRoot":"","sources":["../../src/platform/agent-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,wEAAwE;IACxE,YAAY;IACZ,gFAAgF;IAChF,wBAAwB;IACxB,6EAA6E;IAC7E,oBAAoB;IACpB,mEAAmE;IACnE,qBAAqB;IACrB,kEAAkE;IAClE,aAAa;IACb,qDAAqD;IACrD,iBAAiB;IACjB,uEAAuE;IACvE,0BAA0B;CAClB,CAAC;AAEX;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Session-context detection (#188).
3
+ *
4
+ * ## Why this is not platform detection
5
+ *
6
+ * The keychain accessors in this package used to branch on nothing at all:
7
+ * one code path, which implicitly assumed an interactive GUI session. That
8
+ * assumption is wrong in exactly the contexts a credential store matters most
9
+ * — a launchd system-domain daemon and an SSH login both run **without a
10
+ * security session** attached to the user's login keychain:
11
+ *
12
+ * - no consent UI can render, so an item whose ACL is not preauthorized at
13
+ * write time is unreadable and there is nothing to click;
14
+ * - the keychain **search list** cannot be trusted, because it leads with
15
+ * the (locked) login keychain, whose copy of an item shadows a perfectly
16
+ * readable System-keychain copy.
17
+ *
18
+ * `process.platform === "darwin"` answers neither question — a Mac is a Mac in
19
+ * all three contexts. So the branch that matters is *session vs sessionless*,
20
+ * and that is what this module reports.
21
+ *
22
+ * ## The signals, and their limits
23
+ *
24
+ * There is no supported API that says "you are in the launchd system domain",
25
+ * so this is a heuristic and is documented as one. It is deliberately
26
+ * conservative, and the read path is built so that a misclassification is
27
+ * harmless rather than fatal: a sessionless read consults the System keychain
28
+ * *first* and only then falls back to the search list, so classifying an
29
+ * interactive session as sessionless can never lose a credential that was
30
+ * previously readable (see `readKeychainCredential` in
31
+ * `../crypto/darwin-keychain.ts`).
32
+ *
33
+ * The override exists for the case the heuristic cannot see — a daemon whose
34
+ * environment is scrubbed, or a test rig — and it wins over every signal.
35
+ */
36
+ /** Environment variable that forces the answer. `sessionless` | `interactive`. */
37
+ export declare const SESSION_CONTEXT_OVERRIDE_ENV = "CENTIENT_SECRETS_SESSION_CONTEXT";
38
+ /** Injectable seam. Both fields default to the live process. */
39
+ export interface SessionContextDeps {
40
+ platform: NodeJS.Platform;
41
+ env: NodeJS.ProcessEnv;
42
+ }
43
+ /**
44
+ * Why a context was classified the way it was. Carried so a diagnostic can
45
+ * explain the read path it is about to take instead of asserting it.
46
+ */
47
+ export type SessionContext = {
48
+ kind: "sessionless";
49
+ /**
50
+ * - `ssh` — an SSH login: `SSH_CONNECTION`/`SSH_TTY`/`SSH_CLIENT` set.
51
+ * - `launchd-daemon` — a launchd-managed job with no controlling
52
+ * terminal (`XPC_SERVICE_NAME` set to a real job label, `TERM` unset).
53
+ * - `forced` — the override said so.
54
+ */
55
+ reason: "ssh" | "launchd-daemon" | "forced";
56
+ } | {
57
+ kind: "interactive";
58
+ /**
59
+ * - `session` — no sessionless signal was present.
60
+ * - `not-darwin` — the distinction is macOS-specific; elsewhere there is
61
+ * no keychain search list to mistrust.
62
+ * - `forced` — the override said so.
63
+ */
64
+ reason: "session" | "not-darwin" | "forced";
65
+ };
66
+ /**
67
+ * Classify the current execution context.
68
+ *
69
+ * Order of precedence: explicit override, then SSH, then launchd-without-a-tty,
70
+ * then interactive. Off darwin the answer is always `interactive` with reason
71
+ * `not-darwin` — the search-list shadowing problem is a macOS keychain problem,
72
+ * and other backends have no equivalent notion.
73
+ */
74
+ export declare function detectSessionContext(deps?: Partial<SessionContextDeps>): SessionContext;
75
+ /** Convenience predicate over {@link detectSessionContext}. */
76
+ export declare function isSessionlessContext(deps?: Partial<SessionContextDeps>): boolean;
77
+ //# sourceMappingURL=session-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-context.d.ts","sourceRoot":"","sources":["../../src/platform/session-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,kFAAkF;AAClF,eAAO,MAAM,4BAA4B,qCAAqC,CAAC;AAE/E,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GACtB;IACE,IAAI,EAAE,aAAa,CAAC;IACpB;;;;;OAKG;IACH,MAAM,EAAE,KAAK,GAAG,gBAAgB,GAAG,QAAQ,CAAC;CAC7C,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB;;;;;OAKG;IACH,MAAM,EAAE,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC;CAC7C,CAAC;AAaN;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,GAAE,OAAO,CAAC,kBAAkB,CAAM,GACrC,cAAc,CAyBhB;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAClC,IAAI,GAAE,OAAO,CAAC,kBAAkB,CAAM,GACrC,OAAO,CAET"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Session-context detection (#188).
3
+ *
4
+ * ## Why this is not platform detection
5
+ *
6
+ * The keychain accessors in this package used to branch on nothing at all:
7
+ * one code path, which implicitly assumed an interactive GUI session. That
8
+ * assumption is wrong in exactly the contexts a credential store matters most
9
+ * — a launchd system-domain daemon and an SSH login both run **without a
10
+ * security session** attached to the user's login keychain:
11
+ *
12
+ * - no consent UI can render, so an item whose ACL is not preauthorized at
13
+ * write time is unreadable and there is nothing to click;
14
+ * - the keychain **search list** cannot be trusted, because it leads with
15
+ * the (locked) login keychain, whose copy of an item shadows a perfectly
16
+ * readable System-keychain copy.
17
+ *
18
+ * `process.platform === "darwin"` answers neither question — a Mac is a Mac in
19
+ * all three contexts. So the branch that matters is *session vs sessionless*,
20
+ * and that is what this module reports.
21
+ *
22
+ * ## The signals, and their limits
23
+ *
24
+ * There is no supported API that says "you are in the launchd system domain",
25
+ * so this is a heuristic and is documented as one. It is deliberately
26
+ * conservative, and the read path is built so that a misclassification is
27
+ * harmless rather than fatal: a sessionless read consults the System keychain
28
+ * *first* and only then falls back to the search list, so classifying an
29
+ * interactive session as sessionless can never lose a credential that was
30
+ * previously readable (see `readKeychainCredential` in
31
+ * `../crypto/darwin-keychain.ts`).
32
+ *
33
+ * The override exists for the case the heuristic cannot see — a daemon whose
34
+ * environment is scrubbed, or a test rig — and it wins over every signal.
35
+ */
36
+ /** Environment variable that forces the answer. `sessionless` | `interactive`. */
37
+ export const SESSION_CONTEXT_OVERRIDE_ENV = "CENTIENT_SECRETS_SESSION_CONTEXT";
38
+ function resolve(deps) {
39
+ return {
40
+ platform: deps.platform ?? process.platform,
41
+ env: deps.env ?? process.env,
42
+ };
43
+ }
44
+ function isSet(value) {
45
+ return typeof value === "string" && value.trim().length > 0;
46
+ }
47
+ /**
48
+ * Classify the current execution context.
49
+ *
50
+ * Order of precedence: explicit override, then SSH, then launchd-without-a-tty,
51
+ * then interactive. Off darwin the answer is always `interactive` with reason
52
+ * `not-darwin` — the search-list shadowing problem is a macOS keychain problem,
53
+ * and other backends have no equivalent notion.
54
+ */
55
+ export function detectSessionContext(deps = {}) {
56
+ const { platform, env } = resolve(deps);
57
+ const override = env[SESSION_CONTEXT_OVERRIDE_ENV]?.trim();
58
+ if (override === "sessionless")
59
+ return { kind: "sessionless", reason: "forced" };
60
+ if (override === "interactive")
61
+ return { kind: "interactive", reason: "forced" };
62
+ if (platform !== "darwin")
63
+ return { kind: "interactive", reason: "not-darwin" };
64
+ if (isSet(env["SSH_CONNECTION"]) || isSet(env["SSH_TTY"]) || isSet(env["SSH_CLIENT"])) {
65
+ return { kind: "sessionless", reason: "ssh" };
66
+ }
67
+ // launchd exports `XPC_SERVICE_NAME` as the job label for a managed job; a
68
+ // process started from a shell either has it unset or set to the literal
69
+ // `"0"`. A managed job that also has no `TERM` has no controlling terminal
70
+ // and therefore no way to render a consent prompt. Both halves are required:
71
+ // a GUI application is also a launchd job, and demoting one of those to
72
+ // "sessionless" would be a needless change of read path.
73
+ const xpc = env["XPC_SERVICE_NAME"];
74
+ if (isSet(xpc) && xpc?.trim() !== "0" && !isSet(env["TERM"])) {
75
+ return { kind: "sessionless", reason: "launchd-daemon" };
76
+ }
77
+ return { kind: "interactive", reason: "session" };
78
+ }
79
+ /** Convenience predicate over {@link detectSessionContext}. */
80
+ export function isSessionlessContext(deps = {}) {
81
+ return detectSessionContext(deps).kind === "sessionless";
82
+ }
83
+ //# sourceMappingURL=session-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-context.js","sourceRoot":"","sources":["../../src/platform/session-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,kFAAkF;AAClF,MAAM,CAAC,MAAM,4BAA4B,GAAG,kCAAkC,CAAC;AAkC/E,SAAS,OAAO,CAAC,IAAiC;IAChD,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ;QAC3C,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG;KAC7B,CAAC;AACJ,CAAC;AAED,SAAS,KAAK,CAAC,KAAyB;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAoC,EAAE;IAEtC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAExC,MAAM,QAAQ,GAAG,GAAG,CAAC,4BAA4B,CAAC,EAAE,IAAI,EAAE,CAAC;IAC3D,IAAI,QAAQ,KAAK,aAAa;QAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IACjF,IAAI,QAAQ,KAAK,aAAa;QAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAEjF,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IAEhF,IAAI,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QACtF,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAChD,CAAC;IAED,2EAA2E;IAC3E,yEAAyE;IACzE,2EAA2E;IAC3E,6EAA6E;IAC7E,wEAAwE;IACxE,yDAAyD;IACzD,MAAM,GAAG,GAAG,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACpC,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QAC7D,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3D,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AACpD,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,oBAAoB,CAClC,OAAoC,EAAE;IAEtC,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { CredentialAuditEvent } from "../audit/ocsf.js";
2
+ import type { AuditSink } from "../sinks/types.js";
3
+ import type { SecretsPolicy } from "../vault/policy.js";
4
+ /** Structural seam implemented by `createHmacAuditChain()`. */
5
+ export interface AuditEventChain {
6
+ append(event: CredentialAuditEvent): CredentialAuditEvent;
7
+ }
8
+ export interface AuditTrailOptions {
9
+ /** Defaults to the application-owned global OpenTelemetry tracer. */
10
+ readonly sink?: AuditSink;
11
+ /** Successful and missing reads are included unless explicitly disabled. */
12
+ readonly includeReads?: boolean;
13
+ /** Optional synchronous integrity chain applied before the record reaches a sink. */
14
+ readonly chain?: AuditEventChain;
15
+ /** Actor used when the operation did not carry an explicit caller. */
16
+ readonly defaultActor?: string;
17
+ /** Injectable record UID seam. */
18
+ readonly uid?: () => string;
19
+ }
20
+ /**
21
+ * Map value-free policy outcomes to OCSF, optionally chain them, then emit to
22
+ * one synchronous sink boundary. Rejected and failed reads are never filtered.
23
+ */
24
+ export declare function auditTrail(options?: AuditTrailOptions): SecretsPolicy;
25
+ //# sourceMappingURL=audit-trail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-trail.d.ts","sourceRoot":"","sources":["../../src/policies/audit-trail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEtE,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,KAAK,EAAE,oBAAoB,GAAG,oBAAoB,CAAC;CAC3D;AAED,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC1B,4EAA4E;IAC5E,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC;IACjC,sEAAsE;IACtE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,kCAAkC;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,aAAa,CA2BzE"}
@@ -0,0 +1,31 @@
1
+ import { toCredentialAuditEvent } from "../audit/ocsf.js";
2
+ import { otelAuditSink } from "../sinks/otel.js";
3
+ /**
4
+ * Map value-free policy outcomes to OCSF, optionally chain them, then emit to
5
+ * one synchronous sink boundary. Rejected and failed reads are never filtered.
6
+ */
7
+ export function auditTrail(options = {}) {
8
+ const includeReads = options.includeReads ?? true;
9
+ const sink = options.sink ?? otelAuditSink();
10
+ const chain = options.chain;
11
+ const appendToChain = chain?.append.bind(chain);
12
+ const defaultActor = options.defaultActor;
13
+ const uid = options.uid;
14
+ return {
15
+ name: "auditTrail",
16
+ observesPolicyRejections: true,
17
+ after(event) {
18
+ if (!includeReads &&
19
+ (event.type === "credential_read" ||
20
+ event.type === "credential_read_missing")) {
21
+ return;
22
+ }
23
+ const projected = toCredentialAuditEvent(event, {
24
+ ...(defaultActor !== undefined ? { defaultActor } : {}),
25
+ ...(uid !== undefined ? { uid } : {}),
26
+ });
27
+ sink(appendToChain?.(projected) ?? projected);
28
+ },
29
+ };
30
+ }
31
+ //# sourceMappingURL=audit-trail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-trail.js","sourceRoot":"","sources":["../../src/policies/audit-trail.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAsBjD;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,UAA6B,EAAE;IACxD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC;IAClD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,aAAa,EAAE,CAAC;IAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,MAAM,aAAa,GAAG,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAExB,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,wBAAwB,EAAE,IAAI;QAC9B,KAAK,CAAC,KAAmB;YACvB,IACE,CAAC,YAAY;gBACb,CAAC,KAAK,CAAC,IAAI,KAAK,iBAAiB;oBAC/B,KAAK,CAAC,IAAI,KAAK,yBAAyB,CAAC,EAC3C,CAAC;gBACD,OAAO;YACT,CAAC;YAED,MAAM,SAAS,GAAG,sBAAsB,CAAC,KAAK,EAAE;gBAC9C,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtC,CAAC,CAAC;YACH,IAAI,CAAC,aAAa,EAAE,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,CAAC;QAChD,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The five-way credential state (#188).
3
+ *
4
+ * Every probe in this package answers with this shape, at both credential
5
+ * layers — the `KeyProvider` layer (the vault master key) and the
6
+ * `VaultBackend` cascade (credential values).
7
+ *
8
+ * ## Why five kinds and not a boolean
9
+ *
10
+ * The defect this type exists to kill is the collapse of "there is no such
11
+ * credential" into "I could not read the credential". They have opposite
12
+ * remedies — one says *store it*, the other says *unlock the store / fix the
13
+ * ACL / run me in a context that has a session* — and a caller handed a single
14
+ * `null` cannot tell them apart. A backend that reports `absent` for an item
15
+ * it simply could not open turns a context change into a silent outage: the
16
+ * reader logs "none configured" and everything downstream behaves as though
17
+ * the operator never set it up.
18
+ *
19
+ * So the kinds are deliberately irreducible:
20
+ *
21
+ * - `found` — the credential is there. **Value-free**: a probe never carries
22
+ * secret material, so this variant has no `value` field. Reading the bytes
23
+ * is a separate, explicit call.
24
+ * - `absent` — the store answered, and there is no such item.
25
+ * - `locked` — the item exists but this execution context cannot open it
26
+ * (locked keychain, an ACL that does not preauthorize the reader, no
27
+ * session in which a consent prompt could render).
28
+ * - `not-applicable` — this store cannot exist here at all (a macOS Keychain
29
+ * probe on Linux). Distinct from `failed`: nothing went wrong.
30
+ * - `failed` — the store was contacted and did not give a usable answer.
31
+ * Includes the corrupt case where a successful read yields zero bytes: an
32
+ * empty credential is never reported as `found`.
33
+ *
34
+ * `not-applicable` and `failed` carry a value-free human-readable string for
35
+ * diagnostics. No variant ever carries a credential.
36
+ *
37
+ * See issue #188, ADR-005, and `docs/threat-model.md`.
38
+ */
39
+ export type SecretState = {
40
+ kind: "found";
41
+ } | {
42
+ kind: "absent";
43
+ } | {
44
+ kind: "locked";
45
+ } | {
46
+ kind: "not-applicable";
47
+ reason: string;
48
+ } | {
49
+ kind: "failed";
50
+ detail: string;
51
+ };
52
+ /** The discriminant of {@link SecretState}, for exhaustive switches. */
53
+ export type SecretStateKind = SecretState["kind"];
54
+ //# sourceMappingURL=secret-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-state.d.ts","sourceRoot":"","sources":["../src/secret-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,wEAAwE;AACxE,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=secret-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-state.js","sourceRoot":"","sources":["../src/secret-state.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ export { jsonlAuditSink } from "./jsonl.js";
2
+ export type { JsonlAuditSinkOptions } from "./jsonl.js";
3
+ export { credentialAuditSpanAttributes, otelAuditSink, OtelAuditSinkDegradedError, } from "./otel.js";
4
+ export type { OtelAuditSinkOptions } from "./otel.js";
5
+ export { syslogAuditSink } from "./syslog.js";
6
+ export type { SyslogAuditSender, SyslogAuditSinkOptions, } from "./syslog.js";
7
+ export { AuditSinkOverflowError } from "./types.js";
8
+ export type { AuditSink, AuditSinkErrorHandler, AuditSinkHealth, } from "./types.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sinks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EACL,6BAA6B,EAC7B,aAAa,EACb,0BAA0B,GAC3B,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EACV,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,YAAY,EACV,SAAS,EACT,qBAAqB,EACrB,eAAe,GAChB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { jsonlAuditSink } from "./jsonl.js";
2
+ export { credentialAuditSpanAttributes, otelAuditSink, OtelAuditSinkDegradedError, } from "./otel.js";
3
+ export { syslogAuditSink } from "./syslog.js";
4
+ export { AuditSinkOverflowError } from "./types.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sinks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EACL,6BAA6B,EAC7B,aAAa,EACb,0BAA0B,GAC3B,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAK9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { AuditSink, AuditSinkErrorHandler } from "./types.js";
2
+ export interface JsonlAuditSinkOptions {
3
+ readonly filePath: string;
4
+ /** Creation mode for a new log file. Defaults to owner-only `0o600`. */
5
+ readonly fileMode?: number;
6
+ /** Creation mode for missing directories. Defaults to owner-only `0o700`. */
7
+ readonly directoryMode?: number;
8
+ readonly maxPending?: number;
9
+ readonly onError?: AuditSinkErrorHandler;
10
+ }
11
+ /**
12
+ * Append bare OCSF records as newline-delimited JSON. Writes are serialized in
13
+ * emission order; `flush()` rejects if any queued append failed.
14
+ */
15
+ export declare function jsonlAuditSink(options: JsonlAuditSinkOptions): AuditSink;
16
+ //# sourceMappingURL=jsonl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonl.d.ts","sourceRoot":"","sources":["../../src/sinks/jsonl.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAGnE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC;CAC1C;AAQD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,SAAS,CAuCxE"}
@@ -0,0 +1,51 @@
1
+ import { appendFile, mkdir } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ import { createQueuedAuditSink } from "./queue.js";
4
+ function assertMode(mode, field) {
5
+ if (!Number.isInteger(mode) || mode < 0 || mode > 0o777) {
6
+ throw new RangeError(`${field} must be an integer permission mode from 0o000 to 0o777`);
7
+ }
8
+ }
9
+ /**
10
+ * Append bare OCSF records as newline-delimited JSON. Writes are serialized in
11
+ * emission order; `flush()` rejects if any queued append failed.
12
+ */
13
+ export function jsonlAuditSink(options) {
14
+ if (options.filePath.length === 0) {
15
+ throw new TypeError("filePath must not be empty");
16
+ }
17
+ const fileMode = options.fileMode ?? 0o600;
18
+ const directoryMode = options.directoryMode ?? 0o700;
19
+ assertMode(fileMode, "fileMode");
20
+ assertMode(directoryMode, "directoryMode");
21
+ let directoryReady = false;
22
+ return createQueuedAuditSink({
23
+ name: "jsonl",
24
+ ...(options.maxPending !== undefined ? { maxPending: options.maxPending } : {}),
25
+ ...(options.onError !== undefined ? { onError: options.onError } : {}),
26
+ async write(event) {
27
+ if (!directoryReady) {
28
+ await mkdir(dirname(options.filePath), {
29
+ recursive: true,
30
+ mode: directoryMode,
31
+ });
32
+ directoryReady = true;
33
+ }
34
+ try {
35
+ await appendFile(options.filePath, `${JSON.stringify(event)}\n`, {
36
+ encoding: "utf8",
37
+ mode: fileMode,
38
+ });
39
+ }
40
+ catch (error) {
41
+ if (error instanceof Error &&
42
+ "code" in error &&
43
+ error.code === "ENOENT") {
44
+ directoryReady = false;
45
+ }
46
+ throw error;
47
+ }
48
+ },
49
+ });
50
+ }
51
+ //# sourceMappingURL=jsonl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonl.js","sourceRoot":"","sources":["../../src/sinks/jsonl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAYnD,SAAS,UAAU,CAAC,IAAY,EAAE,KAAa;IAC7C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QACxD,MAAM,IAAI,UAAU,CAAC,GAAG,KAAK,yDAAyD,CAAC,CAAC;IAC1F,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,OAA8B;IAC3D,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,SAAS,CAAC,4BAA4B,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,KAAK,CAAC;IAC3C,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,KAAK,CAAC;IACrD,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACjC,UAAU,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;IAE3C,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,OAAO,qBAAqB,CAAC;QAC3B,IAAI,EAAE,OAAO;QACb,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,KAAK,CAAC,KAAK,CAAC,KAAK;YACf,IAAI,CAAC,cAAc,EAAE,CAAC;gBACpB,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;oBACrC,SAAS,EAAE,IAAI;oBACf,IAAI,EAAE,aAAa;iBACpB,CAAC,CAAC;gBACH,cAAc,GAAG,IAAI,CAAC;YACxB,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE;oBAC/D,QAAQ,EAAE,MAAM;oBAChB,IAAI,EAAE,QAAQ;iBACf,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IACE,KAAK,YAAY,KAAK;oBACtB,MAAM,IAAI,KAAK;oBACd,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAClD,CAAC;oBACD,cAAc,GAAG,KAAK,CAAC;gBACzB,CAAC;gBACD,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { type Attributes, type Tracer } from "@opentelemetry/api";
2
+ import type { CredentialAuditEvent } from "../audit/ocsf.js";
3
+ import { type AuditSink, type AuditSinkErrorHandler } from "./types.js";
4
+ export declare class OtelAuditSinkDegradedError extends Error {
5
+ readonly code: "OTEL_AUDIT_SINK_DEGRADED";
6
+ constructor(reason: "not-recording" | "not-sampled");
7
+ }
8
+ export interface OtelAuditSinkOptions {
9
+ /** Application-owned tracer; defaults to the global OTel API tracer. */
10
+ readonly tracer?: Tracer;
11
+ /** Called once when spans are not recording/sampled, and on synchronous errors. */
12
+ readonly onError?: AuditSinkErrorHandler;
13
+ }
14
+ /** Flatten one OCSF JSON record into primitive span attributes. */
15
+ export declare function credentialAuditSpanAttributes(event: CredentialAuditEvent): Attributes;
16
+ /**
17
+ * Emit one completed credential operation as a retroactive OTel span. The
18
+ * application owns SDK/exporter configuration; this package depends only on
19
+ * the OTel API, as required for reusable instrumentation libraries.
20
+ */
21
+ export declare function otelAuditSink(options?: OtelAuditSinkOptions): AuditSink;
22
+ //# sourceMappingURL=otel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otel.d.ts","sourceRoot":"","sources":["../../src/sinks/otel.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,MAAM,EACZ,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,qBAAqB,EAE3B,MAAM,YAAY,CAAC;AAKpB,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,QAAQ,CAAC,IAAI,EAAG,0BAA0B,CAAU;gBAExC,MAAM,EAAE,eAAe,GAAG,aAAa;CAQpD;AAED,MAAM,WAAW,oBAAoB;IACnC,wEAAwE;IACxE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC;CAC1C;AAED,mEAAmE;AACnE,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,oBAAoB,GAC1B,UAAU,CA6DZ;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,SAAS,CA0E3E"}