@homeflare/alchemy 0.14.0 → 0.19.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 (567) hide show
  1. package/README.md +29 -0
  2. package/dist/linux/directory-lifecycle.d.ts +50 -0
  3. package/dist/linux/directory-lifecycle.d.ts.map +1 -0
  4. package/dist/linux/directory.d.ts +19 -0
  5. package/dist/linux/directory.d.ts.map +1 -0
  6. package/dist/linux/fake-linux-host.d.ts +35 -0
  7. package/dist/linux/fake-linux-host.d.ts.map +1 -0
  8. package/dist/linux/fake-systemd.d.ts +34 -0
  9. package/dist/linux/fake-systemd.d.ts.map +1 -0
  10. package/dist/linux/index.d.ts +27 -0
  11. package/dist/linux/index.d.ts.map +1 -0
  12. package/dist/linux/index.js +1554 -0
  13. package/dist/linux/index.js.map +37 -0
  14. package/dist/linux/providers.d.ts +17 -0
  15. package/dist/linux/providers.d.ts.map +1 -0
  16. package/dist/linux/region.d.ts +43 -0
  17. package/dist/linux/region.d.ts.map +1 -0
  18. package/dist/linux/remote-file-form.d.ts +47 -0
  19. package/dist/linux/remote-file-form.d.ts.map +1 -0
  20. package/dist/linux/remote-file-lifecycle.d.ts +36 -0
  21. package/dist/linux/remote-file-lifecycle.d.ts.map +1 -0
  22. package/dist/linux/remote-file-plan.d.ts +33 -0
  23. package/dist/linux/remote-file-plan.d.ts.map +1 -0
  24. package/dist/linux/remote-file.d.ts +28 -0
  25. package/dist/linux/remote-file.d.ts.map +1 -0
  26. package/dist/linux/ssh-command.d.ts +68 -0
  27. package/dist/linux/ssh-command.d.ts.map +1 -0
  28. package/dist/linux/ssh-runner.d.ts +22 -0
  29. package/dist/linux/ssh-runner.d.ts.map +1 -0
  30. package/dist/linux/ssh-scripts.d.ts +27 -0
  31. package/dist/linux/ssh-scripts.d.ts.map +1 -0
  32. package/dist/linux/systemctl.d.ts +67 -0
  33. package/dist/linux/systemctl.d.ts.map +1 -0
  34. package/dist/linux/unit-form.d.ts +78 -0
  35. package/dist/linux/unit-form.d.ts.map +1 -0
  36. package/dist/linux/unit-handlers.d.ts +15 -0
  37. package/dist/linux/unit-handlers.d.ts.map +1 -0
  38. package/dist/linux/unit-lifecycle.d.ts +44 -0
  39. package/dist/linux/unit-lifecycle.d.ts.map +1 -0
  40. package/dist/linux/unit-settle.d.ts +31 -0
  41. package/dist/linux/unit-settle.d.ts.map +1 -0
  42. package/dist/linux/unit.d.ts +35 -0
  43. package/dist/linux/unit.d.ts.map +1 -0
  44. package/dist/netbox/client.d.ts +52 -0
  45. package/dist/netbox/client.d.ts.map +1 -0
  46. package/dist/netbox/constraint-guard.d.ts +26 -0
  47. package/dist/netbox/constraint-guard.d.ts.map +1 -0
  48. package/dist/netbox/constraints.d.ts +76 -0
  49. package/dist/netbox/constraints.d.ts.map +1 -0
  50. package/dist/netbox/generated/constraints/index.d.ts +19 -0
  51. package/dist/netbox/generated/constraints/index.d.ts.map +1 -0
  52. package/dist/netbox/generated/constraints/netbox-ipam.d.ts +21 -0
  53. package/dist/netbox/generated/constraints/netbox-ipam.d.ts.map +1 -0
  54. package/dist/netbox/index.d.ts +17 -0
  55. package/dist/netbox/index.d.ts.map +1 -0
  56. package/dist/netbox/index.js +331 -0
  57. package/dist/netbox/index.js.map +18 -0
  58. package/dist/netbox/prefix-form.d.ts +54 -0
  59. package/dist/netbox/prefix-form.d.ts.map +1 -0
  60. package/dist/netbox/prefix.d.ts +80 -0
  61. package/dist/netbox/prefix.d.ts.map +1 -0
  62. package/dist/netbox/resource.d.ts +94 -0
  63. package/dist/netbox/resource.d.ts.map +1 -0
  64. package/dist/netbox/values.d.ts +24 -0
  65. package/dist/netbox/values.d.ts.map +1 -0
  66. package/dist/openbao/index.d.ts +10 -3
  67. package/dist/openbao/index.d.ts.map +1 -1
  68. package/dist/proxmox/acl.d.ts.map +1 -1
  69. package/dist/proxmox/api-token-form.d.ts.map +1 -1
  70. package/dist/proxmox/apply-endpoints.d.ts +30 -0
  71. package/dist/proxmox/apply-endpoints.d.ts.map +1 -0
  72. package/dist/proxmox/backup-job.d.ts.map +1 -1
  73. package/dist/proxmox/ceph-daemon-form.d.ts +29 -1
  74. package/dist/proxmox/ceph-daemon-form.d.ts.map +1 -1
  75. package/dist/proxmox/ceph-daemon.d.ts.map +1 -1
  76. package/dist/proxmox/ceph-flag.d.ts.map +1 -1
  77. package/dist/proxmox/ceph-fs.d.ts.map +1 -1
  78. package/dist/proxmox/ceph-osd-write.d.ts +19 -0
  79. package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
  80. package/dist/proxmox/ceph-pool.d.ts.map +1 -1
  81. package/dist/proxmox/constraint-guard.d.ts +28 -0
  82. package/dist/proxmox/constraint-guard.d.ts.map +1 -0
  83. package/dist/proxmox/constraints.d.ts +94 -0
  84. package/dist/proxmox/constraints.d.ts.map +1 -0
  85. package/dist/proxmox/firewall-alias.d.ts.map +1 -1
  86. package/dist/proxmox/generated/constraints/index.d.ts +19 -0
  87. package/dist/proxmox/generated/constraints/index.d.ts.map +1 -0
  88. package/dist/proxmox/generated/constraints/pbs-config.d.ts +23 -0
  89. package/dist/proxmox/generated/constraints/pbs-config.d.ts.map +1 -0
  90. package/dist/proxmox/generated/constraints/pve-access.d.ts +23 -0
  91. package/dist/proxmox/generated/constraints/pve-access.d.ts.map +1 -0
  92. package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts +23 -0
  93. package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts.map +1 -0
  94. package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts +23 -0
  95. package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts.map +1 -0
  96. package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts +23 -0
  97. package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts.map +1 -0
  98. package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts +23 -0
  99. package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts.map +1 -0
  100. package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts +23 -0
  101. package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts.map +1 -0
  102. package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts +23 -0
  103. package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts.map +1 -0
  104. package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts +23 -0
  105. package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts.map +1 -0
  106. package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts +23 -0
  107. package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts.map +1 -0
  108. package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts +23 -0
  109. package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts.map +1 -0
  110. package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts +23 -0
  111. package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts.map +1 -0
  112. package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts +23 -0
  113. package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts.map +1 -0
  114. package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts +23 -0
  115. package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts.map +1 -0
  116. package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts +23 -0
  117. package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts.map +1 -0
  118. package/dist/proxmox/generated/constraints/pve-pools.d.ts +23 -0
  119. package/dist/proxmox/generated/constraints/pve-pools.d.ts.map +1 -0
  120. package/dist/proxmox/generated/constraints/pve-storage.d.ts +23 -0
  121. package/dist/proxmox/generated/constraints/pve-storage.d.ts.map +1 -0
  122. package/dist/proxmox/generated/pbs/access-users.d.ts +137 -0
  123. package/dist/proxmox/generated/pbs/access-users.d.ts.map +1 -0
  124. package/dist/proxmox/generated/pbs/access.d.ts +171 -0
  125. package/dist/proxmox/generated/pbs/access.d.ts.map +1 -0
  126. package/dist/proxmox/generated/pbs/admin-datastore-store.d.ts +252 -0
  127. package/dist/proxmox/generated/pbs/admin-datastore-store.d.ts.map +1 -0
  128. package/dist/proxmox/generated/pbs/admin-metrics.d.ts +147 -0
  129. package/dist/proxmox/generated/pbs/admin-metrics.d.ts.map +1 -0
  130. package/dist/proxmox/generated/pbs/admin.d.ts +217 -0
  131. package/dist/proxmox/generated/pbs/admin.d.ts.map +1 -0
  132. package/dist/proxmox/generated/pbs/backup.d.ts +114 -0
  133. package/dist/proxmox/generated/pbs/backup.d.ts.map +1 -0
  134. package/dist/proxmox/generated/pbs/config-access-pam.d.ts +218 -0
  135. package/dist/proxmox/generated/pbs/config-access-pam.d.ts.map +1 -0
  136. package/dist/proxmox/generated/pbs/config-access.d.ts +203 -0
  137. package/dist/proxmox/generated/pbs/config-access.d.ts.map +1 -0
  138. package/dist/proxmox/generated/pbs/config-datastore.d.ts +195 -0
  139. package/dist/proxmox/generated/pbs/config-datastore.d.ts.map +1 -0
  140. package/dist/proxmox/generated/pbs/config-media-pool.d.ts +207 -0
  141. package/dist/proxmox/generated/pbs/config-media-pool.d.ts.map +1 -0
  142. package/dist/proxmox/generated/pbs/config-notifications-matchers.d.ts +159 -0
  143. package/dist/proxmox/generated/pbs/config-notifications-matchers.d.ts.map +1 -0
  144. package/dist/proxmox/generated/pbs/config-notifications.d.ts +199 -0
  145. package/dist/proxmox/generated/pbs/config-notifications.d.ts.map +1 -0
  146. package/dist/proxmox/generated/pbs/config-remote.d.ts +175 -0
  147. package/dist/proxmox/generated/pbs/config-remote.d.ts.map +1 -0
  148. package/dist/proxmox/generated/pbs/config-sync.d.ts +145 -0
  149. package/dist/proxmox/generated/pbs/config-sync.d.ts.map +1 -0
  150. package/dist/proxmox/generated/pbs/config-tape.d.ts +200 -0
  151. package/dist/proxmox/generated/pbs/config-tape.d.ts.map +1 -0
  152. package/dist/proxmox/generated/pbs/config-verify.d.ts +77 -0
  153. package/dist/proxmox/generated/pbs/config-verify.d.ts.map +1 -0
  154. package/dist/proxmox/generated/pbs/config.d.ts +119 -0
  155. package/dist/proxmox/generated/pbs/config.d.ts.map +1 -0
  156. package/dist/proxmox/generated/pbs/nodes-node-dns.d.ts +178 -0
  157. package/dist/proxmox/generated/pbs/nodes-node-dns.d.ts.map +1 -0
  158. package/dist/proxmox/generated/pbs/nodes-node-services.d.ts +205 -0
  159. package/dist/proxmox/generated/pbs/nodes-node-services.d.ts.map +1 -0
  160. package/dist/proxmox/generated/pbs/nodes-node.d.ts +166 -0
  161. package/dist/proxmox/generated/pbs/nodes-node.d.ts.map +1 -0
  162. package/dist/proxmox/generated/pbs/nodes.d.ts +171 -0
  163. package/dist/proxmox/generated/pbs/nodes.d.ts.map +1 -0
  164. package/dist/proxmox/generated/pbs/ping.d.ts +18 -0
  165. package/dist/proxmox/generated/pbs/ping.d.ts.map +1 -0
  166. package/dist/proxmox/generated/pbs/pull.d.ts +37 -0
  167. package/dist/proxmox/generated/pbs/pull.d.ts.map +1 -0
  168. package/dist/proxmox/generated/pbs/push.d.ts +36 -0
  169. package/dist/proxmox/generated/pbs/push.d.ts.map +1 -0
  170. package/dist/proxmox/generated/pbs/reader.d.ts +41 -0
  171. package/dist/proxmox/generated/pbs/reader.d.ts.map +1 -0
  172. package/dist/proxmox/generated/pbs/root.d.ts +16 -0
  173. package/dist/proxmox/generated/pbs/root.d.ts.map +1 -0
  174. package/dist/proxmox/generated/pbs/status.d.ts +54 -0
  175. package/dist/proxmox/generated/pbs/status.d.ts.map +1 -0
  176. package/dist/proxmox/generated/pbs/tape-drive.d.ts +181 -0
  177. package/dist/proxmox/generated/pbs/tape-drive.d.ts.map +1 -0
  178. package/dist/proxmox/generated/pbs/tape-media.d.ts +126 -0
  179. package/dist/proxmox/generated/pbs/tape-media.d.ts.map +1 -0
  180. package/dist/proxmox/generated/pbs/tape.d.ts +90 -0
  181. package/dist/proxmox/generated/pbs/tape.d.ts.map +1 -0
  182. package/dist/proxmox/generated/pbs/version.d.ts +20 -0
  183. package/dist/proxmox/generated/pbs/version.d.ts.map +1 -0
  184. package/dist/proxmox/generated/pbs.d.ts +44 -662
  185. package/dist/proxmox/generated/pbs.d.ts.map +1 -1
  186. package/dist/proxmox/generated/pve/access-roles.d.ts +164 -0
  187. package/dist/proxmox/generated/pve/access-roles.d.ts.map +1 -0
  188. package/dist/proxmox/generated/pve/access-users.d.ts +152 -0
  189. package/dist/proxmox/generated/pve/access-users.d.ts.map +1 -0
  190. package/dist/proxmox/generated/pve/access.d.ts +221 -0
  191. package/dist/proxmox/generated/pve/access.d.ts.map +1 -0
  192. package/dist/proxmox/generated/pve/cluster-acme-plugins-id.d.ts +45 -0
  193. package/dist/proxmox/generated/pve/cluster-acme-plugins-id.d.ts.map +1 -0
  194. package/dist/proxmox/generated/pve/cluster-acme-plugins.d.ts +47 -0
  195. package/dist/proxmox/generated/pve/cluster-acme-plugins.d.ts.map +1 -0
  196. package/dist/proxmox/generated/pve/cluster-acme-tos.d.ts +240 -0
  197. package/dist/proxmox/generated/pve/cluster-acme-tos.d.ts.map +1 -0
  198. package/dist/proxmox/generated/pve/cluster-bulk-action.d.ts +200 -0
  199. package/dist/proxmox/generated/pve/cluster-bulk-action.d.ts.map +1 -0
  200. package/dist/proxmox/generated/pve/cluster-firewall-refs.d.ts +109 -0
  201. package/dist/proxmox/generated/pve/cluster-firewall-refs.d.ts.map +1 -0
  202. package/dist/proxmox/generated/pve/cluster-firewall.d.ts +225 -0
  203. package/dist/proxmox/generated/pve/cluster-firewall.d.ts.map +1 -0
  204. package/dist/proxmox/generated/pve/cluster-ha.d.ts +199 -0
  205. package/dist/proxmox/generated/pve/cluster-ha.d.ts.map +1 -0
  206. package/dist/proxmox/generated/pve/cluster-jobs.d.ts +183 -0
  207. package/dist/proxmox/generated/pve/cluster-jobs.d.ts.map +1 -0
  208. package/dist/proxmox/generated/pve/cluster-metrics.d.ts +110 -0
  209. package/dist/proxmox/generated/pve/cluster-metrics.d.ts.map +1 -0
  210. package/dist/proxmox/generated/pve/cluster-notifications-endpoints.d.ts +224 -0
  211. package/dist/proxmox/generated/pve/cluster-notifications-endpoints.d.ts.map +1 -0
  212. package/dist/proxmox/generated/pve/cluster-notifications.d.ts +91 -0
  213. package/dist/proxmox/generated/pve/cluster-notifications.d.ts.map +1 -0
  214. package/dist/proxmox/generated/pve/cluster-options.d.ts +85 -0
  215. package/dist/proxmox/generated/pve/cluster-options.d.ts.map +1 -0
  216. package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models-cputype.d.ts +48 -0
  217. package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models-cputype.d.ts.map +1 -0
  218. package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models.d.ts +45 -0
  219. package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models.d.ts.map +1 -0
  220. package/dist/proxmox/generated/pve/cluster-replication.d.ts +130 -0
  221. package/dist/proxmox/generated/pve/cluster-replication.d.ts.map +1 -0
  222. package/dist/proxmox/generated/pve/cluster-sdn-fabrics.d.ts +220 -0
  223. package/dist/proxmox/generated/pve/cluster-sdn-fabrics.d.ts.map +1 -0
  224. package/dist/proxmox/generated/pve/cluster-sdn-ipams.d.ts +229 -0
  225. package/dist/proxmox/generated/pve/cluster-sdn-ipams.d.ts.map +1 -0
  226. package/dist/proxmox/generated/pve/cluster-sdn-vnets-vnet.d.ts +229 -0
  227. package/dist/proxmox/generated/pve/cluster-sdn-vnets-vnet.d.ts.map +1 -0
  228. package/dist/proxmox/generated/pve/cluster-sdn-vnets.d.ts +51 -0
  229. package/dist/proxmox/generated/pve/cluster-sdn-vnets.d.ts.map +1 -0
  230. package/dist/proxmox/generated/pve/cluster-sdn-zones.d.ts +225 -0
  231. package/dist/proxmox/generated/pve/cluster-sdn-zones.d.ts.map +1 -0
  232. package/dist/proxmox/generated/pve/cluster-sdn.d.ts +202 -0
  233. package/dist/proxmox/generated/pve/cluster-sdn.d.ts.map +1 -0
  234. package/dist/proxmox/generated/pve/cluster.d.ts +69 -0
  235. package/dist/proxmox/generated/pve/cluster.d.ts.map +1 -0
  236. package/dist/proxmox/generated/pve/nodes-node-ceph.d.ts +167 -0
  237. package/dist/proxmox/generated/pve/nodes-node-ceph.d.ts.map +1 -0
  238. package/dist/proxmox/generated/pve/nodes-node-config.d.ts +43 -0
  239. package/dist/proxmox/generated/pve/nodes-node-config.d.ts.map +1 -0
  240. package/dist/proxmox/generated/pve/nodes-node-disks.d.ts +225 -0
  241. package/dist/proxmox/generated/pve/nodes-node-disks.d.ts.map +1 -0
  242. package/dist/proxmox/generated/pve/nodes-node-firewall.d.ts +145 -0
  243. package/dist/proxmox/generated/pve/nodes-node-firewall.d.ts.map +1 -0
  244. package/dist/proxmox/generated/pve/nodes-node-hardware.d.ts +195 -0
  245. package/dist/proxmox/generated/pve/nodes-node-hardware.d.ts.map +1 -0
  246. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-firewall.d.ts +191 -0
  247. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-firewall.d.ts.map +1 -0
  248. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-move-volume.d.ts +33 -0
  249. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-move-volume.d.ts.map +1 -0
  250. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-mtunnel.d.ts +56 -0
  251. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-mtunnel.d.ts.map +1 -0
  252. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-resize.d.ts +28 -0
  253. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-resize.d.ts.map +1 -0
  254. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-rrd.d.ts +186 -0
  255. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-rrd.d.ts.map +1 -0
  256. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid.d.ts +191 -0
  257. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid.d.ts.map +1 -0
  258. package/dist/proxmox/generated/pve/nodes-node-network.d.ts +150 -0
  259. package/dist/proxmox/generated/pve/nodes-node-network.d.ts.map +1 -0
  260. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-config.d.ts +301 -0
  261. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-config.d.ts.map +1 -0
  262. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-dbus-vmstate.d.ts +170 -0
  263. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-dbus-vmstate.d.ts.map +1 -0
  264. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-firewall-rules.d.ts +144 -0
  265. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-firewall-rules.d.ts.map +1 -0
  266. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-move-disk.d.ts +34 -0
  267. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-move-disk.d.ts.map +1 -0
  268. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-mtunnel.d.ts +137 -0
  269. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-mtunnel.d.ts.map +1 -0
  270. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-status.d.ts +179 -0
  271. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-status.d.ts.map +1 -0
  272. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid.d.ts +143 -0
  273. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid.d.ts.map +1 -0
  274. package/dist/proxmox/generated/pve/nodes-node-qemu.d.ts +158 -0
  275. package/dist/proxmox/generated/pve/nodes-node-qemu.d.ts.map +1 -0
  276. package/dist/proxmox/generated/pve/nodes-node-replication.d.ts +187 -0
  277. package/dist/proxmox/generated/pve/nodes-node-replication.d.ts.map +1 -0
  278. package/dist/proxmox/generated/pve/nodes-node-services.d.ts +115 -0
  279. package/dist/proxmox/generated/pve/nodes-node-services.d.ts.map +1 -0
  280. package/dist/proxmox/generated/pve/nodes-node-storage-storage.d.ts +202 -0
  281. package/dist/proxmox/generated/pve/nodes-node-storage-storage.d.ts.map +1 -0
  282. package/dist/proxmox/generated/pve/nodes-node-storage.d.ts +40 -0
  283. package/dist/proxmox/generated/pve/nodes-node-storage.d.ts.map +1 -0
  284. package/dist/proxmox/generated/pve/nodes-node-subscription.d.ts +173 -0
  285. package/dist/proxmox/generated/pve/nodes-node-subscription.d.ts.map +1 -0
  286. package/dist/proxmox/generated/pve/nodes-node-vzdump.d.ts +97 -0
  287. package/dist/proxmox/generated/pve/nodes-node-vzdump.d.ts.map +1 -0
  288. package/dist/proxmox/generated/pve/nodes-node.d.ts +207 -0
  289. package/dist/proxmox/generated/pve/nodes-node.d.ts.map +1 -0
  290. package/dist/proxmox/generated/pve/nodes.d.ts +236 -0
  291. package/dist/proxmox/generated/pve/nodes.d.ts.map +1 -0
  292. package/dist/proxmox/generated/pve/pools.d.ts +82 -0
  293. package/dist/proxmox/generated/pve/pools.d.ts.map +1 -0
  294. package/dist/proxmox/generated/pve/storage.d.ts +159 -0
  295. package/dist/proxmox/generated/pve/storage.d.ts.map +1 -0
  296. package/dist/proxmox/generated/pve/version.d.ts +21 -0
  297. package/dist/proxmox/generated/pve/version.d.ts.map +1 -0
  298. package/dist/proxmox/generated/pve.d.ts +69 -4766
  299. package/dist/proxmox/generated/pve.d.ts.map +1 -1
  300. package/dist/proxmox/group.d.ts.map +1 -1
  301. package/dist/proxmox/ha-resource.d.ts.map +1 -1
  302. package/dist/proxmox/ha-rule.d.ts.map +1 -1
  303. package/dist/proxmox/index.d.ts +6 -1
  304. package/dist/proxmox/index.d.ts.map +1 -1
  305. package/dist/proxmox/index.js +1483 -300
  306. package/dist/proxmox/index.js.map +70 -45
  307. package/dist/proxmox/lxc-lifecycle.d.ts.map +1 -1
  308. package/dist/proxmox/metric-server-form.d.ts +11 -0
  309. package/dist/proxmox/metric-server-form.d.ts.map +1 -1
  310. package/dist/proxmox/metric-server.d.ts.map +1 -1
  311. package/dist/proxmox/network-apply.d.ts.map +1 -1
  312. package/dist/proxmox/node-network-form.d.ts +15 -0
  313. package/dist/proxmox/node-network-form.d.ts.map +1 -1
  314. package/dist/proxmox/node-network.d.ts.map +1 -1
  315. package/dist/proxmox/notification-matcher.d.ts.map +1 -1
  316. package/dist/proxmox/notification-target-endpoint.d.ts +26 -0
  317. package/dist/proxmox/notification-target-endpoint.d.ts.map +1 -0
  318. package/dist/proxmox/notification-target-form.d.ts +7 -0
  319. package/dist/proxmox/notification-target-form.d.ts.map +1 -1
  320. package/dist/proxmox/notification-target.d.ts.map +1 -1
  321. package/dist/proxmox/pbs-datastore-endpoint.d.ts +22 -0
  322. package/dist/proxmox/pbs-datastore-endpoint.d.ts.map +1 -0
  323. package/dist/proxmox/pbs-datastore.d.ts.map +1 -1
  324. package/dist/proxmox/pbs-notification-matcher.d.ts.map +1 -1
  325. package/dist/proxmox/pbs-notification-target-endpoint.d.ts +29 -0
  326. package/dist/proxmox/pbs-notification-target-endpoint.d.ts.map +1 -0
  327. package/dist/proxmox/pbs-notification-target-lifecycle.d.ts.map +1 -1
  328. package/dist/proxmox/pbs-prune-job.d.ts.map +1 -1
  329. package/dist/proxmox/pbs-sync-job-form.d.ts.map +1 -1
  330. package/dist/proxmox/pbs-verify-job.d.ts.map +1 -1
  331. package/dist/proxmox/pool.d.ts.map +1 -1
  332. package/dist/proxmox/provision-baseline.d.ts +30 -5
  333. package/dist/proxmox/provision-baseline.d.ts.map +1 -1
  334. package/dist/proxmox/qemu.d.ts +10 -0
  335. package/dist/proxmox/qemu.d.ts.map +1 -1
  336. package/dist/proxmox/replication-job.d.ts.map +1 -1
  337. package/dist/proxmox/resource-guard.d.ts +15 -0
  338. package/dist/proxmox/resource-guard.d.ts.map +1 -0
  339. package/dist/proxmox/resource-spec.d.ts +131 -0
  340. package/dist/proxmox/resource-spec.d.ts.map +1 -0
  341. package/dist/proxmox/resource.d.ts +17 -90
  342. package/dist/proxmox/resource.d.ts.map +1 -1
  343. package/dist/proxmox/role.d.ts.map +1 -1
  344. package/dist/proxmox/sdn-apply.d.ts.map +1 -1
  345. package/dist/proxmox/sdn-subnet.d.ts.map +1 -1
  346. package/dist/proxmox/sdn-vnet.d.ts.map +1 -1
  347. package/dist/proxmox/sdn-zone.d.ts.map +1 -1
  348. package/dist/proxmox/storage.d.ts.map +1 -1
  349. package/dist/proxmox/user.d.ts.map +1 -1
  350. package/dist/proxmox/zfs-pool-write.d.ts +11 -0
  351. package/dist/proxmox/zfs-pool-write.d.ts.map +1 -1
  352. package/dist/proxmox/zfs-pool.d.ts.map +1 -1
  353. package/docs/linux-host-measured.md +56 -0
  354. package/docs/linux-host.md +186 -0
  355. package/docs/netbox.md +103 -0
  356. package/docs/provision-baseline.md +34 -7
  357. package/docs/proxmox-lxc.md +40 -0
  358. package/package.json +9 -1
  359. package/src/linux/directory-lifecycle.ts +220 -0
  360. package/src/linux/directory.test.ts +132 -0
  361. package/src/linux/directory.ts +71 -0
  362. package/src/linux/fake-linux-host.ts +197 -0
  363. package/src/linux/fake-systemd.ts +103 -0
  364. package/src/linux/index.ts +32 -0
  365. package/src/linux/providers.ts +26 -0
  366. package/src/linux/region.test.ts +89 -0
  367. package/src/linux/region.ts +118 -0
  368. package/src/linux/remote-file-form.ts +96 -0
  369. package/src/linux/remote-file-lifecycle.test.ts +191 -0
  370. package/src/linux/remote-file-lifecycle.ts +161 -0
  371. package/src/linux/remote-file-plan.ts +154 -0
  372. package/src/linux/remote-file.ts +88 -0
  373. package/src/linux/ssh-command.test.ts +140 -0
  374. package/src/linux/ssh-command.ts +99 -0
  375. package/src/linux/ssh-runner.ts +188 -0
  376. package/src/linux/ssh-scripts.ts +105 -0
  377. package/src/linux/systemctl.ts +145 -0
  378. package/src/linux/unit-form.ts +183 -0
  379. package/src/linux/unit-handlers.ts +73 -0
  380. package/src/linux/unit-lifecycle.test.ts +220 -0
  381. package/src/linux/unit-lifecycle.ts +193 -0
  382. package/src/linux/unit-settle.ts +110 -0
  383. package/src/linux/unit.ts +81 -0
  384. package/src/netbox/client.test.ts +67 -0
  385. package/src/netbox/client.ts +146 -0
  386. package/src/netbox/constraint-guard.ts +57 -0
  387. package/src/netbox/constraints.test.ts +114 -0
  388. package/src/netbox/constraints.ts +152 -0
  389. package/src/netbox/generated/constraints/index.ts +23 -0
  390. package/src/netbox/generated/constraints/netbox-ipam.ts +32 -0
  391. package/src/netbox/index.ts +34 -0
  392. package/src/netbox/prefix-form.test.ts +127 -0
  393. package/src/netbox/prefix-form.ts +84 -0
  394. package/src/netbox/prefix.ts +136 -0
  395. package/src/netbox/resource.ts +208 -0
  396. package/src/netbox/values.test.ts +66 -0
  397. package/src/netbox/values.ts +40 -0
  398. package/src/openbao/index-types.test.ts +87 -0
  399. package/src/openbao/index.ts +15 -3
  400. package/src/proxmox/acl.ts +2 -0
  401. package/src/proxmox/api-token-form.ts +5 -0
  402. package/src/proxmox/apply-endpoints.ts +34 -0
  403. package/src/proxmox/backup-job.ts +2 -0
  404. package/src/proxmox/ceph-daemon-form.ts +56 -2
  405. package/src/proxmox/ceph-daemon.ts +10 -21
  406. package/src/proxmox/ceph-flag.ts +1 -0
  407. package/src/proxmox/ceph-fs.ts +1 -0
  408. package/src/proxmox/ceph-osd-write.ts +30 -4
  409. package/src/proxmox/ceph-pool.ts +10 -0
  410. package/src/proxmox/constraint-guard.ts +53 -0
  411. package/src/proxmox/constraints-dialect.test.ts +165 -0
  412. package/src/proxmox/constraints-forms.test.ts +220 -0
  413. package/src/proxmox/constraints-host-forms.test.ts +132 -0
  414. package/src/proxmox/constraints-live.test.ts +155 -0
  415. package/src/proxmox/constraints-node-forms.test.ts +188 -0
  416. package/src/proxmox/constraints-required.test.ts +172 -0
  417. package/src/proxmox/constraints.test.ts +205 -0
  418. package/src/proxmox/constraints.ts +160 -0
  419. package/src/proxmox/firewall-alias.ts +5 -0
  420. package/src/proxmox/generated/constraints/index.ts +55 -0
  421. package/src/proxmox/generated/constraints/pbs-config.ts +203 -0
  422. package/src/proxmox/generated/constraints/pve-access.ts +69 -0
  423. package/src/proxmox/generated/constraints/pve-cluster-backup.ts +74 -0
  424. package/src/proxmox/generated/constraints/pve-cluster-ceph.ts +27 -0
  425. package/src/proxmox/generated/constraints/pve-cluster-firewall.ts +35 -0
  426. package/src/proxmox/generated/constraints/pve-cluster-ha.ts +55 -0
  427. package/src/proxmox/generated/constraints/pve-cluster-metrics.ts +59 -0
  428. package/src/proxmox/generated/constraints/pve-cluster-notifications.ts +80 -0
  429. package/src/proxmox/generated/constraints/pve-cluster-replication.ts +43 -0
  430. package/src/proxmox/generated/constraints/pve-cluster-sdn.ts +90 -0
  431. package/src/proxmox/generated/constraints/pve-nodes-ceph.ts +57 -0
  432. package/src/proxmox/generated/constraints/pve-nodes-disks.ts +31 -0
  433. package/src/proxmox/generated/constraints/pve-nodes-lxc.ts +82 -0
  434. package/src/proxmox/generated/constraints/pve-nodes-network.ts +77 -0
  435. package/src/proxmox/generated/constraints/pve-nodes-qemu.ts +125 -0
  436. package/src/proxmox/generated/constraints/pve-pools.ts +31 -0
  437. package/src/proxmox/generated/constraints/pve-storage.ts +80 -0
  438. package/src/proxmox/generated/pbs/access-users.ts +137 -0
  439. package/src/proxmox/generated/pbs/access.ts +232 -0
  440. package/src/proxmox/generated/pbs/admin-datastore-store.ts +238 -0
  441. package/src/proxmox/generated/pbs/admin-metrics.ts +147 -0
  442. package/src/proxmox/generated/pbs/admin.ts +225 -0
  443. package/src/proxmox/generated/pbs/backup.ts +121 -0
  444. package/src/proxmox/generated/pbs/config-access-pam.ts +228 -0
  445. package/src/proxmox/generated/pbs/config-access.ts +228 -0
  446. package/src/proxmox/generated/pbs/config-datastore.ts +217 -0
  447. package/src/proxmox/generated/pbs/config-media-pool.ts +232 -0
  448. package/src/proxmox/generated/pbs/config-notifications-matchers.ts +187 -0
  449. package/src/proxmox/generated/pbs/config-notifications.ts +221 -0
  450. package/src/proxmox/generated/pbs/config-remote.ts +192 -0
  451. package/src/proxmox/generated/pbs/config-sync.ts +167 -0
  452. package/src/proxmox/generated/pbs/config-tape.ts +226 -0
  453. package/src/proxmox/generated/pbs/config-verify.ts +87 -0
  454. package/src/proxmox/generated/pbs/config.ts +135 -0
  455. package/src/proxmox/generated/pbs/nodes-node-dns.ts +229 -0
  456. package/src/proxmox/generated/pbs/nodes-node-services.ts +181 -0
  457. package/src/proxmox/generated/pbs/nodes-node.ts +244 -0
  458. package/src/proxmox/generated/pbs/nodes.ts +160 -0
  459. package/src/proxmox/generated/pbs/ping.ts +16 -0
  460. package/src/proxmox/generated/pbs/pull.ts +37 -0
  461. package/src/proxmox/generated/pbs/push.ts +36 -0
  462. package/src/proxmox/generated/pbs/reader.ts +41 -0
  463. package/src/proxmox/generated/pbs/root.ts +16 -0
  464. package/src/proxmox/generated/pbs/status.ts +50 -0
  465. package/src/proxmox/generated/pbs/tape-drive.ts +220 -0
  466. package/src/proxmox/generated/pbs/tape-media.ts +133 -0
  467. package/src/proxmox/generated/pbs/tape.ts +92 -0
  468. package/src/proxmox/generated/pbs/version.ts +16 -0
  469. package/src/proxmox/generated/pbs.ts +44 -787
  470. package/src/proxmox/generated/pve/access-roles.ts +168 -0
  471. package/src/proxmox/generated/pve/access-users.ts +155 -0
  472. package/src/proxmox/generated/pve/access.ts +217 -0
  473. package/src/proxmox/generated/pve/cluster-acme-plugins-id.ts +367 -0
  474. package/src/proxmox/generated/pve/cluster-acme-plugins.ts +366 -0
  475. package/src/proxmox/generated/pve/cluster-acme-tos.ts +232 -0
  476. package/src/proxmox/generated/pve/cluster-bulk-action.ts +227 -0
  477. package/src/proxmox/generated/pve/cluster-firewall-refs.ts +110 -0
  478. package/src/proxmox/generated/pve/cluster-firewall.ts +236 -0
  479. package/src/proxmox/generated/pve/cluster-ha.ts +203 -0
  480. package/src/proxmox/generated/pve/cluster-jobs.ts +190 -0
  481. package/src/proxmox/generated/pve/cluster-metrics.ts +116 -0
  482. package/src/proxmox/generated/pve/cluster-notifications-endpoints.ts +244 -0
  483. package/src/proxmox/generated/pve/cluster-notifications.ts +99 -0
  484. package/src/proxmox/generated/pve/cluster-options.ts +189 -0
  485. package/src/proxmox/generated/pve/cluster-qemu-custom-cpu-models-cputype.ts +272 -0
  486. package/src/proxmox/generated/pve/cluster-qemu-custom-cpu-models.ts +268 -0
  487. package/src/proxmox/generated/pve/cluster-replication.ts +127 -0
  488. package/src/proxmox/generated/pve/cluster-sdn-fabrics.ts +218 -0
  489. package/src/proxmox/generated/pve/cluster-sdn-ipams.ts +229 -0
  490. package/src/proxmox/generated/pve/cluster-sdn-vnets-vnet.ts +245 -0
  491. package/src/proxmox/generated/pve/cluster-sdn-vnets.ts +49 -0
  492. package/src/proxmox/generated/pve/cluster-sdn-zones.ts +224 -0
  493. package/src/proxmox/generated/pve/cluster-sdn.ts +201 -0
  494. package/src/proxmox/generated/pve/cluster.ts +71 -0
  495. package/src/proxmox/generated/pve/nodes-node-ceph.ts +167 -0
  496. package/src/proxmox/generated/pve/nodes-node-config.ts +56 -0
  497. package/src/proxmox/generated/pve/nodes-node-disks.ts +237 -0
  498. package/src/proxmox/generated/pve/nodes-node-firewall.ts +239 -0
  499. package/src/proxmox/generated/pve/nodes-node-hardware.ts +215 -0
  500. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-firewall.ts +232 -0
  501. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-move-volume.ts +1059 -0
  502. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-mtunnel.ts +49 -0
  503. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-resize.ts +285 -0
  504. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-rrd.ts +184 -0
  505. package/src/proxmox/generated/pve/nodes-node-lxc-vmid.ts +240 -0
  506. package/src/proxmox/generated/pve/nodes-node-network.ts +234 -0
  507. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-config.ts +441 -0
  508. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-dbus-vmstate.ts +215 -0
  509. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-firewall-rules.ts +145 -0
  510. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-move-disk.ts +664 -0
  511. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-mtunnel.ts +188 -0
  512. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-status.ts +233 -0
  513. package/src/proxmox/generated/pve/nodes-node-qemu-vmid.ts +187 -0
  514. package/src/proxmox/generated/pve/nodes-node-qemu.ts +204 -0
  515. package/src/proxmox/generated/pve/nodes-node-replication.ts +187 -0
  516. package/src/proxmox/generated/pve/nodes-node-services.ts +221 -0
  517. package/src/proxmox/generated/pve/nodes-node-storage-storage.ts +226 -0
  518. package/src/proxmox/generated/pve/nodes-node-storage.ts +40 -0
  519. package/src/proxmox/generated/pve/nodes-node-subscription.ts +168 -0
  520. package/src/proxmox/generated/pve/nodes-node-vzdump.ts +96 -0
  521. package/src/proxmox/generated/pve/nodes-node.ts +211 -0
  522. package/src/proxmox/generated/pve/nodes.ts +235 -0
  523. package/src/proxmox/generated/pve/pools.ts +78 -0
  524. package/src/proxmox/generated/pve/storage.ts +213 -0
  525. package/src/proxmox/generated/pve/version.ts +21 -0
  526. package/src/proxmox/generated/pve.ts +69 -7403
  527. package/src/proxmox/group.ts +2 -0
  528. package/src/proxmox/ha-resource.ts +5 -0
  529. package/src/proxmox/ha-rule.ts +2 -0
  530. package/src/proxmox/index.ts +12 -0
  531. package/src/proxmox/lxc-interior.test.ts +77 -0
  532. package/src/proxmox/lxc-lifecycle.ts +48 -9
  533. package/src/proxmox/metric-server-form.ts +10 -0
  534. package/src/proxmox/metric-server.ts +11 -2
  535. package/src/proxmox/network-apply.ts +4 -0
  536. package/src/proxmox/node-network-form.ts +19 -0
  537. package/src/proxmox/node-network.ts +9 -3
  538. package/src/proxmox/notification-matcher.ts +5 -0
  539. package/src/proxmox/notification-target-endpoint.ts +46 -0
  540. package/src/proxmox/notification-target-form.ts +11 -0
  541. package/src/proxmox/notification-target.ts +5 -2
  542. package/src/proxmox/pbs-datastore-endpoint.ts +29 -0
  543. package/src/proxmox/pbs-datastore.ts +8 -1
  544. package/src/proxmox/pbs-notification-matcher.ts +5 -0
  545. package/src/proxmox/pbs-notification-target-endpoint.ts +45 -0
  546. package/src/proxmox/pbs-notification-target-lifecycle.ts +16 -14
  547. package/src/proxmox/pbs-prune-job.ts +2 -0
  548. package/src/proxmox/pbs-sync-job-form.ts +2 -0
  549. package/src/proxmox/pbs-verify-job.ts +2 -0
  550. package/src/proxmox/pool.ts +2 -0
  551. package/src/proxmox/provision-baseline.test.ts +38 -0
  552. package/src/proxmox/provision-baseline.ts +73 -14
  553. package/src/proxmox/provision-bootstrap.test.ts +51 -0
  554. package/src/proxmox/qemu.ts +9 -1
  555. package/src/proxmox/replication-job.ts +5 -0
  556. package/src/proxmox/resource-guard.ts +61 -0
  557. package/src/proxmox/resource-spec.ts +129 -0
  558. package/src/proxmox/resource.ts +52 -93
  559. package/src/proxmox/role.ts +2 -0
  560. package/src/proxmox/sdn-apply.ts +4 -0
  561. package/src/proxmox/sdn-subnet.ts +5 -0
  562. package/src/proxmox/sdn-vnet.ts +2 -0
  563. package/src/proxmox/sdn-zone.ts +2 -0
  564. package/src/proxmox/storage.ts +2 -0
  565. package/src/proxmox/user.ts +2 -0
  566. package/src/proxmox/zfs-pool-write.ts +12 -0
  567. package/src/proxmox/zfs-pool.ts +2 -1
