@homeflare/alchemy 0.39.0 → 0.41.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.
- package/README.md +10 -8
- package/dist/caddy/index.js.map +2 -2
- package/dist/ceph/auth-entity.d.ts +34 -0
- package/dist/ceph/auth-entity.d.ts.map +1 -0
- package/dist/ceph/ceph-argv-config.d.ts +10 -0
- package/dist/ceph/ceph-argv-config.d.ts.map +1 -0
- package/dist/ceph/ceph-argv.d.ts +19 -0
- package/dist/ceph/ceph-argv.d.ts.map +1 -0
- package/dist/ceph/ceph-auth-form.d.ts +54 -0
- package/dist/ceph/ceph-auth-form.d.ts.map +1 -0
- package/dist/ceph/ceph-auth-parse.d.ts +56 -0
- package/dist/ceph/ceph-auth-parse.d.ts.map +1 -0
- package/dist/ceph/ceph-auth-reconcile.d.ts +35 -0
- package/dist/ceph/ceph-auth-reconcile.d.ts.map +1 -0
- package/dist/ceph/ceph-config-options.d.ts +23 -0
- package/dist/ceph/ceph-config-options.d.ts.map +1 -0
- package/dist/ceph/ceph-key-leak-assert.d.ts +25 -0
- package/dist/ceph/ceph-key-leak-assert.d.ts.map +1 -0
- package/dist/ceph/ceph-transport.d.ts +37 -0
- package/dist/ceph/ceph-transport.d.ts.map +1 -0
- package/dist/ceph/fake-ceph-dial.d.ts +35 -0
- package/dist/ceph/fake-ceph-dial.d.ts.map +1 -0
- package/dist/ceph/index.d.ts +13 -0
- package/dist/ceph/index.d.ts.map +1 -0
- package/dist/ceph/index.js +1610 -0
- package/dist/ceph/index.js.map +38 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/launchd/fake-runner.d.ts.map +1 -1
- package/dist/launchd/index.d.ts +1 -1
- package/dist/launchd/index.d.ts.map +1 -1
- package/dist/launchd/index.js +7 -1
- package/dist/launchd/index.js.map +5 -5
- package/dist/launchd/local-runner.d.ts.map +1 -1
- package/dist/launchd/runner.d.ts +21 -0
- package/dist/launchd/runner.d.ts.map +1 -1
- package/dist/launchd/sudo-runner.d.ts.map +1 -1
- package/dist/linux/directory-lifecycle.d.ts.map +1 -1
- package/dist/linux/fake-linux-host.d.ts.map +1 -1
- package/dist/linux/index.d.ts +1 -1
- package/dist/linux/index.d.ts.map +1 -1
- package/dist/linux/index.js +16 -4
- package/dist/linux/index.js.map +7 -7
- package/dist/linux/ssh-runner.d.ts.map +1 -1
- package/dist/linux/sudo-runner.d.ts.map +1 -1
- package/dist/opnsense/alias-form.d.ts +14 -1
- package/dist/opnsense/alias-form.d.ts.map +1 -1
- package/dist/opnsense/alias.d.ts +1 -1
- package/dist/opnsense/alias.d.ts.map +1 -1
- package/dist/opnsense/group-form.d.ts +8 -2
- package/dist/opnsense/group-form.d.ts.map +1 -1
- package/dist/opnsense/group.d.ts +1 -1
- package/dist/opnsense/group.d.ts.map +1 -1
- package/dist/opnsense/index.js +15 -7
- package/dist/opnsense/index.js.map +7 -7
- package/dist/opnsense/wire.d.ts +42 -12
- package/dist/opnsense/wire.d.ts.map +1 -1
- package/dist/proxmox/index.js +62 -39
- package/dist/proxmox/index.js.map +8 -7
- package/dist/proxmox/qemu-volume.d.ts +12 -2
- package/dist/proxmox/qemu-volume.d.ts.map +1 -1
- package/dist/proxmox/storage-form.d.ts +28 -3
- package/dist/proxmox/storage-form.d.ts.map +1 -1
- package/dist/proxmox/storage-plugin-options.d.ts +2 -0
- package/dist/proxmox/storage-plugin-options.d.ts.map +1 -0
- package/dist/proxmox/storage-wire.d.ts +28 -1
- package/dist/proxmox/storage-wire.d.ts.map +1 -1
- package/dist/proxmox/storage.d.ts +6 -1
- package/dist/proxmox/storage.d.ts.map +1 -1
- package/dist/release/index.d.ts +1 -1
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js.map +2 -2
- package/dist/talos/credentials-write.d.ts +46 -0
- package/dist/talos/credentials-write.d.ts.map +1 -0
- package/dist/talos/credentials.d.ts +51 -9
- package/dist/talos/credentials.d.ts.map +1 -1
- package/dist/talos/fake-process.d.ts +56 -0
- package/dist/talos/fake-process.d.ts.map +1 -0
- package/dist/talos/index.d.ts +19 -4
- package/dist/talos/index.d.ts.map +1 -1
- package/dist/talos/index.js +357 -173
- package/dist/talos/index.js.map +16 -10
- package/dist/talos/kubeconfig-attrs.d.ts +4 -0
- package/dist/talos/kubeconfig-attrs.d.ts.map +1 -0
- package/dist/talos/kubeconfig.d.ts +41 -23
- package/dist/talos/kubeconfig.d.ts.map +1 -1
- package/dist/talos/machine-config-fixtures.d.ts +60 -0
- package/dist/talos/machine-config-fixtures.d.ts.map +1 -0
- package/dist/talos/machine-config-poll.d.ts +43 -0
- package/dist/talos/machine-config-poll.d.ts.map +1 -0
- package/dist/talos/machine-config-read.d.ts +49 -0
- package/dist/talos/machine-config-read.d.ts.map +1 -0
- package/dist/talos/resource.d.ts +18 -0
- package/dist/talos/resource.d.ts.map +1 -1
- package/dist/talos/talos-bootstrap-etcd.d.ts +38 -0
- package/dist/talos/talos-bootstrap-etcd.d.ts.map +1 -0
- package/dist/talos/talos-bootstrap.d.ts +87 -0
- package/dist/talos/talos-bootstrap.d.ts.map +1 -1
- package/dist/talos/talos-cluster-health.d.ts +43 -1
- package/dist/talos/talos-cluster-health.d.ts.map +1 -1
- package/dist/talos/talos-errors.d.ts +68 -0
- package/dist/talos/talos-errors.d.ts.map +1 -0
- package/dist/talos/talos-machine-config.d.ts +51 -15
- package/dist/talos/talos-machine-config.d.ts.map +1 -1
- package/dist/talos/talosctl.d.ts +7 -0
- package/dist/talos/talosctl.d.ts.map +1 -1
- package/dist/talos/values.d.ts +23 -3
- package/dist/talos/values.d.ts.map +1 -1
- package/dist/unifi/acl-rule-drift.d.ts +22 -0
- package/dist/unifi/acl-rule-drift.d.ts.map +1 -0
- package/dist/unifi/acl-rule-form.d.ts +90 -0
- package/dist/unifi/acl-rule-form.d.ts.map +1 -0
- package/dist/unifi/acl-rule-ordering-form.d.ts +49 -0
- package/dist/unifi/acl-rule-ordering-form.d.ts.map +1 -0
- package/dist/unifi/acl-rule-ordering.d.ts +54 -0
- package/dist/unifi/acl-rule-ordering.d.ts.map +1 -0
- package/dist/unifi/acl-rule.d.ts +49 -0
- package/dist/unifi/acl-rule.d.ts.map +1 -0
- package/dist/unifi/dns-policy-drift.d.ts +21 -0
- package/dist/unifi/dns-policy-drift.d.ts.map +1 -0
- package/dist/unifi/dns-policy-form.d.ts +97 -0
- package/dist/unifi/dns-policy-form.d.ts.map +1 -0
- package/dist/unifi/dns-policy.d.ts +55 -0
- package/dist/unifi/dns-policy.d.ts.map +1 -0
- package/dist/unifi/firewall-policy-drift.d.ts +26 -0
- package/dist/unifi/firewall-policy-drift.d.ts.map +1 -0
- package/dist/unifi/firewall-policy-form.d.ts +102 -0
- package/dist/unifi/firewall-policy-form.d.ts.map +1 -0
- package/dist/unifi/firewall-policy-ordering-form.d.ts +66 -0
- package/dist/unifi/firewall-policy-ordering-form.d.ts.map +1 -0
- package/dist/unifi/firewall-policy-ordering.d.ts +57 -0
- package/dist/unifi/firewall-policy-ordering.d.ts.map +1 -0
- package/dist/unifi/firewall-policy.d.ts +57 -0
- package/dist/unifi/firewall-policy.d.ts.map +1 -0
- package/dist/unifi/index.d.ts +7 -0
- package/dist/unifi/index.d.ts.map +1 -1
- package/dist/unifi/index.js +588 -3
- package/dist/unifi/index.js.map +24 -4
- package/dist/unifi/paginate.d.ts +0 -12
- package/dist/unifi/paginate.d.ts.map +1 -1
- package/dist/unifi/providers.d.ts +1 -1
- package/dist/unifi/providers.d.ts.map +1 -1
- package/dist/unifi/scan-source.d.ts +11 -0
- package/dist/unifi/scan-source.d.ts.map +1 -0
- package/dist/unifi/traffic-matching-list-drift.d.ts +22 -0
- package/dist/unifi/traffic-matching-list-drift.d.ts.map +1 -0
- package/dist/unifi/traffic-matching-list-form.d.ts +56 -0
- package/dist/unifi/traffic-matching-list-form.d.ts.map +1 -0
- package/dist/unifi/traffic-matching-list.d.ts +51 -0
- package/dist/unifi/traffic-matching-list.d.ts.map +1 -0
- package/dist/unifi/wifi-broadcast-drift.d.ts +22 -0
- package/dist/unifi/wifi-broadcast-drift.d.ts.map +1 -0
- package/dist/unifi/wifi-broadcast-form.d.ts +127 -0
- package/dist/unifi/wifi-broadcast-form.d.ts.map +1 -0
- package/dist/unifi/wifi-broadcast.d.ts +73 -0
- package/dist/unifi/wifi-broadcast.d.ts.map +1 -0
- package/docs/distilled-interim.md +7 -0
- package/docs/launchd.md +5 -3
- package/docs/provider-standard.md +5 -1
- package/docs/talos-argocd-dogfood.md +160 -0
- package/docs/unifi-acl-rule.md +122 -0
- package/docs/unifi-dns-policy.md +75 -0
- package/docs/unifi-firewall-policy.md +109 -0
- package/docs/unifi-traffic-matching-list.md +82 -0
- package/docs/unifi-wifi.md +120 -0
- package/docs/unifi.md +10 -5
- package/package.json +7 -3
- package/src/ceph/auth-entity.ts +74 -0
- package/src/ceph/ceph-argv-config.ts +78 -0
- package/src/ceph/ceph-argv.test.ts +226 -0
- package/src/ceph/ceph-argv.ts +189 -0
- package/src/ceph/ceph-auth-form.test.ts +103 -0
- package/src/ceph/ceph-auth-form.ts +107 -0
- package/src/ceph/ceph-auth-parse.test.ts +155 -0
- package/src/ceph/ceph-auth-parse.ts +121 -0
- package/src/ceph/ceph-auth-reconcile-secrecy.test.ts +82 -0
- package/src/ceph/ceph-auth-reconcile.test.ts +233 -0
- package/src/ceph/ceph-auth-reconcile.ts +119 -0
- package/src/ceph/ceph-config-options.test.ts +44 -0
- package/src/ceph/ceph-config-options.ts +36 -0
- package/src/ceph/ceph-key-leak-assert.ts +35 -0
- package/src/ceph/ceph-no-output-logging.test.ts +52 -0
- package/src/ceph/ceph-transport.test.ts +125 -0
- package/src/ceph/ceph-transport.ts +117 -0
- package/src/ceph/fake-ceph-dial.ts +55 -0
- package/src/ceph/index.ts +12 -0
- package/src/index.ts +1 -0
- package/src/launchd/fake-runner.ts +2 -0
- package/src/launchd/index.ts +8 -1
- package/src/launchd/local-runner.ts +16 -1
- package/src/launchd/runner.ts +22 -0
- package/src/launchd/sudo-runner.ts +3 -0
- package/src/linux/directory-lifecycle.ts +18 -3
- package/src/linux/directory-sudo.test.ts +59 -0
- package/src/linux/directory.test.ts +34 -8
- package/src/linux/fake-linux-host.ts +2 -0
- package/src/linux/index.ts +1 -0
- package/src/linux/ssh-runner.ts +4 -0
- package/src/linux/sudo-runner.ts +3 -0
- package/src/opnsense/alias-form.test.ts +24 -12
- package/src/opnsense/alias-form.ts +20 -7
- package/src/opnsense/alias.test.ts +13 -6
- package/src/opnsense/alias.ts +16 -10
- package/src/opnsense/group-form.test.ts +12 -8
- package/src/opnsense/group-form.ts +13 -4
- package/src/opnsense/group.test.ts +18 -7
- package/src/opnsense/group.ts +10 -3
- package/src/opnsense/wire.ts +57 -12
- package/src/proxmox/qemu-volume.test.ts +153 -4
- package/src/proxmox/qemu-volume.ts +71 -14
- package/src/proxmox/storage-form.ts +48 -8
- package/src/proxmox/storage-plugin-options.ts +45 -0
- package/src/proxmox/storage-update.test.ts +183 -0
- package/src/proxmox/storage-wire.ts +54 -7
- package/src/proxmox/storage.ts +18 -6
- package/src/release/index.ts +1 -0
- package/src/talos/credentials-write.test.ts +81 -0
- package/src/talos/credentials-write.ts +95 -0
- package/src/talos/credentials.test.ts +157 -0
- package/src/talos/credentials.ts +160 -90
- package/src/talos/fake-process.ts +94 -0
- package/src/talos/index.ts +39 -4
- package/src/talos/kubeconfig-attrs.ts +55 -0
- package/src/talos/kubeconfig.test.ts +256 -0
- package/src/talos/kubeconfig.ts +170 -90
- package/src/talos/machine-config-fixtures.ts +86 -0
- package/src/talos/machine-config-poll.test.ts +57 -0
- package/src/talos/machine-config-poll.ts +82 -0
- package/src/talos/machine-config-read.ts +118 -0
- package/src/talos/resource.ts +19 -0
- package/src/talos/secrets-gate.test.ts +63 -0
- package/src/talos/talos-bootstrap-etcd.ts +71 -0
- package/src/talos/talos-bootstrap.test.ts +218 -0
- package/src/talos/talos-bootstrap.ts +151 -45
- package/src/talos/talos-cluster-health.test.ts +143 -0
- package/src/talos/talos-cluster-health.ts +91 -28
- package/src/talos/talos-errors.ts +85 -0
- package/src/talos/talos-machine-config.test.ts +189 -0
- package/src/talos/talos-machine-config.ts +102 -88
- package/src/talos/talosctl.ts +8 -0
- package/src/talos/values.test.ts +34 -6
- package/src/talos/values.ts +41 -7
- package/src/unifi/acl-rule-drift.ts +57 -0
- package/src/unifi/acl-rule-form.ts +135 -0
- package/src/unifi/acl-rule-ordering-form.ts +79 -0
- package/src/unifi/acl-rule-ordering.test.ts +141 -0
- package/src/unifi/acl-rule-ordering.ts +70 -0
- package/src/unifi/acl-rule.test.ts +183 -0
- package/src/unifi/acl-rule.ts +61 -0
- package/src/unifi/discriminated-filter-decode.test.ts +134 -0
- package/src/unifi/dns-policy-drift.ts +48 -0
- package/src/unifi/dns-policy-form.ts +142 -0
- package/src/unifi/dns-policy.test.ts +154 -0
- package/src/unifi/dns-policy.ts +67 -0
- package/src/unifi/firewall-policy-drift.test.ts +151 -0
- package/src/unifi/firewall-policy-drift.ts +55 -0
- package/src/unifi/firewall-policy-filter-roundtrip.test.ts +143 -0
- package/src/unifi/firewall-policy-form.ts +146 -0
- package/src/unifi/firewall-policy-ordering-form.ts +111 -0
- package/src/unifi/firewall-policy-ordering.test.ts +185 -0
- package/src/unifi/firewall-policy-ordering.ts +87 -0
- package/src/unifi/firewall-policy.test.ts +183 -0
- package/src/unifi/firewall-policy.ts +73 -0
- package/src/unifi/index.ts +63 -0
- package/src/unifi/paginate.test.ts +24 -0
- package/src/unifi/paginate.ts +15 -3
- package/src/unifi/providers.ts +19 -1
- package/src/unifi/scan-source.ts +64 -0
- package/src/unifi/traffic-matching-list-drift.ts +40 -0
- package/src/unifi/traffic-matching-list-form.ts +77 -0
- package/src/unifi/traffic-matching-list.test.ts +202 -0
- package/src/unifi/traffic-matching-list.ts +78 -0
- package/src/unifi/wifi-broadcast-details-call.test.ts +92 -0
- package/src/unifi/wifi-broadcast-drift.ts +69 -0
- package/src/unifi/wifi-broadcast-form.ts +211 -0
- package/src/unifi/wifi-broadcast-secrets.test.ts +145 -0
- package/src/unifi/wifi-broadcast.test.ts +155 -0
- package/src/unifi/wifi-broadcast.ts +90 -0
- package/src/unifi/write-op-reference.test.ts +8 -54
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-apply convergence for `Talos.MachineConfig` — split out of talos-machine-config.ts
|
|
3
|
+
* (2026-09-26, K-A3) once the bounded-poll logic needed its own header. See
|
|
4
|
+
* docs/plans/2026-09-26-talos-stack-first-boot.md, "Converged" and "Bootstrap" sections.
|
|
5
|
+
*
|
|
6
|
+
* ⛔ NO SILENT `converged: false` HERE. A single attempt's own transport failure is swallowed
|
|
7
|
+
* ONLY inside the bounded loop below — a rebooting node's API is legitimately unreachable for a
|
|
8
|
+
* while — but the loop AS A WHOLE never swallows: running out of attempts always raises
|
|
9
|
+
* `TalosConvergenceTimeout`, never a quiet `false`. That distinction is read()'s job, not
|
|
10
|
+
* reconcile's — see talos-machine-config.ts.
|
|
11
|
+
* ⚠️ SHORT INTERVALS, A LOW CAP, NEVER ONE LONG SLEEP — the house timeout rule, and the specific
|
|
12
|
+
* reason talosctl's own `health` gate has a 20-minute `--wait-timeout`: a single blocking wait
|
|
13
|
+
* that long would hide whether THIS process is still alive from anything watching it.
|
|
14
|
+
*/
|
|
15
|
+
import * as Effect from 'effect/Effect';
|
|
16
|
+
import type { ApplyMode } from './resource.ts';
|
|
17
|
+
import { TalosConvergenceTimeout } from './talos-errors.ts';
|
|
18
|
+
/**
|
|
19
|
+
* ★ TWO POLICIES, ONE PER MODE CLASS — REASONED, no live cluster to time this against yet.
|
|
20
|
+
* `no-reboot` never drops the API, so a handful of quick retries covers only ordinary
|
|
21
|
+
* config-propagation lag. `reboot`/`auto` can drop the API for a full boot cycle, so the cap is
|
|
22
|
+
* longer and the interval coarser. Both stay well inside the house rule above.
|
|
23
|
+
*/
|
|
24
|
+
export type PollPolicy = {
|
|
25
|
+
readonly intervalMs: number;
|
|
26
|
+
readonly maxAttempts: number;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Confirm convergence per `mode`'s policy, or fail with `TalosConvergenceTimeout`.
|
|
30
|
+
*
|
|
31
|
+
* Returns which CLAIM was proven, never a boolean — `'read-back'` for the immediate policy
|
|
32
|
+
* (no-reboot), `'accepted'` for the reboot-tolerant one (reboot/auto): state records which kind of
|
|
33
|
+
* confirmation actually happened, per the design doc's `converged` field.
|
|
34
|
+
*
|
|
35
|
+
* ⚠️ `policies` IS A TEST SEAM, NOT A PROP. `talos-machine-config.ts` never passes it, so
|
|
36
|
+
* production always runs the REASONED defaults above; tests pass tiny intervals so a bounded
|
|
37
|
+
* poll test finishes in milliseconds instead of the real ~10s/~2m caps.
|
|
38
|
+
*/
|
|
39
|
+
export declare const confirmConverged: <E, R>(node: string, mode: ApplyMode, check: Effect.Effect<boolean, E, R>, policies?: {
|
|
40
|
+
readonly immediate: PollPolicy;
|
|
41
|
+
readonly rebootish: PollPolicy;
|
|
42
|
+
}) => Effect.Effect<'read-back' | 'accepted', TalosConvergenceTimeout, R>;
|
|
43
|
+
//# sourceMappingURL=machine-config-poll.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine-config-poll.d.ts","sourceRoot":"","sources":["../../src/talos/machine-config-poll.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAQ5D;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAwBvF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,EAAE,CAAC,QAC7B,MAAM,QACN,SAAS,SACR,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,aACzB;IAAE,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAA;CAAE,KAC3E,MAAM,CAAC,MAAM,CAAC,WAAW,GAAG,UAAU,EAAE,uBAAuB,EAAE,CAAC,CAWjE,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Input } from 'alchemy/Input';
|
|
2
|
+
import * as Effect from 'effect/Effect';
|
|
3
|
+
import type { MachineConfigAttributes, MachineConfigProps } from './talos-machine-config.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Single live read: `talosctl get machineconfig v1alpha1`, extract `spec`, hash it. No retry, no
|
|
6
|
+
* swallow.
|
|
7
|
+
*
|
|
8
|
+
* ⛔ THE ID IS NEVER OMITTED (fix-first #2, PR 307 red team). An unfiltered `get machineconfig`
|
|
9
|
+
* lists `persistent` AND `v1alpha1`, sorted by id — `persistent` first — so a caller that does not
|
|
10
|
+
* name `v1alpha1` gets whichever the SDK's `doc[0]` happens to be, never provably the applied
|
|
11
|
+
* config (values.ts's own multi-document guard is the second half of this fix).
|
|
12
|
+
* ★ `endpoints: [props.node]` (fix-first #5, same review) — without it talosctl falls back to the
|
|
13
|
+
* talosconfig context's own endpoints, which may be a control-plane VIP that only comes up AFTER
|
|
14
|
+
* bootstrap; every pre-bootstrap call in this file targets the node directly instead.
|
|
15
|
+
*/
|
|
16
|
+
export declare const liveSpecDigest: (props: MachineConfigProps, talosconfigPath: string) => Effect.Effect<string, Error | import("effect/PlatformError").PlatformError | import("./talosctl.ts").TalosError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
17
|
+
/**
|
|
18
|
+
* ⛔ NO SWALLOWING. A transport failure here propagates as its own error (TalosError or the
|
|
19
|
+
* shape error above) — never as `converged: false`. A false only means "read succeeded, and
|
|
20
|
+
* genuinely differs" (docs/plans/2026-09-26-talos-stack-first-boot.md, acceptance test 3).
|
|
21
|
+
* ⛔ THREE-WAY COLD-START ANSWER, NOT TWO (fix-first #1). Alchemy's engine calls this exact
|
|
22
|
+
* function as its adoption probe with no prior state (alchemy beta.79 Plan.ts:1302-1318) and
|
|
23
|
+
* again to recover an interrupted create (`:1413-1450`) — both hand it nothing to distinguish
|
|
24
|
+
* "not created" from "already configured". Answering only "attrs or error" (the shipped shape)
|
|
25
|
+
* meant a maintenance-mode node's expected auth failure aborted the plan instead of reaching
|
|
26
|
+
* CREATE, and a genuinely different node's matching-cluster-CA-but-wrong-content read landed as a
|
|
27
|
+
* plain, unbranded attrs object — a silent adopt with no `adopt()`, breaking first-boot acceptance
|
|
28
|
+
* test 1 ("zero adopts"). Now: authenticated read fails but the maintenance probe succeeds →
|
|
29
|
+
* `undefined` (not created); authenticated read succeeds and the digest matches → plain attrs
|
|
30
|
+
* (ours); succeeds and differs → `Unowned` (exists, not proven ours — the digest match IS this
|
|
31
|
+
* family's ownership proof, not a state-row lookup like `ownership/probe.ts`'s generic
|
|
32
|
+
* `ownedRead`, which answers a different question: "did OUR state row create this name", not
|
|
33
|
+
* "does this node hold OUR pinned content"); both reads fail → the authenticated error propagates.
|
|
34
|
+
*
|
|
35
|
+
* ★ EXPORTED (like proxmox/ceph-daemon.ts's `reconcileDaemon`) so tests call it directly with a
|
|
36
|
+
* fake `ChildProcessSpawner` instead of driving it through the full Alchemy engine.
|
|
37
|
+
*/
|
|
38
|
+
export declare const readMachineConfig: (props: MachineConfigProps) => Effect.Effect<{
|
|
39
|
+
configDigest: string;
|
|
40
|
+
converged: "read-back" | false;
|
|
41
|
+
mode: import("./resource.ts").ApplyMode;
|
|
42
|
+
node: string;
|
|
43
|
+
} | undefined, Error | import("effect/PlatformError").PlatformError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
44
|
+
export declare const diffMachineConfig: (news: Input<MachineConfigProps>, output: MachineConfigAttributes | undefined) => Effect.Effect<{
|
|
45
|
+
readonly action: 'noop';
|
|
46
|
+
} | {
|
|
47
|
+
readonly action: 'update';
|
|
48
|
+
} | undefined, Error | import("effect/PlatformError").PlatformError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
49
|
+
//# sourceMappingURL=machine-config-read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine-config-read.d.ts","sourceRoot":"","sources":["../../src/talos/machine-config-read.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,OAAO,KAAK,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAI7F;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,UAAW,kBAAkB,mBAAmB,MAAM,gMAiB9E,CAAC;AAuBJ;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,UAAW,kBAAkB;;;;;+IAiBxD,CAAC;AAEJ,eAAO,MAAM,iBAAiB,SACtB,KAAK,CAAC,kBAAkB,CAAC,UACvB,uBAAuB,GAAG,SAAS;qBAK4B,MAAM;;qBAC1D,QAAQ;+IACzB,CAAC"}
|
package/dist/talos/resource.d.ts
CHANGED
|
@@ -29,4 +29,22 @@ export type TalosRequirements = ChildProcessSpawner.ChildProcessSpawner;
|
|
|
29
29
|
export type WithTarget = {
|
|
30
30
|
target: TalosTarget;
|
|
31
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* `talosctl apply-config -m/--mode`. Lives here, not in talos-machine-config.ts, so
|
|
34
|
+
* talos-errors.ts can name it in `TalosConvergenceTimeout` without importing that file back
|
|
35
|
+
* (machine-config-poll.ts -> talos-errors.ts -> talos-machine-config.ts would cycle).
|
|
36
|
+
*
|
|
37
|
+
* ★ K-A3 DROPPED THE `insecure` PROP THAT USED TO SIT BESIDE THIS TYPE. A fixed `insecure` prop
|
|
38
|
+
* fails in both directions (`true` breaks every later update, `false` breaks the very first
|
|
39
|
+
* apply against a node with no talosconfig auth yet), so `Talos.MachineConfig` now derives it
|
|
40
|
+
* itself: CREATE (`output === undefined`) applies `--insecure`, UPDATE never does.
|
|
41
|
+
* ⛔ `'staged'` AND `'try'` ARE DROPPED (fix-first #2, PR 307 red team). `try` reverts itself after
|
|
42
|
+
* its timeout, so a bounded poll that later reads the reverted config would see it never match
|
|
43
|
+
* the pin and re-run `apply-config` on every deploy — the poll would be "confirming" a change
|
|
44
|
+
* `try` had already undone. `staged` defers the write to the NEXT reboot rather than applying it,
|
|
45
|
+
* which `isRebootish` (machine-config-poll.ts) cannot honestly claim `'accepted'` for without a
|
|
46
|
+
* reboot ever happening — the reboot for a staged config is a separate, later operator action
|
|
47
|
+
* this package does not drive. Both need their own design work, not a poll-policy guess.
|
|
48
|
+
*/
|
|
49
|
+
export type ApplyMode = 'auto' | 'no-reboot' | 'reboot';
|
|
32
50
|
//# sourceMappingURL=resource.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/talos/resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,KAAK,mBAAmB,MAAM,6CAA6C,CAAC;AACxF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG,mBAAmB,CAAC,mBAAmB,CAAC;AAExE,kEAAkE;AAClE,MAAM,MAAM,UAAU,GAAG;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/talos/resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,KAAK,mBAAmB,MAAM,6CAA6C,CAAC;AACxF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG,mBAAmB,CAAC,mBAAmB,CAAC;AAExE,kEAAkE;AAClE,MAAM,MAAM,UAAU,GAAG;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC;AAEjD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Talos.Bootstrap`'s etcd-members probe and split-brain guard — split out of talos-bootstrap.ts
|
|
3
|
+
* (LAND, 2026-09-26, I4 fix) once adding the guard pushed that file over the 250-line cap, the same
|
|
4
|
+
* reason machine-config-read.ts was split out of talos-machine-config.ts before it. Only
|
|
5
|
+
* `import type` comes back from talos-bootstrap.ts, so there is no runtime cycle between the files.
|
|
6
|
+
*/
|
|
7
|
+
import * as Effect from 'effect/Effect';
|
|
8
|
+
import type { BootstrapProps } from './talos-bootstrap.ts';
|
|
9
|
+
import { TalosReBootstrapRefused } from './talos-errors.ts';
|
|
10
|
+
/**
|
|
11
|
+
* REASONED: `talosctl get etcdmembers -o json` should list members after bootstrap.
|
|
12
|
+
* ⚠️ NOT MEASURED — first live deploy confirms the resource type name.
|
|
13
|
+
* ⛔ NO SWALLOWING (K-talos-first-boot) — a transport failure propagates as its own error; only a
|
|
14
|
+
* SUCCESSFUL read may conclude presence or absence. Every caller decides for itself what a
|
|
15
|
+
* failure here means (talos-bootstrap.ts's `read`/`reconcile`, and `assertNoLivePeers` below), so
|
|
16
|
+
* it is not decided here.
|
|
17
|
+
*/
|
|
18
|
+
export declare const isBootstrapped: (props: BootstrapProps, talosconfigPath: string) => Effect.Effect<boolean, import("effect/PlatformError").PlatformError | import("./talosctl.ts").TalosError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
19
|
+
/**
|
|
20
|
+
* ⛔ I4 FIX (LAND red team, 2026-09-26) — THE CREATE PATH ONLY CHECKED THIS NODE. If the state row
|
|
21
|
+
* is lost (wrong `--stage`, an FQN rename, a wiped state store) while the cluster already lives on
|
|
22
|
+
* OTHER control-plane nodes, the cold-start adoption read on THIS node comes back empty, plan
|
|
23
|
+
* calls `create`, and `talosctl bootstrap` runs here too — a SECOND, isolated etcd cluster: split
|
|
24
|
+
* brain. Before bootstrapping, every OTHER declared control-plane node (`props.peers`) must show a
|
|
25
|
+
* successful, EMPTY etcd-members read — proof no cluster already exists anywhere this row knows
|
|
26
|
+
* about. A peer that already has members, or a peer whose read fails, refuses bootstrap exactly
|
|
27
|
+
* like an already-bootstrapped confirmation failure does (same typed error, same "hand it to a
|
|
28
|
+
* human" posture) — a genuinely fresh cluster has no peers with members yet, so this never blocks
|
|
29
|
+
* a real first boot.
|
|
30
|
+
* ⚠️ `peers` IS OPTIONAL, SO THIS GUARD IS OPT-IN — an existing single-control-plane declaration
|
|
31
|
+
* keeps working unguarded; a consuming stack with more than one control-plane node (decision 66:
|
|
32
|
+
* 3, one per TB4 node) SHOULD list the other two here to get the protection.
|
|
33
|
+
* ★ `Effect.all` over a mapped array, not `Effect.forEach` — oxlint's unicorn/no-array-for-each
|
|
34
|
+
* matches the method NAME and cannot tell Effect's from Array's (same pattern as
|
|
35
|
+
* openbao/cloudflare-permission-groups.ts).
|
|
36
|
+
*/
|
|
37
|
+
export declare const assertNoLivePeers: (props: BootstrapProps, talosconfigPath: string) => Effect.Effect<void, TalosReBootstrapRefused, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
38
|
+
//# sourceMappingURL=talos-bootstrap-etcd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"talos-bootstrap-etcd.d.ts","sourceRoot":"","sources":["../../src/talos/talos-bootstrap-etcd.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAG5D;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,UAAW,cAAc,mBAAmB,MAAM,yLAIM,CAAC;AAEpF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,iBAAiB,UAAW,cAAc,mBAAmB,MAAM,4HA2B7E,CAAC"}
|
|
@@ -6,13 +6,41 @@
|
|
|
6
6
|
* the bootstrap node. This command must run exactly once per cluster.
|
|
7
7
|
*
|
|
8
8
|
* ⛔ NOT A FACTORY RESOURCE — bootstrap cannot be deleted or updated in place; `delete` is a no-op.
|
|
9
|
+
*
|
|
10
|
+
* ⛔ ONCE MEANS ONCE (K-talos-first-boot, 2026-09-26) — THE SHIPPED SHAPE COULD BOOTSTRAP A SECOND
|
|
11
|
+
* etcd CLUSTER. The original `isBootstrapped` turned every read failure into `false`
|
|
12
|
+
* (`Effect.orElseSucceed`), `diff` then planned `update`, and `reconcile` re-ran `talosctl
|
|
13
|
+
* bootstrap` — Talos's only server-side guard is a non-empty etcd data directory (REASONED,
|
|
14
|
+
* `v1alpha1_server.go:441`), so a reinstalled or reset bootstrap node re-bootstrapped a fresh,
|
|
15
|
+
* isolated single-member cluster: split brain. Fixed per
|
|
16
|
+
* docs/plans/2026-09-26-talos-stack-first-boot.md's "Bootstrap — once means once" section:
|
|
17
|
+
* - `read` now answers presence/absence correctly instead of always returning a defined
|
|
18
|
+
* object — `undefined` only from a SUCCESSFUL read that finds no members (cold-start
|
|
19
|
+
* absence); a failing read propagates its error instead of being reinterpreted as absence.
|
|
20
|
+
* - `diff` trusts `output.bootstrapped` once it is `true` and reports `noop` without touching
|
|
21
|
+
* the live cluster at all — confirmation is `reconcile`'s job now, not plan's.
|
|
22
|
+
* - `reconcile` checks `output?.bootstrapped` FIRST: once true, it NEVER calls `talosctl
|
|
23
|
+
* bootstrap` again, no matter what a live read says. A live read that fails OR comes back
|
|
24
|
+
* empty both raise the same `TalosReBootstrapRefused` — re-bootstrap is a human decision.
|
|
9
25
|
*/
|
|
10
26
|
import { Resource } from 'alchemy';
|
|
27
|
+
import type { Input } from 'alchemy/Input';
|
|
11
28
|
import * as Provider from 'alchemy/Provider';
|
|
29
|
+
import * as Effect from 'effect/Effect';
|
|
12
30
|
import type { TalosRequirements, WithTarget } from './resource.ts';
|
|
31
|
+
import { TalosReBootstrapRefused } from './talos-errors.ts';
|
|
13
32
|
export interface BootstrapProps extends WithTarget {
|
|
14
33
|
/** The ONE control-plane node that receives `talosctl bootstrap`. */
|
|
15
34
|
node: string;
|
|
35
|
+
/**
|
|
36
|
+
* The OTHER declared control-plane nodes — never `node` itself. Optional, but a multi-control-
|
|
37
|
+
* plane cluster (decision 66: 3, one per TB4 node) SHOULD set it: `reconcileBootstrap`'s CREATE
|
|
38
|
+
* path (I4 fix, LAND red team, 2026-09-26) requires every one of these to show a successful,
|
|
39
|
+
* EMPTY etcd-members read before it will bootstrap `node` — the guard against re-bootstrapping a
|
|
40
|
+
* split-brain second cluster when this row's own state was lost. See talos-bootstrap-etcd.ts's
|
|
41
|
+
* `assertNoLivePeers`.
|
|
42
|
+
*/
|
|
43
|
+
peers?: readonly string[];
|
|
16
44
|
/** Machine configs for this node (and peers) must be applied first. */
|
|
17
45
|
after?: readonly unknown[];
|
|
18
46
|
}
|
|
@@ -23,5 +51,64 @@ export interface BootstrapAttributes {
|
|
|
23
51
|
export interface TalosBootstrap extends Resource<'Talos.Bootstrap', BootstrapProps, BootstrapAttributes, never, TalosRequirements> {
|
|
24
52
|
}
|
|
25
53
|
export declare const TalosBootstrap: import("alchemy").ResourceClass<TalosBootstrap>;
|
|
54
|
+
/**
|
|
55
|
+
* ⛔ WRAPPED IN `Effect.scoped` (K-A3, 2026-09-26) — `mintTalosconfig` contributes `Scope.Scope`
|
|
56
|
+
* to its own return type rather than closing its scope internally (the C1 fix, credentials.ts's
|
|
57
|
+
* own header); this is the caller that owns the temp talosconfig's lifetime for the read.
|
|
58
|
+
*
|
|
59
|
+
* ⛔ ANSWERS PRESENCE/ABSENCE, NOT "attrs-or-error" (K-talos-first-boot, fixes the shipped shape).
|
|
60
|
+
* `undefined` only when a read SUCCEEDS and finds no members — the honest "not created yet"
|
|
61
|
+
* Alchemy's engine expects from a cold-start adoption probe. A failing read propagates instead
|
|
62
|
+
* of being reinterpreted as absence — this is the fix `isBootstrapped` no longer hides.
|
|
63
|
+
*
|
|
64
|
+
* ★ EXPORTED (like proxmox/ceph-daemon.ts's `reconcileDaemon`, machine-config-read.ts's
|
|
65
|
+
* `readMachineConfig`) so talos-bootstrap.test.ts calls it directly with a fake spawner instead
|
|
66
|
+
* of driving it through the full Alchemy engine.
|
|
67
|
+
*/
|
|
68
|
+
export declare const readBootstrap: (props: BootstrapProps) => Effect.Effect<{
|
|
69
|
+
readonly bootstrapped: true;
|
|
70
|
+
readonly node: string;
|
|
71
|
+
} | undefined, Error | import("effect/PlatformError").PlatformError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
72
|
+
/**
|
|
73
|
+
* ⛔ TRUSTS STATE, NEVER TOUCHES THE LIVE CLUSTER (K-talos-first-boot) — once `output.bootstrapped`
|
|
74
|
+
* is `true` this always reports `noop`, unconditionally, with zero live calls.
|
|
75
|
+
*
|
|
76
|
+
* ⛔ I3 CORRECTION (LAND red team, 2026-09-26) — THE OLD COMMENT HERE CLAIMED "confirming the
|
|
77
|
+
* invariant against etcd is reconcile's job (every deploy calls it)". THAT IS FALSE, VERIFIED
|
|
78
|
+
* against the pinned alchemy beta.79 source: Apply never reconciles a node whose diff came back
|
|
79
|
+
* `noop` (`Apply.ts`'s `noop` branch just refreshes row metadata and signals ready — it does not
|
|
80
|
+
* call `provider.reconcile` at all). This file's own `noop` above IS what skips it. So
|
|
81
|
+
* `reconcileBootstrap`'s re-confirm branch (the one that raises `TalosReBootstrapRefused` on a
|
|
82
|
+
* failed or empty read) never runs on an ordinary `plan`/`deploy` once `bootstrapped: true` is
|
|
83
|
+
* recorded — only `--force` reaches it, by forcing a reconcile regardless of the plan action.
|
|
84
|
+
* Safety still holds — `talosctl bootstrap` genuinely never re-runs while state exists — but a
|
|
85
|
+
* reset control-plane node (etcd wiped, VM replaced) stays silently invisible to `plan` and
|
|
86
|
+
* `deploy` alike until an operator runs `--force` or a verify pass.
|
|
87
|
+
* ⚠️ NOT FIXED BY HAVING `diff` READ HERE TOO (the finding's other offered fix) — that would touch
|
|
88
|
+
* the live cluster (and mint a talosconfig) on EVERY plan for an already-bootstrapped node, for a
|
|
89
|
+
* scenario (a reset node) that a `configDigest`-style pinned check can't distinguish from a merely
|
|
90
|
+
* slow/unreachable read; a single transient failure would then abort every future plan for a
|
|
91
|
+
* healthy node, for no benefit — the exact cost the original (correct) half of this comment
|
|
92
|
+
* already named. `MachineConfig`/`ClusterHealth`'s diffs DO mint and read live on every plan
|
|
93
|
+
* (D2 puts that on the admin/operator lane, not agent), so this isn't a lane-access limit; it is
|
|
94
|
+
* this resource's own choice to trust a `true` boolean forever rather than re-derive it from a
|
|
95
|
+
* live signal that cannot yet tell "reset" apart from "briefly unreachable". Recorded as an open
|
|
96
|
+
* gap for whoever builds the operator verify pass, not silently fixed here.
|
|
97
|
+
*/
|
|
98
|
+
export declare const diffBootstrap: (news: Input<BootstrapProps>, output: BootstrapAttributes | undefined) => Effect.Effect<{
|
|
99
|
+
readonly action: 'noop';
|
|
100
|
+
} | {
|
|
101
|
+
readonly action: 'update';
|
|
102
|
+
} | undefined, Error | import("effect/PlatformError").PlatformError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
103
|
+
/**
|
|
104
|
+
* ⛔ ONCE MEANS ONCE — see this file's own header. `output?.bootstrapped === true` is checked
|
|
105
|
+
* BEFORE anything else, and that branch never builds a `talosctl bootstrap` argv at all — the
|
|
106
|
+
* confirmation read below can fail, or succeed and say "absent", and EITHER way this raises
|
|
107
|
+
* `TalosReBootstrapRefused` rather than treating "absent" as licence to bootstrap again.
|
|
108
|
+
*/
|
|
109
|
+
export declare const reconcileBootstrap: (props: BootstrapProps, output: BootstrapAttributes | undefined) => Effect.Effect<{
|
|
110
|
+
bootstrapped: boolean;
|
|
111
|
+
node: string;
|
|
112
|
+
}, Error | import("effect/PlatformError").PlatformError | TalosReBootstrapRefused, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
26
113
|
export declare const TalosBootstrapProvider: () => import("effect/Layer").Layer<Provider.Provider<TalosBootstrap>, never, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
27
114
|
//# sourceMappingURL=talos-bootstrap.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"talos-bootstrap.d.ts","sourceRoot":"","sources":["../../src/talos/talos-bootstrap.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"talos-bootstrap.d.ts","sourceRoot":"","sources":["../../src/talos/talos-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAG5D,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,uEAAuE;IACvE,KAAK,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,cAAe,SAAQ,QAAQ,CAC9C,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,KAAK,EACL,iBAAiB,CAClB;CAAG;AAEJ,eAAO,MAAM,cAAc,iDAGzB,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,aAAa,UAAW,cAAc;;;+IAOhD,CAAC;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,aAAa,SAClB,KAAK,CAAC,cAAc,CAAC,UACnB,mBAAmB,GAAG,SAAS;qBAIK,MAAM;;qBAIjC,QAAQ;+IACvB,CAAC;AAEL;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,UACtB,cAAc,UACb,mBAAmB,GAAG,SAAS;;;6JAmDtC,CAAC;AAsBJ,eAAO,MAAM,sBAAsB,yJACoD,CAAC"}
|
|
@@ -6,9 +6,27 @@
|
|
|
6
6
|
*
|
|
7
7
|
* ⚠️ PLAN READS USE A SHORT TIMEOUT SO `plan` DOES NOT BLOCK TWENTY MINUTES. Reconcile uses the
|
|
8
8
|
* declared timeout — that is the deploy gate, not the plan gate.
|
|
9
|
+
*
|
|
10
|
+
* ⛔ THIS RESOURCE ASSUMES A CNI IS ALREADY RUNNING (K-talos-first-boot, 2026-09-26). The default
|
|
11
|
+
* `talosctl health` suite checks nodes Ready, kube-proxy and CoreDNS, and Talos's own source
|
|
12
|
+
* comment says these wait on the CNI (REASONED, `pkg/cluster/check/default.go:28-60,89-91`;
|
|
13
|
+
* docs/plans/2026-09-26-talos-stack-first-boot.md's "CNI ordering" section). A consuming stack's
|
|
14
|
+
* `after` MUST include the Cilium install step, not just `Talos.Bootstrap`/`Talos.Kubeconfig` —
|
|
15
|
+
* declaring this row directly after bootstrap deadlocks into the `--wait-timeout` on every first
|
|
16
|
+
* deploy, because Argo CD itself needs pod networking before it can install Cilium. Row order:
|
|
17
|
+
* Bootstrap → Kubeconfig → Cilium (inline manifests in the seeded machine config, D-S2) →
|
|
18
|
+
* `Talos.ClusterHealth`.
|
|
19
|
+
* ⛔ NO SWALLOWED TRANSPORT ERRORS (K-talos-first-boot) — the shipped `read` caught EVERY error
|
|
20
|
+
* from `check()`, including a `mintTalosconfig`/`bao` failure, into a plain `healthy: false`. A
|
|
21
|
+
* vault outage would then read as "cluster not healthy yet" — an operator chasing a Cilium
|
|
22
|
+
* rollout would never learn the real problem was vault. Both `read` and `reconcile` now only
|
|
23
|
+
* catch `TalosError` (`talosctl health` itself ran and exited non-zero — the one case this
|
|
24
|
+
* family may honestly call "not healthy"); anything else propagates untouched.
|
|
9
25
|
*/
|
|
10
26
|
import { Resource } from 'alchemy';
|
|
27
|
+
import type { Input } from 'alchemy/Input';
|
|
11
28
|
import * as Provider from 'alchemy/Provider';
|
|
29
|
+
import * as Effect from 'effect/Effect';
|
|
12
30
|
import type { TalosRequirements, WithTarget } from './resource.ts';
|
|
13
31
|
export interface ClusterHealthProps extends WithTarget {
|
|
14
32
|
/** Control-plane node IPs passed to `--control-plane-nodes`. */
|
|
@@ -21,7 +39,11 @@ export interface ClusterHealthProps extends WithTarget {
|
|
|
21
39
|
* ⚠️ REASONED default — not measured here.
|
|
22
40
|
*/
|
|
23
41
|
waitTimeout?: string;
|
|
24
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* Ordering edge. ⛔ MUST reach past `Talos.Bootstrap`/`Talos.Kubeconfig` all the way through the
|
|
44
|
+
* Cilium CNI install (this file's own header, "CNI ordering") — the default health checks wait
|
|
45
|
+
* on kube-proxy and CoreDNS, both of which wait on a CNI that does not exist yet at bootstrap.
|
|
46
|
+
*/
|
|
25
47
|
after?: readonly unknown[];
|
|
26
48
|
}
|
|
27
49
|
export interface ClusterHealthAttributes {
|
|
@@ -32,5 +54,25 @@ export interface ClusterHealthAttributes {
|
|
|
32
54
|
export interface TalosClusterHealth extends Resource<'Talos.ClusterHealth', ClusterHealthProps, ClusterHealthAttributes, never, TalosRequirements> {
|
|
33
55
|
}
|
|
34
56
|
export declare const TalosClusterHealth: import("alchemy").ResourceClass<TalosClusterHealth>;
|
|
57
|
+
/** ★ EXPORTED for talos-cluster-health.test.ts — see talos-bootstrap.ts's own note on the pattern. */
|
|
58
|
+
export declare const readClusterHealth: (props: ClusterHealthProps) => Effect.Effect<{
|
|
59
|
+
controlPlaneNodes: string;
|
|
60
|
+
healthy: boolean;
|
|
61
|
+
workerNodes: string;
|
|
62
|
+
} | {
|
|
63
|
+
controlPlaneNodes: string;
|
|
64
|
+
healthy: boolean;
|
|
65
|
+
workerNodes: string;
|
|
66
|
+
}, Error | import("effect/PlatformError").PlatformError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
67
|
+
export declare const diffClusterHealth: (news: Input<ClusterHealthProps>, output: ClusterHealthAttributes | undefined) => Effect.Effect<{
|
|
68
|
+
readonly action: 'noop';
|
|
69
|
+
} | {
|
|
70
|
+
readonly action: 'update';
|
|
71
|
+
} | undefined, Error | import("effect/PlatformError").PlatformError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
72
|
+
export declare const reconcileClusterHealth: (props: ClusterHealthProps) => Effect.Effect<{
|
|
73
|
+
controlPlaneNodes: string;
|
|
74
|
+
healthy: boolean;
|
|
75
|
+
workerNodes: string;
|
|
76
|
+
}, Error | import("effect/PlatformError").PlatformError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
35
77
|
export declare const TalosClusterHealthProvider: () => import("effect/Layer").Layer<Provider.Provider<TalosClusterHealth>, never, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
36
78
|
//# sourceMappingURL=talos-cluster-health.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"talos-cluster-health.d.ts","sourceRoot":"","sources":["../../src/talos/talos-cluster-health.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"talos-cluster-health.d.ts","sourceRoot":"","sources":["../../src/talos/talos-cluster-health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGnE,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,gEAAgE;IAChE,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,kDAAkD;IAClD,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAmB,SAAQ,QAAQ,CAClD,qBAAqB,EACrB,kBAAkB,EAClB,uBAAuB,EACvB,KAAK,EACL,iBAAiB,CAClB;CAAG;AAEJ,eAAO,MAAM,kBAAkB,qDAAsD,CAAC;AAgEtF,sGAAsG;AACtG,eAAO,MAAM,iBAAiB,UAAW,kBAAkB;;;;;;;;mIASxD,CAAC;AAEJ,eAAO,MAAM,iBAAiB,SACtB,KAAK,CAAC,kBAAkB,CAAC,UACvB,uBAAuB,GAAG,SAAS;qBAKN,MAAM;;qBACxB,QAAQ;+IACzB,CAAC;AAEL,eAAO,MAAM,sBAAsB,UAAW,kBAAkB;;;;mIAU7D,CAAC;AAgBJ,eAAO,MAAM,0BAA0B,6JACwD,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ApplyMode } from './resource.ts';
|
|
2
|
+
declare const TalosConfigDigestMismatch_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
3
|
+
readonly _tag: "TalosConfigDigestMismatch";
|
|
4
|
+
} & Readonly<A>;
|
|
5
|
+
/**
|
|
6
|
+
* The OpenBao KV content at `mount/key` does not hash to the pinned `configDigest`.
|
|
7
|
+
*
|
|
8
|
+
* ★ FAIL CLOSED, NO SPAWN — docs/plans/2026-09-26-talos-secrets-flow.md's O-A: "a poisoned or
|
|
9
|
+
* fat-fingered KV write cannot silently reach a node". Raised BEFORE any talosctl process
|
|
10
|
+
* starts, so a mismatch never sends an unpinned config anywhere — see reconcile() in
|
|
11
|
+
* talos-machine-config.ts, which checks this ahead of minting the talosconfig credential too.
|
|
12
|
+
* ⛔ NEITHER DIGEST IN THIS MESSAGE IS THE CONFIG. Both are sha256 hex digests — safe to log,
|
|
13
|
+
* safe to persist — never the KV content itself.
|
|
14
|
+
*/
|
|
15
|
+
export declare class TalosConfigDigestMismatch extends TalosConfigDigestMismatch_base<{
|
|
16
|
+
readonly mount: string;
|
|
17
|
+
readonly key: string;
|
|
18
|
+
readonly expected: string;
|
|
19
|
+
readonly got: string;
|
|
20
|
+
}> {
|
|
21
|
+
get message(): string;
|
|
22
|
+
}
|
|
23
|
+
declare const TalosConvergenceTimeout_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
24
|
+
readonly _tag: "TalosConvergenceTimeout";
|
|
25
|
+
} & Readonly<A>;
|
|
26
|
+
/**
|
|
27
|
+
* `apply-config` returned success but the live machineconfig digest never matched the pin within
|
|
28
|
+
* the bounded poll (machine-config-poll.ts). See
|
|
29
|
+
* docs/plans/2026-09-26-talos-stack-first-boot.md's "Converged" section.
|
|
30
|
+
*
|
|
31
|
+
* ⛔ THIS IS THE REPLACEMENT FOR A SILENT `converged: false`. The shipped code let a read
|
|
32
|
+
* failure during convergence checking disguise itself as "not converged yet" forever
|
|
33
|
+
* (`orElseSucceed`); this type makes cap expiry a refusal an operator sees, not a plan that
|
|
34
|
+
* quietly retries the same apply on every future run.
|
|
35
|
+
*/
|
|
36
|
+
export declare class TalosConvergenceTimeout extends TalosConvergenceTimeout_base<{
|
|
37
|
+
readonly node: string;
|
|
38
|
+
readonly mode: ApplyMode;
|
|
39
|
+
readonly attempts: number;
|
|
40
|
+
}> {
|
|
41
|
+
get message(): string;
|
|
42
|
+
}
|
|
43
|
+
declare const TalosReBootstrapRefused_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
44
|
+
readonly _tag: "TalosReBootstrapRefused";
|
|
45
|
+
} & Readonly<A>;
|
|
46
|
+
/**
|
|
47
|
+
* `Talos.Bootstrap` reconcile found state already recording `bootstrapped: true`, and a live
|
|
48
|
+
* check against etcd could not reconfirm it — either the read itself failed (`detail` carries the
|
|
49
|
+
* propagated cause), or it succeeded and came back with no members.
|
|
50
|
+
*
|
|
51
|
+
* ★ K-talos-first-boot's "once means once" — docs/plans/2026-09-26-talos-stack-first-boot.md's own
|
|
52
|
+
* section of that name. EITHER cause raises this SAME typed error, and both ways `talosctl
|
|
53
|
+
* bootstrap` is never spawned a second time: re-running it against a node that lost its etcd
|
|
54
|
+
* data (a VM replace, a reset) forms a second, isolated single-member etcd cluster instead of
|
|
55
|
+
* rejoining the existing one (REASONED, `v1alpha1_server.go:441` — Talos's only server-side
|
|
56
|
+
* guard is a non-empty data directory, not "did this cluster already bootstrap"). That is split
|
|
57
|
+
* brain, and nothing here can tell a genuinely reset node (needs its own operator-run recovery)
|
|
58
|
+
* apart from a merely slow or unreachable read (needs a retry) — so both refuse alike and hand
|
|
59
|
+
* the node to a human instead of guessing.
|
|
60
|
+
*/
|
|
61
|
+
export declare class TalosReBootstrapRefused extends TalosReBootstrapRefused_base<{
|
|
62
|
+
readonly node: string;
|
|
63
|
+
readonly detail: string;
|
|
64
|
+
}> {
|
|
65
|
+
get message(): string;
|
|
66
|
+
}
|
|
67
|
+
export {};
|
|
68
|
+
//# sourceMappingURL=talos-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"talos-errors.d.ts","sourceRoot":"","sources":["../../src/talos/talos-errors.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;;;;AAE/C;;;;;;;;;GASG;AACH,qBAAa,yBAA0B,SAAQ,+BAA8C;IAC3F,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAO7B;CACF;;;;AAED;;;;;;;;;GASG;AACH,qBAAa,uBAAwB,SAAQ,6BAA4C;IACvF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAM7B;CACF;;;;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,uBAAwB,SAAQ,6BAA4C;IACvF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAM7B;CACF"}
|
|
@@ -2,28 +2,44 @@
|
|
|
2
2
|
* `Talos.MachineConfig` — apply one machine configuration document to one node.
|
|
3
3
|
*
|
|
4
4
|
* ★ REASONED FROM talosctl apply-config (Talos v1.13 CLI reference): `-f/--file`, `-n/--nodes`,
|
|
5
|
-
* `-m/--mode`, `-i/--insecure` for maintenance mode
|
|
5
|
+
* `-m/--mode`, `-i/--insecure` for maintenance mode.
|
|
6
6
|
*
|
|
7
|
-
* ⛔ THE CONFIG BODY IS NEVER AN ATTRIBUTE
|
|
8
|
-
*
|
|
7
|
+
* ⛔ THE CONFIG BODY IS NEVER AN ATTRIBUTE, A PROP, OR ARGV — ONLY ITS DIGEST. K-A3
|
|
8
|
+
* (docs/plans/2026-09-26-talos-secrets-flow.md, option O-A) moved the source of truth from a
|
|
9
|
+
* repo file (the shipped `configFile` + `STACK_DIR`, gone with this rewrite) to OpenBao: props
|
|
10
|
+
* carry a `configKey` (a vault path) and a `configDigest` PINNED IN GIT, never the bytes. The
|
|
11
|
+
* source is write-only from Alchemy's point of view — content is read once per reconcile,
|
|
12
|
+
* verified against the pin, written to a session-temp file, and never returned from any
|
|
13
|
+
* handler.
|
|
14
|
+
* ⛔ NEVER `--dry-run`. Talos's dry-run prints a full, unredacted old/new config diff — with an
|
|
15
|
+
* empty old config (the first apply) that diff IS the whole config, CA private key and
|
|
16
|
+
* bootstrap token included (REASONED, `internal/app/machined/.../v1alpha1_server.go:258-272` +
|
|
17
|
+
* `configdiff.go`; docs/plans/2026-09-26-talos-stack-first-boot.md). This file never builds
|
|
18
|
+
* that flag.
|
|
19
|
+
* ⛔ `insecure` IS NOT A PROP. A fixed value fails in both directions — `true` breaks every later
|
|
20
|
+
* update, `false` breaks the very first apply against a node with no talosconfig auth yet — so
|
|
21
|
+
* CREATE (`output === undefined`) applies `--insecure` and UPDATE never does (resource.ts).
|
|
9
22
|
*/
|
|
10
23
|
import { Resource } from 'alchemy';
|
|
11
24
|
import * as Provider from 'alchemy/Provider';
|
|
12
|
-
import
|
|
13
|
-
|
|
25
|
+
import * as Effect from 'effect/Effect';
|
|
26
|
+
import { type PollPolicy } from './machine-config-poll.ts';
|
|
27
|
+
import type { ApplyMode, TalosRequirements, WithTarget } from './resource.ts';
|
|
28
|
+
import { TalosConfigDigestMismatch } from './talos-errors.ts';
|
|
29
|
+
export type { ApplyMode } from './resource.ts';
|
|
14
30
|
export interface MachineConfigProps extends WithTarget {
|
|
15
31
|
/** Node IP or hostname — the `-n` target. */
|
|
16
32
|
node: string;
|
|
17
|
-
/**
|
|
18
|
-
|
|
19
|
-
/** talosctl `-m` mode. Default `auto` per published CLI. */
|
|
20
|
-
mode?: ApplyMode;
|
|
33
|
+
/** OpenBao KV path under `target.mount` holding this node's rendered config, e.g. `nodes/10001`. */
|
|
34
|
+
configKey: string;
|
|
21
35
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
36
|
+
* sha256(canonicalText(content)) of the seeded KV value (values.ts `configDigest`), pinned in
|
|
37
|
+
* git by the operator. ⛔ Verified against the live KV content before ANY talosctl spawn — a
|
|
38
|
+
* mismatch fails closed (`TalosConfigDigestMismatch`), nothing is applied.
|
|
25
39
|
*/
|
|
26
|
-
|
|
40
|
+
configDigest: string;
|
|
41
|
+
/** talosctl `-m` mode. Default `auto` per published CLI. */
|
|
42
|
+
mode?: ApplyMode;
|
|
27
43
|
/** Ordering edge — e.g. wait for Proxmox.Vm. */
|
|
28
44
|
after?: readonly unknown[];
|
|
29
45
|
}
|
|
@@ -31,11 +47,31 @@ export interface MachineConfigAttributes {
|
|
|
31
47
|
node: string;
|
|
32
48
|
configDigest: string;
|
|
33
49
|
mode: ApplyMode;
|
|
34
|
-
/**
|
|
35
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Which convergence claim was made. `'read-back'`/`'accepted'` only come from `reconcile` (see
|
|
52
|
+
* machine-config-poll.ts); `false` only comes from `read`, meaning a live digest was
|
|
53
|
+
* successfully fetched and genuinely differs — never a stand-in for a failed read, which
|
|
54
|
+
* propagates as its own error instead (docs/plans/2026-09-26-talos-stack-first-boot.md).
|
|
55
|
+
*/
|
|
56
|
+
converged: 'read-back' | 'accepted' | false;
|
|
36
57
|
}
|
|
37
58
|
export interface TalosMachineConfig extends Resource<'Talos.MachineConfig', MachineConfigProps, MachineConfigAttributes, never, TalosRequirements> {
|
|
38
59
|
}
|
|
39
60
|
export declare const TalosMachineConfig: import("alchemy").ResourceClass<TalosMachineConfig>;
|
|
61
|
+
/**
|
|
62
|
+
* The read path (`readMachineConfig`, `diffMachineConfig`, `liveSpecDigest`) lives in
|
|
63
|
+
* machine-config-read.ts — see that file's own header for the ownership-aware three-way answer
|
|
64
|
+
* `read` now gives (fix-first #1/#2, PR 307 red team).
|
|
65
|
+
*/
|
|
66
|
+
/** `pollPolicies` is a test seam only — see machine-config-poll.ts's `confirmConverged`. */
|
|
67
|
+
export declare const reconcileMachineConfig: (props: MachineConfigProps, output: MachineConfigAttributes | undefined, pollPolicies?: {
|
|
68
|
+
readonly immediate: PollPolicy;
|
|
69
|
+
readonly rebootish: PollPolicy;
|
|
70
|
+
}) => Effect.Effect<{
|
|
71
|
+
configDigest: string;
|
|
72
|
+
converged: "accepted" | "read-back";
|
|
73
|
+
mode: ApplyMode;
|
|
74
|
+
node: string;
|
|
75
|
+
}, Error | import("effect/PlatformError").PlatformError | TalosConfigDigestMismatch | import("./talos-errors.ts").TalosConvergenceTimeout, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
40
76
|
export declare const TalosMachineConfigProvider: () => import("effect/Layer").Layer<Provider.Provider<TalosMachineConfig>, never, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
41
77
|
//# sourceMappingURL=talos-machine-config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"talos-machine-config.d.ts","sourceRoot":"","sources":["../../src/talos/talos-machine-config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"talos-machine-config.d.ts","sourceRoot":"","sources":["../../src/talos/talos-machine-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,0BAA0B,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAI9D,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,oGAAoG;IACpG,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,gDAAgD;IAChD,KAAK,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,SAAS,CAAC;IAChB;;;;;OAKG;IACH,SAAS,EAAE,WAAW,GAAG,UAAU,GAAG,KAAK,CAAC;CAC7C;AAED,MAAM,WAAW,kBAAmB,SAAQ,QAAQ,CAClD,qBAAqB,EACrB,kBAAkB,EAClB,uBAAuB,EACvB,KAAK,EACL,iBAAiB,CAClB;CAAG;AAEJ,eAAO,MAAM,kBAAkB,qDAAsD,CAAC;AAEtF;;;;GAIG;AAEH,4FAA4F;AAC5F,eAAO,MAAM,sBAAsB,UAC1B,kBAAkB,UACjB,uBAAuB,GAAG,SAAS,iBAC5B;IAAE,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAA;CAAE;;;;;qNAkDhF,CAAC;AAsBJ,eAAO,MAAM,0BAA0B,6JACwD,CAAC"}
|
package/dist/talos/talosctl.d.ts
CHANGED
|
@@ -21,6 +21,13 @@ export type TalosRunOptions = {
|
|
|
21
21
|
readonly talosconfigPath: string;
|
|
22
22
|
readonly nodes?: readonly string[];
|
|
23
23
|
readonly endpoints?: readonly string[];
|
|
24
|
+
/**
|
|
25
|
+
* `-i/--insecure` — a maintenance-mode node has no established PKI yet. Used by the CREATE apply
|
|
26
|
+
* (resource.ts's own header) and by talos-machine-config.ts's maintenance-mode probe (fix-first
|
|
27
|
+
* #1, PR 307 red team): `--talosconfig` is still passed alongside it, matching the CREATE path,
|
|
28
|
+
* since insecure mode ignores the file's certs rather than requiring their absence.
|
|
29
|
+
*/
|
|
30
|
+
readonly insecure?: boolean;
|
|
24
31
|
};
|
|
25
32
|
/** Run `talosctl <args…>`. Returns trimmed stdout, or '' when empty. */
|
|
26
33
|
export declare const talosctl: (args: readonly string[], options: TalosRunOptions) => Effect.Effect<string, import("effect/PlatformError").PlatformError | TalosError, ChildProcessSpawner.ChildProcessSpawner>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"talosctl.d.ts","sourceRoot":"","sources":["../../src/talos/talosctl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,OAAO,KAAK,mBAAmB,MAAM,6CAA6C,CAAC;AAEnF,qBAAa,UAAW,SAAQ,KAAK;IAEjC,QAAQ,CAAC,OAAO,EAAE,MAAM;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM;IAF3B,YACW,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EACzB,MAAM,EAAE,MAAM,EAIf;CACF;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"talosctl.d.ts","sourceRoot":"","sources":["../../src/talos/talosctl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,OAAO,KAAK,mBAAmB,MAAM,6CAA6C,CAAC;AAEnF,qBAAa,UAAW,SAAQ,KAAK;IAEjC,QAAQ,CAAC,OAAO,EAAE,MAAM;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM;IAF3B,YACW,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EACzB,MAAM,EAAE,MAAM,EAIf;CACF;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,wEAAwE;AACxE,eAAO,MAAM,QAAQ,SAAU,SAAS,MAAM,EAAE,WAAW,eAAe,8HA+CtE,CAAC;AAEL,uFAAuF;AACvF,eAAO,MAAM,iBAAiB,SAAU,SAAS,MAAM,EAAE,WAAW,eAAe,iHAShF,CAAC"}
|
package/dist/talos/values.d.ts
CHANGED
|
@@ -2,8 +2,30 @@
|
|
|
2
2
|
export declare const canonicalText: (text: string) => string;
|
|
3
3
|
/** SHA-256 hex digest of canonical text. Safe to persist — it is not reversible to the input. */
|
|
4
4
|
export declare const sha256: (text: string) => string;
|
|
5
|
-
/** Digest of a machine config
|
|
5
|
+
/** Digest of a machine config's canonical text. ⛔ Never persist the text itself. */
|
|
6
6
|
export declare const configDigest: (text: string) => string;
|
|
7
|
+
/**
|
|
8
|
+
* Extract the raw config text under `spec` from `talosctl get machineconfig -o yaml`'s wrapper.
|
|
9
|
+
*
|
|
10
|
+
* ⛔ THE WHOLE WRAPPER CAN NEVER MATCH THE PINNED DIGEST, AND HASHING IT WAS THE SHIPPED BUG.
|
|
11
|
+
* REASONED from talosctl source (`cmd/talosctl/.../output/yaml.go:63`,
|
|
12
|
+
* `resources/config/machine_config.go:40-50`): the resource envelope nests a `node:` line and
|
|
13
|
+
* resource metadata (version, timestamps) around the config, which is itself a raw YAML STRING
|
|
14
|
+
* under `spec`. Metadata changes on every observation, so `configDigest(wrapper)` never equals
|
|
15
|
+
* `configDigest(seededConfigText)` even when nothing changed — every reconcile would die, every
|
|
16
|
+
* diff would plan `update`, verify would never go quiet (all three MEASURED against the shipped
|
|
17
|
+
* code's shape, docs/plans/2026-09-26-talos-stack-first-boot.md).
|
|
18
|
+
* ⚠️ Returns `undefined` for any shape without a string `spec`, so a caller cannot mistake
|
|
19
|
+
* "unparsable wrapper" for "empty config" — those must fail differently (the caller's job).
|
|
20
|
+
* ⛔ MORE THAN ONE DOCUMENT IS REFUSED, NEVER `doc[0]` (fix-first #2, PR 307 red team). An unfiltered
|
|
21
|
+
* `get machineconfig` lists BOTH the `persistent` and `v1alpha1` resources, sorted by id
|
|
22
|
+
* (REASONED, cosi-project/runtime `inmem/collection.go:122-124`), so a bare `doc[0]` is always
|
|
23
|
+
* `persistent` — never the config this package applies. The caller (machine-config-read.ts) now
|
|
24
|
+
* always requests the single named resource (`get machineconfig v1alpha1`); a second document
|
|
25
|
+
* showing up here means that request shape changed without this guard changing with it, and
|
|
26
|
+
* silently picking one would repeat the exact shipped bug.
|
|
27
|
+
*/
|
|
28
|
+
export declare const extractMachineConfigSpec: (wrapperYaml: string) => string | undefined;
|
|
7
29
|
/**
|
|
8
30
|
* Public metadata extracted from a kubeconfig file on disk.
|
|
9
31
|
*
|
|
@@ -15,6 +37,4 @@ export declare const kubeconfigMetadata: (yamlText: string, contextName: string)
|
|
|
15
37
|
caFingerprint: string;
|
|
16
38
|
clientFingerprint: string;
|
|
17
39
|
} | undefined;
|
|
18
|
-
/** Resolve a config file path relative to the declaring stack file. */
|
|
19
|
-
export declare const resolveConfigPath: (stackDir: string, configFile: string) => string;
|
|
20
40
|
//# sourceMappingURL=values.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../../src/talos/values.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../../src/talos/values.ts"],"names":[],"mappings":"AASA,2EAA2E;AAC3E,eAAO,MAAM,aAAa,SAAU,MAAM,WAAmB,CAAC;AAE9D,iGAAiG;AACjG,eAAO,MAAM,MAAM,SAAU,MAAM,WAC6B,CAAC;AAEjE,oFAAoF;AACpF,eAAO,MAAM,YAAY,SAAU,MAAM,WAAiB,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,wBAAwB,gBAAiB,MAAM,KAAG,MAAM,GAAG,SAcvE,CAAC;AAeF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,aACnB,MAAM,eACH,MAAM,KAClB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GAAG,SAyB3E,CAAC"}
|