@homeflare/alchemy 0.4.1 → 0.6.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 (215) hide show
  1. package/README.md +26 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/launchd/fake-runner.d.ts +36 -0
  5. package/dist/launchd/fake-runner.d.ts.map +1 -0
  6. package/dist/launchd/host-effect.d.ts +19 -0
  7. package/dist/launchd/host-effect.d.ts.map +1 -0
  8. package/dist/launchd/host-file-form.d.ts +24 -0
  9. package/dist/launchd/host-file-form.d.ts.map +1 -0
  10. package/dist/launchd/host-file-lifecycle.d.ts +29 -0
  11. package/dist/launchd/host-file-lifecycle.d.ts.map +1 -0
  12. package/dist/launchd/host-file.d.ts +25 -0
  13. package/dist/launchd/host-file.d.ts.map +1 -0
  14. package/dist/launchd/host-lookup.d.ts +27 -0
  15. package/dist/launchd/host-lookup.d.ts.map +1 -0
  16. package/dist/launchd/index.d.ts +21 -0
  17. package/dist/launchd/index.d.ts.map +1 -0
  18. package/dist/launchd/index.js +969 -0
  19. package/dist/launchd/index.js.map +25 -0
  20. package/dist/launchd/job-form.d.ts +90 -0
  21. package/dist/launchd/job-form.d.ts.map +1 -0
  22. package/dist/launchd/job-lifecycle.d.ts +34 -0
  23. package/dist/launchd/job-lifecycle.d.ts.map +1 -0
  24. package/dist/launchd/job-preflight.d.ts +50 -0
  25. package/dist/launchd/job-preflight.d.ts.map +1 -0
  26. package/dist/launchd/job-validate.d.ts +25 -0
  27. package/dist/launchd/job-validate.d.ts.map +1 -0
  28. package/dist/launchd/job.d.ts +34 -0
  29. package/dist/launchd/job.d.ts.map +1 -0
  30. package/dist/launchd/launchctl.d.ts +62 -0
  31. package/dist/launchd/launchctl.d.ts.map +1 -0
  32. package/dist/launchd/local-runner.d.ts +7 -0
  33. package/dist/launchd/local-runner.d.ts.map +1 -0
  34. package/dist/launchd/plist.d.ts +41 -0
  35. package/dist/launchd/plist.d.ts.map +1 -0
  36. package/dist/launchd/providers.d.ts +15 -0
  37. package/dist/launchd/providers.d.ts.map +1 -0
  38. package/dist/launchd/runner.d.ts +91 -0
  39. package/dist/launchd/runner.d.ts.map +1 -0
  40. package/dist/launchd/secret-tripwire.d.ts +23 -0
  41. package/dist/launchd/secret-tripwire.d.ts.map +1 -0
  42. package/dist/openbao/approle-login-form.d.ts +72 -0
  43. package/dist/openbao/approle-login-form.d.ts.map +1 -0
  44. package/dist/openbao/approle-login-result.d.ts +39 -0
  45. package/dist/openbao/approle-login-result.d.ts.map +1 -0
  46. package/dist/openbao/approle-login.d.ts +77 -0
  47. package/dist/openbao/approle-login.d.ts.map +1 -0
  48. package/dist/openbao/auth-method-form.d.ts +7 -0
  49. package/dist/openbao/auth-method-form.d.ts.map +1 -1
  50. package/dist/openbao/auth-method-reconcile.d.ts +15 -0
  51. package/dist/openbao/auth-method-reconcile.d.ts.map +1 -0
  52. package/dist/openbao/auth-method.d.ts +6 -0
  53. package/dist/openbao/auth-method.d.ts.map +1 -1
  54. package/dist/openbao/auth-role-form.d.ts +9 -0
  55. package/dist/openbao/auth-role-form.d.ts.map +1 -1
  56. package/dist/openbao/auth-role.d.ts.map +1 -1
  57. package/dist/openbao/auth-token-form.d.ts +48 -0
  58. package/dist/openbao/auth-token-form.d.ts.map +1 -0
  59. package/dist/openbao/bao-http.d.ts +2 -0
  60. package/dist/openbao/bao-http.d.ts.map +1 -1
  61. package/dist/openbao/bao-identity.d.ts +81 -0
  62. package/dist/openbao/bao-identity.d.ts.map +1 -0
  63. package/dist/openbao/bao-namespace.d.ts +20 -0
  64. package/dist/openbao/bao-namespace.d.ts.map +1 -0
  65. package/dist/openbao/cloudflare-roles-expand.d.ts.map +1 -1
  66. package/dist/openbao/host-approles.d.ts +62 -0
  67. package/dist/openbao/host-approles.d.ts.map +1 -0
  68. package/dist/openbao/index.d.ts +26 -0
  69. package/dist/openbao/index.d.ts.map +1 -1
  70. package/dist/openbao/index.js +1889 -477
  71. package/dist/openbao/index.js.map +46 -17
  72. package/dist/openbao/jwt-config-form.d.ts +51 -0
  73. package/dist/openbao/jwt-config-form.d.ts.map +1 -0
  74. package/dist/openbao/jwt-config.d.ts +25 -0
  75. package/dist/openbao/jwt-config.d.ts.map +1 -0
  76. package/dist/openbao/jwt-role-form.d.ts +91 -0
  77. package/dist/openbao/jwt-role-form.d.ts.map +1 -0
  78. package/dist/openbao/jwt-role.d.ts +31 -0
  79. package/dist/openbao/jwt-role.d.ts.map +1 -0
  80. package/dist/openbao/kubernetes-role-form.d.ts +68 -0
  81. package/dist/openbao/kubernetes-role-form.d.ts.map +1 -0
  82. package/dist/openbao/kubernetes-role.d.ts +25 -0
  83. package/dist/openbao/kubernetes-role.d.ts.map +1 -0
  84. package/dist/openbao/mfa-enforcement-form.d.ts +46 -0
  85. package/dist/openbao/mfa-enforcement-form.d.ts.map +1 -0
  86. package/dist/openbao/mfa-enforcement.d.ts +41 -0
  87. package/dist/openbao/mfa-enforcement.d.ts.map +1 -0
  88. package/dist/openbao/mfa-totp-form.d.ts +52 -0
  89. package/dist/openbao/mfa-totp-form.d.ts.map +1 -0
  90. package/dist/openbao/mfa-totp.d.ts +33 -0
  91. package/dist/openbao/mfa-totp.d.ts.map +1 -0
  92. package/dist/openbao/mfa-wire.d.ts +63 -0
  93. package/dist/openbao/mfa-wire.d.ts.map +1 -0
  94. package/dist/openbao/mount-form.d.ts +7 -0
  95. package/dist/openbao/mount-form.d.ts.map +1 -1
  96. package/dist/openbao/mount-move.d.ts +49 -0
  97. package/dist/openbao/mount-move.d.ts.map +1 -0
  98. package/dist/openbao/mount-path.d.ts +18 -0
  99. package/dist/openbao/mount-path.d.ts.map +1 -0
  100. package/dist/openbao/mount-reconcile.d.ts +16 -0
  101. package/dist/openbao/mount-reconcile.d.ts.map +1 -0
  102. package/dist/openbao/mount.d.ts +9 -0
  103. package/dist/openbao/mount.d.ts.map +1 -1
  104. package/dist/openbao/pki-role-canonical.d.ts +46 -0
  105. package/dist/openbao/pki-role-canonical.d.ts.map +1 -0
  106. package/dist/openbao/pki-role-form.d.ts +38 -30
  107. package/dist/openbao/pki-role-form.d.ts.map +1 -1
  108. package/dist/openbao/pki-role.d.ts.map +1 -1
  109. package/dist/openbao/plugin-form.d.ts +60 -0
  110. package/dist/openbao/plugin-form.d.ts.map +1 -0
  111. package/dist/openbao/plugin-reconcile.d.ts +18 -0
  112. package/dist/openbao/plugin-reconcile.d.ts.map +1 -0
  113. package/dist/openbao/plugin-wire.d.ts +45 -0
  114. package/dist/openbao/plugin-wire.d.ts.map +1 -0
  115. package/dist/openbao/plugin.d.ts +31 -0
  116. package/dist/openbao/plugin.d.ts.map +1 -0
  117. package/dist/openbao/remount-wire.d.ts +44 -0
  118. package/dist/openbao/remount-wire.d.ts.map +1 -0
  119. package/dist/openbao/role-reconcile.d.ts +40 -0
  120. package/dist/openbao/role-reconcile.d.ts.map +1 -0
  121. package/dist/openbao/ssh-role-form.d.ts +6 -5
  122. package/dist/openbao/ssh-role-form.d.ts.map +1 -1
  123. package/dist/openbao/ssh-role.d.ts.map +1 -1
  124. package/docs/launchd.md +167 -0
  125. package/package.json +7 -2
  126. package/src/index.ts +1 -0
  127. package/src/launchd/fake-runner.ts +176 -0
  128. package/src/launchd/host-effect.ts +28 -0
  129. package/src/launchd/host-file-form.ts +71 -0
  130. package/src/launchd/host-file-lifecycle.test.ts +198 -0
  131. package/src/launchd/host-file-lifecycle.ts +164 -0
  132. package/src/launchd/host-file.ts +64 -0
  133. package/src/launchd/host-lookup.test.ts +92 -0
  134. package/src/launchd/host-lookup.ts +94 -0
  135. package/src/launchd/index.ts +26 -0
  136. package/src/launchd/job-form.test.ts +171 -0
  137. package/src/launchd/job-form.ts +180 -0
  138. package/src/launchd/job-identity.test.ts +147 -0
  139. package/src/launchd/job-lifecycle.test.ts +220 -0
  140. package/src/launchd/job-lifecycle.ts +194 -0
  141. package/src/launchd/job-preflight.ts +152 -0
  142. package/src/launchd/job-validate.ts +134 -0
  143. package/src/launchd/job.ts +96 -0
  144. package/src/launchd/launchctl.test.ts +181 -0
  145. package/src/launchd/launchctl.ts +188 -0
  146. package/src/launchd/local-runner.test.ts +125 -0
  147. package/src/launchd/local-runner.ts +143 -0
  148. package/src/launchd/plist.test.ts +186 -0
  149. package/src/launchd/plist.ts +156 -0
  150. package/src/launchd/providers.test.ts +222 -0
  151. package/src/launchd/providers.ts +21 -0
  152. package/src/launchd/runner.ts +95 -0
  153. package/src/launchd/secret-tripwire.test.ts +110 -0
  154. package/src/launchd/secret-tripwire.ts +81 -0
  155. package/src/openbao/README.md +181 -0
  156. package/src/openbao/REPLACE.md +87 -0
  157. package/src/openbao/approle-login-form.test.ts +64 -0
  158. package/src/openbao/approle-login-form.ts +153 -0
  159. package/src/openbao/approle-login-result.ts +96 -0
  160. package/src/openbao/approle-login.test.ts +200 -0
  161. package/src/openbao/approle-login.ts +156 -0
  162. package/src/openbao/auth-method-form.ts +7 -0
  163. package/src/openbao/auth-method-reconcile.ts +74 -0
  164. package/src/openbao/auth-method.ts +20 -41
  165. package/src/openbao/auth-role-form.test.ts +57 -0
  166. package/src/openbao/auth-role-form.ts +11 -0
  167. package/src/openbao/auth-role.ts +12 -0
  168. package/src/openbao/auth-token-form.ts +161 -0
  169. package/src/openbao/bao-http.ts +2 -0
  170. package/src/openbao/bao-identity.test.ts +131 -0
  171. package/src/openbao/bao-identity.ts +188 -0
  172. package/src/openbao/bao-namespace.ts +32 -0
  173. package/src/openbao/cloudflare-roles-expand.ts +2 -5
  174. package/src/openbao/host-approles.test.ts +121 -0
  175. package/src/openbao/host-approles.ts +126 -0
  176. package/src/openbao/index.ts +32 -0
  177. package/src/openbao/jwt-config-form.ts +161 -0
  178. package/src/openbao/jwt-config.ts +85 -0
  179. package/src/openbao/jwt-role-form.test.ts +130 -0
  180. package/src/openbao/jwt-role-form.ts +231 -0
  181. package/src/openbao/jwt-role.ts +102 -0
  182. package/src/openbao/kubernetes-role-form.test.ts +82 -0
  183. package/src/openbao/kubernetes-role-form.ts +149 -0
  184. package/src/openbao/kubernetes-role.ts +94 -0
  185. package/src/openbao/mfa-enforcement-form.ts +147 -0
  186. package/src/openbao/mfa-enforcement.ts +143 -0
  187. package/src/openbao/mfa-totp-form.ts +155 -0
  188. package/src/openbao/mfa-totp.ts +118 -0
  189. package/src/openbao/mfa-wire.ts +117 -0
  190. package/src/openbao/mfa.test.ts +200 -0
  191. package/src/openbao/mount-form.ts +9 -1
  192. package/src/openbao/mount-move.test.ts +164 -0
  193. package/src/openbao/mount-move.ts +113 -0
  194. package/src/openbao/mount-path.test.ts +33 -0
  195. package/src/openbao/mount-path.ts +31 -0
  196. package/src/openbao/mount-reconcile.ts +75 -0
  197. package/src/openbao/mount-wire.test.ts +13 -0
  198. package/src/openbao/mount.ts +26 -43
  199. package/src/openbao/pki-role-canonical.ts +163 -0
  200. package/src/openbao/pki-role-form.test.ts +112 -0
  201. package/src/openbao/pki-role-form.ts +76 -110
  202. package/src/openbao/pki-role.ts +12 -27
  203. package/src/openbao/plugin-form.test.ts +86 -0
  204. package/src/openbao/plugin-form.ts +164 -0
  205. package/src/openbao/plugin-reconcile.ts +92 -0
  206. package/src/openbao/plugin-wire.test.ts +146 -0
  207. package/src/openbao/plugin-wire.ts +65 -0
  208. package/src/openbao/plugin.ts +100 -0
  209. package/src/openbao/remount-wire.test.ts +87 -0
  210. package/src/openbao/remount-wire.ts +112 -0
  211. package/src/openbao/role-reconcile.test.ts +104 -0
  212. package/src/openbao/role-reconcile.ts +84 -0
  213. package/src/openbao/ssh-role-form.test.ts +105 -0
  214. package/src/openbao/ssh-role-form.ts +18 -16
  215. package/src/openbao/ssh-role.ts +3 -4
