@homeflare/alchemy 0.39.0 → 0.40.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 (207) hide show
  1. package/README.md +10 -8
  2. package/dist/ceph/auth-entity.d.ts +34 -0
  3. package/dist/ceph/auth-entity.d.ts.map +1 -0
  4. package/dist/ceph/ceph-argv-config.d.ts +10 -0
  5. package/dist/ceph/ceph-argv-config.d.ts.map +1 -0
  6. package/dist/ceph/ceph-argv.d.ts +19 -0
  7. package/dist/ceph/ceph-argv.d.ts.map +1 -0
  8. package/dist/ceph/ceph-auth-form.d.ts +54 -0
  9. package/dist/ceph/ceph-auth-form.d.ts.map +1 -0
  10. package/dist/ceph/ceph-auth-parse.d.ts +56 -0
  11. package/dist/ceph/ceph-auth-parse.d.ts.map +1 -0
  12. package/dist/ceph/ceph-auth-reconcile.d.ts +35 -0
  13. package/dist/ceph/ceph-auth-reconcile.d.ts.map +1 -0
  14. package/dist/ceph/ceph-config-options.d.ts +23 -0
  15. package/dist/ceph/ceph-config-options.d.ts.map +1 -0
  16. package/dist/ceph/ceph-key-leak-assert.d.ts +25 -0
  17. package/dist/ceph/ceph-key-leak-assert.d.ts.map +1 -0
  18. package/dist/ceph/ceph-transport.d.ts +37 -0
  19. package/dist/ceph/ceph-transport.d.ts.map +1 -0
  20. package/dist/ceph/fake-ceph-dial.d.ts +35 -0
  21. package/dist/ceph/fake-ceph-dial.d.ts.map +1 -0
  22. package/dist/ceph/index.d.ts +13 -0
  23. package/dist/ceph/index.d.ts.map +1 -0
  24. package/dist/ceph/index.js +1609 -0
  25. package/dist/ceph/index.js.map +38 -0
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/proxmox/index.js +15 -6
  29. package/dist/proxmox/index.js.map +3 -3
  30. package/dist/proxmox/qemu-volume.d.ts +12 -2
  31. package/dist/proxmox/qemu-volume.d.ts.map +1 -1
  32. package/dist/talos/credentials-write.d.ts +46 -0
  33. package/dist/talos/credentials-write.d.ts.map +1 -0
  34. package/dist/talos/credentials.d.ts +51 -9
  35. package/dist/talos/credentials.d.ts.map +1 -1
  36. package/dist/talos/fake-process.d.ts +56 -0
  37. package/dist/talos/fake-process.d.ts.map +1 -0
  38. package/dist/talos/index.d.ts +19 -4
  39. package/dist/talos/index.d.ts.map +1 -1
  40. package/dist/talos/index.js +357 -173
  41. package/dist/talos/index.js.map +16 -10
  42. package/dist/talos/kubeconfig-attrs.d.ts +4 -0
  43. package/dist/talos/kubeconfig-attrs.d.ts.map +1 -0
  44. package/dist/talos/kubeconfig.d.ts +41 -23
  45. package/dist/talos/kubeconfig.d.ts.map +1 -1
  46. package/dist/talos/machine-config-fixtures.d.ts +60 -0
  47. package/dist/talos/machine-config-fixtures.d.ts.map +1 -0
  48. package/dist/talos/machine-config-poll.d.ts +43 -0
  49. package/dist/talos/machine-config-poll.d.ts.map +1 -0
  50. package/dist/talos/machine-config-read.d.ts +49 -0
  51. package/dist/talos/machine-config-read.d.ts.map +1 -0
  52. package/dist/talos/resource.d.ts +18 -0
  53. package/dist/talos/resource.d.ts.map +1 -1
  54. package/dist/talos/talos-bootstrap-etcd.d.ts +38 -0
  55. package/dist/talos/talos-bootstrap-etcd.d.ts.map +1 -0
  56. package/dist/talos/talos-bootstrap.d.ts +87 -0
  57. package/dist/talos/talos-bootstrap.d.ts.map +1 -1
  58. package/dist/talos/talos-cluster-health.d.ts +43 -1
  59. package/dist/talos/talos-cluster-health.d.ts.map +1 -1
  60. package/dist/talos/talos-errors.d.ts +68 -0
  61. package/dist/talos/talos-errors.d.ts.map +1 -0
  62. package/dist/talos/talos-machine-config.d.ts +51 -15
  63. package/dist/talos/talos-machine-config.d.ts.map +1 -1
  64. package/dist/talos/talosctl.d.ts +7 -0
  65. package/dist/talos/talosctl.d.ts.map +1 -1
  66. package/dist/talos/values.d.ts +23 -3
  67. package/dist/talos/values.d.ts.map +1 -1
  68. package/dist/unifi/acl-rule-drift.d.ts +22 -0
  69. package/dist/unifi/acl-rule-drift.d.ts.map +1 -0
  70. package/dist/unifi/acl-rule-form.d.ts +90 -0
  71. package/dist/unifi/acl-rule-form.d.ts.map +1 -0
  72. package/dist/unifi/acl-rule-ordering-form.d.ts +49 -0
  73. package/dist/unifi/acl-rule-ordering-form.d.ts.map +1 -0
  74. package/dist/unifi/acl-rule-ordering.d.ts +54 -0
  75. package/dist/unifi/acl-rule-ordering.d.ts.map +1 -0
  76. package/dist/unifi/acl-rule.d.ts +49 -0
  77. package/dist/unifi/acl-rule.d.ts.map +1 -0
  78. package/dist/unifi/dns-policy-drift.d.ts +21 -0
  79. package/dist/unifi/dns-policy-drift.d.ts.map +1 -0
  80. package/dist/unifi/dns-policy-form.d.ts +97 -0
  81. package/dist/unifi/dns-policy-form.d.ts.map +1 -0
  82. package/dist/unifi/dns-policy.d.ts +55 -0
  83. package/dist/unifi/dns-policy.d.ts.map +1 -0
  84. package/dist/unifi/firewall-policy-drift.d.ts +26 -0
  85. package/dist/unifi/firewall-policy-drift.d.ts.map +1 -0
  86. package/dist/unifi/firewall-policy-form.d.ts +102 -0
  87. package/dist/unifi/firewall-policy-form.d.ts.map +1 -0
  88. package/dist/unifi/firewall-policy-ordering-form.d.ts +66 -0
  89. package/dist/unifi/firewall-policy-ordering-form.d.ts.map +1 -0
  90. package/dist/unifi/firewall-policy-ordering.d.ts +57 -0
  91. package/dist/unifi/firewall-policy-ordering.d.ts.map +1 -0
  92. package/dist/unifi/firewall-policy.d.ts +57 -0
  93. package/dist/unifi/firewall-policy.d.ts.map +1 -0
  94. package/dist/unifi/index.d.ts +7 -0
  95. package/dist/unifi/index.d.ts.map +1 -1
  96. package/dist/unifi/index.js +588 -3
  97. package/dist/unifi/index.js.map +24 -4
  98. package/dist/unifi/paginate.d.ts +0 -12
  99. package/dist/unifi/paginate.d.ts.map +1 -1
  100. package/dist/unifi/providers.d.ts +1 -1
  101. package/dist/unifi/providers.d.ts.map +1 -1
  102. package/dist/unifi/scan-source.d.ts +11 -0
  103. package/dist/unifi/scan-source.d.ts.map +1 -0
  104. package/dist/unifi/traffic-matching-list-drift.d.ts +22 -0
  105. package/dist/unifi/traffic-matching-list-drift.d.ts.map +1 -0
  106. package/dist/unifi/traffic-matching-list-form.d.ts +56 -0
  107. package/dist/unifi/traffic-matching-list-form.d.ts.map +1 -0
  108. package/dist/unifi/traffic-matching-list.d.ts +51 -0
  109. package/dist/unifi/traffic-matching-list.d.ts.map +1 -0
  110. package/dist/unifi/wifi-broadcast-drift.d.ts +22 -0
  111. package/dist/unifi/wifi-broadcast-drift.d.ts.map +1 -0
  112. package/dist/unifi/wifi-broadcast-form.d.ts +127 -0
  113. package/dist/unifi/wifi-broadcast-form.d.ts.map +1 -0
  114. package/dist/unifi/wifi-broadcast.d.ts +73 -0
  115. package/dist/unifi/wifi-broadcast.d.ts.map +1 -0
  116. package/docs/unifi-acl-rule.md +122 -0
  117. package/docs/unifi-dns-policy.md +75 -0
  118. package/docs/unifi-firewall-policy.md +109 -0
  119. package/docs/unifi-traffic-matching-list.md +82 -0
  120. package/docs/unifi-wifi.md +120 -0
  121. package/docs/unifi.md +10 -5
  122. package/package.json +6 -2
  123. package/src/ceph/auth-entity.ts +74 -0
  124. package/src/ceph/ceph-argv-config.ts +78 -0
  125. package/src/ceph/ceph-argv.test.ts +226 -0
  126. package/src/ceph/ceph-argv.ts +189 -0
  127. package/src/ceph/ceph-auth-form.test.ts +103 -0
  128. package/src/ceph/ceph-auth-form.ts +107 -0
  129. package/src/ceph/ceph-auth-parse.test.ts +155 -0
  130. package/src/ceph/ceph-auth-parse.ts +121 -0
  131. package/src/ceph/ceph-auth-reconcile-secrecy.test.ts +82 -0
  132. package/src/ceph/ceph-auth-reconcile.test.ts +233 -0
  133. package/src/ceph/ceph-auth-reconcile.ts +119 -0
  134. package/src/ceph/ceph-config-options.test.ts +44 -0
  135. package/src/ceph/ceph-config-options.ts +36 -0
  136. package/src/ceph/ceph-key-leak-assert.ts +35 -0
  137. package/src/ceph/ceph-no-output-logging.test.ts +52 -0
  138. package/src/ceph/ceph-transport.test.ts +125 -0
  139. package/src/ceph/ceph-transport.ts +117 -0
  140. package/src/ceph/fake-ceph-dial.ts +55 -0
  141. package/src/ceph/index.ts +12 -0
  142. package/src/index.ts +1 -0
  143. package/src/proxmox/qemu-volume.test.ts +153 -4
  144. package/src/proxmox/qemu-volume.ts +71 -14
  145. package/src/talos/credentials-write.test.ts +81 -0
  146. package/src/talos/credentials-write.ts +95 -0
  147. package/src/talos/credentials.test.ts +157 -0
  148. package/src/talos/credentials.ts +160 -90
  149. package/src/talos/fake-process.ts +94 -0
  150. package/src/talos/index.ts +39 -4
  151. package/src/talos/kubeconfig-attrs.ts +55 -0
  152. package/src/talos/kubeconfig.test.ts +256 -0
  153. package/src/talos/kubeconfig.ts +170 -90
  154. package/src/talos/machine-config-fixtures.ts +86 -0
  155. package/src/talos/machine-config-poll.test.ts +57 -0
  156. package/src/talos/machine-config-poll.ts +82 -0
  157. package/src/talos/machine-config-read.ts +118 -0
  158. package/src/talos/resource.ts +19 -0
  159. package/src/talos/secrets-gate.test.ts +63 -0
  160. package/src/talos/talos-bootstrap-etcd.ts +71 -0
  161. package/src/talos/talos-bootstrap.test.ts +218 -0
  162. package/src/talos/talos-bootstrap.ts +151 -45
  163. package/src/talos/talos-cluster-health.test.ts +143 -0
  164. package/src/talos/talos-cluster-health.ts +91 -28
  165. package/src/talos/talos-errors.ts +85 -0
  166. package/src/talos/talos-machine-config.test.ts +189 -0
  167. package/src/talos/talos-machine-config.ts +102 -88
  168. package/src/talos/talosctl.ts +8 -0
  169. package/src/talos/values.test.ts +34 -6
  170. package/src/talos/values.ts +41 -7
  171. package/src/unifi/acl-rule-drift.ts +57 -0
  172. package/src/unifi/acl-rule-form.ts +135 -0
  173. package/src/unifi/acl-rule-ordering-form.ts +79 -0
  174. package/src/unifi/acl-rule-ordering.test.ts +141 -0
  175. package/src/unifi/acl-rule-ordering.ts +70 -0
  176. package/src/unifi/acl-rule.test.ts +183 -0
  177. package/src/unifi/acl-rule.ts +61 -0
  178. package/src/unifi/discriminated-filter-decode.test.ts +134 -0
  179. package/src/unifi/dns-policy-drift.ts +48 -0
  180. package/src/unifi/dns-policy-form.ts +142 -0
  181. package/src/unifi/dns-policy.test.ts +154 -0
  182. package/src/unifi/dns-policy.ts +67 -0
  183. package/src/unifi/firewall-policy-drift.test.ts +151 -0
  184. package/src/unifi/firewall-policy-drift.ts +55 -0
  185. package/src/unifi/firewall-policy-filter-roundtrip.test.ts +143 -0
  186. package/src/unifi/firewall-policy-form.ts +146 -0
  187. package/src/unifi/firewall-policy-ordering-form.ts +111 -0
  188. package/src/unifi/firewall-policy-ordering.test.ts +185 -0
  189. package/src/unifi/firewall-policy-ordering.ts +87 -0
  190. package/src/unifi/firewall-policy.test.ts +183 -0
  191. package/src/unifi/firewall-policy.ts +73 -0
  192. package/src/unifi/index.ts +63 -0
  193. package/src/unifi/paginate.test.ts +24 -0
  194. package/src/unifi/paginate.ts +15 -3
  195. package/src/unifi/providers.ts +19 -1
  196. package/src/unifi/scan-source.ts +64 -0
  197. package/src/unifi/traffic-matching-list-drift.ts +40 -0
  198. package/src/unifi/traffic-matching-list-form.ts +77 -0
  199. package/src/unifi/traffic-matching-list.test.ts +202 -0
  200. package/src/unifi/traffic-matching-list.ts +78 -0
  201. package/src/unifi/wifi-broadcast-details-call.test.ts +92 -0
  202. package/src/unifi/wifi-broadcast-drift.ts +69 -0
  203. package/src/unifi/wifi-broadcast-form.ts +211 -0
  204. package/src/unifi/wifi-broadcast-secrets.test.ts +145 -0
  205. package/src/unifi/wifi-broadcast.test.ts +155 -0
  206. package/src/unifi/wifi-broadcast.ts +90 -0
  207. package/src/unifi/write-op-reference.test.ts +8 -54
