@homeflare/alchemy 0.6.0 → 0.8.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 (219) hide show
  1. package/README.md +74 -41
  2. package/dist/caddy/admin-calls.d.ts +48 -0
  3. package/dist/caddy/admin-calls.d.ts.map +1 -0
  4. package/dist/caddy/admin-guard.d.ts +40 -0
  5. package/dist/caddy/admin-guard.d.ts.map +1 -0
  6. package/dist/caddy/admin.d.ts +73 -0
  7. package/dist/caddy/admin.d.ts.map +1 -0
  8. package/dist/caddy/caddyfile-tripwire.d.ts +5 -0
  9. package/dist/caddy/caddyfile-tripwire.d.ts.map +1 -0
  10. package/dist/caddy/config-form.d.ts +27 -0
  11. package/dist/caddy/config-form.d.ts.map +1 -0
  12. package/dist/caddy/config-lifecycle.d.ts +91 -0
  13. package/dist/caddy/config-lifecycle.d.ts.map +1 -0
  14. package/dist/caddy/config.d.ts +34 -0
  15. package/dist/caddy/config.d.ts.map +1 -0
  16. package/dist/caddy/digest.d.ts +7 -0
  17. package/dist/caddy/digest.d.ts.map +1 -0
  18. package/dist/caddy/fake-caddy.d.ts +54 -0
  19. package/dist/caddy/fake-caddy.d.ts.map +1 -0
  20. package/dist/caddy/index.d.ts +22 -0
  21. package/dist/caddy/index.d.ts.map +1 -0
  22. package/dist/caddy/index.js +970 -0
  23. package/dist/caddy/index.js.map +28 -0
  24. package/dist/caddy/local-admin.d.ts +45 -0
  25. package/dist/caddy/local-admin.d.ts.map +1 -0
  26. package/dist/caddy/providers.d.ts +14 -0
  27. package/dist/caddy/providers.d.ts.map +1 -0
  28. package/dist/caddy/with-file.d.ts +51 -0
  29. package/dist/caddy/with-file.d.ts.map +1 -0
  30. package/dist/cloudflare/fake-mesh.d.ts +58 -0
  31. package/dist/cloudflare/fake-mesh.d.ts.map +1 -0
  32. package/dist/cloudflare/index.d.ts +9 -3
  33. package/dist/cloudflare/index.d.ts.map +1 -1
  34. package/dist/cloudflare/index.js +218 -7
  35. package/dist/cloudflare/index.js.map +9 -4
  36. package/dist/cloudflare/mesh-node-api.d.ts +75 -0
  37. package/dist/cloudflare/mesh-node-api.d.ts.map +1 -0
  38. package/dist/cloudflare/mesh-node-form.d.ts +82 -0
  39. package/dist/cloudflare/mesh-node-form.d.ts.map +1 -0
  40. package/dist/cloudflare/mesh-node-harness.d.ts +46 -0
  41. package/dist/cloudflare/mesh-node-harness.d.ts.map +1 -0
  42. package/dist/cloudflare/mesh-node-lifecycle.d.ts +22 -0
  43. package/dist/cloudflare/mesh-node-lifecycle.d.ts.map +1 -0
  44. package/dist/cloudflare/mesh-node-token.d.ts +23 -0
  45. package/dist/cloudflare/mesh-node-token.d.ts.map +1 -0
  46. package/dist/cloudflare/mesh-node.d.ts +48 -0
  47. package/dist/cloudflare/mesh-node.d.ts.map +1 -0
  48. package/dist/cloudflare/providers.d.ts +1 -12
  49. package/dist/cloudflare/providers.d.ts.map +1 -1
  50. package/dist/index.d.ts +1 -0
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/launchd/fake-sudo.d.ts +50 -0
  53. package/dist/launchd/fake-sudo.d.ts.map +1 -0
  54. package/dist/launchd/host-effect.d.ts +18 -9
  55. package/dist/launchd/host-effect.d.ts.map +1 -1
  56. package/dist/launchd/host-file-form.d.ts +5 -0
  57. package/dist/launchd/host-file-form.d.ts.map +1 -1
  58. package/dist/launchd/host-file-lifecycle.d.ts.map +1 -1
  59. package/dist/launchd/index.d.ts +2 -0
  60. package/dist/launchd/index.d.ts.map +1 -1
  61. package/dist/launchd/index.js +342 -8
  62. package/dist/launchd/index.js.map +16 -12
  63. package/dist/launchd/job-preflight.d.ts.map +1 -1
  64. package/dist/launchd/job-validate.d.ts +2 -0
  65. package/dist/launchd/job-validate.d.ts.map +1 -1
  66. package/dist/launchd/local-runner.d.ts +2 -0
  67. package/dist/launchd/local-runner.d.ts.map +1 -1
  68. package/dist/launchd/providers.d.ts +2 -1
  69. package/dist/launchd/providers.d.ts.map +1 -1
  70. package/dist/launchd/runner.d.ts +7 -5
  71. package/dist/launchd/runner.d.ts.map +1 -1
  72. package/dist/launchd/secret-tripwire.d.ts +1 -0
  73. package/dist/launchd/secret-tripwire.d.ts.map +1 -1
  74. package/dist/launchd/sudo-allowlist.d.ts +47 -0
  75. package/dist/launchd/sudo-allowlist.d.ts.map +1 -0
  76. package/dist/launchd/sudo-guard.d.ts +56 -0
  77. package/dist/launchd/sudo-guard.d.ts.map +1 -0
  78. package/dist/launchd/sudo-runner.d.ts +60 -0
  79. package/dist/launchd/sudo-runner.d.ts.map +1 -0
  80. package/dist/launchd/sudo-stage.d.ts +7 -0
  81. package/dist/launchd/sudo-stage.d.ts.map +1 -0
  82. package/dist/openbao/auth-role-form.d.ts +0 -9
  83. package/dist/openbao/auth-role-form.d.ts.map +1 -1
  84. package/dist/openbao/auth-role.d.ts +3 -2
  85. package/dist/openbao/auth-role.d.ts.map +1 -1
  86. package/dist/openbao/cloudflare-role.d.ts.map +1 -1
  87. package/dist/openbao/fake-engines-roles.d.ts +32 -0
  88. package/dist/openbao/fake-engines-roles.d.ts.map +1 -0
  89. package/dist/openbao/fake-engines.d.ts +36 -0
  90. package/dist/openbao/fake-engines.d.ts.map +1 -0
  91. package/dist/openbao/fake-families.d.ts +49 -0
  92. package/dist/openbao/fake-families.d.ts.map +1 -0
  93. package/dist/openbao/fake-stack.d.ts +29 -0
  94. package/dist/openbao/fake-stack.d.ts.map +1 -0
  95. package/dist/openbao/host-approles.d.ts.map +1 -1
  96. package/dist/openbao/index.js +393 -234
  97. package/dist/openbao/index.js.map +23 -19
  98. package/dist/openbao/jwt-config.d.ts +5 -0
  99. package/dist/openbao/jwt-config.d.ts.map +1 -1
  100. package/dist/openbao/jwt-role.d.ts +2 -1
  101. package/dist/openbao/jwt-role.d.ts.map +1 -1
  102. package/dist/openbao/kubernetes-role.d.ts +2 -1
  103. package/dist/openbao/kubernetes-role.d.ts.map +1 -1
  104. package/dist/openbao/mfa-enforcement.d.ts +6 -3
  105. package/dist/openbao/mfa-enforcement.d.ts.map +1 -1
  106. package/dist/openbao/mfa-totp.d.ts.map +1 -1
  107. package/dist/openbao/pki-role.d.ts.map +1 -1
  108. package/dist/openbao/plugin.d.ts.map +1 -1
  109. package/dist/openbao/policy.d.ts +2 -0
  110. package/dist/openbao/policy.d.ts.map +1 -1
  111. package/dist/openbao/proxmox-role-form.d.ts +18 -8
  112. package/dist/openbao/proxmox-role-form.d.ts.map +1 -1
  113. package/dist/openbao/proxmox-role-wire.d.ts +18 -0
  114. package/dist/openbao/proxmox-role-wire.d.ts.map +1 -0
  115. package/dist/openbao/proxmox-role.d.ts.map +1 -1
  116. package/dist/openbao/rename-identity.d.ts +69 -0
  117. package/dist/openbao/rename-identity.d.ts.map +1 -0
  118. package/dist/openbao/rename.d.ts +107 -0
  119. package/dist/openbao/rename.d.ts.map +1 -0
  120. package/dist/openbao/ssh-role-erase.d.ts +11 -0
  121. package/dist/openbao/ssh-role-erase.d.ts.map +1 -0
  122. package/dist/openbao/ssh-role.d.ts.map +1 -1
  123. package/docs/caddy-admin.md +24 -0
  124. package/docs/caddy.md +199 -0
  125. package/docs/launchd-sudo.md +122 -0
  126. package/docs/launchd.md +7 -4
  127. package/docs/mesh-node.md +188 -0
  128. package/docs/peers.md +39 -0
  129. package/package.json +7 -2
  130. package/src/caddy/admin-calls.ts +128 -0
  131. package/src/caddy/admin-guard.ts +170 -0
  132. package/src/caddy/admin.ts +74 -0
  133. package/src/caddy/adopt-scope.test.ts +82 -0
  134. package/src/caddy/caddyfile-tripwire.ts +133 -0
  135. package/src/caddy/config-adopt.test.ts +235 -0
  136. package/src/caddy/config-form.ts +64 -0
  137. package/src/caddy/config-lifecycle.test.ts +196 -0
  138. package/src/caddy/config-lifecycle.ts +239 -0
  139. package/src/caddy/config.ts +153 -0
  140. package/src/caddy/digest.ts +44 -0
  141. package/src/caddy/fake-caddy.ts +179 -0
  142. package/src/caddy/guards.test.ts +156 -0
  143. package/src/caddy/index.ts +26 -0
  144. package/src/caddy/local-admin.test.ts +160 -0
  145. package/src/caddy/local-admin.ts +189 -0
  146. package/src/caddy/providers.test.ts +229 -0
  147. package/src/caddy/providers.ts +17 -0
  148. package/src/caddy/with-file.ts +66 -0
  149. package/src/cloudflare/fake-mesh.ts +181 -0
  150. package/src/cloudflare/index.ts +9 -3
  151. package/src/cloudflare/mesh-node-api.ts +127 -0
  152. package/src/cloudflare/mesh-node-edges.test.ts +103 -0
  153. package/src/cloudflare/mesh-node-form.test.ts +80 -0
  154. package/src/cloudflare/mesh-node-form.ts +115 -0
  155. package/src/cloudflare/mesh-node-harness.ts +124 -0
  156. package/src/cloudflare/mesh-node-lifecycle.ts +187 -0
  157. package/src/cloudflare/mesh-node-policy.test.ts +151 -0
  158. package/src/cloudflare/mesh-node-token.test.ts +117 -0
  159. package/src/cloudflare/mesh-node-token.ts +125 -0
  160. package/src/cloudflare/mesh-node.test.ts +172 -0
  161. package/src/cloudflare/mesh-node.ts +120 -0
  162. package/src/cloudflare/providers.ts +20 -2
  163. package/src/index.ts +1 -0
  164. package/src/launchd/fake-sudo.ts +136 -0
  165. package/src/launchd/host-effect.ts +33 -1
  166. package/src/launchd/host-file-form.ts +10 -2
  167. package/src/launchd/host-file-lifecycle.ts +2 -1
  168. package/src/launchd/index.ts +2 -0
  169. package/src/launchd/job-preflight.ts +3 -2
  170. package/src/launchd/job-validate.ts +1 -1
  171. package/src/launchd/local-runner.ts +6 -3
  172. package/src/launchd/providers.test.ts +3 -0
  173. package/src/launchd/providers.ts +2 -1
  174. package/src/launchd/runner.ts +7 -5
  175. package/src/launchd/secret-tripwire.ts +1 -1
  176. package/src/launchd/sudo-allowlist.test.ts +191 -0
  177. package/src/launchd/sudo-allowlist.ts +213 -0
  178. package/src/launchd/sudo-guard.test.ts +100 -0
  179. package/src/launchd/sudo-guard.ts +151 -0
  180. package/src/launchd/sudo-lifecycle.test.ts +172 -0
  181. package/src/launchd/sudo-runner-files.test.ts +240 -0
  182. package/src/launchd/sudo-runner.test.ts +126 -0
  183. package/src/launchd/sudo-runner.ts +235 -0
  184. package/src/launchd/sudo-stage.ts +28 -0
  185. package/src/openbao/README.md +8 -2
  186. package/src/openbao/REPLACE.md +126 -22
  187. package/src/openbao/auth-role-form.test.ts +2 -16
  188. package/src/openbao/auth-role-form.ts +0 -11
  189. package/src/openbao/auth-role.ts +35 -14
  190. package/src/openbao/cloudflare-role-wire.test.ts +8 -34
  191. package/src/openbao/cloudflare-role.ts +22 -8
  192. package/src/openbao/fake-engines-roles.ts +114 -0
  193. package/src/openbao/fake-engines.ts +126 -0
  194. package/src/openbao/fake-families.ts +182 -0
  195. package/src/openbao/fake-stack.ts +112 -0
  196. package/src/openbao/host-approles.test.ts +15 -2
  197. package/src/openbao/host-approles.ts +19 -4
  198. package/src/openbao/jwt-config.ts +26 -5
  199. package/src/openbao/jwt-role.ts +24 -8
  200. package/src/openbao/kubernetes-role.ts +20 -8
  201. package/src/openbao/mfa-enforcement.ts +23 -8
  202. package/src/openbao/mfa-totp.ts +21 -8
  203. package/src/openbao/pki-role.ts +19 -7
  204. package/src/openbao/plugin.ts +41 -15
  205. package/src/openbao/policy-rename.test.ts +112 -0
  206. package/src/openbao/policy-wire.test.ts +7 -26
  207. package/src/openbao/policy.ts +27 -4
  208. package/src/openbao/proxmox-role-form.ts +27 -8
  209. package/src/openbao/proxmox-role-wire.ts +24 -0
  210. package/src/openbao/proxmox-role.ts +52 -36
  211. package/src/openbao/rename-adoption.test.ts +82 -0
  212. package/src/openbao/rename-families.test.ts +122 -0
  213. package/src/openbao/rename-identity.test.ts +129 -0
  214. package/src/openbao/rename-identity.ts +117 -0
  215. package/src/openbao/rename-occupied.test.ts +166 -0
  216. package/src/openbao/rename.ts +166 -0
  217. package/src/openbao/role-rename.test.ts +205 -0
  218. package/src/openbao/ssh-role-erase.ts +50 -0
  219. package/src/openbao/ssh-role.ts +16 -54