@@ -1 +1 @@
1
- {"version":3,"file":"mount-form.d.ts","sourceRoot":"","sources":["../../src/openbao/mount-form.ts"],"names":[],"mappings":"AAEA,0FAA0F;AAC1F,eAAO,MAAM,SAAS,SAAU,MAAM,WAA6B,CAAC;AAIpE,qEAAqE;AACrE,eAAO,MAAM,aAAa,SAAU,MAAM,KAAG,MAAM,GAAG,SAkBrD,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,UAAU,UAAW,OAAO,KAAG,MAAM,GAAG,SAIpD,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,sGAAsG;IACtG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mCAAmC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kGAAkG;IAClG,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB;AAiBD,eAAO,MAAM,YAAY,UAChB,aAAa,QACd,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,kBAYF,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,QAAQ,SAAU,MAAM,WAAoC,CAAC;AAE1E;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,SAAU,MAAM,WAA6B,CAAC;AAEnE;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,UAAW,aAAa,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CACsB,CAAC;AAE/F;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,UAAW,aAAa,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAMpE,CAAC;AASF,6EAA6E;AAC7E,eAAO,MAAM,OAAO,eAAgB,kBAAkB,SAAS,aAAa,YAIxB,CAAC;AAErD,eAAO,MAAM,SAAS,UAAW,aAAa,YAGb,CAAC"}
1
+ {"version":3,"file":"mount-form.d.ts","sourceRoot":"","sources":["../../src/openbao/mount-form.ts"],"names":[],"mappings":"AAGA,0FAA0F;AAC1F,eAAO,MAAM,SAAS,SAAU,MAAM,WAA8B,CAAC;AAIrE,qEAAqE;AACrE,eAAO,MAAM,aAAa,SAAU,MAAM,KAAG,MAAM,GAAG,SAkBrD,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,UAAU,UAAW,OAAO,KAAG,MAAM,GAAG,SAIpD,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,sGAAsG;IACtG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mCAAmC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kGAAkG;IAClG,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IAChB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB;AAiBD,eAAO,MAAM,YAAY,UAChB,aAAa,QACd,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,kBAYF,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,QAAQ,SAAU,MAAM,WAAoC,CAAC;AAE1E;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,SAAU,MAAM,WAA6B,CAAC;AAEnE;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,UAAW,aAAa,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CACsB,CAAC;AAE/F;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,UAAW,aAAa,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAMpE,CAAC;AASF,6EAA6E;AAC7E,eAAO,MAAM,OAAO,eAAgB,kBAAkB,SAAS,aAAa,YAIxB,CAAC;AAErD,eAAO,MAAM,SAAS,UAAW,aAAa,YAGb,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * What a changed path means for Bao.Mount and Bao.AuthMethod — and the move, when one is declared.
3
+ *
4
+ * ⛔ A CHANGED PATH USED TO PLAN `update` AND ENABLE AN EMPTY MOUNT AT THE NEW PATH. diff read the
5
+ * new path, found nothing, answered `update`, and reconcile ran `enable` there: a fresh, empty
6
+ * `kv2/` beside the retained `kv/` that still held every secret, with Alchemy's state now naming
7
+ * only the empty one. Nothing failed, so nothing said so (site-config plan, Guards).
8
+ * ★ NOW A CHANGED PATH FAILS AT PLAN TIME, unless the declaration says where it came from:
9
+ * `remountFrom: '<old path>'` moves the mount with `sys/remount` (remount-wire.ts), which keeps
10
+ * every secret. A genuinely new, empty mount is a new resource id, never an edited path.
11
+ * ★ THE MOVE IS DECIDED BY LIVE STATE, SO A RE-RUN CONVERGES. Source present and target absent is
12
+ * a move; target present and source absent is a move that already happened; both present, or
13
+ * neither, is a refusal — "neither" in particular is exactly the empty-mount failure above.
14
+ */
15
+ import * as Effect from 'effect/Effect';
16
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
17
+ import type { BaoError } from './bao-status.ts';
18
+ import { type RemountError, type RemountOptions } from './remount-wire.ts';
19
+ export type Move = {
20
+ readonly kind: 'stay';
21
+ } | {
22
+ readonly kind: 'move';
23
+ readonly from: string;
24
+ } | {
25
+ readonly kind: 'refuse';
26
+ readonly message: string;
27
+ };
28
+ /**
29
+ * @param family `Bao.Mount` or `Bao.AuthMethod`, for the message.
30
+ * @param stated the path Alchemy's state holds, or undefined on a first reconcile.
31
+ * @param path the declared path.
32
+ * @param remountFrom the declared source, if any.
33
+ */
34
+ export declare const planMove: (family: string, stated: string | undefined, path: string, remountFrom: string | undefined) => Move;
35
+ export interface MoveTarget {
36
+ readonly family: string;
37
+ /** Declared path, bare. */
38
+ readonly path: string;
39
+ readonly type: string;
40
+ /** Read one path's live entry — undefined when absent. */
41
+ readonly read: (path: string) => Effect.Effect<{
42
+ readonly type: string;
43
+ } | undefined, BaoError, HttpClient.HttpClient>;
44
+ /** The path as sys/remount takes it: the bare path for secrets, `auth/<path>` for auth. */
45
+ readonly wire: (path: string) => string;
46
+ }
47
+ /** Perform a planned move, deciding by live state. Returns once the target is in place. */
48
+ export declare const performMove: (target: MoveTarget, from: string, options?: RemountOptions) => Effect.Effect<void, BaoError | RemountError, HttpClient.HttpClient>;
49
+ //# sourceMappingURL=mount-move.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-move.d.ts","sourceRoot":"","sources":["../../src/openbao/mount-move.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAkB,MAAM,mBAAmB,CAAC;AAE3F,MAAM,MAAM,IAAI,GACZ;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,WACX,MAAM,UACN,MAAM,GAAG,SAAS,QACpB,MAAM,eACC,MAAM,GAAG,SAAS,KAC9B,IAyBF,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,2BAA2B;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,CACb,IAAI,EAAE,MAAM,KACT,MAAM,CAAC,MAAM,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;IAC3F,2FAA2F;IAC3F,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACzC;AAID,2FAA2F;AAC3F,eAAO,MAAM,WAAW,WACd,UAAU,QACZ,MAAM,YACF,cAAc,KACvB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,YAAY,EAAE,UAAU,CAAC,UAAU,CA6BjE,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Trimming runs of one character from caller-supplied paths and names.
3
+ *
4
+ * ★ LOOPS, NOT `/^\/+|\/+$/g`, `/\/+$/` OR `/^-+|-+$/g`. A trailing `x+$` backtracks polynomially
5
+ * on a long run of `x` followed by anything else (CodeQL js/polynomial-redos), and mount paths,
6
+ * namespaces and slugs are caller input. Every loop here is linear in the input length.
7
+ */
8
+ /** `text` without a trailing run of `char` (one UTF-16 unit). */
9
+ export declare const trimTrailing: (text: string, char: string) => string;
10
+ /** `text` without a leading or trailing run of `char` (one UTF-16 unit). */
11
+ export declare const trimRuns: (text: string, char: string) => string;
12
+ /** `text` without trailing `/`. */
13
+ export declare const trimTrailingSlashes: (text: string) => string;
14
+ /** `text` without leading or trailing `/`. */
15
+ export declare const trimSlashes: (text: string) => string;
16
+ /** SSH mount path without a trailing slash; `ssh` when the caller did not say. */
17
+ export declare const sshMountOf: (mount: string | undefined) => string;
18
+ //# sourceMappingURL=mount-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-path.d.ts","sourceRoot":"","sources":["../../src/openbao/mount-path.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,iEAAiE;AACjE,eAAO,MAAM,YAAY,SAAU,MAAM,QAAQ,MAAM,KAAG,MAIzD,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,QAAQ,SAAU,MAAM,QAAQ,MAAM,KAAG,MAIrD,CAAC;AAEF,mCAAmC;AACnC,eAAO,MAAM,mBAAmB,SAAU,MAAM,KAAG,MAAiC,CAAC;AAErF,8CAA8C;AAC9C,eAAO,MAAM,WAAW,SAAU,MAAM,KAAG,MAA6B,CAAC;AAEzE,kFAAkF;AAClF,eAAO,MAAM,UAAU,UAAW,MAAM,GAAG,SAAS,KAAG,MAClB,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Bao.Mount's read and reconcile as plain effects — split from mount.ts so the move (and its
3
+ * refusals) run against a fake server, not only in a reviewer's head.
4
+ */
5
+ import * as Effect from 'effect/Effect';
6
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
7
+ import type { BaoError } from './bao-status.ts';
8
+ import { type BaoMountAttributes, type BaoMountProps } from './mount-form.ts';
9
+ import type { RemountError, RemountOptions } from './remount-wire.ts';
10
+ export declare const readMount: (props: BaoMountProps) => Effect.Effect<BaoMountAttributes | undefined, BaoError, HttpClient.HttpClient>;
11
+ /**
12
+ * Converge one mount. `stated` is the path in Alchemy's state (undefined on a first reconcile).
13
+ * Dies on a refusal; fails with OpenBao's own error on a refused call.
14
+ */
15
+ export declare const reconcileMount: (news: BaoMountProps, stated: string | undefined, options?: RemountOptions) => Effect.Effect<BaoMountAttributes, BaoError | RemountError, HttpClient.HttpClient>;
16
+ //# sourceMappingURL=mount-reconcile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-reconcile.d.ts","sourceRoot":"","sources":["../../src/openbao/mount-reconcile.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAKnB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEtE,eAAO,MAAM,SAAS,UACb,aAAa,KACnB,MAAM,CAAC,MAAM,CAAC,kBAAkB,GAAG,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAK5E,CAAC;AAUL;;;GAGG;AACH,eAAO,MAAM,cAAc,SACnB,aAAa,UACX,MAAM,GAAG,SAAS,YAChB,cAAc,KACvB,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE,QAAQ,GAAG,YAAY,EAAE,UAAU,CAAC,UAAU,CA8B/E,CAAC"}
@@ -7,6 +7,15 @@
7
7
  *