package/README.md CHANGED
@@ -304,14 +304,16 @@ import { ArgocdRepository, providers } from '@homeflare/alchemy/argocd';
304
304
 
305
305
  ## UniFi Network — `@homeflare/alchemy/unifi`
306
306
 
307
- `Unifi.Network` and `Unifi.FirewallZone`, generated from Ubiquiti's own UniFi Network
308
- Integration API 10.4.57 via `@distilled.cloud/unifi-network`. ⛔ **READ-ONLY, by Tim's rule
309
- (2026-09-24):** `reconcile`/`delete` both fail with a typed `UnifiWriteRefused` naming the
310
- policy — this family never calls a write operation, only `getNetworkDetails`/`getFirewallZone`
311
- and their list counterparts. ⛔ `read` answers `Unowned` on every match (never a silent adopt —
312
- `adopt(true)` is on by default via the `network`/`firewallZone` constructors), and a UniFi
313
- **Console ID** (part of a cloud-connector base URL) is never logged, committed or written to
314
- state: [docs/unifi.md](./docs/unifi.md).
307
+ `Unifi.Network`, `Unifi.FirewallZone`, `Unifi.DnsPolicy`, `Unifi.AclRule` and
308
+ `Unifi.AclRuleOrdering`, generated from Ubiquiti's own UniFi Network Integration API 10.4.57 via
309
+ `@distilled.cloud/unifi-network`. ⛔ **READ-ONLY, by Tim's rule (2026-09-24):** `reconcile`/`delete`
310
+ both fail with a typed `UnifiWriteRefused` naming the policy — no family here calls a write
311
+ operation, only each object's own `get*` and its list counterpart. ⛔ `read` answers `Unowned` on
312
+ every match (never a silent adopt — `adopt(true)` is on by default via each convenience
313
+ constructor), and a UniFi **Console ID** (part of a cloud-connector base URL) is never logged,
314
+ committed or written to state: [docs/unifi.md](./docs/unifi.md) (Network/FirewallZone),
315
+ [docs/unifi-dns-policy.md](./docs/unifi-dns-policy.md) and
316
+ [docs/unifi-acl-rule.md](./docs/unifi-acl-rule.md).
315
317
 