@@ -10,6 +10,11 @@
10
10
  *
11
11
  * ★ REPLACE SEMANTICS (REPLACE.md): `mount` changed → `replace`: the new mount gets the config;
12
12
  * the old one keeps its own until that mount is disabled. There is no identity but the mount.
13
+ * ⛔ A MOVE ONTO A MOUNT WHOSE CONFIG EXISTS FAILS THE PLAN, like every other family's move onto an
14
+ * occupied path (rename-identity.ts). With no delete, nothing is lost to a swap, which MEASURED
15
+ * 2026-09-21 ended with each config where it was declared. But the new generation writes over
16
+ * the config it lands on, which changes who can log in on that mount: an issuer or key set
17
+ * someone else manages, silently replaced. Move through a mount with no config instead.
13
18
  */
14
19
  import { Resource } from 'alchemy';
15
20
  import * as Provider from 'alchemy/Provider';
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-config.d.ts","sourceRoot":"","sources":["../../src/openbao/jwt-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;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,0BAA0B,EAC/B,KAAK,qBAAqB,EAQ3B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,QAAQ,EAAuC,MAAM,qBAAqB,CAAC;AAEzF,YAAY,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE9F,MAAM,WAAW,gBAAiB,SAAQ,QAAQ,CAChD,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,EAC1B,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,gBAAgB,mDAE3B,CAAC;AAEH,eAAO,MAAM,aAAa,UACjB,qBAAqB,KAC3B,QAAQ,CAAC,0BAA0B,CAQpC,CAAC;AAEH,eAAO,MAAM,wBAAwB,uGA2BlC,CAAC"}
1
+ {"version":3,"file":"jwt-config.d.ts","sourceRoot":"","sources":["../../src/openbao/jwt-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;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,0BAA0B,EAC/B,KAAK,qBAAqB,EAO3B,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,KAAK,QAAQ,EAAuC,MAAM,qBAAqB,CAAC;AAEzF,YAAY,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE9F,MAAM,WAAW,gBAAiB,SAAQ,QAAQ,CAChD,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,EAC1B,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,gBAAgB,mDAE3B,CAAC;AAYH,eAAO,MAAM,aAAa,UACjB,qBAAqB,KAC3B,QAAQ,CAAC,0BAA0B,CAQpC,CAAC;AAEH,eAAO,MAAM,wBAAwB,uGAgClC,CAAC"}
@@ -14,7 +14,8 @@
14
14
  *
15
15
  * ★ REPLACE SEMANTICS (REPLACE.md): `mount` or `name` changed → `replace`, create-first. The new
16
16
  * path cannot collide with the old, so no `deleteFirst`. Under the default `retain` the old role
17
- * stays live, and still admits logins, until removed by hand.
17
+ * stays live, and still admits logins, until removed by hand. ⛔ A move onto a role that already
18
+ * exists fails the plan (rename-identity.ts).
18
19
  * ★ `defaultRemovalPolicy: 'retain'`, like every Bao.* family.
19
20
  */
20
21
  import { Resource } from 'alchemy';
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-role.d.ts","sourceRoot":"","sources":["../../src/openbao/jwt-role.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;AAEnE,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EAOrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,KAAK,QAAQ,EAAuC,MAAM,qBAAqB,CAAC;AAEzF,YAAY,EACV,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,cAAc,GACf,MAAM,oBAAoB,CAAC;AAE5B,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,WAAW,UAAW,eAAe,KAAG,QAAQ,CAAC,oBAAoB,CAOhF,CAAC;AAEH,eAAO,MAAM,kBAAkB,iGAoC5B,CAAC"}
1
+ {"version":3,"file":"jwt-role.d.ts","sourceRoot":"","sources":["../../src/openbao/jwt-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EAMrB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,KAAK,QAAQ,EAAuC,MAAM,qBAAqB,CAAC;AAEzF,YAAY,EACV,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,cAAc,GACf,MAAM,oBAAoB,CAAC;AAE5B,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;AAcH,eAAO,MAAM,WAAW,UAAW,eAAe,KAAG,QAAQ,CAAC,oBAAoB,CAOhF,CAAC;AAEH,eAAO,MAAM,kBAAkB,iGAuC5B,CAAC"}
@@ -9,7 +9,8 @@
9
9
  * and nothing else (path_role.go:239-256).
10
10
  *
11
11
  * ★ REPLACE SEMANTICS (REPLACE.md): `mount` or `name` changed → `replace`, create-first (the new
12
- * path cannot collide). Under the default `retain` the old role stays live until removed by hand.
12
+ * path cannot collide with the old). Under the default `retain` the old role stays live until
13
+ * removed by hand. ⛔ A move onto a role that already exists fails the plan (rename-identity.ts).
13
14
  */
14
15
  import { Resource } from 'alchemy';
15
16
  import * as Provider from 'alchemy/Provider';
@@ -1 +1 @@
1
- {"version":3,"file":"kubernetes-role.d.ts","sourceRoot":"","sources":["../../src/openbao/kubernetes-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EACL,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAO5B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,KAAK,QAAQ,EAAuC,MAAM,qBAAqB,CAAC;AAEzF,YAAY,EACV,wBAAwB,EACxB,2BAA2B,EAC3B,sBAAsB,GACvB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,iBAAkB,SAAQ,QAAQ,CACjD,oBAAoB,EACpB,sBAAsB,EACtB,2BAA2B,EAC3B,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,iBAAiB,oDAE5B,CAAC;AAEH,eAAO,MAAM,kBAAkB,UACtB,sBAAsB,KAC5B,QAAQ,CAAC,2BAA2B,CAOrC,CAAC;AAEH,eAAO,MAAM,yBAAyB,wGAiCnC,CAAC"}
1
+ {"version":3,"file":"kubernetes-role.d.ts","sourceRoot":"","sources":["../../src/openbao/kubernetes-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EACL,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAM5B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,KAAK,QAAQ,EAAuC,MAAM,qBAAqB,CAAC;AAEzF,YAAY,EACV,wBAAwB,EACxB,2BAA2B,EAC3B,sBAAsB,GACvB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,iBAAkB,SAAQ,QAAQ,CACjD,oBAAoB,EACpB,sBAAsB,EACtB,2BAA2B,EAC3B,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,iBAAiB,oDAE5B,CAAC;AAUH,eAAO,MAAM,kBAAkB,UACtB,sBAAsB,KAC5B,QAAQ,CAAC,2BAA2B,CAOrC,CAAC;AAEH,eAAO,MAAM,yBAAyB,wGAoCnC,CAAC"}
@@ -19,9 +19,12 @@
19
19
  * default `retain` it never runs; with `destroy`, set `retain` to drop it from state and leave it
20
20
  * live — which is what the server would do anyway.
21
21
  *
22
- * ★ REPLACE SEMANTICS (REPLACE.md): `name` changed → `replace`, create-first (names are per
23
- * namespace; the new one cannot collide). Under `retain` BOTH enforcements then apply — fail
24
- * closed. Under `destroy` the old one's delete is refused, so the deploy stops after creating.
22
+ * ★ REPLACE SEMANTICS (REPLACE.md): `name` changed → `replace`, create-first. Under `retain` BOTH
23
+ * enforcements then apply — fail closed. Under `destroy` the old one's delete is refused, so the
24
+ * deploy stops after creating. ⛔ A rename onto an enforcement that exists fails the plan
25
+ * (rename-identity.ts): the upsert by name would otherwise rewrite, in place, what someone else's
26
+ * enforcement demands. MEASURED 2026-09-21: a swap of two under `destroy` wrote each over the
27
+ * other, then stopped on the two refused deletes.
25
28
  */
26
29
  import { Resource } from 'alchemy';
27
30
  import * as Provider from 'alchemy/Provider';
@@ -1 +1 @@
1
- {"version":3,"file":"mfa-enforcement.d.ts","sourceRoot":"","sources":["../../src/openbao/mfa-enforcement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,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,gCAAgC,EACrC,KAAK,2BAA2B,EAMjC,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EACV,gCAAgC,EAChC,2BAA2B,GAC5B,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,sBAAuB,SAAQ,QAAQ,CACtD,yBAAyB,EACzB,2BAA2B,EAC3B,gCAAgC,EAChC,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,sBAAsB,yDAEjC,CAAC;AAEH,KAAK,GAAG,GAAG,UAAU,CAAC,UAAU,CAAC;AAmBjC,eAAO,MAAM,eAAe,UACnB,2BAA2B,KACjC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,QAAQ,EAAE,QAAQ,EAAE,GAAG,CAM7C,CAAC;AAEL,8DAA8D;AAC9D,eAAO,MAAM,oBAAoB,UACxB,2BAA2B,KACjC,MAAM,CAAC,MAAM,CAAC,gCAAgC,EAAE,QAAQ,EAAE,GAAG,CAe5D,CAAC;AAEL,eAAO,MAAM,8BAA8B,6GAkCxC,CAAC"}
1
+ {"version":3,"file":"mfa-enforcement.d.ts","sourceRoot":"","sources":["../../src/openbao/mfa-enforcement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,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,gCAAgC,EACrC,KAAK,2BAA2B,EAMjC,MAAM,2BAA2B,CAAC;AAInC,YAAY,EACV,gCAAgC,EAChC,2BAA2B,GAC5B,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,sBAAuB,SAAQ,QAAQ,CACtD,yBAAyB,EACzB,2BAA2B,EAC3B,gCAAgC,EAChC,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,sBAAsB,yDAEjC,CAAC;AAEH,KAAK,GAAG,GAAG,UAAU,CAAC,UAAU,CAAC;AAyBjC,eAAO,MAAM,eAAe,UACnB,2BAA2B,KACjC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,QAAQ,EAAE,QAAQ,EAAE,GAAG,CAM7C,CAAC;AAEL,8DAA8D;AAC9D,eAAO,MAAM,oBAAoB,UACxB,2BAA2B,KACjC,MAAM,CAAC,MAAM,CAAC,gCAAgC,EAAE,QAAQ,EAAE,GAAG,CAe5D,CAAC;AAEL,eAAO,MAAM,8BAA8B,6GAuCxC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"mfa-totp.d.ts","sourceRoot":"","sources":["../../src/openbao/mfa-totp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,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,0BAA0B,EAC/B,KAAK,qBAAqB,EAM3B,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EACV,0BAA0B,EAC1B,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,gBAAiB,SAAQ,QAAQ,CAChD,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,EAC1B,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,gBAAgB,mDAE3B,CAAC;AAKH,eAAO,MAAM,QAAQ,UACZ,qBAAqB,KAC3B,MAAM,CAAC,MAAM,CAAC,0BAA0B,GAAG,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAGrF,CAAC;AAEJ,eAAO,MAAM,QAAQ,UACZ,qBAAqB,KAC3B,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAK/D,CAAC;AAEL,uEAAuE;AACvE,eAAO,MAAM,aAAa,UACjB,qBAAqB,KAC3B,MAAM,CAAC,MAAM,CAAC,0BAA0B,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAWxE,CAAC;AAEL,eAAO,MAAM,wBAAwB,uGA8BlC,CAAC"}
1
+ {"version":3,"file":"mfa-totp.d.ts","sourceRoot":"","sources":["../../src/openbao/mfa-totp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,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,0BAA0B,EAC/B,KAAK,qBAAqB,EAM3B,MAAM,oBAAoB,CAAC;AAI5B,YAAY,EACV,0BAA0B,EAC1B,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,gBAAiB,SAAQ,QAAQ,CAChD,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,EAC1B,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,gBAAgB,mDAE3B,CAAC;AAKH,eAAO,MAAM,QAAQ,UACZ,qBAAqB,KAC3B,MAAM,CAAC,MAAM,CAAC,0BAA0B,GAAG,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAGrF,CAAC;AAEJ,eAAO,MAAM,QAAQ,UACZ,qBAAqB,KAC3B,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAK/D,CAAC;AAEL,uEAAuE;AACvE,eAAO,MAAM,aAAa,UACjB,qBAAqB,KAC3B,MAAM,CAAC,MAAM,CAAC,0BAA0B,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAWxE,CAAC;AAEL,eAAO,MAAM,wBAAwB,uGA0ClC,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,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"}
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;AAEnE,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EAMrB,MAAM,oBAAoB,CAAC;AAG5B,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;AAgBH,eAAO,MAAM,kBAAkB,iGAiH5B,CAAC"}
@@ -1 +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"}
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,EACL,KAAK,mBAAmB,EACxB,KAAK,cAAc,EAKpB,MAAM,kBAAkB,CAAC;AAM1B,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;AAoBH,eAAO,MAAM,iBAAiB,gGAsD3B,CAAC"}
@@ -77,6 +77,8 @@ export interface BaoPolicy extends Resource<'Bao.Policy', BaoPolicyProps, BaoPol
77
77
  * orphaned resource; a caller that means it opts in with `.pipe(RemovalPolicy.destroy())`. This
78
78
  * is Terraform's `prevent_destroy`, not a stubbed operation — a delete that silently did nothing
79
79
  * would lie to whoever read the plan.
80
+ * ⚠️ `retain` ALSO KEEPS THE OLD GENERATION OF A RENAME. A new `name` plans `replace`, and under
81
+ * `retain` the old policy is left live and unmanaged (rename.ts, REPLACE.md).
80
82
  */
81
83
  export declare const BaoPolicy: import("alchemy").ResourceClass<BaoPolicy>;
82
84
  export declare const BaoPolicyProvider: () => import("effect/Layer").Layer<Provider.Provider<BaoPolicy>, never, FileSystem.FileSystem | HttpClient.HttpClient | Path.Path>;
@@ -1 +1 @@
1
- {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/openbao/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAKnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAU,SAAQ,QAAQ,CACzC,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,KAAK,EACL,UAAU,CAAC,UAAU,GAAG,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAC1D;CAAG;AAEJ;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,SAAS,4CAEpB,CAAC;AAYH,eAAO,MAAM,iBAAiB,oIAuG3B,CAAC"}
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/openbao/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAOnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAU,SAAQ,QAAQ,CACzC,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,KAAK,EACL,UAAU,CAAC,UAAU,GAAG,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAC1D;CAAG;AAEJ;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,SAAS,4CAEpB,CAAC;AAeH,eAAO,MAAM,iBAAiB,oIAuH3B,CAAC"}
@@ -63,18 +63,18 @@ export interface BaoProxmoxRoleAttributes {
63
63
  }
64
64
  /** `proxmox-tb4/roles/read` — read, write and delete all address the role here. */
65
65
  export declare const rolePath: (mount: string, name: string) => string;
66
- export declare const attributesOf: (props: BaoProxmoxRoleProps, live: Record<string, unknown>) => BaoProxmoxRoleAttributes;
66
+ export declare const attributesOf: (props: Pick<BaoProxmoxRoleProps, 'mount' | 'name'>, live: Record<string, unknown>) => BaoProxmoxRoleAttributes;
67
67
  /**
68
68
  * The body for `PUT <mount>/roles/<name>` — all strings, the `k=v` pairs `bao write` sent — or
69
69
  * the prop names whose duration would not parse.
70
70
  *
71
- * ⛔ A WRITE TO roles/{name} REPLACES THE ROLE, IT DOES NOT MERGE. An omitted `ttl` is written
72
- * as the field's zero value, so a resource that treated undeclared TTLs as "unmanaged" — the
73
- * Bao.Mount shape — would silently reset a lease ceiling every time it rewrote the role for an
74
- * unrelated reason. Both TTLs are therefore required props and EVERY write carries all three
75
- * fields. REASONED from the Vault secrets-framework write semantics plus this plugin's schema
76
- * marking only `mint_user` required; NOT measured, because this session was read-only and
77
- * proving it would have meant writing to the live engine.
71
+ * ⛔ EVERY WRITE CARRIES ALL THREE FIELDS, and both TTLs are required props, so `matches` covers
72
+ * the whole role and no field is left unmanaged behind a green plan.
73
+ * ⚠️ CORRECTED 2026-09-21 FROM THE PLUGIN SOURCE. This said a write REPLACES the role and resets an
74
+ * omitted TTL to zero. The port in homeflare-openbao-plugins (secrets/proxmox/path_roles.go,
75
+ * pathRolesWrite, commit 0e79154) MERGES: it loads the stored role and sets only the fields
76
+ * present (`d.GetOk`). An omitted TTL would keep its old value, which is still a value this
77
+ * resource would not be managing. The build running live was not re-checked against that source.
78
78
  *
79
79
  * ⚠️ Seconds go on the wire as integers, not as `1h`. The schema declares both TTLs
80
80
  * `"format": "seconds"`, and an integer is accepted unambiguously by every path that reads
@@ -87,6 +87,16 @@ export declare const writeBody: (props: BaoProxmoxRoleProps) => {
87
87
  ok: false;
88
88
  bad: string[];
89
89
  };
90
+ /**
91
+ * Why moving the role's mint user from `before` to the declared one must be refused, or undefined.
92
+ * The ⛔ on reconcile in proxmox-role.ts says why a re-scope needs `allowMintUserChange`.
93
+ *
94
+ * ★ ONE DEFINITION FOR BOTH PLACES THAT ASK. Reconcile asks it of the live role at the same path.
95
+ * The diff asks it across a rename, where `before` is the role being replaced: a rename writes a
96
+ * brand-new role, so reconcile alone would see nothing to re-scope, and a rename would become the
97
+ * way around the guard.
98
+ */
99
+ export declare const rescopeRefusal: (before: string, mintUser: string, allowMintUserChange: string | undefined) => string | undefined;
90
100
  /** True when the live role already matches the declaration on every field the plugin stores. */
91
101
  export declare const matches: (attributes: BaoProxmoxRoleAttributes, props: BaoProxmoxRoleProps) => boolean;
92
102
  //# sourceMappingURL=proxmox-role-form.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"proxmox-role-form.d.ts","sourceRoot":"","sources":["../../src/openbao/proxmox-role-form.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,mBAAmB;IAClC,8FAA8F;IAC9F,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,yFAAyF;IACzF,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;;OASG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAwB;IACvC,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,GAAG,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB;AAmBD,mFAAmF;AACnF,eAAO,MAAM,QAAQ,UAAW,MAAM,QAAQ,MAAM,WAAwC,CAAC;AAE7F,eAAO,MAAM,YAAY,UAChB,mBAAmB,QACpB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,wBAYF,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS,UACb,mBAAmB,KACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAA;CAWzE,CAAC;AAaF,gGAAgG;AAChG,eAAO,MAAM,OAAO,eAAgB,wBAAwB,SAAS,mBAAmB,YAG9C,CAAC"}
1
+ {"version":3,"file":"proxmox-role-form.d.ts","sourceRoot":"","sources":["../../src/openbao/proxmox-role-form.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,mBAAmB;IAClC,8FAA8F;IAC9F,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,yFAAyF;IACzF,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;;OASG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAwB;IACvC,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,GAAG,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB;AAmBD,mFAAmF;AACnF,eAAO,MAAM,QAAQ,UAAW,MAAM,QAAQ,MAAM,WAAwC,CAAC;AAE7F,eAAO,MAAM,YAAY,UAChB,IAAI,CAAC,mBAAmB,EAAE,OAAO,GAAG,MAAM,CAAC,QAC5C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,wBAYF,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS,UACb,mBAAmB,KACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAA;CAWzE,CAAC;AAaF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,WACjB,MAAM,YACJ,MAAM,uBACK,MAAM,GAAG,SAAS,KACtC,MAAM,GAAG,SAIyF,CAAC;AAEtG,gGAAgG;AAChG,eAAO,MAAM,OAAO,eAAgB,wBAAwB,SAAS,mBAAmB,YAG9C,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The read Bao.ProxmoxRole makes of `<mount>/roles/<name>`, split from proxmox-role.ts so the diff,
3
+ * reconcile and the rename's re-scope check share one definition of "the live role".
4
+ */
5
+ import * as Effect from 'effect/Effect';
6
+ import { type BaoProxmoxRoleProps } from './proxmox-role-form.ts';
7
+ /**
8
+ * The live role, or undefined when OpenBao answers 404.
9
+ *
10
+ * ⚠️ A missing MOUNT and a missing ROLE both read as undefined here, because both answer 404:
11
+ * an absent role is a read that found nothing, and a path under no mount is OpenBao's
12
+ * unsupported-path error, which is also a 404 (sdk/logical/response_util.go). They are not the
13
+ * same failure — one is a typo in `mount`, the other is a role that has yet to be created — so
14
+ * reconcile lets OpenBao's own `errors` through on the write rather than inventing a message.
15
+ * A bad mount says "no handler for route".
16
+ */
17
+ export declare const readRole: (props: Pick<BaoProxmoxRoleProps, 'mount' | 'name'>) => Effect.Effect<import("./proxmox-role-form.ts").BaoProxmoxRoleAttributes | undefined, import("./bao-status.ts").BaoError, import("effect/unstable/http/HttpClient").HttpClient>;
18
+ //# sourceMappingURL=proxmox-role-wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxmox-role-wire.d.ts","sourceRoot":"","sources":["../../src/openbao/proxmox-role-wire.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,KAAK,mBAAmB,EAA0B,MAAM,wBAAwB,CAAC;AAE1F;;;;;;;;;GASG;AACH,eAAO,MAAM,QAAQ,UAAW,IAAI,CAAC,mBAAmB,EAAE,OAAO,GAAG,MAAM,CAAC,mLAKvE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"proxmox-role.d.ts","sourceRoot":"","sources":["../../src/openbao/proxmox-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EAKzB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,CAAC;AAE9D,MAAM,WAAW,cAAe,SAAQ,QAAQ,CAC9C,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,cAAc,iDAEzB,CAAC;AAiBH,eAAO,MAAM,sBAAsB,qGAoIhC,CAAC"}
1
+ {"version":3,"file":"proxmox-role.d.ts","sourceRoot":"","sources":["../../src/openbao/proxmox-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EAKzB,MAAM,wBAAwB,CAAC;AAKhC,YAAY,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,CAAC;AAE9D,MAAM,WAAW,cAAe,SAAQ,QAAQ,CAC9C,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,cAAc,iDAEzB,CAAC;AAKH,eAAO,MAAM,sBAAsB,qGA6JhC,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The rename guard every Bao.* family whose identity is a name, a mount, or a catalog key shares:
3
+ * one `Identity` per family, and two steps built from rename.ts, `judgeRename` at the top of `diff`
4
+ * and `guardRename` at the top of `reconcile`. REPLACE.md has the audit behind both.
5
+ *
6
+ * ★ ONE DESCRIPTION OF "WHICH OBJECT", NOT TWELVE COPIES OF THE CHECK. The rename-safety fix went
7
+ * in family by family, and the families it skipped were the ones that kept the bug: nine of them
8
+ * judged the identity only after `isResolved(news)` and never asked whether the new path was
9
+ * taken. 🔴 MEASURED 2026-09-21 through the engine (rename-families.test.ts): two Bao.AuthRole,
10
+ * Bao.PkiRole, Bao.JwtRole, Bao.KubernetesRole, Bao.SshRole or Bao.Plugin resources that swapped
11
+ * names under `RemovalPolicy.destroy()` both planned `replace`, each wrote over the other, and
12
+ * both old deletes then removed what had just been written: a green deploy, both objects gone.
13
+ * With any other prop still an Output, all nine planned `update` and left the old object live
14
+ * under no state record; for Bao.MfaTotpMethod that wrote a second method and stranded every
15
+ * enrolment.
16
+ */
17
+ import * as Effect from 'effect/Effect';
18
+ /** How one family names the object it manages — the thing a rename changes. */
19
+ export interface Identity<A> {
20
+ /** `Bao.JwtRole` etc., for messages. */
21
+ readonly family: string;
22
+ /** The identity a set of props declares; undefined while any part of it is still an Output. */
23
+ readonly declared: (props: unknown) => string | undefined;
24
+ /** The identity a generation's attributes record. */
25
+ readonly recorded: (output: A) => string;
26
+ /** The API path an identity is read at, for the occupied check. Default: the identity. */
27
+ readonly pathOf?: ((identity: string) => string) | undefined;
28
+ /** How the server keys it (`policyKey`). Default: exact. */
29
+ readonly key?: ((identity: string) => string) | undefined;
30
+ }
31
+ /** A family keyed by `name` alone, read at `pathOf(name)`. */
32
+ export declare const nameIdentity: <A extends {
33
+ readonly name: string;
34
+ }>(family: string, pathOf: (name: string) => string, key?: (name: string) => string) => Identity<A>;
35
+ /**
36
+ * A role at `rolePath(mount, name)`; the identity is that path. `defaultMount` is what an absent
37
+ * `mount` prop means — undefined when `mount` is required.
38
+ */
39
+ export declare const roleIdentity: <A extends {
40
+ readonly mount: string;
41
+ readonly name: string;
42
+ }>(family: string, rolePath: (mount: string, name: string) => string, defaultMount?: string, key?: (path: string) => string) => Identity<A>;
43
+ /**
44
+ * ⚠️ THE LAST SEGMENT LOWERCASED: a role store that folds the name and not the mount. openbao v2.6.2
45
+ * AppRole (builtin/credential/approle/path_role.go:1485, :1537) and Kubernetes
46
+ * (builtin/credential/kubernetes/backend.go:362, path_role.go:396) both store `role/<lowercased
47
+ * name>`, and JWT reads its `name` as a TypeLowerCaseString (builtin/credential/jwt/path_role.go:77),
48
+ * while the router folds no case in a mount path. So `Host` → `host` is the same role, never a
49
+ * replace that would delete, under `destroy`, the role it had just written.
50
+ */
51
+ export declare const foldName: (path: string) => string;
52
+ /**
53
+ * `diff`'s first step, before `isResolved(news)`: the move from the identity this resource last
54
+ * wrote or tried to the declared one, or undefined when both name the same object or either is not
55
+ * known yet. ⛔ Fails the plan when the new identity is already taken (`judgeMove`).
56
+ *
57
+ * ★ `olds` STANDS IN FOR `output` WHILE A CREATE OR A REPLACEMENT IS UNFINISHED, which is what
58
+ * catches reverting a move whose new generation failed (rename.ts, `judgeMove`).
59
+ */
60
+ export declare const judgeRename: <A>(identity: Identity<A>, olds: unknown, news: unknown, output: A | undefined) => Effect.Effect<{
61
+ from: string;
62
+ to: string;
63
+ } | undefined, import("./bao-status.ts").BaoError, import("effect/unstable/http/HttpClient").HttpClient>;
64
+ /**
65
+ * `reconcile`'s first step: an `update` whose prior attributes name another object dies before any
66
+ * read or write (`refuseMovedUpdate`). Only reached when the diff could not see the new identity.
67
+ */
68
+ export declare const guardRename: <A>(identity: Identity<A>, news: unknown, output: A | undefined) => Effect.Effect<void>;
69
+ //# sourceMappingURL=rename-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rename-identity.d.ts","sourceRoot":"","sources":["../../src/openbao/rename-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AASxC,+EAA+E;AAC/E,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,wCAAwC;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+FAA+F;IAC/F,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC;IAC1D,qDAAqD;IACrD,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,CAAC;IACzC,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;IAC7D,4DAA4D;IAC5D,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;CAC3D;AAED,8DAA8D;AAC9D,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,UACtD,MAAM,UACN,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,QAC1B,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,KAC7B,QAAQ,CAAC,CAAC,CAMX,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,UAC9E,MAAM,YACJ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,iBAClC,MAAM,QACf,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,KAC7B,QAAQ,CAAC,CAAC,CAKX,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,SAAU,MAAM,KAAG,MACc,CAAC;AAEvD;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,YACjB,QAAQ,CAAC,CAAC,CAAC,QACf,OAAO,QACP,OAAO,UACL,CAAC,GAAG,SAAS;;;wGAQpB,CAAC;AAEJ;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,YACjB,QAAQ,CAAC,CAAC,CAAC,QACf,OAAO,UACL,CAAC,GAAG,SAAS,KACpB,MAAM,CAAC,MAAM,CAAC,IAAI,CAOpB,CAAC"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Rename safety for the families whose identity is a name, a mount and a name, or a catalog key:
3
+ * the primitives. rename-identity.ts builds each family's diff and reconcile step from them, and
4
+ * REPLACE.md has the audit and what each answer does.
5
+ *
6
+ * ⛔ THE BUG THIS CLOSES, REPRODUCED 2026-09-21 AGAINST alchemy@2.0.0-beta.79's OWN PLAN AND APPLY
7
+ * (fake-stack.ts): a Bao.Policy deployed as `old`, then redeclared as `new` under
8
+ * `RemovalPolicy.destroy()`, planned `update` and left BOTH policies live. diff read the NEW
9
+ * path, found nothing, answered `update`, and reconcile wrote the new object. The old one stayed
10
+ * live under no state record, so no later plan would mention it, and not even `destroy` could
11
+ * remove it.
12
+ * ★ A CHANGED IDENTITY IS A DIFFERENT OBJECT, SO THE ANSWER IS `replace`. Create-first
13
+ * (`deleteFirst` false): the new path never collides with the old, the new generation is written,
14
+ * dependents are updated in the same graph, and only then is the old generation deleted. The
15
+ * engine hands that delete the OLD generation's attributes (Apply.ts deleteOldGenerations and the
16
+ * GC pass both pass `output: old.attr`), and every delete here reads `output`, never `news`.
17
+ * ⛔ A new path that collides with ANOTHER live object is refused at plan instead (`judgeMove`).
18
+ * ⚠️ UNDER `retain` THE OLD OBJECT STAYS LIVE. Apply.ts:2164-2173 skips the old generation's delete
19
+ * and logs "Retaining replaced resource (removal policy: retain)". The plan still says `replace`
20
+ * and the apply says what it kept, so it is no longer silent, but the old object is unmanaged
21
+ * from then on. Remove it by hand, or opt into `RemovalPolicy.destroy()`.
22
+ */
23
+ import * as Effect from 'effect/Effect';
24
+ /**
25
+ * A string prop of a diff's `news`, once that one prop is resolved; `undefined` while it is still an
26
+ * Output of a changing upstream (a function-typed proxy) or an Effect.
27
+ *
28
+ * ★ THE IDENTITY IS JUDGED BEFORE `isResolved(news)`. That guard returns `undefined` when ANY prop is
29
+ * pending, and the engine then falls back to `update` (Plan.ts, `havePropsChanged`). A rename that
30
+ * lands in the same deploy as a pending `fragments` or `policies` Output would slip through as
31
+ * `update`, which is the orphan again. launchd/host-effect.ts reads its identity the same way.
32
+ */
33
+ export declare const declaredString: (news: unknown, key: string) => string | undefined;
34
+ /** True while an optional prop is declared but is not yet a value: an Output of a changing upstream. */
35
+ export declare const isPendingProp: (news: unknown, key: string) => boolean;
36
+ /**
37
+ * An optional string prop: `fallback` when it is absent, undefined while it is still an Output.
38
+ * ⚠️ Not `declaredString(…) ?? fallback`, which would read a pending mount as the default mount.
39
+ */
40
+ export declare const declaredOr: (news: unknown, key: string, fallback: string) => string | undefined;
41
+ /**
42
+ * A role's API path from a diff's `news`, once both `mount` and `name` are resolved. `defaultMount`
43
+ * is what an absent `mount` means; without one, an absent mount is unknown.
44
+ */
45
+ export declare const declaredRolePath: (news: unknown, rolePath: (mount: string, name: string) => string, defaultMount?: string) => string | undefined;
46
+ /**
47
+ * How OpenBao keys an ACL policy: trimmed and lowercased. openbao v2.6.2
48
+ * vault/policy/policy_store.go:698-700 (`sanitizeName`), applied by SetPolicy (:268), GetPolicy
49
+ * (:378) and DeletePolicy (:562).
50
+ *
51
+ * ⛔ SO `Admin` → `admin` IS THE SAME POLICY, NOT A RENAME. A `replace` there would write it, and then,
52
+ * under `destroy`, delete the old generation, which is that same policy. Every grant it carries
53
+ * would be revoked by a change of case.
54
+ */
55
+ export declare const policyKey: (name: string) => string;
56
+ /**
57
+ * Whether the declared identity names a different object than the one in state: `true` → moved (the
58
+ * diff asks `judgeMove`, which also reads the target); `false` → the same object; `undefined` → not
59
+ * knowable yet, because the declared side is still an Output. `key` is how the SERVER keys the object (`policyKey`); the default is exact,
60
+ * which is right for a mount path (vault/routing/router.go folds no case) and for both plugins'
61
+ * roles (each stores `roles/<name>` verbatim).
62
+ *
63
+ * ⛔ NEVER `replace` ON AN UNKNOWN IDENTITY. The Output may resolve to the same path, and a replace
64
+ * onto the same path deletes, under `destroy`, the object it has just written. The diff defers
65
+ * instead. If the engine then plans `update` and the identity turns out to have changed,
66
+ * `refuseMovedUpdate` stops reconcile before it writes anything.
67
+ */
68
+ export declare const isMoved: (stored: string, declared: string | undefined, key?: (identity: string) => string) => boolean | undefined;
69
+ /**
70
+ * The diff's first question, asked before `isResolved(news)`: the move from the identity this
71
+ * resource last wrote or tried (`tried`) to the declared one, or undefined when both name the same
72
+ * object or either is still unknown. `pathOf` is the API path an identity is read at.
73
+ *
74
+ * ⛔ A MOVE ONTO AN OBJECT THAT ALREADY EXISTS FAILS THE PLAN. MEASURED 2026-09-21 through the engine
75
+ * (rename-occupied.test.ts): two policies that swapped names under `RemovalPolicy.destroy()` each
76
+ * planned `replace`, each new generation wrote over the other's live policy, and each old
77
+ * generation's delete then removed the name the other had just written. The deploy was green and
78
+ * both policies were gone, every grant revoked. A shift (a → b while b → c), and a move onto the
79
+ * name of a resource leaving the stack, were measured ending the same way. So was reverting a
80
+ * move whose new generation failed: the old generation still holds the name, and its delete runs
81
+ * after the revert has rewritten it. That is why `tried` falls back to the props of an unfinished
82
+ * write.
83
+ * ⚠️ THE DIFF CANNOT SEE THE REMOVAL POLICY, SO THIS REFUSES UNDER `retain` TOO, where a swap, or a
84
+ * move back onto a retained old generation, would have been harmless. The cost is a move in two
85
+ * deploys through a free name, or removing the target by hand. The alternative is a green deploy
86
+ * that deletes what it has just written.
87
+ * ★ ONE PLAN-TIME READ, OF A PATH THE NEW GENERATION'S RECONCILE READS ANYWAY. A 404, a missing mount
88
+ * included, is free; a refused read fails the plan, as any other diff read does.
89
+ */
90
+ export declare const judgeMove: (family: string, tried: string | undefined, declared: string | undefined, pathOf: (identity: string) => string, key?: (identity: string) => string) => Effect.Effect<{
91
+ from: string;
92
+ to: string;
93
+ } | undefined, import("./bao-status.ts").BaoError, import("effect/unstable/http/HttpClient").HttpClient>;
94
+ /**
95
+ * Reconcile's guard: an `update` whose prior attributes name another object.
96
+ *
97
+ * ★ REACHED ONLY WHEN THE DIFF COULD NOT SEE THE NEW IDENTITY at plan time. A fresh create, and the
98
+ * new generation of a `replace`, both reach reconcile with `output` undefined (Apply.ts passes
99
+ * `output: attr`, which is empty for a new generation). An `update` reaches it with the previous
100
+ * generation's attributes.
101
+ * ★ THE FAILED DEPLOY SETTLES ITSELF. Apply has already committed the row as `updating`, with the new
102
+ * props and the OLD attributes. By the next plan the upstream Output has landed, so the diff sees
103
+ * both names and answers `replace` (or refuses, if the new name is already taken: `judgeMove`).
104
+ * The old object is then deleted, or retained, by the removal policy, with no hand repair.
105
+ */
106
+ export declare const refuseMovedUpdate: (family: string, from: string, to: string) => Effect.Effect<never, never, never>;
107
+ //# sourceMappingURL=rename.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rename.d.ts","sourceRoot":"","sources":["../../src/openbao/rename.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAKxC;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,SAAU,OAAO,OAAO,MAAM,KAAG,MAAM,GAAG,SAIpE,CAAC;AAEF,wGAAwG;AACxG,eAAO,MAAM,aAAa,SAAU,OAAO,OAAO,MAAM,KAAG,OAI1D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,UAAU,SAAU,OAAO,OAAO,MAAM,YAAY,MAAM,KAAG,MAAM,GAAG,SACH,CAAC;AAEjF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,SACrB,OAAO,YACH,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,iBAClC,MAAM,KACpB,MAAM,GAAG,SAOX,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,SAAU,MAAM,KAAG,MAAmC,CAAC;AAE7E;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,OAAO,WACV,MAAM,YACJ,MAAM,GAAG,SAAS,QACvB,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,KAChC,OAAO,GAAG,SAAiF,CAAC;AAE/F;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,SAAS,WACZ,MAAM,SACP,MAAM,GAAG,SAAS,YACf,MAAM,GAAG,SAAS,UACpB,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,QAC/B,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM;;;wGAgB/B,CAAC;AAEL;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,WAAY,MAAM,QAAQ,MAAM,MAAM,MAAM,uCAOvE,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * ⛔ THE FIELDS A WRITE WOULD SILENTLY DESTROY. Because the write is a full replace, a role
3
+ * someone tuned by hand — `allowed_user_key_lengths` (a minimum RSA size), a
4
+ * `key_id_format` the audit trail is grepped by, a `not_before_duration` widened to
5
+ * survive clock skew, a non-default issuer — loses all of it the moment this resource
6
+ * decides to update. A vanished key-length floor is a security regression that no plan
7
+ * output would ever mention, and a vanished backdating window breaks signing on exactly
8
+ * the skewed host it was added for. So reconcile refuses instead of writing.
9
+ */
10
+ export declare const wouldErase: (live: Record<string, unknown>) => readonly string[];
11
+ //# sourceMappingURL=ssh-role-erase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssh-role-erase.d.ts","sourceRoot":"","sources":["../../src/openbao/ssh-role-erase.ts"],"names":[],"mappings":"AAkCA;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,SAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,SAAS,MAAM,EAMzE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ssh-role.d.ts","sourceRoot":"","sources":["../../src/openbao/ssh-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EACL,KAAK,oBAAoB,EAEzB,KAAK,eAAe,EAQrB,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;AAyDH,eAAO,MAAM,kBAAkB,iGAqH5B,CAAC"}
1
+ {"version":3,"file":"ssh-role.d.ts","sourceRoot":"","sources":["../../src/openbao/ssh-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EACL,KAAK,oBAAoB,EAEzB,KAAK,eAAe,EAOrB,MAAM,oBAAoB,CAAC;AAI5B,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,iGAwH5B,CAAC"}
@@ -0,0 +1,24 @@
1
+ # Caddy's admin endpoint — `@homeflare/alchemy/caddy`
2
+
3
+ How the provider reaches Caddy's admin API, and what it refuses so a Caddyfile cannot cut it off.
4
+ The overview is [caddy.md](./caddy.md).
5
+
6
+ ⛔ The admin API has no authentication. `localCaddyAdmin()` accepts only `http://` loopback
7
+ (`127.0.0.0/8`, `localhost`, `[::1]`) or `unix:///path`; the default is `http://127.0.0.1:2019`.
8
+
9
+ - **Host and Origin.** Caddy refuses a request whose `Host` is not an allowed origin (DNS-rebinding
10
+ guard; measured on Caddy 2.11.4: `403 host not allowed`), and checks `Origin` when one is sent or
11
+ `enforce_origin` is on. The transport sends both as the Caddy CLI does. A unix socket skips the
12
+ Host check entirely.
13
+ - **`admin { origins … }`** narrowed, or **an SSH-forwarded port** (Caddy checks the Host against
14
+ ITS port): pass `hostHeader: 'localhost:2019'`.
15
+ - **Another host's Caddy** (SSH later): forward its socket or port to loopback here and point a
16
+ `localCaddyAdmin()` at it, or implement `CaddyAdmin` over your own route. Never expose :2019.
17
+ - **A Caddyfile cannot strand the provider.** Before loading, the adapted `admin` block is refused
18
+ if it turns the API off, listens off loopback or somewhere the transport does not reach (another
19
+ port, socket or loopback address: `[::1]` is not `127.0.0.1`, and `localhost` binds IPv4), allows
20
+ no Host the transport sends (its `origins`, or Caddy's loopback defaults when there are none), sets
21
+ `enforce_origin` over a unix socket (no Origin is sent there), enables `remote`, or pulls config.
22
+ - ⛔ **No `admin` address means Caddy's default** (`localhost:2019`, or `$CADDY_ADMIN`) after the
23
+ load. That is refused unless the transport is at that default: a Caddy reached on a socket or
24
+ another port declares `admin <address>` in its Caddyfile.