8
8
  * ★ `defaultRemovalPolicy: 'retain'` — disabling a mount destroys every secret under it.
9
9
  * Opt in with `.pipe(RemovalPolicy.destroy())`; see resource.ts in house/proxmox.
10
+ *
11
+ * ★ REPLACE SEMANTICS (audited 2026-09-21, see src/openbao/REPLACE.md):
12
+ * · `type` changed → plans `replace`, and the APPLY FAILS, destroying nothing: the new
13
+ * generation's path is the old one's, still occupied, so its reconcile dies "type is
14
+ * immutable" before any write (mount-reconcile.ts). Change a type by hand. ⛔ Not `deleteFirst`
15
+ * on purpose — under `destroy` that would disable the mount, every secret with it, on a typo.
16
+ * · `path` changed → FAILS the plan unless `remountFrom` names the old path, which is an
17
+ * in-place `update` that moves the mount and its data (mount-move.ts). It used to be an
18
+ * `update` that enabled an EMPTY mount at the new path.
10
19
  */
11
20
  import { Resource } from 'alchemy';
12
21
  import * as Provider from 'alchemy/Provider';
@@ -1 +1 @@
1
- {"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../src/openbao/mount.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AACnE,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAKnB,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,CAAC;AAElD,MAAM,WAAW,QAAS,SAAQ,QAAQ,CACxC,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,QAAQ,2CAEnB,CAAC;AASH,eAAO,MAAM,gBAAgB,+FAqF1B,CAAC"}
1
+ {"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../src/openbao/mount.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,aAAa,EAAW,MAAM,iBAAiB,CAAC;AAKvF,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,CAAC;AAElD,MAAM,WAAW,QAAS,SAAQ,QAAQ,CACxC,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,QAAQ,2CAEnB,CAAC;AAEH,eAAO,MAAM,gBAAgB,+FAuE1B,CAAC"}
@@ -0,0 +1,46 @@
1
+ import type { BaoPkiRoleProps } from './pki-role-form.ts';
2
+ /**
3
+ * The managed field set, normalised so both sides of a diff are byte-comparable.
4
+ *
5
+ * ⚠️ KEY ORDER IS THE DIGEST. The props side and the live side are both built by the single
6
+ * canonical() literal below, so `JSON.stringify` emits the same key order for each. Two
7
+ * hand-written object literals would drift apart and produce a forever-diff nobody could
8
+ * read from the plan output.
9
+ */
10
+ export interface BaoPkiRoleCanonical {
11
+ allowBareDomains: boolean;
12
+ allowGlobDomains: boolean;
13
+ allowIpSans: boolean;
14
+ allowLocalhost: boolean;
15
+ allowSubdomains: boolean;
16
+ allowWildcardCertificates: boolean;
17
+ allowedDomains: readonly string[];
18
+ allowedDomainsTemplate: boolean;
19
+ clientFlag: boolean;
20
+ cnValidations: readonly string[];
21
+ enforceHostnames: boolean;
22
+ extKeyUsage: readonly string[];
23
+ generateLease: boolean;
24
+ keyBits: number;
25
+ keyType: string;
26
+ keyUsage: readonly string[];
27
+ /** ⚠️ `-1` means the duration prop did not parse — reconcile refuses rather than writing it. */
28
+ maxTtlSeconds: number;
29
+ noStore: boolean;
30
+ requireCn: boolean;
31
+ serverFlag: boolean;
32
+ signatureBits: number;
33
+ ttlSeconds: number;
34
+ }
35
+ /** ★ OpenBao's own `key_usage` default (path_roles.go:697-698) — what an omitted field becomes. */
36
+ export declare const DEFAULT_KEY_USAGE: readonly string[];
37
+ export declare const canonicalFromProps: (props: BaoPkiRoleProps) => BaoPkiRoleCanonical;
38
+ /**
39
+ * ⚠️ AN ABSENT NEW FIELD READS AS ITS ZERO VALUE, NOT ITS SCHEMA DEFAULT. A role read always carries
40
+ * the six new fields (ToResponseData, path_roles.go:1720-1780; `generate_lease` only when set,
41
+ * and getRole upgrades a missing one to false at :1034), so the fallback only answers a body
42
+ * that is not OpenBao's — and then "false"/"none" reads as drift rather than a false noop.
43
+ */
44
+ export declare const canonicalFromLive: (live: Record<string, unknown>) => BaoPkiRoleCanonical;
45
+ export declare const digestOf: (form: BaoPkiRoleCanonical) => string;
46
+ //# sourceMappingURL=pki-role-canonical.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pki-role-canonical.d.ts","sourceRoot":"","sources":["../../src/openbao/pki-role-canonical.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;IACzB,yBAAyB,EAAE,OAAO,CAAC;IACnC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,sBAAsB,EAAE,OAAO,CAAC;IAChC,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,gGAAgG;IAChG,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,mGAAmG;AACnG,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAI9C,CAAC;AAqCF,eAAO,MAAM,kBAAkB,UAAW,eAAe,KAAG,mBAwBxD,CAAC;AAYL;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,SAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,mBAwB9D,CAAC;AAEL,eAAO,MAAM,QAAQ,SAAU,mBAAmB,KAAG,MAAsC,CAAC"}
@@ -1,3 +1,5 @@
1
+ import { type BaoPkiRoleCanonical } from './pki-role-canonical.ts';
2
+ export type { BaoPkiRoleCanonical };
1
3
  /** ★ MEASURED: the OpenAPI enum for `key_type` is exactly these four, lowercase. */