@@ -0,0 +1,132 @@
1
+ /**
2
+ * The host families' REAL create forms — interfaces and ZFS pools — and PBS's notification
3
+ * targets, which carry the very rule the 2026-09-22 incident was about.
4
+ *
5
+ * ★ SPLIT OUT OF constraints-node-forms.test.ts FOR THE 250-LINE CAP. That file is the Ceph and
6
+ * guest families; this one is what a host itself is made of, plus the PBS half.
7
+ * ⛔ SAME PROOF, SAME REASON: a table that refuses a declaration the vendor would have ACCEPTED is
8
+ * worse than the 400 it replaces, so each family's own builder goes through
9
+ * `formViolations(key, form, true)` and an empty result is required.
10
+ */
11
+ import { describe, expect, test } from 'bun:test';
12
+ import { constraintsFor, formViolations } from './constraint-guard.ts';
13
+ import type { PbsTarget, PveTarget } from './credentials.ts';
14
+ import { createBody as ifaceCreateForm } from './node-network-form.ts';
15
+ import { resolveGroups, targetForm } from './pbs-notification-target-form.ts';
16
+ import { createForm as zfsCreateForm } from './zfs-pool-write.ts';
17
+
18
+ const TARGET: PveTarget = { members: ['pve.test:8006'], mount: 'pve-test', scheme: 'pve' };
19
+ const PBS: PbsTarget = { api: 'https://pbs.test:8007/api2/json', mount: 'pbs-test', scheme: 'pbs' };
20
+
21
+ const onCreate = (key: string, form: Record<string, string | readonly string[]>) =>
22
+ formViolations(key, form, true);
23
+
24
+ describe('the host families plan clean against their own creates', () => {
25
+ /**
26
+ * 🔴 THE BUG THIS PROOF FOUND. `createForm` was `body`, which never sent `iface` — and PVE marks
27
+ * it REQUIRED on the POST while `{node}` is the only path parameter. Every NodeNetwork create
28
+ * this repository could have made would have 400ed; nothing caught it because C1's three nodes
29
+ * were all adopted, which takes the PUT path. See the 🔴 on `createBody`.
30
+ */
31
+ test('an interface create carries iface, which PVE requires in the body', () => {
32
+ const form = ifaceCreateForm({
33
+ autostart: true,
34
+ cidr: '192.0.2.10/24',
35
+ iface: 'vmbr1.42',
36
+ node: 'n2',
37
+ target: TARGET,
38
+ type: 'vlan',
39
+ 'vlan-raw-device': 'vmbr1',
40
+ });
41
+ expect(form['iface']).toBe('vmbr1.42');
42
+ expect(onCreate('pve:POST /nodes/{node}/network', form)).toEqual([]);
43
+ });
44
+
45
+ test('iface and type are the required pair, and iface is 2..20 characters', () => {
46
+ const table = constraintsFor('pve:POST /nodes/{node}/network');
47
+ expect(
48
+ Object.entries(table)
49
+ .filter(([, rule]) => rule.required)
50
+ .map(([name]) => name),
51
+ ).toEqual(['iface', 'type']);
52
+ expect(table['iface']).toMatchObject({ maxLength: 20, minLength: 2 });
53
+ });
54
+
55
+ /** ⚠️ The PUT takes `iface` in the path, so the update form is right to leave it out. */
56
+ test('the update form, without iface, passes the PUT table', () => {
57
+ expect(constraintsFor('pve:PUT /nodes/{node}/network/{iface}')['iface']).toBeUndefined();
58
+ });
59
+
60
+ test('a ZFS pool create passes, and its three required parameters are all sent', () => {
61
+ const form = zfsCreateForm({
62
+ ashift: 12,
63
+ compression: 'lz4',
64
+ devices: ['/dev/nvme0n1', '/dev/nvme1n1'],
65
+ name: 'rpool-data',
66
+ node: 'n2',
67
+ raidlevel: 'mirror',
68
+ target: TARGET,
69
+ });
70
+ expect(onCreate('pve:POST /nodes/{node}/disks/zfs', form)).toEqual([]);
71
+ for (const name of ['devices', 'name', 'raidlevel']) expect(form[name]).toBeDefined();
72
+ });
73
+
74
+ test('an ashift above PVE own maximum of 16 is refused', () => {
75
+ expect(
76
+ onCreate(
77
+ 'pve:POST /nodes/{node}/disks/zfs',
78
+ zfsCreateForm({
79
+ ashift: 17,
80
+ devices: ['/dev/nvme0n1'],
81
+ name: 'rpool-data',
82
+ node: 'n2',
83
+ raidlevel: 'single',
84
+ target: TARGET,
85
+ }),
86
+ ),
87
+ ).toEqual(['ashift: at most 16']);
88
+ });
89
+ });
90
+
91
+ /**
92
+ * 🔴 `Pbs.NotificationTarget` CARRIES THE INCIDENT'S OWN PARAMETER. `comment` is `maxLength: 128`
93
+ * with a no-control-characters pattern on all three PBS creates — the same rule, on the same
94
+ * product, that failed `POST /config/verify` half a deploy in. This family was missing from the
95
+ * list the sweep started from; it is wired with the rest.
96
+ */
97
+ describe('Pbs.NotificationTarget plans clean, and its comment is the 128 again', () => {
98
+ const declared = {
99
+ comment: 'PBS failure mail',
100
+ mailto: ['someone@example.invalid'],
101
+ name: 'mail-to-root',
102
+ target: PBS,
103
+ type: 'sendmail',
104
+ } as const;
105
+ const carry = { header: true, sealed: true } as const;
106
+
107
+ test('a sendmail target has no violations', () => {
108
+ const form = targetForm(declared, resolveGroups(declared, {}), carry, 'create');
109
+ expect(form['name']).toBe('mail-to-root');
110
+ expect(onCreate('pbs:POST /config/notifications/endpoints/sendmail', form)).toEqual([]);
111
+ });
112
+
113
+ test('a 129-character comment is refused, exactly as on POST /config/verify', () => {
114
+ const over = { ...declared, comment: 'c'.repeat(129) };
115
+ const form = targetForm(over, resolveGroups(over, {}), carry, 'create');
116
+ expect(onCreate('pbs:POST /config/notifications/endpoints/sendmail', form)).toEqual([
117
+ 'comment: at most 128 characters',
118
+ ]);
119
+ });
120
+
121
+ test('a webhook target sends the url and method PBS requires', () => {
122
+ const hook = {
123
+ method: 'post',
124
+ name: 'hook-house',
125
+ target: PBS,
126
+ type: 'webhook',
127
+ url: 'https://hooks.example.invalid/pbs',
128
+ } as const;
129
+ const form = targetForm(hook, resolveGroups(hook, {}), carry, 'create');
130
+ expect(onCreate('pbs:POST /config/notifications/endpoints/webhook', form)).toEqual([]);
131
+ });
132
+ });
@@ -0,0 +1,155 @@
1
+ /**
2
+ * The whole live PBS estate, through its own create and update tables, expecting NOTHING.
3
+ *
4
+ * ⛔ THIS IS THE RISK THE CONSTRAINT GUARD CARRIES, NOT THE ONE IT FIXES. A table that refuses a
5
+ * declaration the vendor would have ACCEPTED blocks a deploy that was always legal, and the
6
+ * operator cannot tell that from a genuine violation. `guardForms` runs in `diff` AND in
7
+ * `reconcile`, and `reconcile` runs for an ADOPTED row — so every object the estate has already
8
+ * adopted faces these tables on its next plan. A false positive here is a broken plan for ten
9
+ * live objects, including a datastore holding the offsite copies.
10
+ *
11
+ * ★ THE VALUES ARE THE LIVE ONES, read from homeflare-proxmox's own inventory fixture
12
+ * (`tests/fixtures/pbs-live-2026-09-21.json`, captured read-only 2026-09-21): the ten objects
13
+ * PBS actually holds, with their real ids, stores, schedules and retention numbers.
14
+ * ⚠️ EXCEPT THE COMMENT TEXT, WHICH IS REPLACED BY A STRING OF THE SAME CHARACTER LENGTH. This
15
+ * package is public and the live comments name hosts and runbook paths. Length and character
16
+ * class are the whole of what a `maxLength`/`pattern` rule sees, so the substitution costs the
17
+ * test nothing — and the lengths (106, 116, 88, 107, 120) are the live ones, asserted below.
18
+ */
19
+ import { describe, expect, test } from 'bun:test';
20
+ import { formViolations } from './constraint-guard.ts';
21
+ import type { PbsTarget } from './credentials.ts';
22
+ import { createForm as datastoreCreateForm, updateForm } from './pbs-datastore-form.ts';
23
+ import { createBody as pruneCreateBody, updateBody as pruneUpdate } from './pbs-prune-job-form.ts';
24
+ import { createBody as syncCreateBody, updateBody as syncUpdate } from './pbs-sync-job-form.ts';
25
+ import type { PbsVerifyJobProps } from './pbs-verify-job.ts';
26
+ import { shape as verifyShape } from './pbs-verify-job-form.ts';
27
+
28
+ const PBS: PbsTarget = { api: 'https://pbs.test:8007/api2/json', mount: 'pbs-test', scheme: 'pbs' };
29
+ const filler = (length: number) => 'c'.repeat(length);
30
+
31
+ /** What `pbs-verify-job.ts` builds inline for a create: the update shape plus the required `id`. */
32
+ const verifyCreate = (props: PbsVerifyJobProps) => ({ ...verifyShape(props), id: props.id });
33
+
34
+ describe('every live PBS object passes its own create table', () => {
35
+ test('the three prune jobs, including the parked one', () => {
36
+ for (const job of [
37
+ { id: 'prune-cluster-all', keep: 3, schedule: 'Sat 06:00', store: 'cluster' },
38
+ { comment: filler(88), id: 'prune-datacenter-all', keep: 3, store: 'datacenter' },
39
+ { id: 'prune-r2-offsite-all', keep: 3, schedule: 'Sat 07:30', store: 'r2-offsite' },
40
+ ]) {
41
+ const form = pruneCreateBody({
42
+ ...job,
43
+ 'keep-daily': 7,
44
+ 'keep-last': job.keep,
45
+ 'keep-monthly': 3,
46
+ 'keep-weekly': 4,
47
+ 'max-depth': 7,
48
+ schedule: job.schedule ?? 'Sat 08:00',
49
+ target: PBS,
50
+ });
51
+ expect([job.id, formViolations('pbs:POST /config/prune', form, true)]).toEqual([job.id, []]);
52
+ }
53
+ });
54
+
55
+ /**
56
+ * ⚠️ `sync-all-to-dc` HAS NO `schedule` AND `v-datacenter` HAS NEITHER `schedule` NOR `ns`. Both
57
+ * are parked, and both are legal: PBS marks `schedule` optional on sync and verify jobs. If
58
+ * the presence check ever read `required` from the wrong place, these two rows are what fails.
59
+ */
60
+ test('the two sync jobs, one of them parked with no schedule', () => {
61
+ const parked = syncCreateBody({
62
+ comment: filler(107),
63
+ id: 'sync-all-to-dc',
64
+ 'max-depth': 7,
65
+ 'remote-store': 'cluster',
66
+ 'remove-vanished': false,
67
+ store: 'datacenter',
68
+ target: PBS,
69
+ 'verified-only': true,
70
+ });
71
+ expect(formViolations('pbs:POST /config/sync', parked, true)).toEqual([]);
72
+ const live = syncCreateBody({
73
+ id: 'sync-all-to-r2',
74
+ owner: 'root@pam',
75
+ 'remote-store': 'cluster',
76
+ schedule: '08:30',
77
+ store: 'r2-offsite',
78
+ target: PBS,
79
+ });
80
+ expect(formViolations('pbs:POST /config/sync', live, true)).toEqual([]);
81
+ });
82
+
83
+ /**
84
+ * ⚠️ `{...shape(props), id}` IS THE CREATE FORM, SPELLED OUT. `pbs-verify-job.ts` builds it
85
+ * inline and exports only `shape`, which is the UPDATE form and carries no `id` — and `id` is
86
+ * one of the two parameters PBS marks required on this endpoint. Calling `shape` here and
87
+ * expecting no violations reported `id: required`, which is the presence check working, not a
88
+ * defect. If that inline `id` is ever dropped, this test is what says so.
89
+ * ⚠️ `ns: ''` IS A LIVE VALUE AND `shape` DROPS IT rather than sending the empty string, so the
90
+ * table never sees it. The vendor's pattern would accept it either way — it ends `)?$`.
91
+ */
92
+ test('the two verify jobs, one with an empty namespace', () => {
93
+ const running = verifyCreate({
94
+ id: 'v-b7d7ff81-17d6',
95
+ 'ignore-verified': true,
96
+ ns: '',
97
+ 'outdated-after': 30,
98
+ schedule: '06:30',
99
+ store: 'cluster',
100
+ target: PBS,
101
+ });
102
+ expect(formViolations('pbs:POST /config/verify', running, true)).toEqual([]);
103
+ const parked = verifyCreate({
104
+ comment: filler(120),
105
+ id: 'v-datacenter',
106
+ 'ignore-verified': true,
107
+ 'outdated-after': 30,
108
+ schedule: null,
109
+ store: 'datacenter',
110
+ target: PBS,
111
+ });
112
+ expect(formViolations('pbs:POST /config/verify', parked, true)).toEqual([]);
113
+ });
114
+
115
+ test('the three datastores, on create and on update', () => {
116
+ for (const store of [
117
+ { comment: filler(106), name: 'cluster', path: '/mnt/datastore/cluster' },
118
+ { comment: filler(116), name: 'datacenter', path: '/mnt/cluster_pbs' },
119
+ { comment: filler(106), name: 'r2-offsite', path: '/mnt/datastore/r2-cache' },
120
+ ]) {
121
+ const props = { ...store, target: PBS };
122
+ expect([
123
+ store.name,
124
+ formViolations('pbs:POST /config/datastore', datastoreCreateForm(props), true),
125
+ ]).toEqual([store.name, []]);
126
+ // ⚠️ THE UPDATE FORM IS PARTIAL BY DESIGN, so presence is off — value rules still apply.
127
+ expect([
128
+ store.name,
129
+ formViolations('pbs:PUT /config/datastore/{name}', updateForm(props), false),
130
+ ]).toEqual([store.name, []]);
131
+ }
132
+ });
133
+
134
+ test('the prune and sync update forms, which send only what changed', () => {
135
+ const prune = pruneUpdate({
136
+ id: 'prune-cluster-all',
137
+ 'keep-daily': 7,
138
+ 'keep-last': 3,
139
+ 'max-depth': 7,
140
+ schedule: 'Sat 06:00',
141
+ store: 'cluster',
142
+ target: PBS,
143
+ });
144
+ expect(formViolations('pbs:PUT /config/prune/{id}', prune, false)).toEqual([]);
145
+ const sync = syncUpdate({
146
+ id: 'sync-all-to-r2',
147
+ owner: 'root@pam',
148
+ 'remote-store': 'cluster',
149
+ schedule: '08:30',
150
+ store: 'r2-offsite',
151
+ target: PBS,
152
+ });
153
+ expect(formViolations('pbs:PUT /config/sync/{id}', sync, false)).toEqual([]);
154
+ });
155
+ });
@@ -0,0 +1,188 @@
1
+ /**
2
+ * The node-scoped families' REAL create forms, against the vendor's own tables — and PBS's
3
+ * notification targets, which carry the very rule the 2026-09-22 incident was about.
4
+ *
5
+ * ⛔ SAME PROOF AS constraints-forms.test.ts, AND THE SAME REASON FOR IT: a table that refuses a
6
+ * declaration the vendor would have ACCEPTED is worse than the 400 it replaces, because the
7
+ * operator cannot tell it from a genuine violation. Each family's own builder, through
8
+ * `formViolations(key, form, true)`, empty result required.
9
+ */
10
+ import { describe, expect, test } from 'bun:test';
11
+ import { createForm as daemonCreateForm } from './ceph-daemon-form.ts';
12
+ import { createForm as cephFsCreateForm } from './ceph-fs-wire.ts';
13
+ import { createOsdForm } from './ceph-osd-write.ts';
14
+ import { createBody as cephPoolCreateForm } from './ceph-pool-form.ts';
15
+ import { constraintsFor, formViolations } from './constraint-guard.ts';
16
+ import type { PveTarget } from './credentials.ts';
17
+ import { TARGET as LXC_TARGET, pasted } from './lxc-harness.ts';
18
+ import { createForm as lxcCreateForm } from './lxc-create-form.ts';
19
+ import { createForm as vmCreateForm } from './qemu.ts';
20
+
21
+ const TARGET: PveTarget = { members: ['pve.test:8006'], mount: 'pve-test', scheme: 'pve' };
22
+
23
+ const onCreate = (key: string, form: Record<string, string | readonly string[]>) =>
24
+ formViolations(key, form, true);
25
+
26
+ describe('the Ceph families plan clean against their own creates', () => {
27
+ /** ⚠️ Three kinds, three endpoints, three parameter schemas — see `DAEMON_ENDPOINTS`. */
28
+ test('a mon, an mds and a mgr each pass their own table', () => {
29
+ expect(
30
+ onCreate(
31
+ 'pve:POST /nodes/{node}/ceph/mon/{monid}',
32
+ daemonCreateForm({ kind: 'mon', 'mon-address': '192.0.2.11', node: 'n2', target: TARGET }),
33
+ ),
34
+ ).toEqual([]);
35
+ expect(
36
+ onCreate(
37
+ 'pve:POST /nodes/{node}/ceph/mds/{name}',
38
+ daemonCreateForm({ hotstandby: true, kind: 'mds', node: 'n2', target: TARGET }),
39
+ ),
40
+ ).toEqual([]);
41
+ expect(
42
+ onCreate(
43
+ 'pve:POST /nodes/{node}/ceph/mgr/{id}',
44
+ daemonCreateForm({ kind: 'mgr', node: 'n2', target: TARGET }),
45
+ ),
46
+ ).toEqual([]);
47
+ });
48
+
49
+ test('a CephFS create passes, and pg_num carries the vendor own 8..32768', () => {
50
+ expect(
51
+ onCreate(
52
+ 'pve:POST /nodes/{node}/ceph/fs/{name}',
53
+ cephFsCreateForm({ 'add-storage': true, name: 'cephfs-c1', node: 'n2', target: TARGET }),
54
+ ),
55
+ ).toEqual([]);
56
+ expect(constraintsFor('pve:POST /nodes/{node}/ceph/fs/{name}')['pg_num']).toMatchObject({
57
+ maximum: 32_768,
58
+ minimum: 8,
59
+ });
60
+ });
61
+
62
+ test('an OSD create passes, and dev is the parameter PVE requires', () => {
63
+ expect(
64
+ onCreate(
65
+ 'pve:POST /nodes/{node}/ceph/osd',
66
+ createOsdForm({ node: 'n2', osdid: 4, target: TARGET }, '/dev/nvme1n1'),
67
+ ),
68
+ ).toEqual([]);
69
+ expect(constraintsFor('pve:POST /nodes/{node}/ceph/osd')['dev']?.required).toBe(true);
70
+ });
71
+
72
+ /** The estate's own pools: `cephtb4` and the two `cephfs-tb4_*` halves, size 3 / min_size 2. */
73
+ test('the live CephPool declarations have no violations', () => {
74
+ for (const name of ['cephtb4', 'cephfs-tb4_data', 'cephfs-tb4_metadata']) {
75
+ expect(
76
+ onCreate(
77
+ 'pve:POST /nodes/{node}/ceph/pool',
78
+ cephPoolCreateForm({
79
+ crush_rule: 'replicated_rule',
80
+ min_size: 2,
81
+ name,
82
+ node: 'n2',
83
+ pg_autoscale_mode: 'on',
84
+ size: 3,
85
+ target: TARGET,
86
+ }),
87
+ ),
88
+ name,
89
+ ).toEqual([]);
90
+ }
91
+ });
92
+
93
+ test('a pool asking for size 8 is refused: PVE own maximum is 7', () => {
94
+ expect(
95
+ onCreate(
96
+ 'pve:POST /nodes/{node}/ceph/pool',
97
+ cephPoolCreateForm({ name: 'toobig', node: 'n2', size: 8, target: TARGET }),
98
+ ),
99
+ ).toEqual(['size: at most 7']);
100
+ });
101
+ });
102
+
103
+ describe('the guest families plan clean against their own creates', () => {
104
+ /**
105
+ * ⚠️ THE HARNESS DECLARATION, PLUS THE ONE CREATE-ONLY KEY IT CANNOT CARRY. `pasted()` is the
106
+ * production-SHAPED config with placeholder values (lxc-harness.ts); `ostemplate` is absent
107
+ * from it because a live config never reports one, and PVE requires it on create.
108
+ */
109
+ test('a full LXC declaration with its template has no violations', () => {
110
+ const form = lxcCreateForm(
111
+ pasted({ ostemplate: 'local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst' }),
112
+ );
113
+ expect(form['vmid']).toBe('900');
114
+ expect(onCreate('pve:POST /nodes/{node}/lxc', form)).toEqual([]);
115
+ });
116
+
117
+ /** ⛔ `ostemplate` AND `vmid` ARE THE TWO PVE MARKS REQUIRED, and `{node}` is the path. */
118
+ test('ostemplate and vmid are the required pair, and node is not in the table', () => {
119
+ const table = constraintsFor('pve:POST /nodes/{node}/lxc');
120
+ expect(
121
+ Object.entries(table)
122
+ .filter(([, rule]) => rule.required)
123
+ .map(([name]) => name),
124
+ ).toEqual(['ostemplate', 'vmid']);
125
+ expect(table['node']).toBeUndefined();
126
+ });
127
+
128
+ /** ⚠️ The same harness props, against the SECOND endpoint this family writes. */
129
+ test('a resize form passes its own table', () => {
130
+ expect(
131
+ formViolations(
132
+ 'pve:PUT /nodes/{node}/lxc/{vmid}/resize',
133
+ { disk: 'rootfs', size: '+8G' },
134
+ true,
135
+ ),
136
+ ).toEqual([]);
137
+ expect(LXC_TARGET.scheme).toBe('pve');
138
+ });
139
+
140
+ /**
141
+ * ⛔ THE ONE VALUE THIS PACKAGE ECHOES BACK TO PVE UNCHANGED, AND IT HAS A BOUND. `updateGuest`
142
+ * carries the `digest` of the config it was judged against so PVE can refuse a write over an
143
+ * edit that landed meanwhile — and PVE's own schema caps that parameter at 40 characters,
144
+ * which is exactly a sha1_hex. A version that started returning a longer digest would refuse
145
+ * its own echo server-side; the point of the assertion is that 40 is not refused HERE.
146
+ */
147
+ test('a config PUT carrying a 40-character digest is not refused', () => {
148
+ expect(
149
+ formViolations(
150
+ 'pve:PUT /nodes/{node}/lxc/{vmid}/config',
151
+ { digest: 'a'.repeat(40), memory: '8192' },
152
+ false,
153
+ ),
154
+ ).toEqual([]);
155
+ expect(constraintsFor('pve:PUT /nodes/{node}/lxc/{vmid}/config')['digest']).toMatchObject({
156
+ maxLength: 40,
157
+ });
158
+ });
159
+
160
+ test('a VM create passes, and vmid carries PVE own 100..999999999', () => {
161
+ expect(
162
+ onCreate(
163
+ 'pve:POST /nodes/{node}/qemu',
164
+ vmCreateForm({
165
+ cores: 2,
166
+ memory: 2048,
167
+ name: 'vm-example',
168
+ node: 'n2',
169
+ target: TARGET,
170
+ vmid: 150,
171
+ }),
172
+ ),
173
+ ).toEqual([]);
174
+ expect(constraintsFor('pve:POST /nodes/{node}/qemu')['vmid']).toMatchObject({
175
+ maximum: 999_999_999,
176
+ minimum: 100,
177
+ });
178
+ });
179
+
180
+ test('a vmid below PVE own minimum is refused rather than sent', () => {
181
+ expect(
182
+ onCreate(
183
+ 'pve:POST /nodes/{node}/qemu',
184
+ vmCreateForm({ node: 'n2', target: TARGET, vmid: 99 }),
185
+ ),
186
+ ).toEqual(['vmid: at least 100']);
187
+ });
188
+ });
@@ -0,0 +1,172 @@
1
+ /**
2
+ * What the create check will actually DEMAND, committed — plus the families PR 102 wired without
3
+ * a create-form proof of their own.
4
+ *
5
+ * ⛔ THE OBJECTION THIS ANSWERS. Since 2026-09-22 the create form's required parameters are
6
+ * demanded only when a create is really about to happen (resource-guard.ts), which is correct —
7
+ * refusing a plan over a request that will never be made is a false positive by construction —
8
+ * but it moves some coverage out of the runtime and into here. So the required set is written
9
+ * down: a schema refresh that adds a required parameter to an endpoint this package writes to
10
+ * is EXACTLY the change that would start refusing creates, and it fails here, with a diff a
11
+ * reviewer can read, instead of on the first deploy that creates one.
12
+ *
13
+ * ⚠️ THE LIST IS THE VENDOR'S, NOT OURS. Nothing here asserts that a rule is sensible, only that
14
+ * it is what the two products publish today (pve-manager 9.2.11, proxmox-backup-server 4.2.6-1).
15
+ */
16
+ import { describe, expect, test } from 'bun:test';
17
+ import { constraintsFor, formViolations } from './constraint-guard.ts';
18
+ import type { PveTarget } from './credentials.ts';
19
+ import { body as aliasBody } from './firewall-alias-form.ts';
20
+ import { PROXMOX_CONSTRAINTS } from './generated/constraints/index.ts';
21
+ import { body as haRuleBody } from './ha-rule-form.ts';
22
+ import { matcherCreateForm } from './notification-matcher-form.ts';
23
+ import { poolCreateForm } from './pool.ts';
24
+ import { createBody as replicationCreateBody } from './replication-job-form.ts';
25
+
26
+ const TARGET: PveTarget = { members: ['pve.test:8006'], mount: 'pve-test', scheme: 'pve' };
27
+
28
+ const onCreate = (key: string, form: Record<string, string | readonly string[]>) =>
29
+ formViolations(key, form, true);
30
+
31
+ const requiredOf = (key: string) =>
32
+ Object.entries(constraintsFor(key))
33
+ .filter(([, rule]) => rule.required === true)
34
+ .map(([name]) => name)
35
+ .sort();
36
+
37
+ describe('every create this package makes, and what the vendor requires of it', () => {
38
+ /**
39
+ * ⚠️ AN ENDPOINT WITH NO REQUIRED PARAMETER IS NOT A MISTAKE. `POST /cluster/backup` genuinely
40
+ * marks nothing required; recording the empty set is the same information as recording a full
41
+ * one. ⛔ `POST /cluster/ha/rules` LOOKED LIKE ONE OF THOSE until PR 113 taught the reader to
42
+ * follow PVE's `allOf`/`oneOf`, which is exactly the class of change this census exists to
43
+ * make visible in a diff.
44
+ */
45
+ test('the required set of every tabled POST is exactly this', () => {
46
+ const creates = Object.keys(PROXMOX_CONSTRAINTS)
47
+ .filter((key) => key.includes(':POST '))
48
+ .sort();
49
+ const census = Object.fromEntries(
50
+ creates.map((key) => [key, requiredOf(key)] as const).filter(([, names]) => names.length > 0),
51
+ );
52
+ expect(census).toEqual({
53
+ 'pbs:POST /config/datastore': ['name', 'path'],
54
+ 'pbs:POST /config/notifications/endpoints/sendmail': ['name'],
55
+ 'pbs:POST /config/notifications/endpoints/smtp': ['from-address', 'name', 'server'],
56
+ 'pbs:POST /config/notifications/endpoints/webhook': ['method', 'name', 'url'],
57
+ 'pbs:POST /config/notifications/matchers': ['name'],
58
+ 'pbs:POST /config/prune': ['id', 'schedule', 'store'],
59
+ 'pbs:POST /config/sync': ['id', 'remote-store', 'store'],
60
+ 'pbs:POST /config/verify': ['id', 'store'],
61
+ 'pve:POST /access/groups': ['groupid'],
62
+ 'pve:POST /access/roles': ['roleid'],
63
+ 'pve:POST /access/users': ['userid'],
64
+ 'pve:POST /cluster/firewall/aliases': ['cidr', 'name'],
65
+ 'pve:POST /cluster/ha/resources': ['sid'],
66
+ 'pve:POST /cluster/ha/rules': ['resources', 'rule'],
67
+ 'pve:POST /cluster/metrics/server/{id}': ['port', 'server', 'type'],
68
+ 'pve:POST /cluster/notifications/endpoints/gotify': ['name', 'server', 'token'],
69
+ 'pve:POST /cluster/notifications/endpoints/sendmail': ['name'],
70
+ 'pve:POST /cluster/notifications/endpoints/smtp': ['from-address', 'name', 'server'],
71
+ 'pve:POST /cluster/notifications/endpoints/webhook': ['method', 'name', 'url'],
72
+ 'pve:POST /cluster/notifications/matchers': ['name'],
73
+ 'pve:POST /cluster/replication': ['id', 'target', 'type'],
74
+ 'pve:POST /cluster/sdn/vnets': ['vnet', 'zone'],
75
+ 'pve:POST /cluster/sdn/vnets/{vnet}/subnets': ['subnet', 'type'],
76
+ 'pve:POST /cluster/sdn/zones': ['type', 'zone'],
77
+ 'pve:POST /nodes/{node}/ceph/osd': ['dev'],
78
+ 'pve:POST /nodes/{node}/ceph/pool': ['name'],
79
+ 'pve:POST /nodes/{node}/disks/zfs': ['devices', 'name', 'raidlevel'],
80
+ 'pve:POST /nodes/{node}/lxc': ['ostemplate', 'vmid'],
81
+ 'pve:POST /nodes/{node}/network': ['iface', 'type'],
82
+ 'pve:POST /nodes/{node}/qemu': ['vmid'],
83
+ 'pve:POST /pools': ['poolid'],
84
+ 'pve:POST /storage': ['storage', 'type'],
85
+ });
86
+ });
87
+
88
+ /**
89
+ * ⛔ `PUT /access/acl` IS A CREATE HERE. PVE registers no POST on the ACL collection, so acl.ts
90
+ * names the same PUT for both — which means its required pair IS demanded on the create path.
91
+ */
92
+ test('the ACL PUT requires a path and a role list, and both are its own props', () => {
93
+ expect(requiredOf('pve:PUT /access/acl')).toEqual(['path', 'roles']);
94
+ });
95
+
96
+ /** ⚠️ No POST/PUT this package writes requires a parameter it sends only as a path segment. */
97
+ test('no required parameter is also a path segment of its own endpoint', () => {
98
+ for (const key of Object.keys(PROXMOX_CONSTRAINTS)) {
99
+ const segments = new Set([...key.matchAll(/\{([^}]+)\}/g)].map((m) => m[1]));
100
+ for (const name of requiredOf(key)) expect(segments.has(name), `${key} ${name}`).toBe(false);
101
+ }
102
+ });
103
+ });
104
+
105
+ /**
106
+ * ★ THE FAMILIES PR 102 WIRED, WITH THE PROOF IT DID NOT WRITE. Five of them build their create
107
+ * form from a builder that is already exported, so covering them costs nothing but this file.
108
+ * The rest build theirs inline in a spec literal and are covered by the required-set census
109
+ * above instead — recorded honestly rather than claimed.
110
+ */
111
+ describe('the families wired before this sweep pass their own create tables', () => {
112
+ test('Proxmox.Pool', () => {
113
+ expect(
114
+ onCreate(
115
+ 'pve:POST /pools',
116
+ poolCreateForm({ comment: 'house', poolid: 'house', target: TARGET }),
117
+ ),
118
+ ).toEqual([]);
119
+ });
120
+
121
+ test('Proxmox.FirewallAlias', () => {
122
+ const form = {
123
+ ...aliasBody({ cidr: '192.0.2.0/24', name: 'lab', target: TARGET }),
124
+ name: 'lab',
125
+ };
126
+ expect(onCreate('pve:POST /cluster/firewall/aliases', form)).toEqual([]);
127
+ });
128
+
129
+ test('Proxmox.HaRule', () => {
130
+ const form = {
131
+ ...haRuleBody({
132
+ affinity: 'positive',
133
+ nodes: ['n2', 'n3'],
134
+ resources: ['ct:101', 'ct:102'],
135
+ rule: 'keep-together',
136
+ strict: true,
137
+ target: TARGET,
138
+ type: 'node-affinity',
139
+ }),
140
+ rule: 'keep-together',
141
+ };
142
+ expect(onCreate('pve:POST /cluster/ha/rules', form)).toEqual([]);
143
+ });
144
+
145
+ test('Proxmox.ReplicationJob', () => {
146
+ expect(
147
+ onCreate(
148
+ 'pve:POST /cluster/replication',
149
+ replicationCreateBody({
150
+ guest: 150,
151
+ jobnum: 0,
152
+ schedule: '*/15',
153
+ target: TARGET,
154
+ targetNode: 'n3',
155
+ }),
156
+ ),
157
+ ).toEqual([]);
158
+ });
159
+
160
+ /** ⚠️ One builder, two products: both matcher families share `matcherCreateForm`. */
161
+ test('Proxmox.NotificationMatcher and Pbs.NotificationMatcher', () => {
162
+ const form = matcherCreateForm({
163
+ comment: 'route everything to mail-to-root',
164
+ 'match-severity': ['warning', 'error'],
165
+ mode: 'all',
166
+ name: 'default-matcher',
167
+ targets: ['mail-to-root'],
168
+ });
169
+ expect(onCreate('pve:POST /cluster/notifications/matchers', form)).toEqual([]);
170
+ expect(onCreate('pbs:POST /config/notifications/matchers', form)).toEqual([]);
171
+ });
172
+ });