@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,199 @@
1
+ /**
2
+ * The compatibility floor: what an OLD `@centient/secrets` silently does wrong,
3
+ * published as data so a consumer can grade itself (#214).
4
+ *
5
+ * ## Why this exists
6
+ *
7
+ * Five consumers pin this package at four disjoint minors (`^0.5.0` … `0.10.0`)
8
+ * with no negotiation surface between them and the provider. Several releases
9
+ * closed defects whose only symptom, at the old version, is **silence**: a
10
+ * denied credential operation that leaves no audit trace, a keychain write that
11
+ * reports success into a keychain this context's reader cannot see, a malformed
12
+ * key that stores on one backend and reads as absent on the next. A consumer
13
+ * running such a version has no way to learn that from the package — the
14
+ * behaviour looks fine and the logs look clean.
15
+ *
16
+ * So the provider publishes the list. {@link COMPATIBILITY_FLOOR} names each
17
+ * closed gap, the version that closed it, and the symptom it presented before
18
+ * then; {@link assessCompatibility} turns an installed version into a grade a
19
+ * `doctor` command can print.
20
+ *
21
+ * ## What this is NOT
22
+ *
23
+ * **Never a boot-time refusal.** Nothing here runs at import, nothing throws
24
+ * from a constructor, and no vault path consults it. A package that refuses to
25
+ * load because the caller is old converts a documentation problem into an
26
+ * outage. Every function in this module is pure, total, and advisory: malformed
27
+ * input comes back as a typed `"unknown"` grade carrying the reason (P2, No
28
+ * Silent Degradation; P10, Honest Uncertainty), never as a throw.
29
+ *
30
+ * ## What a consumer does with it
31
+ *
32
+ * ```ts
33
+ * import { assessCompatibility, SECRETS_PACKAGE_VERSION } from "@centient/secrets";
34
+ *
35
+ * const assessment = assessCompatibility(SECRETS_PACKAGE_VERSION);
36
+ * if (assessment.grade !== "ok") {
37
+ * for (const gap of assessment.openGaps) {
38
+ * report(`${gap.severity}: ${gap.symptom} (fixed in ${gap.closedIn}, ${gap.reference})`);
39
+ * }
40
+ * }
41
+ * ```
42
+ *
43
+ * `SECRETS_PACKAGE_VERSION` is the version of the build the consumer actually
44
+ * imported, so the assessment describes the code in that tree — not whatever is
45
+ * latest on the registry. A consumer auditing a *manifest* range instead (`the
46
+ * pin says ^0.6.0 — what does that admit at worst?`) uses {@link assessPin}.
47
+ *
48
+ * Issue: centient-labs/centient-sdk#214 (findings C6-27, C6-29, C6-61).
49
+ */
50
+ /**
51
+ * The version of THIS build of `@centient/secrets`.
52
+ *
53
+ * Kept in step with `package.json` two ways: `scripts/sync-claudemd-versions.mjs`
54
+ * rewrites it during `pnpm run version-packages` (the same step that syncs the
55
+ * CLAUDE.md package table), and `tests/compatibility.test.ts` fails the build if
56
+ * the two ever disagree. A stale constant here would misgrade every consumer, so
57
+ * drift is a test failure rather than a silent wrong answer.
58
+ */
59
+ export declare const SECRETS_PACKAGE_VERSION = "0.11.0";
60
+ /**
61
+ * The oldest version {@link COMPATIBILITY_FLOOR} can honestly describe.
62
+ *
63
+ * `0.5.0` is the oldest release any current consumer pins, and the oldest one
64
+ * whose behaviour the table's entries were written against. Below it the table
65
+ * is not wrong so much as **incomplete** — returning its short list for a 0.4.x
66
+ * install would understate what is open — so {@link assessCompatibility} grades
67
+ * such a version `"unsupported"` and says so, rather than quietly reporting the
68
+ * gaps it happens to know about.
69
+ *
70
+ * This is an epistemic limit on the table, not a support policy and not a gate:
71
+ * an `"unsupported"` grade still returns every gap the table does know about.
72
+ */
73
+ export declare const MIN_ASSESSABLE_VERSION = "0.5.0";
74
+ /** How badly the gap bites a consumer still running below `closedIn`. */
75
+ export type GapSeverity = "high" | "medium" | "low";
76
+ /**
77
+ * One known behavioural gap, keyed by the version that closed it.
78
+ *
79
+ * A gap is **open** for an installed version `v` exactly when
80
+ * `v < closedIn` — there is no upper bound, because a fix that shipped is not
81
+ * un-shipped. Everything here is value-free public metadata: no credential
82
+ * material, no host paths, nothing that changes at runtime.
83
+ */
84
+ export interface CompatibilityGap {
85
+ /** Stable machine-readable id. Never renamed — consumers may suppress by id. */
86
+ readonly id: string;
87
+ /** The first release in which the gap is closed. A valid `major.minor.patch`. */
88
+ readonly closedIn: string;
89
+ /** How badly this bites a consumer still below `closedIn`. */
90
+ readonly severity: GapSeverity;
91
+ /** One line, consumer-facing: what the OLD version does wrong. */
92
+ readonly symptom: string;
93
+ /** Issue or PR that closed it, `owner/repo#n`. */
94
+ readonly reference: string;
95
+ /**
96
+ * What the consumer must change when it adopts the fix, when adopting is not
97
+ * a pure no-op. Absent means "bump and nothing else". This is the field that
98
+ * turns the table from a scorecard into a bump plan.
99
+ */
100
+ readonly adoptionNote?: string;
101
+ /** The C6 audit finding this gap corresponds to, where one exists. */
102
+ readonly finding?: string;
103
+ }
104
+ /**
105
+ * The published floor — deeply frozen at module initialization (every field on
106
+ * a {@link CompatibilityGap} is a primitive, so freezing each entry plus the
107
+ * array is a complete freeze). `assessCompatibility()` defaults to this same
108
+ * object, so a runtime mutation — a JS consumer, a test helper, a cast past
109
+ * the `readonly` type — would silently change every later assessment in the
110
+ * process. Frozen, the mutation throws at the mutation site instead
111
+ * (mb:f/7e54ba; the same no-silent-degradation stance as the rest of this
112
+ * module).
113
+ */
114
+ export declare const COMPATIBILITY_FLOOR: readonly CompatibilityGap[];
115
+ /** The grade a consumer's installed version earns against the floor. */
116
+ export type CompatibilityGrade =
117
+ /** At or above every known fix. Nothing in the table is open. */
118
+ "ok"
119
+ /** Assessable, but one or more known gaps are open. `openGaps` lists them. */
120
+ | "degraded"
121
+ /** Below {@link MIN_ASSESSABLE_VERSION}: the table cannot claim to be complete. */
122
+ | "unsupported"
123
+ /** The version could not be parsed. `reason` says why. Never a throw. */
124
+ | "unknown";
125
+ /**
126
+ * The result of grading one version against the floor. Every field is derived
127
+ * and value-free; the input is echoed back so a caller can see what was graded
128
+ * (P6, Single Source of Truth — echo interpreted parameters).
129
+ */
130
+ export interface CompatibilityAssessment {
131
+ readonly grade: CompatibilityGrade;
132
+ /** The version as given, echoed verbatim — including unparseable input. */
133
+ readonly installedVersion: string;
134
+ /** The version of the build that produced this assessment. */
135
+ readonly currentVersion: string;
136
+ /** The floor below which the table is incomplete. */
137
+ readonly minAssessableVersion: string;
138
+ /**
139
+ * Gaps open at `installedVersion`, oldest fix first. Empty for `"ok"` and for
140
+ * `"unknown"` — and for `"unknown"` that emptiness means `not assessed`, which
141
+ * is why the grade, not the list length, is what a caller branches on.
142
+ */
143
+ readonly openGaps: readonly CompatibilityGap[];
144
+ /** The worst severity among `openGaps`, or `null` when there are none. */
145
+ readonly highestSeverity: GapSeverity | null;
146
+ /** One line suitable for a doctor's status column. */
147
+ readonly summary: string;
148
+ /** Why the grade is `"unknown"` or `"unsupported"`. Absent otherwise. */
149
+ readonly reason?: string;
150
+ }
151
+ /**
152
+ * Grade an installed version against the compatibility floor.
153
+ *
154
+ * Pure and total: it reads no environment, touches no keychain, and **never
155
+ * throws** — a version string it cannot parse comes back as
156
+ * `grade: "unknown"` naming the problem. Totality is enforced here rather than
157
+ * assumed of the parser: input is narrowed by this module's own guard, so a JS
158
+ * caller handing it `null`, `undefined`, a number or an object gets the same
159
+ * typed `"unknown"` result as a misspelt version, never an exception. Call it
160
+ * from a `doctor`, a startup log line, or a CI check; do not call it from a
161
+ * code path that would refuse to run on the answer.
162
+ *
163
+ * @param installedVersion - the version actually installed in the consumer's
164
+ * tree. Import {@link SECRETS_PACKAGE_VERSION} for that; a leading `v` and
165
+ * surrounding whitespace are tolerated.
166
+ * @param floor - the gap table to grade against. Defaults to
167
+ * {@link COMPATIBILITY_FLOOR}; injectable so a test can grade a fixture table
168
+ * without pinning itself to the shipped one.
169
+ */
170
+ export declare function assessCompatibility(installedVersion: string, floor?: readonly CompatibilityGap[]): CompatibilityAssessment;
171
+ /**
172
+ * The lowest version a dependency range admits, or `null` when the range form
173
+ * is one this helper does not understand.
174
+ *
175
+ * Deliberately narrow: it recognises the forms that actually appear in the
176
+ * consumers' manifests — `^x.y.z`, `~x.y.z`, `>=x.y.z` and a bare `x.y.z` — and
177
+ * returns `null` for everything else rather than guessing. A guess here would
178
+ * grade the wrong version and report a clean bill of health for a pin nobody
179
+ * checked.
180
+ *
181
+ * The accepted grammar is matched whole and enumerated on
182
+ * {@link SUPPORTED_RANGE}; nothing outside it is partially interpreted. Total:
183
+ * a non-string, an empty string, and every unsupported form all return `null`.
184
+ */
185
+ export declare function lowestVersionInRange(range: string): string | null;
186
+ /**
187
+ * Grade a manifest **pin** by its worst admissible version.
188
+ *
189
+ * `assessCompatibility` answers "what is open in the build I imported"; this
190
+ * answers "what could be open in any build this pin admits". A `^0.6.0` pin can
191
+ * resolve to any 0.6.x, so the version worth grading is its base — which is also
192
+ * the one a lockfile that has never been refreshed is most likely holding.
193
+ *
194
+ * Returns `grade: "unknown"` carrying the reason for a range form
195
+ * {@link lowestVersionInRange} does not recognise — including a non-string a JS
196
+ * caller slipped past the signature. Never throws.
197
+ */
198
+ export declare function assessPin(pin: string, floor?: readonly CompatibilityGap[]): CompatibilityAssessment;
199
+ //# sourceMappingURL=compatibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compatibility.d.ts","sourceRoot":"","sources":["../src/compatibility.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAIH;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,WAAW,CAAC;AAEhD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,UAAU,CAAC;AAE9C,yEAAyE;AACzE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAQpD;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AA+ED;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,gBAAgB,EAE1D,CAAC;AA4DF,wEAAwE;AACxE,MAAM,MAAM,kBAAkB;AAC5B,iEAAiE;AAC/D,IAAI;AACN,8EAA8E;GAC5E,UAAU;AACZ,mFAAmF;GACjF,aAAa;AACf,yEAAyE;GACvE,SAAS,CAAC;AAEd;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,2EAA2E;IAC3E,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,qDAAqD;IACrD,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC/C,0EAA0E;IAC1E,QAAQ,CAAC,eAAe,EAAE,WAAW,GAAG,IAAI,CAAC;IAC7C,sDAAsD;IACtD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,gBAAgB,EAAE,MAAM,EACxB,KAAK,GAAE,SAAS,gBAAgB,EAAwB,GACvD,uBAAuB,CAwEzB;AA0FD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,EACX,KAAK,GAAE,SAAS,gBAAgB,EAAwB,GACvD,uBAAuB,CAezB"}
@@ -0,0 +1,419 @@
1
+ /**
2
+ * The compatibility floor: what an OLD `@centient/secrets` silently does wrong,
3
+ * published as data so a consumer can grade itself (#214).
4
+ *
5
+ * ## Why this exists
6
+ *
7
+ * Five consumers pin this package at four disjoint minors (`^0.5.0` … `0.10.0`)
8
+ * with no negotiation surface between them and the provider. Several releases
9
+ * closed defects whose only symptom, at the old version, is **silence**: a
10
+ * denied credential operation that leaves no audit trace, a keychain write that
11
+ * reports success into a keychain this context's reader cannot see, a malformed
12
+ * key that stores on one backend and reads as absent on the next. A consumer
13
+ * running such a version has no way to learn that from the package — the
14
+ * behaviour looks fine and the logs look clean.
15
+ *
16
+ * So the provider publishes the list. {@link COMPATIBILITY_FLOOR} names each
17
+ * closed gap, the version that closed it, and the symptom it presented before
18
+ * then; {@link assessCompatibility} turns an installed version into a grade a
19
+ * `doctor` command can print.
20
+ *
21
+ * ## What this is NOT
22
+ *
23
+ * **Never a boot-time refusal.** Nothing here runs at import, nothing throws
24
+ * from a constructor, and no vault path consults it. A package that refuses to
25
+ * load because the caller is old converts a documentation problem into an
26
+ * outage. Every function in this module is pure, total, and advisory: malformed
27
+ * input comes back as a typed `"unknown"` grade carrying the reason (P2, No
28
+ * Silent Degradation; P10, Honest Uncertainty), never as a throw.
29
+ *
30
+ * ## What a consumer does with it
31
+ *
32
+ * ```ts
33
+ * import { assessCompatibility, SECRETS_PACKAGE_VERSION } from "@centient/secrets";
34
+ *
35
+ * const assessment = assessCompatibility(SECRETS_PACKAGE_VERSION);
36
+ * if (assessment.grade !== "ok") {
37
+ * for (const gap of assessment.openGaps) {
38
+ * report(`${gap.severity}: ${gap.symptom} (fixed in ${gap.closedIn}, ${gap.reference})`);
39
+ * }
40
+ * }
41
+ * ```
42
+ *
43
+ * `SECRETS_PACKAGE_VERSION` is the version of the build the consumer actually
44
+ * imported, so the assessment describes the code in that tree — not whatever is
45
+ * latest on the registry. A consumer auditing a *manifest* range instead (`the
46
+ * pin says ^0.6.0 — what does that admit at worst?`) uses {@link assessPin}.
47
+ *
48
+ * Issue: centient-labs/centient-sdk#214 (findings C6-27, C6-29, C6-61).
49
+ */
50
+ import { compareSemver, formatSemver, tryParseSemver } from "@centient/cli-utils";
51
+ /**
52
+ * The version of THIS build of `@centient/secrets`.
53
+ *
54
+ * Kept in step with `package.json` two ways: `scripts/sync-claudemd-versions.mjs`
55
+ * rewrites it during `pnpm run version-packages` (the same step that syncs the
56
+ * CLAUDE.md package table), and `tests/compatibility.test.ts` fails the build if
57
+ * the two ever disagree. A stale constant here would misgrade every consumer, so
58
+ * drift is a test failure rather than a silent wrong answer.
59
+ */
60
+ export const SECRETS_PACKAGE_VERSION = "0.11.0";
61
+ /**
62
+ * The oldest version {@link COMPATIBILITY_FLOOR} can honestly describe.
63
+ *
64
+ * `0.5.0` is the oldest release any current consumer pins, and the oldest one
65
+ * whose behaviour the table's entries were written against. Below it the table
66
+ * is not wrong so much as **incomplete** — returning its short list for a 0.4.x
67
+ * install would understate what is open — so {@link assessCompatibility} grades
68
+ * such a version `"unsupported"` and says so, rather than quietly reporting the
69
+ * gaps it happens to know about.
70
+ *
71
+ * This is an epistemic limit on the table, not a support policy and not a gate:
72
+ * an `"unsupported"` grade still returns every gap the table does know about.
73
+ */
74
+ export const MIN_ASSESSABLE_VERSION = "0.5.0";
75
+ const SEVERITY_RANK = {
76
+ low: 0,
77
+ medium: 1,
78
+ high: 2,
79
+ };
80
+ /**
81
+ * Every known behavioural gap this package has closed, oldest fix first.
82
+ *
83
+ * Ordering is part of the contract (ascending `closedIn`, then `id`) so that
84
+ * the list a consumer prints reads as an upgrade path rather than an unordered
85
+ * bag; `tests/compatibility.test.ts` pins both the ordering and that every
86
+ * `closedIn` parses as a semver.
87
+ *
88
+ * Entries are added when a release closes a defect whose pre-fix symptom is
89
+ * silent. A fix a consumer would notice on its own does not need a row here.
90
+ */
91
+ const FLOOR_TABLE = [
92
+ {
93
+ id: "per-consumer-vault-key",
94
+ closedIn: "0.8.0",
95
+ severity: "high",
96
+ symptom: "Every consumer on the host encrypts its vault with the same `centient-vault`/`vault-key` master key: `KeychainProvider` hardcodes the item and `openVault()` resolves its provider internally, so a consumer cannot name or inject a key of its own.",
97
+ reference: "centient-labs/centient-sdk#80",
98
+ adoptionNote: "Additive: pass `openVault({ keyProvider })` or `{ keychain: { service, account } }`. Defaults are unchanged, so an existing vault keeps opening until the consumer opts in — the bump alone does not isolate the key.",
99
+ finding: "C6-28",
100
+ },
101
+ {
102
+ id: "denied-operation-audit",
103
+ closedIn: "0.9.0",
104
+ severity: "high",
105
+ symptom: "A policy-denied credential operation leaves no audit trace: the `before` hook throws and no `after` event fires, so denied reads, writes, deletes and enumerations are simply absent from the audit trail.",
106
+ reference: "centient-labs/centient-sdk#120",
107
+ adoptionNote: "`SecretsEventType` gains four `*_rejected` members. A consumer that exhaustively switches on the event type must handle them; one that only matches the prior types is unaffected.",
108
+ finding: "C6-29",
109
+ },
110
+ {
111
+ id: "libsecret-fallback-silence",
112
+ closedIn: "0.9.0",
113
+ severity: "medium",
114
+ symptom: "On Linux, the libsecret D-Bus enumeration falls back to `secret-tool search` — which briefly materializes secret values on stdout — inside a bare `catch {}`, so a security-relevant degradation happens with no signal at all.",
115
+ reference: "centient-labs/centient-sdk#121",
116
+ finding: "C6-29",
117
+ },
118
+ {
119
+ id: "credential-key-grammar",
120
+ closedIn: "0.10.0",
121
+ severity: "high",
122
+ symptom: "The documented credential-key grammar is enforced nowhere on the shared path, so a key like `Auth_Token` stores successfully on the macOS keychain and env backends and is unreadable on every other one — and the enforcing backends return `null`, which is indistinguishable from `no such credential`.",
123
+ reference: "centient-labs/centient-sdk#168",
124
+ adoptionNote: "Breaking behaviour change: `storeCredential`/`getCredential`/`deleteCredential`/`listCredentials` now throw `InvalidCredentialKeyError` for a non-conforming key instead of dispatching it. Audit operator-supplied keys before bumping. `listCredentials(prefix)` is validated against the looser prefix grammar, so `\"soma.anthropic.\"` still works.",
125
+ },
126
+ {
127
+ id: "sessionless-keychain-read",
128
+ closedIn: "0.10.0",
129
+ severity: "high",
130
+ symptom: "On macOS, keychain writes preauthorize no reader (`-T \"\"`) and reads walk the session search list, so a context with no security session — a launchd system-domain daemon, an SSH login — cannot read its own credentials, and a locked login-keychain copy shadows a readable System-keychain one. Every such failure collapses to `null`, reported as `nothing configured`.",
131
+ reference: "centient-labs/centient-sdk#188",
132
+ adoptionNote: "Consumers carrying a private fork of this fix should reconcile deliberately rather than bundling it into a routine bump: the two postures can differ. See centient-labs/centient-sdk#214 (C6-31).",
133
+ finding: "C6-31",
134
+ },
135
+ {
136
+ id: "sessionless-write-reachability",
137
+ closedIn: "0.10.0",
138
+ severity: "medium",
139
+ symptom: "A sessionless keychain write that falls back to the default keychain for want of privileges is reported as `true` by the boolean accessors, even though this context's reader cannot see it there — a write recorded as a success the reader will never experience.",
140
+ reference: "centient-labs/centient-sdk#188",
141
+ adoptionNote: "Behaviour change on an unchanged signature: from 0.10.0 the boolean means `landed where this context's reader looks`, so a sessionless fallback write now returns `false` where it used to return `true`. Code that branches on `storeCredential`'s boolean should be tested against the new meaning before bumping, or read the discriminated `writeKeychainCredential()` result, which carries the destination and a value-free promotion command.",
142
+ finding: "C6-61",
143
+ },
144
+ ];
145
+ /**
146
+ * The published floor — deeply frozen at module initialization (every field on
147
+ * a {@link CompatibilityGap} is a primitive, so freezing each entry plus the
148
+ * array is a complete freeze). `assessCompatibility()` defaults to this same
149
+ * object, so a runtime mutation — a JS consumer, a test helper, a cast past
150
+ * the `readonly` type — would silently change every later assessment in the
151
+ * process. Frozen, the mutation throws at the mutation site instead
152
+ * (mb:f/7e54ba; the same no-silent-degradation stance as the rest of this
153
+ * module).
154
+ */
155
+ export const COMPATIBILITY_FLOOR = Object.freeze(FLOOR_TABLE.map((gap) => Object.freeze({ ...gap })));
156
+ /**
157
+ * The one place caller input is narrowed to a usable string.
158
+ *
159
+ * Every exported function here is documented as total, and a JS caller — or a
160
+ * `JSON.parse`d manifest, or an `any` at a module boundary — can hand any of
161
+ * them `null`, a number, or an object regardless of what the TypeScript
162
+ * signature says. Rather than trusting each downstream parser to guard for
163
+ * itself (`tryParseSemver` does today; that is an implementation detail of
164
+ * another package, not a contract this module may rest its never-throws
165
+ * promise on), both entry points funnel through this guard, so the two paths
166
+ * cannot drift apart the way they had (`[mb:f/f8ecdf]`).
167
+ *
168
+ * Returns the trimmed string, or `null` for a non-string and for a string that
169
+ * is empty or whitespace-only — inputs no grammar below could accept anyway.
170
+ */
171
+ function asInputString(value) {
172
+ if (typeof value !== "string")
173
+ return null;
174
+ const trimmed = value.trim();
175
+ return trimmed === "" ? null : trimmed;
176
+ }
177
+ /** `null`/`array`/`number`/… — `typeof` with the two cases it gets wrong fixed. */
178
+ function typeNameOf(value) {
179
+ if (value === null)
180
+ return "null";
181
+ if (Array.isArray(value))
182
+ return "array";
183
+ return typeof value;
184
+ }
185
+ /**
186
+ * Render any value as a string without ever throwing.
187
+ *
188
+ * `String(value)` is not total: an object with a null prototype, or one whose
189
+ * `toString`/`Symbol.toPrimitive` throws, throws from the conversion itself —
190
+ * which would turn *reporting* a bad input into exactly the exception this
191
+ * module promises never to raise.
192
+ */
193
+ function stringifySafely(value) {
194
+ if (value === null)
195
+ return "null";
196
+ if (value === undefined)
197
+ return "undefined";
198
+ try {
199
+ return String(value);
200
+ }
201
+ catch {
202
+ return `[unstringifiable ${typeof value}]`;
203
+ }
204
+ }
205
+ /** The input as the `installedVersion` echo field, whose declared type is `string`. */
206
+ function echoInput(value) {
207
+ return typeof value === "string" ? value : stringifySafely(value);
208
+ }
209
+ /** The input as it appears in a `reason`: quoted when a string, named when not. */
210
+ function describeInput(value) {
211
+ if (typeof value === "string")
212
+ return `'${value}'`;
213
+ if (value === null || value === undefined)
214
+ return stringifySafely(value);
215
+ return `a ${typeNameOf(value)} (${stringifySafely(value)})`;
216
+ }
217
+ /**
218
+ * Grade an installed version against the compatibility floor.
219
+ *
220
+ * Pure and total: it reads no environment, touches no keychain, and **never
221
+ * throws** — a version string it cannot parse comes back as
222
+ * `grade: "unknown"` naming the problem. Totality is enforced here rather than
223
+ * assumed of the parser: input is narrowed by this module's own guard, so a JS
224
+ * caller handing it `null`, `undefined`, a number or an object gets the same
225
+ * typed `"unknown"` result as a misspelt version, never an exception. Call it
226
+ * from a `doctor`, a startup log line, or a CI check; do not call it from a
227
+ * code path that would refuse to run on the answer.
228
+ *
229
+ * @param installedVersion - the version actually installed in the consumer's
230
+ * tree. Import {@link SECRETS_PACKAGE_VERSION} for that; a leading `v` and
231
+ * surrounding whitespace are tolerated.
232
+ * @param floor - the gap table to grade against. Defaults to
233
+ * {@link COMPATIBILITY_FLOOR}; injectable so a test can grade a fixture table
234
+ * without pinning itself to the shipped one.
235
+ */
236
+ export function assessCompatibility(installedVersion, floor = COMPATIBILITY_FLOOR) {
237
+ const base = {
238
+ // Echoed through the guard so the declared `string` type of this field is
239
+ // true at runtime too, for a caller that got here holding a non-string.
240
+ installedVersion: echoInput(installedVersion),
241
+ currentVersion: SECRETS_PACKAGE_VERSION,
242
+ minAssessableVersion: MIN_ASSESSABLE_VERSION,
243
+ };
244
+ const candidate = asInputString(installedVersion);
245
+ const installed = candidate === null ? null : tryParseSemver(candidate);
246
+ if (installed === null) {
247
+ const reason = `${describeInput(installedVersion)} is not a parseable semantic version`;
248
+ return {
249
+ ...base,
250
+ grade: "unknown",
251
+ openGaps: [],
252
+ highestSeverity: null,
253
+ reason,
254
+ summary: `@centient/secrets compatibility not assessed: ${reason}`,
255
+ };
256
+ }
257
+ // A gap with an unparseable `closedIn` cannot be positioned against the
258
+ // installed version. Reporting it as closed would understate the risk, so it
259
+ // is reported as OPEN: over-reporting is recoverable, silence is not.
260
+ const openGaps = floor.filter((gap) => {
261
+ const closedIn = tryParseSemver(gap.closedIn);
262
+ return closedIn === null || compareSemver(installed, closedIn) < 0;
263
+ });
264
+ const highestSeverity = openGaps.reduce((worst, gap) => worst === null || SEVERITY_RANK[gap.severity] > SEVERITY_RANK[worst] ? gap.severity : worst, null);
265
+ const minAssessable = tryParseSemver(MIN_ASSESSABLE_VERSION);
266
+ const belowFloor = minAssessable !== null && compareSemver(installed, minAssessable) < 0;
267
+ if (belowFloor) {
268
+ const reason = `${base.installedVersion} is below ${MIN_ASSESSABLE_VERSION}, the oldest version this table describes; ` +
269
+ `the ${openGaps.length} gap(s) listed are what is known, not necessarily all that is open`;
270
+ return {
271
+ ...base,
272
+ grade: "unsupported",
273
+ openGaps,
274
+ highestSeverity,
275
+ reason,
276
+ summary: `@centient/secrets ${base.installedVersion} is older than this table covers (below ${MIN_ASSESSABLE_VERSION}); upgrade to ${SECRETS_PACKAGE_VERSION}`,
277
+ };
278
+ }
279
+ if (openGaps.length === 0) {
280
+ return {
281
+ ...base,
282
+ grade: "ok",
283
+ openGaps,
284
+ highestSeverity: null,
285
+ summary: `@centient/secrets ${base.installedVersion} has no known open compatibility gaps`,
286
+ };
287
+ }
288
+ const worstFix = openGaps[openGaps.length - 1].closedIn;
289
+ return {
290
+ ...base,
291
+ grade: "degraded",
292
+ openGaps,
293
+ highestSeverity,
294
+ summary: `@centient/secrets ${base.installedVersion} has ${openGaps.length} known open gap(s) (highest severity: ${highestSeverity}); all are closed by ${worstFix}`,
295
+ };
296
+ }
297
+ /**
298
+ * The complete grammar {@link lowestVersionInRange} resolves, anchored.
299
+ *
300
+ * Anchored on purpose. The previous implementation asked only whether the
301
+ * string *started with* `^`, `~` or `>=` and then handed everything after the
302
+ * prefix to the parser, so a composite range like `>=0.6.0 <0.8.0` was rejected
303
+ * only as a side effect of its tail failing to parse. Any parser lenience —
304
+ * ignored build metadata, a tolerated trailing token — would silently reduce a
305
+ * two-sided range to its lower bound and grade a version the pin does not pin
306
+ * (`[mb:f/a6210f]`). Matching the WHOLE range means an unsupported form is
307
+ * rejected by the grammar, never by luck.
308
+ *
309
+ * Accepted, and nothing else:
310
+ *
311
+ * | Form | Example |
312
+ * |---|---|
313
+ * | caret | `^0.6.0` |
314
+ * | tilde | `~0.9.1` |
315
+ * | inclusive lower bound | `>=0.8.0` |
316
+ * | exact | `0.10.0` |
317
+ *
318
+ * The version component is a full `major.minor.patch`, optionally with a
319
+ * conventional leading `v` and a `-prerelease` suffix (kept, not rounded off —
320
+ * see below). Horizontal whitespace is allowed after the operator and around
321
+ * the whole range, and nowhere else.
322
+ *
323
+ * Rejected, each as `null`: composite ranges (`>=0.6.0 <0.8.0`), `||` unions,
324
+ * hyphen ranges (`1.0.0 - 2.0.0`), wildcards (`*`, `""`), x-ranges (`1.x`,
325
+ * `1.2.x`), partial versions (`1.2`), upper bounds and exclusive lower bounds
326
+ * (`<0.9.0`, `>0.9.0`), protocol pins (`workspace:*`, `npm:…`, `file:…`, a git
327
+ * URL), build metadata (`^1.2.3+build` — it is *discarded* by the parser rather
328
+ * than interpreted, which is exactly the ignored-suffix case), and anything
329
+ * carrying a trailing token of any kind.
330
+ */
331
+ const SUPPORTED_RANGE = /^(\^|~|>=)?[ \t]*(v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/;
332
+ /** One line naming the whole accepted grammar, for a `reason` a consumer reads. */
333
+ const RANGE_GRAMMAR_HELP = "expected exactly '^x.y.z', '~x.y.z', '>=x.y.z' or 'x.y.z' " +
334
+ "(a leading 'v' and a '-prerelease' suffix are allowed; composite ranges, '||' unions, " +
335
+ "hyphen ranges, wildcards, x-ranges, protocol pins and build metadata are not)";
336
+ /**
337
+ * The single strict resolver behind {@link lowestVersionInRange} and
338
+ * {@link assessPin} — the former discards the reason, the latter grades on it.
339
+ *
340
+ * Two independent checks, both of which must pass: {@link SUPPORTED_RANGE}
341
+ * validates the *shape* of the entire trimmed range, and `tryParseSemver`
342
+ * validates the *contents* of the captured version (per-identifier pre-release
343
+ * rules live there, and stay there). Neither is asked to stand in for the other.
344
+ */
345
+ function resolveRange(range) {
346
+ const candidate = asInputString(range);
347
+ if (candidate === null) {
348
+ return {
349
+ ok: false,
350
+ reason: `${describeInput(range)} is not a range form this helper resolves (${RANGE_GRAMMAR_HELP})`,
351
+ };
352
+ }
353
+ const match = SUPPORTED_RANGE.exec(candidate);
354
+ if (match === null) {
355
+ return {
356
+ ok: false,
357
+ reason: `'${candidate}' is not a range form this helper resolves (${RANGE_GRAMMAR_HELP})`,
358
+ };
359
+ }
360
+ const parsed = tryParseSemver(match[2]);
361
+ if (parsed === null) {
362
+ return {
363
+ ok: false,
364
+ reason: `'${candidate}' has a version component that is not a parseable semantic version (${RANGE_GRAMMAR_HELP})`,
365
+ };
366
+ }
367
+ // Re-serialized rather than returned verbatim, so a leading `v` or stray
368
+ // whitespace is normalized away — but the pre-release suffix is KEPT.
369
+ // Dropping it would round `^1.0.0-rc.1` up to `1.0.0` and credit the consumer
370
+ // for a release it is not running.
371
+ return { ok: true, version: formatSemver(parsed) };
372
+ }
373
+ /**
374
+ * The lowest version a dependency range admits, or `null` when the range form
375
+ * is one this helper does not understand.
376
+ *
377
+ * Deliberately narrow: it recognises the forms that actually appear in the
378
+ * consumers' manifests — `^x.y.z`, `~x.y.z`, `>=x.y.z` and a bare `x.y.z` — and
379
+ * returns `null` for everything else rather than guessing. A guess here would
380
+ * grade the wrong version and report a clean bill of health for a pin nobody
381
+ * checked.
382
+ *
383
+ * The accepted grammar is matched whole and enumerated on
384
+ * {@link SUPPORTED_RANGE}; nothing outside it is partially interpreted. Total:
385
+ * a non-string, an empty string, and every unsupported form all return `null`.
386
+ */
387
+ export function lowestVersionInRange(range) {
388
+ const resolved = resolveRange(range);
389
+ return resolved.ok ? resolved.version : null;
390
+ }
391
+ /**
392
+ * Grade a manifest **pin** by its worst admissible version.
393
+ *
394
+ * `assessCompatibility` answers "what is open in the build I imported"; this
395
+ * answers "what could be open in any build this pin admits". A `^0.6.0` pin can
396
+ * resolve to any 0.6.x, so the version worth grading is its base — which is also
397
+ * the one a lockfile that has never been refreshed is most likely holding.
398
+ *
399
+ * Returns `grade: "unknown"` carrying the reason for a range form
400
+ * {@link lowestVersionInRange} does not recognise — including a non-string a JS
401
+ * caller slipped past the signature. Never throws.
402
+ */
403
+ export function assessPin(pin, floor = COMPATIBILITY_FLOOR) {
404
+ const resolved = resolveRange(pin);
405
+ if (!resolved.ok) {
406
+ return {
407
+ grade: "unknown",
408
+ installedVersion: echoInput(pin),
409
+ currentVersion: SECRETS_PACKAGE_VERSION,
410
+ minAssessableVersion: MIN_ASSESSABLE_VERSION,
411
+ openGaps: [],
412
+ highestSeverity: null,
413
+ reason: resolved.reason,
414
+ summary: `@centient/secrets compatibility not assessed: ${resolved.reason}`,
415
+ };
416
+ }
417
+ return assessCompatibility(resolved.version, floor);
418
+ }
419
+ //# sourceMappingURL=compatibility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compatibility.js","sourceRoot":"","sources":["../src/compatibility.ts"],"names":[],"mappings":"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"}