2
4
  export type BaoPkiKeyType = 'any' | 'ec' | 'ed25519' | 'rsa';
3
5
  /** ★ MEASURED: live roles carry `["hostname"]` or the default `["email","hostname"]`. */
@@ -51,33 +53,29 @@ export interface BaoPkiRoleProps {
51
53
  cnValidations?: readonly BaoPkiCnValidation[];
52
54
  /** Signature hash bits; `0` auto-detects from key length. One live role pins 256. */
53
55
  signatureBits?: number;
54
- }
55
- /**
56
- * The managed field set, normalised so both sides of a diff are byte-comparable.
57
- *
58
- * ⚠️ KEY ORDER IS THE DIGEST. The props side and the live side are both built by the single
59
- * canonical() literal below, so `JSON.stringify` emits the same key order for each. Two
60
- * hand-written object literals would drift apart and produce a forever-diff nobody could
61
- * read from the plan output.
62
- */
63
- export interface BaoPkiRoleCanonical {
64
- allowBareDomains: boolean;
65
- allowGlobDomains: boolean;
66
- allowIpSans: boolean;
67
- allowLocalhost: boolean;
68
- allowSubdomains: boolean;
69
- allowWildcardCertificates: boolean;
70
- allowedDomains: readonly string[];
71
- clientFlag: boolean;
72
- cnValidations: readonly string[];
73
- extKeyUsage: readonly string[];
74
- keyBits: number;
75
- keyType: string;
76
- /** ⚠️ `-1` means the duration prop did not parse — reconcile refuses rather than writing it. */
77
- maxTtlSeconds: number;
78
- serverFlag: boolean;
79
- signatureBits: number;
80
- ttlSeconds: number;
56
+ /**
57
+ * ★ THE SIX BELOW (added 2026-09-21) default to OpenBao's OWN values, not closed ones — a role this
58
+ * resource wrote before they were props carries exactly those, so it still plans `noop`. The
59
+ * write already sent them implicitly; see the header of pki-role-canonical.ts.
60
+ */
61
+ /** A request must carry a common_name. Default true. */
62
+ requireCn?: boolean;
63
+ /** Only valid host names in the CN and DNS SANs. Default true. */
64
+ enforceHostnames?: boolean;
65
+ /**
66
+ * Key usages minus the `KeyUsage` prefix. Default `DigitalSignature, KeyAgreement,
67
+ * KeyEncipherment`. ⚠️ `[]` is a real value — it removes every key usage — and is sent as such.
68
+ */
69
+ keyUsage?: readonly string[];
70
+ /** Allowed domains may use identity templates (`{{identity.entity.name}}`). Default false. */
71
+ allowedDomainsTemplate?: boolean;
72
+ /**
73
+ * Do not store issued certificates. Default false. ⛔ They can then be neither listed nor
74
+ * revoked. ⚠️ Implies `generateLease: false`; declaring both true is refused (see problems).
75
+ */
76
+ noStore?: boolean;
77
+ /** Attach an OpenBao lease to every issued certificate. Default false — leases slow startup. */
78
+ generateLease?: boolean;
81
79
  }