316
318
  ```ts
317
319
  import { declareNetwork, network, providers } from '@homeflare/alchemy/unifi';
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `Ceph.AuthEntity` (K-A4) — a Ceph client auth entity (`client.k8s-*`), minted over the ssh
3
+ * mon-command transport and stored only in OpenBao. Design: docs/plans/2026-09-26-ceph-mon-
4
+ * transport.md, "`Ceph.AuthEntity` (K-A4)"; the loop itself lives in ceph-auth-reconcile.ts, the
5
+ * transport in ceph-transport.ts, the allowlist in ceph-argv.ts.
6
+ *
7
+ * ⛔ `read` AND `diff` NEVER SSH. "A plan never elevates" (../linux/sudo-runner.ts's own header
8
+ * makes the same rule for the file family): this family's props/state comparison is the whole
9
+ * of `diff`, and `read` hands back exactly the attributes state already holds. Live drift is
10
+ * caught only at `reconcile` (which does elevate, on the admin lane) and by the post-deploy
11
+ * operator check — this family cannot prove live convergence at plan time, and says so rather
12
+ * than pretending an unprivileged probe exists where none does.
13
+ * ⛔ `delete` IS REFUSED UNCONDITIONALLY. `defaultRemovalPolicy: 'retain'` keeps Alchemy from ever
14
+ * calling it on an ordinary `destroy`, and the handler itself refuses too — belt and suspenders
15
+ * with ceph-argv.ts's own refusal of the `auth del` shape, so there is no path, `--adopt` or a
16
+ * resource-level removal-policy override included, that ever reaches it (D3).
17
+ * ⛔ NEVER ADOPTED. See ceph-auth-reconcile.ts's header for why the generic `refuseTakeover` is not
18
+ * used here.
19
+ * ⛔ ROWS ARE CREATES THROUGH THE FIRST-CREATE GATE, NO `adopt()` — `list` answers empty, the same
20
+ * as every Ceph family in this kit (ceph-pool.ts's header has the reason a non-empty list would
21
+ * invite exactly the takeover this family refuses).
22
+ */
23
+ import { Resource } from 'alchemy';
24
+ import * as Provider from 'alchemy/Provider';
25
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
26
+ import type { CephAuthEntityAttributes, CephAuthEntityProps } from './ceph-auth-form.ts';
27
+ export type { CephAuthEntityAttributes, CephAuthEntityProps } from './ceph-auth-form.ts';
28
+ export type { CephCaps } from './ceph-auth-parse.ts';
29
+ export interface CephAuthEntity extends Resource<'Ceph.AuthEntity', CephAuthEntityProps, CephAuthEntityAttributes, never, HttpClient.HttpClient> {
30
+ }
31
+ /** ★ `retain` — the delete handler below refuses regardless, but this stops Alchemy calling it. */
32
+ export declare const CephAuthEntity: import("alchemy").ResourceClass<CephAuthEntity>;
33
+ export declare const CephAuthEntityProvider: () => import("effect/Layer").Layer<Provider.Provider<CephAuthEntity>, never, HttpClient.HttpClient>;
34
+ //# sourceMappingURL=auth-entity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-entity.d.ts","sourceRoot":"","sources":["../../src/ceph/auth-entity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;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,KAAK,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAIzF,YAAY,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACzF,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,WAAW,cAAe,SAAQ,QAAQ,CAC9C,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,mGAAmG;AACnG,eAAO,MAAM,cAAc,iDAEzB,CAAC;AASH,eAAO,MAAM,sBAAsB,qGAmBhC,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `undefined` when `value` is a safe ceph config value — exported (like `boundedEntityProblem`)
3
+ * so the shape itself is directly testable, since `NAMED_CONFIG_OPTIONS` being empty today means
4
+ * `cephCommandProblem` never reaches this check on any real argv (`namedOptionProblem` refuses
5
+ * first) — this stays exercised until K-D's first named option arms the path for real.
6
+ */
7
+ export declare const configValueProblem: (value: string) => string | undefined;
8
+ /** `config get|set|rm <who> <name> [value]`, called with the operands after `config` stripped. */
9
+ export declare const configProblem: (rest: readonly string[]) => string | undefined;
10
+ //# sourceMappingURL=ceph-argv-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-argv-config.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-argv-config.ts"],"names":[],"mappings":"AAiCA;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,UAAW,MAAM,KAAG,MAAM,GAAG,SAG0B,CAAC;AAevF,kGAAkG;AAClG,eAAO,MAAM,aAAa,SAAU,SAAS,MAAM,EAAE,KAAG,MAAM,GAAG,SAmBhE,CAAC"}
@@ -0,0 +1,19 @@
1
+ export { configValueProblem } from './ceph-argv-config.ts';
2
+ /** ★ Absolute, so neither sudo nor `ceph` is looked up on the operator's PATH. */
3
+ export declare const CEPH_BIN = "/usr/bin/ceph";
4
+ /** Every entity this transport may ever touch starts with this. */
5
+ export declare const ENTITY_PREFIX = "client.k8s-";
6
+ /** `undefined` when `entity` is a name this transport may ever create, get or re-cap. */
7
+ export declare const boundedEntityProblem: (entity: string) => string | undefined;
8
+ declare const DAEMONS: readonly ['mon', 'osd', 'mgr'];
9
+ /**
10
+ * `undefined` when `argv` is exactly an allowed ceph shape (the FULL argv `sudo -n` would run,
11
+ * `/usr/bin/ceph` included), else the reason it is not.
12
+ */
13
+ export declare const cephCommandProblem: (argv: readonly string[]) => string | undefined;
14
+ /** The exact argv for each allowed shape, so callers never hand-assemble one that could drift. */
15
+ export declare const authGetArgv: (entity: string) => readonly string[];
16
+ export declare const authGetOrCreateArgv: (entity: string, caps: Readonly<Record<(typeof DAEMONS)[number], string>>) => readonly string[];
17
+ export declare const authCapsArgv: (entity: string, caps: Readonly<Record<(typeof DAEMONS)[number], string>>) => readonly string[];
18
+ export declare const quorumStatusArgv: () => readonly string[];
19
+ //# sourceMappingURL=ceph-argv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-argv.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-argv.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,kFAAkF;AAClF,eAAO,MAAM,QAAQ,kBAAkB,CAAC;AAExC,mEAAmE;AACnE,eAAO,MAAM,aAAa,gBAAgB,CAAC;AAK3C,yFAAyF;AACzF,eAAO,MAAM,oBAAoB,WAAY,MAAM,KAAG,MAAM,GAAG,SAGiD,CAAC;AAejH,QAAA,MAAM,OAAO,YAAI,KAAK,EAAE,KAAK,EAAE,KAAK,CAAU,CAAC;AA6E/C;;;GAGG;AACH,eAAO,MAAM,kBAAkB,SAAU,SAAS,MAAM,EAAE,KAAG,MAAM,GAAG,SAWrE,CAAC;AAEF,kGAAkG;AAClG,eAAO,MAAM,WAAW,WAAY,MAAM,KAAG,SAAS,MAAM,EAM3D,CAAC;AAEF,eAAO,MAAM,mBAAmB,WACtB,MAAM,QACR,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,KACvD,SAAS,MAAM,EAOjB,CAAC;AAEF,eAAO,MAAM,YAAY,WACf,MAAM,QACR,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,KACvD,SAAS,MAAM,EAOjB,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAO,SAAS,MAAM,EAIlD,CAAC"}
@@ -0,0 +1,54 @@
1
+ import type { CephCaps } from './ceph-auth-parse.ts';
2
+ export type { CephCaps };
3
+ export type CephAuthEntityProps = {
4
+ /** `client.k8s-<name>` — bounded by ceph-argv.ts's allowlist, checked on every transport call. */
5
+ readonly entity: string;
6
+ readonly caps: CephCaps;
7
+ /** TB4 mon ssh destinations, tried in this order (D1). At least one. */
8
+ readonly nodes: readonly string[];
9
+ /** OpenBao KV-v2 mount holding Talos/Ceph material, e.g. `talos-c1` (D2). */
10
+ readonly mount: string;
11
+ };
12
+ export type CephAuthEntityAttributes = {
13
+ readonly entity: string;
14
+ readonly caps: CephCaps;
15
+ /** `sha256(key)`, hex — never the key itself. */
16
+ readonly fingerprint: string;
17
+ /** CLI-style path (`<mount>/ceph/<entity>`) — safe to persist and log; the key is not here. */
18
+ readonly baoPath: string;
19
+ /** Which mon actually answered the write that produced this row. Never key material. */
20
+ readonly node: string;
21
+ };
22
+ export declare const capsEqual: (a: CephCaps, b: CephCaps) => boolean;
23
+ /** The CLI-style path an operator's `bao kv get` would use — what `baoPath` records. */
24
+ export declare const cephCliPath: (mount: string, entity: string) => string;
25
+ /**
26
+ * The raw KV-v2 HTTP API path `../openbao/bao-http.ts`'s `baoRead`/`baoWrite` take — the CLI path
27
+ * with `data/` inserted, the same segment `bao kv get`/`bao kv put` insert themselves
28
+ * (`../talos/credentials.ts`'s header has the shipped-default bug this convention avoids: never
29
+ * include `data/` in the CLI-style path itself, only here).
30
+ */
31
+ export declare const cephDataPath: (mount: string, entity: string) => string;
32
+ export type CephAuthEntityPlan = {
33
+ readonly action: 'noop' | 'update' | 'replace';
34
+ };
35
+ /**
36
+ * Whether `output` (if any) names a different entity/mount than `news` declares — the one
37
+ * question both `planCephAuthEntity` and `reconcileCephAuthEntity`'s guard ask, so the comparison
38
+ * lives in exactly one place (rename-identity.ts's own header: "one description of which object,
39
+ * not twelve copies of the check").
40
+ */
41
+ export declare const identityMoved: (news: Pick<CephAuthEntityProps, 'entity' | 'mount'>, output: CephAuthEntityAttributes | undefined) => boolean;
42
+ /**
43
+ * ⛔ STATE ONLY, NO SSH — the design's own rule for this family ("a plan never elevates"; diff and
44
+ * verify compare props against state, never the live cluster). `output === undefined` returns
45
+ * `undefined`: a brand-new row plans as a create the same way every other family in this kit
46
+ * does, and reconcile is where the actual ssh work — and the key material — ever appears.
47
+ * A moved identity plans `replace` before caps are even considered: `defaultRemovalPolicy:
48
+ * 'retain'` means the old generation is simply left alone (Apply.ts skips its delete under
49
+ * retain), and the new generation reconciles with `output: undefined`, which is exactly the
50
+ * "never adopted" path if the new identity already has a live entity.
51
+ */
52
+ export declare const planCephAuthEntity: (news: CephAuthEntityProps, output: CephAuthEntityAttributes | undefined) => CephAuthEntityPlan | undefined;
53
+ export declare const attributesOf: (props: Pick<CephAuthEntityProps, 'caps' | 'entity' | 'mount'>, fingerprint: string, node: string) => CephAuthEntityAttributes;
54
+ //# sourceMappingURL=ceph-auth-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-auth-form.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-auth-form.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,YAAY,EAAE,QAAQ,EAAE,CAAC;AAEzB,MAAM,MAAM,mBAAmB,GAAG;IAChC,kGAAkG;IAClG,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,iDAAiD;IACjD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,+FAA+F;IAC/F,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,SAAS,MAAO,QAAQ,KAAK,QAAQ,KAAG,OACE,CAAC;AAExD,wFAAwF;AACxF,eAAO,MAAM,WAAW,UAAW,MAAM,UAAU,MAAM,KAAG,MACZ,CAAC;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,YAAY,UAAW,MAAM,UAAU,MAAM,KAAG,MACR,CAAC;AAEtD,MAAM,MAAM,kBAAkB,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAA;CAAE,CAAC;AAEpF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,SAClB,IAAI,CAAC,mBAAmB,EAAE,QAAQ,GAAG,OAAO,CAAC,UAC3C,wBAAwB,GAAG,SAAS,KAC3C,OAEyF,CAAC;AAE7F;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,SACvB,mBAAmB,UACjB,wBAAwB,GAAG,SAAS,KAC3C,kBAAkB,GAAG,SAIvB,CAAC;AAEF,eAAO,MAAM,YAAY,UAChB,IAAI,CAAC,mBAAmB,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC,eAChD,MAAM,QACb,MAAM,KACX,wBAMD,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Parsing for the three ceph `-f json` shapes `Ceph.AuthEntity` reads: `auth get`, `auth
3
+ * get-or-create` and `quorum_status`. Pure: no I/O, tested with fixture stdout
4
+ * (ceph-auth-parse.test.ts) — there is no live mon to capture real output from yet, so every shape
5
+ * below is REASONED from public Ceph documentation, not measured, and an unexpected shape is
6
+ * always an error, never a guess.
7
+ *
8
+ * ⛔ `parseAuthGet`'S RETURN TYPE HAS NO `key` FIELD. Decision 65 (2026-09-26, LAND finding 5)
9
+ * amended the design to let the observe step read `auth get`'s unfiltered stdout on every
10
+ * reconcile, not only on create — but the key it carries is dropped in the same breath:
11
+ * `parseKeyringEntry` reads it into a local binding and `parseAuthGet` never puts it in the
12
+ * object it returns. Not a convention, a type: there is no field here to forget to strip.
13
+ * ⛔ `parseQuorumStatus` FAILS CLOSED. A JSON parse error, a missing `quorum` array or an empty one
14
+ * all answer `{ healthy: false }`; nothing here ever calls an unparseable answer healthy.
15
+ */
16
+ export type CephCaps = {
17
+ readonly mon: string;
18
+ readonly osd: string;
19
+ readonly mgr: string;
20
+ };
21
+ export type CephExecOutcome = {
22
+ readonly exitCode: number;
23
+ readonly stdout: string;
24
+ readonly stderr: string;
25
+ };
26
+ export type CephAuthObserved = {
27
+ readonly kind: 'present';
28
+ readonly caps: CephCaps;
29
+ } | {
30
+ readonly kind: 'absent';
31
+ };
32
+ /**
33
+ * ⚠️ ABSENCE IS RECOGNISED ONLY BY `ENOENT` IN STDERR (REASONED from `ceph auth get`'s documented
34
+ * error text). Any other nonzero exit — a permission problem, a malformed entity ceph itself
35
+ * refused, a mon mid-election — propagates as an error, never as "absent": the transient-read
36
+ * test every family in this kit carries.
37
+ */
38
+ export declare const parseAuthGet: (result: CephExecOutcome, entity: string) => CephAuthObserved;
39
+ /**
40
+ * ⚠️ `get-or-create` NEVER READS AS ABSENT — REASONED: it either creates, returns the existing
41
+ * entity unchanged, or fails outright (e.g. an existing entity with different caps). A nonzero
42
+ * exit here is always an error.
43
+ */
44
+ export declare const parseAuthGetOrCreate: (result: CephExecOutcome, entity: string) => {
45
+ readonly caps: CephCaps;
46
+ readonly key: string;
47
+ };
48
+ export type CephQuorum = {
49
+ readonly healthy: true;
50
+ } | {
51
+ readonly healthy: false;
52
+ readonly reason: string;
53
+ };
54
+ /** REASONED shape (public `ceph quorum_status -f json` docs): an object with a `quorum` array. */
55
+ export declare const parseQuorumStatus: (stdout: string) => CephQuorum;
56
+ //# sourceMappingURL=ceph-auth-parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-auth-parse.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-auth-parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5F,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AA6CF,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEhC;;;;;GAKG;AACH,eAAO,MAAM,YAAY,WAAY,eAAe,UAAU,MAAM,KAAG,gBAOtE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,WACvB,eAAe,UACf,MAAM,KACb;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAOjD,CAAC;AAEF,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAA;CAAE,GAC1B;IAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,kGAAkG;AAClG,eAAO,MAAM,iBAAiB,WAAY,MAAM,KAAG,UAYlD,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The observe -> ensure -> sync loop `Ceph.AuthEntity`'s reconcile runs (mon-transport doc,
3
+ * `Ceph.AuthEntity`). Split from auth-entity.ts so the loop itself — the part a fake-runner test
4
+ * actually exercises — is a plain function, the same split ceph-pool.ts and ssh-role.ts use.
5
+ *
6
+ * ⛔ NEVER ADOPTS. A live entity found present while this stack holds no attributes for it is
7
+ * refused outright, `--adopt` included — the generic `refuseTakeover` (../ownership/adopt.ts)
8
+ * is deliberately NOT used here, because it honours `--adopt` and this family's own design says
9
+ * plainly: "Existing auth entities are recorded as observed inventory only — never adopted:
10
+ * adopting one would mean reading and fingerprinting its key, and a key is only ever handled for
11
+ * an entity this stack owns."
12
+ * ⛔ THE OBSERVE STEP READS `auth get`'S UNFILTERED STDOUT ON EVERY RECONCILE (decision 65,
13
+ * 2026-09-26, amending the design after LAND finding 5 — no node-side filter narrows it first).
14
+ * The key that stdout carries is dropped in the same breath: `parseAuthGet` has no `key` field in
15
+ * its return type at all, so there is no variable here ever holding it past that call. Only `auth
16
+ * get-or-create`, run once on the create branch, yields a `key` value, and it goes straight to
17
+ * OpenBao — never assigned to a variable this function returns, logs, or puts in the attributes
18
+ * it hands back — `attributesOf` takes a fingerprint, never a key.
19
+ * ★ CAPS DRIFT NEVER RE-MINTS THE KEY. `auth caps` changes only what an entity may do; the returned
20
+ * attributes reuse `output.fingerprint` unchanged.
21
+ * ⛔ A MOVED IDENTITY IS REFUSED HERE TOO, BELT AND SUSPENDERS WITH `planCephAuthEntity`'s
22
+ * `replace`. `isResolved(news)` in auth-entity.ts's `diff` can defer to the engine's own
23
+ * `update` fallback while any prop is still an Output (rename.ts's own header documents this
24
+ * exact Alchemy behaviour for every other family this pattern protects) — a case in which
25
+ * `planCephAuthEntity` never even runs. Reached with `output` naming a different entity/mount
26
+ * than `props`, this refuses before any ssh call, the same shape of guard `guardRename`
27
+ * (openbao/rename-identity.ts) runs first in every `Bao.*` reconcile.
28
+ */
29
+ import * as Effect from 'effect/Effect';
30
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
31
+ import { type CephAuthEntityAttributes, type CephAuthEntityProps } from './ceph-auth-form.ts';
32
+ import { type CephTransportOptions } from './ceph-transport.ts';
33
+ export type CephAuthDeps = Pick<CephTransportOptions, 'dial' | 'log'>;
34
+ export declare const reconcileCephAuthEntity: (props: CephAuthEntityProps, output: CephAuthEntityAttributes | undefined, deps: CephAuthDeps) => Effect.Effect<CephAuthEntityAttributes, Error, HttpClient.HttpClient>;
35
+ //# sourceMappingURL=ceph-auth-reconcile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-auth-reconcile.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-auth-reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAKnE,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EAKzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,oBAAoB,EAAqC,MAAM,qBAAqB,CAAC;AAEnG,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,oBAAoB,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC;AA2BtE,eAAO,MAAM,uBAAuB,UAC3B,mBAAmB,UAClB,wBAAwB,GAAG,SAAS,QACtC,YAAY,KACjB,MAAM,CAAC,MAAM,CAAC,wBAAwB,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CA2CnE,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The named Ceph config-option list — the only options `ceph config get/set/rm` may ever touch
3
+ * through the mon-command transport (ceph-argv.ts's `configProblem`). Design:
4
+ * docs/plans/2026-09-26-ceph-config-options.md, D-C1.
5
+ *
6
+ * ⛔ THE LIST STARTS EMPTY, AND EACH ADDITION IS ITS OWN REVIEWED PR LINE. Nothing in K-A4 adds to
7
+ * it — `CephConfigOption` (K-D) is a separate, later family; this file exists now only so the
8
+ * transport's allowlist has something to bound `config` against from day one, per the accepted
9
+ * design ("config get/set for the named option list which starts EMPTY").
10
+ * ⛔ NEVER ADD ONE OF THE LOCKOUT CLASSES BELOW. `mon_host`, `public_network`, `cluster_network`,
11
+ * `public_addr`, `cluster_addr`, every `auth_*_required` and every `key`/`keyring`-bearing
12
+ * option re-address the mons or de-authenticate the whole cluster — cutting every VM disk — and
13
+ * `isLockoutConfigOption` is a structural guard a test runs against this file's own list, not a
14
+ * suggestion for the reviewer of the next PR line.
15
+ * ⛔ NEVER ADD A SECRET-VALUED OPTION. mgr module options can hold passwords (REASONED — no live
16
+ * cluster to measure this against yet); a secret-bearing setting belongs in a vault-backed flow,
17
+ * never a `ceph config set` argv, which lands in the runner's log and the node's sudo journal.
18
+ */
19
+ /** Starts empty. Add one reviewed option name per PR line, never a batch. */
20
+ export declare const NAMED_CONFIG_OPTIONS: ReadonlySet<string>;
21
+ /** Whether `name` is a class this transport must never read a value for, adopt, or write. */
22
+ export declare const isLockoutConfigOption: (name: string) => boolean;
23
+ //# sourceMappingURL=ceph-config-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-config-options.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-config-options.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,MAAM,CAAe,CAAC;AAarE,6FAA6F;AAC7F,eAAO,MAAM,qBAAqB,SAAU,MAAM,KAAG,OACE,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Shared by the two test files that prove `Ceph.AuthEntity` never leaks a minted key through a
3
+ * parse-error message: ceph-auth-parse.test.ts (direct parser calls) and
4
+ * ceph-auth-reconcile-secrecy.test.ts (through the full reconcile loop). Split out so the leak
5
+ * check and the malformed-stdout fixtures are identical in both places — the property being
6
+ * proved (decision 65) is the same one, and two hand-copied versions are exactly the kind of thing
7
+ * that quietly drifts apart.
8
+ *
9
+ * ⛔ TEST-ONLY. Nothing in `src/` imports this outside a `.test.ts` file.
10
+ * ★ NO HYPHEN IN THE SENTINEL. LAND red team (2026-09-26), CONFIRMED: a JSON lexer's "unexpected
11
+ * identifier" error for a bare (unquoted) token stops at the first character outside
12
+ * `[A-Za-z0-9_$]`, so a hyphenated sentinel (`sentinel-ceph-key-...`) truncates to its first
13
+ * word — `.not.toContain(SENTINEL)` on the FULL string then never fires even when that first
14
+ * word leaked. Cephx keys are base64 (`[A-Za-z0-9+/=]`, no hyphen), so this sentinel is shaped
15
+ * the same way, and every check here compares 8-character slices, not full-string containment.
16
+ */
17
+ /** A cephx-shaped sentinel: looks like a real minted key, no hyphen anywhere to truncate on. */
18
+ export declare const KEY_SHAPED_SENTINEL = "AQDsentinelKEYsentinelKEY0123456789abcd==";
19
+ /** True if any 8-character window of `key` shows up anywhere in `message`. */
20
+ export declare const leaksSliceOf: (message: string, key?: string) => boolean;
21
+ /** `auth get`/`auth get-or-create` stdout with the key left as a bare (unquoted) JSON token. */
22
+ export declare const unquotedKeyStdout: (entity: string, key?: string) => string;
23
+ /** The same shape with a trailing comma after the entry — a different malformed-JSON path. */
24
+ export declare const trailingCommaKeyStdout: (entity: string, key?: string) => string;
25
+ //# sourceMappingURL=ceph-key-leak-assert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-key-leak-assert.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-key-leak-assert.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,gGAAgG;AAChG,eAAO,MAAM,mBAAmB,8CAA8C,CAAC;AAE/E,8EAA8E;AAC9E,eAAO,MAAM,YAAY,YAAa,MAAM,QAAO,MAAM,KAAyB,OAKjF,CAAC;AAEF,gGAAgG;AAChG,eAAO,MAAM,iBAAiB,WAAY,MAAM,QAAO,MAAM,KAAyB,MAC7C,CAAC;AAE1C,8FAA8F;AAC9F,eAAO,MAAM,sBAAsB,WAAY,MAAM,QAAO,MAAM,KAAyB,MAC/C,CAAC"}
@@ -0,0 +1,37 @@
1
+ export type CephExecResult = {
2
+ readonly exitCode: number;
3
+ readonly stdout: string;
4
+ readonly stderr: string;
5
+ };
6
+ /** One attempt against one mon: run `argv` (already sudo-wrapped by the caller) and report. */
7
+ export type CephDial = (node: string, argv: readonly string[]) => Promise<CephExecResult>;
8
+ /** ★ A fresh nonce per attempt — this dial never reuses a connection or a marker across calls. */
9
+ export declare const sshCephDial: CephDial;
10
+ export type CephTransportOptions = {
11
+ /** TB4 mon ssh destinations, tried in this order. Required; at least one. */
12
+ readonly nodes: readonly string[];
13
+ readonly dial?: CephDial;
14
+ /** One line per attempted argv, before it dials. @default a line on stderr */
15
+ readonly log?: (line: string) => void;
16
+ };
17
+ /**
18
+ * Run one allowed ceph shape against the first mon that answers.
19
+ *
20
+ * ⛔ THE ALLOWLIST CHECK HAPPENS BEFORE THE FIRST NODE IS EVEN TRIED — a refused argv dials no
21
+ * ssh at all, so a bug that builds a bad shape cannot leak so much as a connection attempt.
22
+ */
23
+ export declare const runCephCommand: (options: CephTransportOptions, argv: readonly string[]) => Promise<CephExecResult & {
24
+ readonly node: string;
25
+ }>;
26
+ /**
27
+ * ★ LOCKOUT SAFETY, THE UFW-ESTABLISHED PATTERN: after every write, re-check quorum on a FRESH
28
+ * connection (a new dial, never the one the write used) and fail the row if it degraded. Never
29
+ * auto-repair, never continue — the caller's write is reported as failed even though it may
30
+ * itself have succeeded, because a write that broke quorum is not a success this transport will
31
+ * call one.
32
+ * ⚠️ THE SHAPE OF `quorum_status -f json` IS REASONED FROM PUBLIC CEPH DOCS, NOT MEASURED against
33
+ * this estate's Ceph release — there is no mon yet. An unparseable or missing `quorum` array
34
+ * fails closed as "degraded", never as "healthy"; see ceph-auth-parse.ts.
35
+ */
36
+ export declare const assertFreshQuorum: (options: CephTransportOptions) => Promise<void>;
37
+ //# sourceMappingURL=ceph-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-transport.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-transport.ts"],"names":[],"mappings":"AAyBA,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,+FAA+F;AAC/F,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAK1F,kGAAkG;AAClG,eAAO,MAAM,WAAW,EAAE,QAQzB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IACzB,8EAA8E;IAC9E,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC,CAAC;AAIF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,YAChB,oBAAoB,QACvB,SAAS,MAAM,EAAE,KACtB,OAAO,CAAC,cAAc,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAsBpD,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,YAAmB,oBAAoB,KAAG,OAAO,CAAC,IAAI,CAenF,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * A fake `CephDial` for the tests beside it — no ssh, no spawned process, ever. The same idea as
3
+ * `../linux/fake-sudo.ts` and `../openbao/fake-bao.ts`: production code is handed the real
4
+ * implementation, a test hands this instead, and neither one's internals change to make room for
5
+ * the other.
6
+ *
7
+ * ⛔ TEST-ONLY. Nothing in `src/` imports this outside a `.test.ts` file.
8
+ */
9
+ import type { CephDial, CephExecResult } from './ceph-transport.ts';
10
+ /** One call this fake received. */
11
+ export type SeenCephCall = {
12
+ readonly node: string;
13
+ readonly argv: readonly string[];
14
+ };
15
+ /** What a scripted node answers: a result, or a thrown transport failure. */
16
+ export type CephAnswer = {
17
+ readonly kind: 'result';
18
+ readonly result: CephExecResult;
19
+ } | {
20
+ readonly kind: 'transport-error';
21
+ readonly message: string;
22
+ };
23
+ export type FakeCephDial = {
24
+ readonly dial: CephDial;
25
+ readonly seen: SeenCephCall[];
26
+ };
27
+ declare const ok: (stdout: string, exitCode?: number, stderr?: string) => CephAnswer;
28
+ /**
29
+ * `script` maps a node to the fixed sequence of answers it gives, one per call that reaches it —
30
+ * the last entry repeats once exhausted. A node with no entry always transport-fails, which is
31
+ * exactly "an unreachable mon" without a special case.
32
+ */
33
+ export declare const fakeCephDial: (script: Readonly<Record<string, readonly CephAnswer[]>>) => FakeCephDial;
34
+ export { ok as fakeCephOk };
35
+ //# sourceMappingURL=fake-ceph-dial.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-ceph-dial.d.ts","sourceRoot":"","sources":["../../src/ceph/fake-ceph-dial.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEpE,mCAAmC;AACnC,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAEvF,6EAA6E;AAC7E,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC;CAC/B,CAAC;AAEF,QAAA,MAAM,EAAE,WAAY,MAAM,yCAA8B,UAGtD,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,YAAY,WACf,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC,CAAC,KACtD,YAiBF,CAAC;AAEF,OAAO,EAAE,EAAE,IAAI,UAAU,EAAE,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Ceph providers for Alchemy — the mon-command transport and `Ceph.AuthEntity` (K-A4).
3
+ *
4
+ * ⛔ THIS BARREL IS THE PUBLIC API, DELIBERATELY SMALLER THAN THE DIRECTORY — see
5
+ * `../openbao/index.ts`'s header for why. The allowlist internals (ceph-argv.ts), the parsing
6
+ * (ceph-auth-parse.ts) and the reconcile loop (ceph-auth-reconcile.ts) are exported by path for
7
+ * a future `CephConfigOption` (K-D) or a test to reach directly, not published here.
8
+ */
9
+ export type { CephAuthEntityAttributes, CephAuthEntityProps, CephCaps } from './auth-entity.ts';
10
+ export { CephAuthEntity, CephAuthEntityProvider } from './auth-entity.ts';
11
+ export type { CephDial, CephExecResult, CephTransportOptions } from './ceph-transport.ts';
12
+ export { assertFreshQuorum, runCephCommand, sshCephDial } from './ceph-transport.ts';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ceph/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,YAAY,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAChG,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC1F,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC"}