82
80
  export interface BaoPkiRoleAttributes extends BaoPkiRoleCanonical {
83
81
  name: string;
@@ -88,9 +86,6 @@ export interface BaoPkiRoleAttributes extends BaoPkiRoleCanonical {
88
86
  /** SHA-256 of the canonical form — safe to persist; see policy.ts. */
89
87
  digest: string;
90
88
  }
91
- export declare const canonicalFromProps: (props: BaoPkiRoleProps) => BaoPkiRoleCanonical;
92
- export declare const canonicalFromLive: (live: Record<string, unknown>) => BaoPkiRoleCanonical;
93
- export declare const digestOf: (form: BaoPkiRoleCanonical) => string;
94
89
  export declare const rolePath: (props: {
95
90
  name: string;
96
91
  mount?: string;
@@ -109,10 +104,23 @@ export declare const attributesOf: (props: BaoPkiRoleProps, live: Record<string,
109
104
  * ★ `ext_key_usage` is OMITTED when empty rather than sent as `ext_key_usage=`. The write
110
105
  * replaces the whole role, so an absent field already lands on the `[]` default, and
111
106
  * omitting sidesteps how an empty value would be encoded.
107
+ * ⚠️ `key_usage` CANNOT BE OMITTED THAT WAY — its default is NOT empty — so it is always sent, and
108
+ * an empty declaration goes over as `""`. That encoding is now READ, not guessed: for a
109
+ * comma-string-slice field, go-secure-stdlib parseutil.ParseCommaStringSlice (:389-392)
110
+ * answers `""` with an empty list.
112
111
  *
113
112
  * ★ THE BODY FOR `PUT <mount>/roles/<name>`, ALL STRINGS — the same `k=v` pairs `bao write` sent.
114
113
  */
115
114
  export declare const writeBody: (props: BaoPkiRoleProps) => Record<string, string>;
116
115
  /** True when live already matches the declaration on every managed field. */
117
116
  export declare const matches: (attributes: BaoPkiRoleAttributes, props: BaoPkiRoleProps) => boolean;
117
+ /**
118
+ * Declarations reconcile must refuse rather than write. diff routes any of these to `update` so the
119
+ * refusal is seen on the next deploy, never hidden behind a `noop`.
120
+ *
121
+ * ⚠️ `noStore` WITH `generateLease` IS NOT AN ERROR ON THE SERVER — pathRoleCreate stores
122
+ * generate_lease false and adds a warning (path_roles.go:1250-1256) — so the role would read back
123
+ * different from its declaration and plan `update` forever. Refused here instead.
124
+ */
125
+ export declare const problems: (props: BaoPkiRoleProps) => readonly string[];
118
126
  //# sourceMappingURL=pki-role-form.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pki-role-form.d.ts","sourceRoot":"","sources":["../../src/openbao/pki-role-form.ts"],"names":[],"mappings":"AAGA,oFAAoF;AACpF,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC;AAE7D,yFAAyF;AACzF,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;AAEnE,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,oDAAoD;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iEAAiE;IACjE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;OAMG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,gGAAgG;IAChG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oGAAoG;IACpG,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,gGAAgG;IAChG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kFAAkF;IAClF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iEAAiE;IACjE,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,8FAA8F;IAC9F,aAAa,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC9C,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;IACzB,yBAAyB,EAAE,OAAO,CAAC;IACnC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,gGAAgG;IAChG,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAqB,SAAQ,mBAAmB;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB;AA8BD,eAAO,MAAM,kBAAkB,UAAW,eAAe,KAAG,mBAkBxD,CAAC;AAYL,eAAO,MAAM,iBAAiB,SAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,mBAkB9D,CAAC;AAWL,eAAO,MAAM,QAAQ,SAAU,mBAAmB,WAAiC,CAAC;AAEpF,eAAO,MAAM,QAAQ,UAAW;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,WACN,CAAC;AAE3D,eAAO,MAAM,YAAY,UAChB,eAAe,QAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,oBAUF,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS,UAAW,eAAe,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAsBvE,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,OAAO,eAAgB,oBAAoB,SAAS,eAAe,YACrB,CAAC"}
1
+ {"version":3,"file":"pki-role-form.d.ts","sourceRoot":"","sources":["../../src/openbao/pki-role-form.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,mBAAmB,EAKzB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,oFAAoF;AACpF,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC;AAE7D,yFAAyF;AACzF,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;AAEnE,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,oDAAoD;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iEAAiE;IACjE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;OAMG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,gGAAgG;IAChG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oGAAoG;IACpG,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,gGAAgG;IAChG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kFAAkF;IAClF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iEAAiE;IACjE,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,8FAA8F;IAC9F,aAAa,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC9C,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,wDAAwD;IACxD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,8FAA8F;IAC9F,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gGAAgG;IAChG,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,oBAAqB,SAAQ,mBAAmB;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB;AAWD,eAAO,MAAM,QAAQ,UAAW;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,WACN,CAAC;AAE3D,eAAO,MAAM,YAAY,UAChB,eAAe,QAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,oBAUF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,SAAS,UAAW,eAAe,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CA4BvE,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,OAAO,eAAgB,oBAAoB,SAAS,eAAe,YACrB,CAAC;AAE5D;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,UAAW,eAAe,KAAG,SAAS,MAAM,EAuBhE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"pki-role.d.ts","sourceRoot":"","sources":["../../src/openbao/pki-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAGnE,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EAKrB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,CAAC;AAEtD,MAAM,WAAW,UAAW,SAAQ,QAAQ,CAC1C,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,UAAU,6CAErB,CAAC;AAeH,eAAO,MAAM,kBAAkB,iGAsH5B,CAAC"}
1
+ {"version":3,"file":"pki-role.d.ts","sourceRoot":"","sources":["../../src/openbao/pki-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAGnE,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EAMrB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,CAAC;AAEtD,MAAM,WAAW,UAAW,SAAQ,QAAQ,CAC1C,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,UAAU,6CAErB,CAAC;AASH,eAAO,MAAM,kBAAkB,iGA4G5B,CAAC"}
@@ -0,0 +1,60 @@
1
+ export type BaoPluginType = 'auth' | 'database' | 'secret';
2
+ export interface BaoPluginProps {
3
+ /** Catalog name — what a mount's `type` names, e.g. `openbao-plugin-secrets-cloudflare`. */
4
+ name: string;
5
+ /** Catalog type. `secret` for a secrets engine, `auth` for an auth method. */
6
+ type: BaoPluginType;
7
+ /** Hex SHA-256 of the binary already sitting in plugin_directory. Case is normalised. */
8
+ sha256: string;
9
+ /** The binary's file name inside plugin_directory — a bare name, no path, no arguments. */
10
+ command: string;
11
+ /**
12
+ * Canonical semver with its `v`, e.g. `v0.1.2`. ⚠️ When the binary reports its own version,
13
+ * declare EXACTLY that one: any other is refused at write ("plugin version mismatch",
14
+ * plugin_catalog.go setInternal), and none at all is filed under the reported one — see the ⚠️
15
+ * on SELF_REPORTED in plugin-reconcile.ts.
16
+ */
17
+ version?: string;
18
+ /** Arguments, in order. ⛔ Never a secret: they land in Alchemy state and in every catalog read. */
19
+ args?: readonly string[];
20
+ }
21
+ /** ⛔ NO SECRET HERE — names, a hash, a file name, arguments and a digest. */
22
+ export interface BaoPluginAttributes {
23
+ name: string;
24
+ type: BaoPluginType;
25
+ /** The canonical version the catalog stored, `''` when unversioned. Delete needs it. */
26
+ version: string;
27
+ sha256: string;
28
+ command: string;
29
+ args: readonly string[];
30
+ /** True when the catalog answered with OpenBao's own builtin rather than a registration. */
31
+ builtin: boolean;
32
+ /** SHA-256 of the managed fields — safe to persist; see policy.ts. */
33
+ digest: string;
34
+ }
35
+ /** Every prop resolved to what the register call will store. */
36
+ export type BaoPluginForm = Required<BaoPluginProps>;
37
+ export declare const resolve: (props: BaoPluginProps) => BaoPluginForm;
38
+ /** Everything wrong with the declaration, or `[]`. Checked before any request. */
39
+ export declare const problems: (form: BaoPluginForm) => readonly string[];
40
+ /** `sys/plugins/catalog/<type>/<name>` — register addresses the plugin here. */
41
+ export declare const catalogPath: (type: BaoPluginType, name: string) => string;
42
+ /** Read and delete address one VERSION of the plugin. */
43
+ export declare const versionedPath: (type: BaoPluginType, name: string, version: string) => string;
44
+ /**
45
+ * The register body — the fields RegisterPluginInput sends (api v2.6.0 sys_plugins.go:186-204),
46
+ * which is what `bao plugin register` sends.
47
+ *
48
+ * ★ `type` IS LEFT OUT OF THE BODY ON PURPOSE. The Go client puts it there as a NUMBER (PluginType
49
+ * has no MarshalJSON), and the route's `type` capture is what the handler reads. The path says it.
50
+ * ⛔ NO `env`, EVER. The catalog read never returns env (handlePluginCatalogRead's data map has no
51
+ * such key), so a declared env could not be diffed, and what env exists to carry into a plugin
52
+ * process is exactly what must not sit in Alchemy's unencrypted state. ⚠️ The register call is a
53
+ * FULL REPLACE (setInternal builds a fresh entry), so an env someone set by hand is dropped by
54
+ * the next write — which only happens when a managed field has drifted.
55
+ */
56
+ export declare const registerBody: (form: BaoPluginForm) => Record<string, unknown>;
57
+ export declare const attributesOf: (form: BaoPluginForm, live: Record<string, unknown>) => BaoPluginAttributes;
58
+ /** True when the catalog already holds exactly this registration. A builtin never matches. */
59
+ export declare const matches: (attributes: BaoPluginAttributes, form: BaoPluginForm) => boolean;
60
+ //# sourceMappingURL=plugin-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-form.d.ts","sourceRoot":"","sources":["../../src/openbao/plugin-form.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC7B,4FAA4F;IAC5F,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,IAAI,EAAE,aAAa,CAAC;IACpB,yFAAyF;IACzF,MAAM,EAAE,MAAM,CAAC;IACf,2FAA2F;IAC3F,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mGAAmG;IACnG,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED,6EAA6E;AAC7E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;IACpB,wFAAwF;IACxF,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,4FAA4F;IAC5F,OAAO,EAAE,OAAO,CAAC;IACjB,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,gEAAgE;AAChE,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC;AAErD,eAAO,MAAM,OAAO,UAAW,cAAc,KAAG,aAO9C,CAAC;AAWH,kFAAkF;AAClF,eAAO,MAAM,QAAQ,SAAU,aAAa,KAAG,SAAS,MAAM,EAuB7D,CAAC;AAMF,gFAAgF;AAChF,eAAO,MAAM,WAAW,SAAU,aAAa,QAAQ,MAAM,KAAG,MACzB,CAAC;AAExC,yDAAyD;AACzD,eAAO,MAAM,aAAa,SAAU,aAAa,QAAQ,MAAM,WAAW,MAAM,KAAG,MAC7B,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,SAAU,aAAa,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAKvE,CAAC;AAQH,eAAO,MAAM,YAAY,SACjB,aAAa,QACb,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,mBAWF,CAAC;AAMF,8FAA8F;AAC9F,eAAO,MAAM,OAAO,eAAgB,mBAAmB,QAAQ,aAAa,KAAG,OAKzC,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Bao.Plugin's read and reconcile, as plain effects — split from plugin.ts so the refusals below can
3
+ * be run against a fake server rather than only reasoned about.
4
+ */
5
+ import * as Effect from 'effect/Effect';
6
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
7
+ import type { BaoError } from './bao-status.ts';
8
+ import { type BaoPluginAttributes, type BaoPluginForm, type BaoPluginProps } from './plugin-form.ts';
9
+ type Entry = {
10
+ readonly attributes: BaoPluginAttributes;
11
+ readonly live: Record<string, unknown>;
12
+ };
13
+ /** Live entry, plus the raw body — reconcile needs the raw half for `oci` and `declarative`. */
14
+ export declare const readEntry: (form: BaoPluginForm) => Effect.Effect<Entry | undefined, BaoError, HttpClient.HttpClient>;
15
+ /** Register when the live entry differs, then prove it by reading back. Dies on a refusal. */
16
+ export declare const reconcilePlugin: (props: BaoPluginProps) => Effect.Effect<BaoPluginAttributes, BaoError, HttpClient.HttpClient>;
17
+ export {};
18
+ //# sourceMappingURL=plugin-reconcile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-reconcile.d.ts","sourceRoot":"","sources":["../../src/openbao/plugin-reconcile.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,cAAc,EAMpB,MAAM,kBAAkB,CAAC;AAG1B,KAAK,KAAK,GAAG;IAAE,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAElG,gGAAgG;AAChG,eAAO,MAAM,SAAS,SACd,aAAa,KAClB,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAGhE,CAAC;AAuBJ,8FAA8F;AAC9F,eAAO,MAAM,eAAe,UACnB,cAAc,KACpB,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAsCjE,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The OpenBao calls Bao.Plugin makes — read one catalog entry, register, deregister. Split from
3
+ * plugin.ts so the calls can be pinned against a fake server, the way mount-wire.ts is.
4
+ *
5
+ * ★ ENDPOINTS, READ FROM openbao v2.6.2 api/sys_plugins.go (the client `bao plugin` uses) and the
6
+ * handlers in vault/logical_system.go:
7
+ * read GET sys/plugins/catalog/<type>/<name>[?version=] (GetPlugin, :159-183)
8
+ * register PUT sys/plugins/catalog/<type>/<name> (RegisterPlugin, :212-228)
9
+ * deregister DELETE sys/plugins/catalog/<type>/<name>[?version=] (DeregisterPlugin, :249-261)
10
+ * (api/sys_plugins.go diffed identical between v2.6.0 and v2.6.2.)
11
+ * ⚠️ ALL THREE NEED `sudo` ON THE PATH, not just the verb (docs/api/system/plugins-catalog.mdx). A
12
+ * token without it reads as 403, which is an error here, never "absent".
13
+ */
14
+ import type * as Effect from 'effect/Effect';
15
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
16
+ import type { BaoError } from './bao-status.ts';
17
+ import { type BaoPluginForm, type BaoPluginType } from './plugin-form.ts';
18
+ /**
19
+ * One catalog entry, or undefined when the catalog has none at that name, type and version.
20
+ *
21
+ * ★ UNLIKE A MOUNT, A MISSING PLUGIN REALLY IS A 404. handlePluginCatalogRead returns `nil, nil` when
22
+ * the catalog lookup finds nothing (vault/logical_system.go:545-547), and RespondErrorCommon turns
23
+ * a nil READ response into 404 (sdk v2.6.2 logical/response_util.go:23-26). No second question is
24
+ * needed, unlike the mount-table check in mount-wire.ts.
25
+ * ⚠️ A BUILTIN ANSWERS TOO. With no external registration at an unversioned name, the catalog falls
26
+ * through to OpenBao's own builtin of that name and type (plugin_catalog.go get, :1016-1036), which
27
+ * reads back with `builtin: true` — present, but not a registration. plugin.ts decides what that
28
+ * means.
29
+ */
30
+ export declare const readPluginData: (form: BaoPluginForm) => Effect.Effect<Record<string, unknown> | undefined, BaoError, HttpClient.HttpClient>;
31
+ export declare const registerPlugin: (form: BaoPluginForm) => Effect.Effect<void, BaoError, HttpClient.HttpClient>;
32
+ /**
33
+ * ★ IDEMPOTENT ON THE SERVER. deleteInternal deletes the storage key whether or not it exists
34
+ * (plugin_catalog.go:1272-1284) and the handler answers with no body, so a retried delete succeeds.
35
+ * ⚠️ BUT A MISSING TYPED KEY FALLS BACK TO THE BARE NAME. When `<type>/<name>[/<version>]` is not
36
+ * in storage, the same function deletes the key `<name>` instead — where registrations made
37
+ * before plugin types existed live, whatever their type. A fresh 2.x vault has none; one
38
+ * migrated from an old Vault may. REASONED FROM SOURCE, not run.
39
+ * ⛔ AND THAT IS THE DANGER: NOTHING CHECKS WHETHER A MOUNT STILL USES THE PLUGIN. The same function
40
+ * has no mount lookup at all, so deregistering the plugin a live mount runs succeeds. The running
41
+ * process is not killed by it; the mount breaks the next time OpenBao has to START the plugin — a
42
+ * reload, a restart, an unseal — long after the plan that did it. REASONED FROM SOURCE, not run.
43
+ */
44
+ export declare const deregisterPlugin: (type: BaoPluginType, name: string, version: string) => Effect.Effect<void, BaoError, HttpClient.HttpClient>;
45
+ //# sourceMappingURL=plugin-wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-wire.d.ts","sourceRoot":"","sources":["../../src/openbao/plugin-wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,aAAa,EAInB,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,SACnB,aAAa,KAClB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CACzB,CAAC;AAE7D,eAAO,MAAM,cAAc,SACnB,aAAa,KAClB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CACkB,CAAC;AAEzE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,SACrB,aAAa,QACb,MAAM,WACH,MAAM,KACd,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CACP,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * An OpenBao plugin catalog entry — `sys/plugins/catalog/<type>/<name>`: which binary in
3
+ * plugin_directory, at which SHA-256, may run as a plugin of that name. METADATA ONLY.
4
+ *
5
+ * ⛔ IT REGISTERS; IT DOES NOT DELIVER. The binary must already sit in plugin_directory. Copying it
6
+ * there is a host step.
7
+ * ⚠️ A MISSING FILE FAILS THE WRITE; A WRONG SHA-256 DOES NOT. setInternal (plugin_catalog.go
8
+ * :1150-1230) resolves the path first, which fails loudly, but the run that would notice a
9
+ * checksum mismatch is only the version probe, and that is best-effort: it logs a warning and
10
+ * stores the entry anyway. The mismatch then surfaces when a mount first starts the plugin.
11
+ * ⛔ NO `env` PROP, AND THERE MUST NEVER BE ONE — see registerBody in plugin-form.ts. Alchemy keeps
12
+ * props and attributes UNENCRYPTED in its state store (policy.ts has the reasoning).
13
+ * ⚠️ A NEW SHA-256 DOES NOT RESTART A RUNNING PLUGIN. setInternal writes the catalog entry and
14
+ * reloads nothing, so mounts keep the old process until `sys/plugins/reload/backend` or a
15
+ * restart. Reloading is an operator step, not this resource.
16
+ *
17
+ * ★ `defaultRemovalPolicy: 'retain'`. Deregistering does not check whether a mount still runs the
18
+ * plugin (the ⛔ on deregisterPlugin in plugin-wire.ts), so a destroy would break that mount at its
19
+ * next start. Retain also means a version bump — a REPLACE, below — leaves the old version
20
+ * registered for mounts pinned to it; prune it by hand once nothing uses it.
21
+ */
22
+ import { Resource } from 'alchemy';
23
+ import * as Provider from 'alchemy/Provider';
24
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
25
+ import { type BaoPluginAttributes, type BaoPluginProps } from './plugin-form.ts';
26
+ export type { BaoPluginAttributes, BaoPluginProps, BaoPluginType } from './plugin-form.ts';
27
+ export interface BaoPlugin extends Resource<'Bao.Plugin', BaoPluginProps, BaoPluginAttributes, never, HttpClient.HttpClient> {
28
+ }
29
+ export declare const BaoPlugin: import("alchemy").ResourceClass<BaoPlugin>;
30
+ export declare const BaoPluginProvider: () => import("effect/Layer").Layer<Provider.Provider<BaoPlugin>, never, HttpClient.HttpClient>;
31
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/openbao/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,KAAK,mBAAmB,EAAE,KAAK,cAAc,EAAoB,MAAM,kBAAkB,CAAC;AAInG,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE3F,MAAM,WAAW,SAAU,SAAQ,QAAQ,CACzC,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,SAAS,4CAEpB,CAAC;AAEH,eAAO,MAAM,iBAAiB,gGAuD3B,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * `sys/remount` — move a secrets engine or auth method to a new path WITH its data — and the status
3
+ * polling it needs, because the move finishes after the call returns.
4
+ *
5
+ * ★ READ FROM openbao v2.6.2, NOT RECALLED:
6
+ * · api/sys_mounts.go:95-191 — the CLI's `bao secrets move` POSTs `{from, to}` to sys/remount,
7
+ * takes `data.migration_id`, then GETs sys/remount/status/<id> once a second until
8
+ * `migration_info.status` is `success` or `failure`. This is that loop, bounded.
9
+ * · vault/logical_system.go:1257-1357 — the handler validates, records the migration and
10
+ * answers AT ONCE; a goroutine does the move. So a 200 means "queued", never "moved".
11
+ * · vault/mount.go:630-735 — the mount keeps its UUID, and storage lives under the UUID, so every
12
+ * secret stays. ⛔ BUT EVERY LEASE UNDER THE SOURCE IS REVOKED (`RevokePrefix`, :684): a move of
13
+ * a dynamic-secrets mount kills every credential it has issued. KV has no leases.
14
+ * · vault/logical_system.go:67-69 — `remount` is a sudo path. The status path is not.
15
+ * ⚠️ THE STATUS TRACKER IS IN MEMORY (vault/mount.go:2303-2336, a sync.Map on the active node). A
16
+ * restart or leader change mid-move loses it, and the status read then answers 404. That is not a
17
+ * failure and not a success; `confirm` settles it from the mount tables, or the call fails.
18
+ * ⛔ POLICIES ARE NOT REWRITTEN. Every ACL path naming the old mount keeps naming it.
19
+ */
20
+ import * as Effect from 'effect/Effect';
21
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
22
+ import type { BaoError } from './bao-status.ts';
23
+ /** A move OpenBao reported failed, or one this could not confirm. Never carries a token. */
24
+ export declare class RemountError extends Error {
25
+ constructor(message: string);
26
+ }
27
+ export interface RemountOptions {
28
+ /** Milliseconds between status reads. Default 1000 — the CLI's own pace. */
29
+ readonly intervalMillis?: number;
30
+ /** Status reads before giving up. Default 120, so about two minutes. */
31
+ readonly attempts?: number;
32
+ }
33
+ /** POST sys/remount and return the migration id. `from`/`to` are full paths (`auth/x` for auth). */
34
+ export declare const startRemount: (from: string, to: string) => Effect.Effect<string, BaoError | RemountError, HttpClient.HttpClient>;
35
+ /** `in-progress`, `success`, `failure` — or undefined when the server no longer knows the id. */
36
+ export declare const remountStatus: (id: string) => Effect.Effect<string | undefined, BaoError, HttpClient.HttpClient>;
37
+ /**
38
+ * Move `from` to `to` and wait until OpenBao says it is done.
39
+ *
40
+ * @param confirm answers "does the mount table show the move finished?" — asked only when the
41
+ * status tracker has forgotten the id. True is success; false fails.
42
+ */
43
+ export declare const remountAndWait: (from: string, to: string, confirm: Effect.Effect<boolean, BaoError, HttpClient.HttpClient>, options?: RemountOptions) => Effect.Effect<void, BaoError | RemountError, HttpClient.HttpClient>;
44
+ //# sourceMappingURL=remount-wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remount-wire.d.ts","sourceRoot":"","sources":["../../src/openbao/remount-wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD,4FAA4F;AAC5F,qBAAa,YAAa,SAAQ,KAAK;IACrC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAOD,oGAAoG;AACpG,eAAO,MAAM,YAAY,SACjB,MAAM,MACR,MAAM,KACT,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,YAAY,EAAE,UAAU,CAAC,UAAU,CAMnE,CAAC;AAEL,iGAAiG;AACjG,eAAO,MAAM,aAAa,OACpB,MAAM,KACT,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAKhE,CAAC;AAEL;;;;;GAKG;AACH,eAAO,MAAM,cAAc,SACnB,MAAM,MACR,MAAM,WACD,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAAC,YACvD,cAAc,KACtB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,YAAY,EAAE,UAAU,CAAC,UAAU,CAkCjE,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The read / plan / reconcile loop the newer role families share (Bao.JwtRole, Bao.KubernetesRole,
3
+ * Bao.JwtAuthConfig): one path, one body, one comparison. Each family supplies its own form; this
4
+ * owns the order of operations, which is where the estate's providers have gone wrong before.
5
+ *
6
+ * ★ THE ORDER, AND WHY EACH STEP IS THERE:
7
+ * 1. Refuse a declaration the family knows is wrong, before any call (`problems`).
8
+ * 2. Read live. Write only when it differs — an identical write is still an audit line.
9
+ * 3. Before writing over a live object, refuse if the write would silently destroy something
10
+ * this resource does not model (`wouldErase`, the ssh-role.ts pattern).
11
+ * 4. Re-read, and refuse unless live now MATCHES. A 2xx is not proof: the server can accept a
12
+ * field and store something else (pki-role.ts has the history).
13
+ * ⛔ A DECLARATION reconcile WOULD REFUSE NEVER PLANS `noop` — `planRole` routes it to `update`,
14
+ * so the refusal is seen at the next deploy instead of hiding behind a clean plan.
15
+ */
16
+ import * as Effect from 'effect/Effect';
17
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
18
+ import type { BaoError } from './bao-status.ts';
19
+ export interface RoleSpec<A> {
20
+ /** `Bao.JwtRole` etc., for messages. */
21
+ readonly family: string;
22
+ /** The API path, e.g. `auth/jwt/role/humans`. */
23
+ readonly path: string;
24
+ readonly problems: readonly string[];
25
+ readonly attributesOf: (live: Record<string, unknown>) => A;
26
+ readonly matches: (attributes: A) => boolean;
27
+ readonly body: Readonly<Record<string, unknown>>;
28
+ /** Live fields a write would reset that the declaration does not model. */
29
+ readonly wouldErase?: (live: Record<string, unknown>) => readonly string[];
30
+ }
31
+ type Found<A> = {
32
+ readonly attributes: A;
33
+ readonly live: Record<string, unknown>;
34
+ };
35
+ export declare const readRoleAt: <A>(spec: RoleSpec<A>) => Effect.Effect<Found<A> | undefined, BaoError, HttpClient.HttpClient>;
36
+ /** `update` or `noop` — the part of a diff after the identity checks. */
37
+ export declare const planRole: <A>(spec: RoleSpec<A>) => Effect.Effect<'noop' | 'update', BaoError, HttpClient.HttpClient>;
38
+ export declare const reconcileRole: <A>(spec: RoleSpec<A>) => Effect.Effect<A, BaoError, HttpClient.HttpClient>;
39
+ export {};
40
+ //# sourceMappingURL=role-reconcile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"role-reconcile.d.ts","sourceRoot":"","sources":["../../src/openbao/role-reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,wCAAwC;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC5D,QAAQ,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,CAAC,KAAK,OAAO,CAAC;IAC7C,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACjD,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,SAAS,MAAM,EAAE,CAAC;CAC5E;AAED,KAAK,KAAK,CAAC,CAAC,IAAI;IAAE,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAEnF,eAAO,MAAM,UAAU,GAAI,CAAC,QACpB,QAAQ,CAAC,CAAC,CAAC,KAChB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAGnE,CAAC;AAEJ,yEAAyE;AACzE,eAAO,MAAM,QAAQ,GAAI,CAAC,QAClB,QAAQ,CAAC,CAAC,CAAC,KAChB,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAK/D,CAAC;AAKL,eAAO,MAAM,aAAa,GAAI,CAAC,QACvB,QAAQ,CAAC,CAAC,CAAC,KAChB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CA0B/C,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { sshMountOf as mountOf } from './mount-path.ts';
1
2
  export interface BaoSshRoleProps {
2
3
  /** Role name, as `<mount>/roles/{name}` takes it. */
3
4
  name: string;
@@ -57,8 +58,7 @@ export interface BaoSshRoleAttributes extends Omit<BaoSshRoleForm, 'maxTtl' | 't
57
58
  /** SHA-256 of the managed fields — safe to persist; see policy.ts. */
58
59
  digest: string;
59
60
  }
60
- /** Mount path without a trailing slash; `ssh` when the caller did not say. */
61
- export declare const mountOf: (mount: string | undefined) => string;
61
+ export { mountOf };
62
62
  export declare const readPath: (mount: string | undefined, name: string) => string;
63
63
  /**
64
64
  * ⚠️ SETS, NOT SEQUENCES. OpenBao stores these as one comma-separated string and promises
@@ -77,10 +77,11 @@ export declare const attributesOf: (form: BaoSshRoleForm, live: Record<string, u
77
77
  /**
78
78
  * ⛔ EVERY MANAGED FIELD IS SENT ON EVERY WRITE, INCLUDING THE FALSE ONES. The role write is
79
79
  * a full replace (see ssh-role.ts), so an omitted field is not "left alone" — it is reset.
80
- * Sending the resolved form makes the body and the declaration the same statement. All
81
- * strings, exactly the `k=v` pairs `bao write` sent, for `PUT <mount>/roles/<name>`.
80
+ * Sending the resolved form makes the body and the declaration the same statement. Strings,
81
+ * exactly the `k=v` pairs `bao write` sent, for `PUT <mount>/roles/<name>` — except the two
82
+ * maps, which must be objects (the ⛔ on mapValue).
82
83
  */
83
- export declare const writeBody: (form: BaoSshRoleForm) => Record<string, string>;
84
+ export declare const writeBody: (form: BaoSshRoleForm) => Record<string, unknown>;
84
85
  /**
85
86
  * ⛔ AN UNPARSEABLE TTL IS A PLAN THAT NEVER GOES GREEN. parseDuration understands `0` and
86
87
  * `<n>[smhd]` and nothing else. A prop like `4h30m` writes fine, reads back as 16200,