@homeflare/alchemy 0.25.0 → 0.26.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 (70) hide show
  1. package/dist/launchd/index.js +51 -47
  2. package/dist/launchd/index.js.map +5 -4
  3. package/dist/launchd/sudo-guard-mode.d.ts +62 -0
  4. package/dist/launchd/sudo-guard-mode.d.ts.map +1 -0
  5. package/dist/launchd/sudo-guard.d.ts +1 -38
  6. package/dist/launchd/sudo-guard.d.ts.map +1 -1
  7. package/dist/linux/fake-linux-host.d.ts.map +1 -1
  8. package/dist/linux/fake-sudo-root.d.ts +26 -0
  9. package/dist/linux/fake-sudo-root.d.ts.map +1 -0
  10. package/dist/linux/fake-sudo.d.ts +56 -0
  11. package/dist/linux/fake-sudo.d.ts.map +1 -0
  12. package/dist/linux/fake-systemd.d.ts +15 -0
  13. package/dist/linux/fake-systemd.d.ts.map +1 -1
  14. package/dist/linux/index.d.ts +2 -0
  15. package/dist/linux/index.d.ts.map +1 -1
  16. package/dist/linux/index.js +1151 -8
  17. package/dist/linux/index.js.map +24 -7
  18. package/dist/linux/sudo-allowlist-chown.d.ts +12 -0
  19. package/dist/linux/sudo-allowlist-chown.d.ts.map +1 -0
  20. package/dist/linux/sudo-allowlist-dir.d.ts +6 -0
  21. package/dist/linux/sudo-allowlist-dir.d.ts.map +1 -0
  22. package/dist/linux/sudo-allowlist.d.ts +40 -0
  23. package/dist/linux/sudo-allowlist.d.ts.map +1 -0
  24. package/dist/linux/sudo-exec.d.ts +31 -0
  25. package/dist/linux/sudo-exec.d.ts.map +1 -0
  26. package/dist/linux/sudo-guard.d.ts +36 -0
  27. package/dist/linux/sudo-guard.d.ts.map +1 -0
  28. package/dist/linux/sudo-runner.d.ts +37 -0
  29. package/dist/linux/sudo-runner.d.ts.map +1 -0
  30. package/dist/linux/sudo-stage.d.ts +22 -0
  31. package/dist/linux/sudo-stage.d.ts.map +1 -0
  32. package/dist/linux/sudo-write.d.ts +25 -0
  33. package/dist/linux/sudo-write.d.ts.map +1 -0
  34. package/dist/linux/unit-form.d.ts +43 -0
  35. package/dist/linux/unit-form.d.ts.map +1 -1
  36. package/dist/linux/unit-lifecycle.d.ts.map +1 -1
  37. package/dist/linux/unit-settle.d.ts.map +1 -1
  38. package/dist/litellm/fake-litellm.d.ts.map +1 -1
  39. package/dist/proxmox/fake-pve-lxc.d.ts.map +1 -1
  40. package/docs/launchd-sudo.md +12 -3
  41. package/docs/linux-host.md +5 -3
  42. package/docs/linux-sudo.md +187 -0
  43. package/package.json +1 -1
  44. package/src/launchd/sudo-guard-mode.ts +111 -0
  45. package/src/launchd/sudo-guard.ts +3 -79
  46. package/src/launchd/sudo-modes.test.ts +38 -1
  47. package/src/linux/fake-linux-host.ts +2 -0
  48. package/src/linux/fake-sudo-root.ts +157 -0
  49. package/src/linux/fake-sudo.ts +142 -0
  50. package/src/linux/fake-systemd.ts +36 -2
  51. package/src/linux/index.ts +2 -0
  52. package/src/linux/sudo-allowlist-chown.ts +71 -0
  53. package/src/linux/sudo-allowlist-dir.ts +103 -0
  54. package/src/linux/sudo-allowlist.test.ts +252 -0
  55. package/src/linux/sudo-allowlist.ts +223 -0
  56. package/src/linux/sudo-exec.ts +118 -0
  57. package/src/linux/sudo-guard.test.ts +136 -0
  58. package/src/linux/sudo-guard.ts +142 -0
  59. package/src/linux/sudo-lifecycle.test.ts +151 -0
  60. package/src/linux/sudo-runner.test.ts +206 -0
  61. package/src/linux/sudo-runner.ts +164 -0
  62. package/src/linux/sudo-stage.ts +50 -0
  63. package/src/linux/sudo-write.ts +167 -0
  64. package/src/linux/unit-activating.test.ts +164 -0
  65. package/src/linux/unit-form.ts +53 -1
  66. package/src/linux/unit-lifecycle.ts +9 -2
  67. package/src/linux/unit-settle.ts +8 -4
  68. package/src/litellm/fake-litellm.ts +2 -0
  69. package/src/proxmox/client.test.ts +17 -3
  70. package/src/proxmox/fake-pve-lxc.ts +10 -1
@@ -0,0 +1,164 @@
1
+ /**
2
+ * `started: false` against a unit that is `ActiveState=activating` — the timer-driven `Type=oneshot`
3
+ * scenario `isUnitRunning` (unit-form.ts) exists for, and the crash-restart (`auto-restart`)
4
+ * `SubState` that scenario must not be confused with. Split from unit-lifecycle.test.ts to stay
5
+ * under this file's line cap; see that file for the rest of the family's behaviour.
6
+ *
7
+ * ⛔ THE BUG THIS GUARDS: before `isUnitRunning`, `diffUnit` read `ActiveState=activating` on a
8
+ * `started: false` unit as drift and planned `update`; `settle` then called `systemctl stop` on a
9
+ * check that was already running, mid-run, driven by its own `.timer`. A redeploy must plan to
10
+ * nothing while the run is in progress — these tests are that redeploy.
11
+ * ⛔ THE SECOND BUG THAT ALMOST SHIPPED WITH THE FIRST FIX: an `activating` unit whose `SubState`
12
+ * is `auto-restart` (or `auto-restart-queued`) is systemd's crash-restart backoff, not a start —
13
+ * see isUnitRunning's own comment. A `started: false` unit that is crash-looping must still be
14
+ * stopped; the "auto-restart backoff is still drift" test below is that case.
15
+ */
16
+ import { describe, expect, test } from 'bun:test';
17
+ import { fakeLinuxHost } from './fake-linux-host.ts';
18
+ import { type SystemdUnitProps, isUnitRunning, renderUnit } from './unit-form.ts';
19
+ import { diffUnit, readUnit, reconcileUnit } from './unit-lifecycle.ts';
20
+
21
+ const NAME = 'hf-node-check.service';
22
+ const PATH = `/etc/systemd/system/${NAME}`;
23
+ /** ⛔ No `[Install]`: a timer-driven oneshot is `enabled: false` — its `.timer` starts it, not `systemctl enable`. */
24
+ const content = renderUnit([
25
+ { lines: [['Description', 'a PVE node check']], name: 'Unit' },
26
+ {
27
+ lines: [
28
+ ['Type', 'oneshot'],
29
+ ['ExecStart', '/usr/bin/check-node'],
30
+ ],
31
+ name: 'Service',
32
+ },
33
+ ]);
34
+ const props: SystemdUnitProps = { content, enabled: false, name: NAME, started: false };
35
+ const host = () => fakeLinuxHost({ dirs: { '/etc/systemd/system': 0 } });
36
+ const verbs = (calls: string[][]) =>
37
+ calls.filter((call) => call[0] === 'systemctl').map((call) => call[1]);
38
+
39
+ /** `readUnit` narrowed to defined, so callers can pass it straight to diffUnit/reconcileUnit. */
40
+ const outputFor = async (fake: ReturnType<typeof host>, of: SystemdUnitProps) => {
41
+ const found = await readUnit(fake.runner, of);
42
+ if (found === undefined) throw new Error(`${of.name} not found on the fake host`);
43
+ return found;
44
+ };
45
+
46
+ describe('isUnitRunning — the one predicate diff and settle share', () => {
47
+ test('active always counts as running, whatever started declares', () => {
48
+ expect(isUnitRunning('active', 'running', true)).toBe(true);
49
+ expect(isUnitRunning('active', 'running', false)).toBe(true);
50
+ });
51
+ test('a genuine start counts as running only when started is declared', () => {
52
+ expect(isUnitRunning('activating', 'start', true)).toBe(true);
53
+ expect(isUnitRunning('activating', 'start', false)).toBe(false);
54
+ });
55
+ // ⛔ Added on adversarial review: `auto-restart`/`auto-restart-queued` are ALSO
56
+ // `ActiveState=activating` (systemd's crash-restart backoff, service.c), not a fresh start —
57
+ // see isUnitRunning's own comment. Without this, started: false would stop enforcing itself on
58
+ // exactly the unit most in need of it: one that is crash-looping.
59
+ test('auto-restart backoff always counts as running — it is a crash loop, not a fresh start', () => {
60
+ expect(isUnitRunning('activating', 'auto-restart', false)).toBe(true);
61
+ expect(isUnitRunning('activating', 'auto-restart-queued', false)).toBe(true);
62
+ });
63
+ test('inactive and failed never count as running', () => {
64
+ expect(isUnitRunning('inactive', 'dead', true)).toBe(false);
65
+ expect(isUnitRunning('failed', 'failed', false)).toBe(false);
66
+ });
67
+ });
68
+
69
+ describe('started: false against a oneshot mid-run', () => {
70
+ test('activating, everything else converged: diff is noop', async () => {
71
+ const fake = host();
72
+ fake.placeUnit(PATH, content, { activeState: 'activating', enabled: false, subState: 'start' });
73
+ const output = await outputFor(fake, props);
74
+ expect(await diffUnit(fake.runner, props, output)).toEqual({ action: 'noop' });
75
+ });
76
+
77
+ test('active is drift: diff is update, and settle stops it', async () => {
78
+ const fake = host();
79
+ fake.placeUnit(PATH, content, { active: true, enabled: false });
80
+ const output = await outputFor(fake, props);
81
+ expect(await diffUnit(fake.runner, props, output)).toEqual({ action: 'update' });
82
+ const before = fake.calls.length;
83
+ const settled = await reconcileUnit(fake.runner, props, output);
84
+ expect(verbs(fake.calls.slice(before))).toContain('stop');
85
+ expect(settled.active).toBe(false);
86
+ });
87
+
88
+ test('activating during an unrelated unit-file update: settle does not stop it', async () => {
89
+ const fake = host();
90
+ fake.placeUnit(PATH, content, { activeState: 'activating', enabled: false, subState: 'start' });
91
+ const output = await outputFor(fake, props);
92
+ const changed = { ...props, content: content.replace('check-node', 'check-node-v2') };
93
+ expect(await diffUnit(fake.runner, changed, output)).toEqual({ action: 'update' });
94
+ const before = fake.calls.length;
95
+ await reconcileUnit(fake.runner, changed, output);
96
+ expect(verbs(fake.calls.slice(before))).not.toContain('stop');
97
+ });
98
+
99
+ test('failed is not running either: diff is noop', async () => {
100
+ const fake = host();
101
+ fake.placeUnit(PATH, content, { activeState: 'failed', enabled: false });
102
+ const output = await outputFor(fake, props);
103
+ expect(await diffUnit(fake.runner, props, output)).toEqual({ action: 'noop' });
104
+ });
105
+
106
+ // ⛔ ADVERSARIAL-REVIEW CASE: `activating` is not only a fresh start. A unit that was started by
107
+ // hand and now crash-loops (`Restart=on-failure`) sits in `ActiveState=activating`,
108
+ // `SubState=auto-restart` for nearly all of its wall-clock time. The oneshot exemption above
109
+ // must NOT swallow this one — started: false has to keep stopping it, same as plain `active`.
110
+ test('auto-restart backoff is still drift: diff is update, and settle still stops it', async () => {
111
+ const fake = host();
112
+ const crashy = renderUnit([
113
+ { lines: [['Description', 'started by hand, now crash-looping']], name: 'Unit' },
114
+ {
115
+ lines: [
116
+ ['ExecStart', '/usr/bin/flaky'],
117
+ ['Restart', 'on-failure'],
118
+ ['RestartSec', '5'],
119
+ ],
120
+ name: 'Service',
121
+ },
122
+ ]);
123
+ const crashyProps: SystemdUnitProps = {
124
+ content: crashy,
125
+ enabled: false,
126
+ name: NAME,
127
+ started: false,
128
+ };
129
+ fake.placeUnit(PATH, crashy, {
130
+ activeState: 'activating',
131
+ enabled: false,
132
+ subState: 'auto-restart',
133
+ });
134
+ const output = await outputFor(fake, crashyProps);
135
+ expect(await diffUnit(fake.runner, crashyProps, output)).toEqual({ action: 'update' });
136
+ const before = fake.calls.length;
137
+ const settled = await reconcileUnit(fake.runner, crashyProps, output);
138
+ expect(verbs(fake.calls.slice(before))).toContain('stop');
139
+ expect(settled.active).toBe(false);
140
+ });
141
+ });
142
+
143
+ describe('started: true (or omitted) keeps counting activating as running', () => {
144
+ test('no start is issued while the unit is already activating', async () => {
145
+ const fake = host();
146
+ const enabledContent = renderUnit([
147
+ { lines: [['Description', 'a long-running service']], name: 'Unit' },
148
+ { lines: [['ExecStart', '/usr/bin/thing']], name: 'Service' },
149
+ { lines: [['WantedBy', 'multi-user.target']], name: 'Install' },
150
+ ]);
151
+ const started: SystemdUnitProps = { content: enabledContent, name: NAME };
152
+ fake.placeUnit(PATH, enabledContent, {
153
+ activeState: 'activating',
154
+ enabled: true,
155
+ subState: 'start',
156
+ });
157
+ const output = await outputFor(fake, started);
158
+ expect(await diffUnit(fake.runner, started, output)).toEqual({ action: 'noop' });
159
+ const before = fake.calls.length;
160
+ const settled = await reconcileUnit(fake.runner, started, output);
161
+ expect(verbs(fake.calls.slice(before))).not.toContain('start');
162
+ expect(settled.active).toBe(true);
163
+ });
164
+ });
@@ -90,6 +90,57 @@ export const digestOf = (text: string): string => sha256Hex(new TextEncoder().en
90
90
  export const configDigest = (restartOn: readonly string[] | undefined): string =>
91
91
  digestOf((restartOn ?? []).join('\n'));
92
92
 
93
+ /**
94
+ * Whether `activeState`/`subState` count as "the unit is running" against a declared `started` —
95
+ * the ONE place this decision is made, so `diffUnit` (unit-lifecycle.ts) and `settle`
96
+ * (unit-settle.ts) can never disagree about it.
97
+ *
98
+ * ⛔ WHY THIS EXISTS: a `Type=oneshot` service driven by a `.timer` (no `[Install]`, declared
99
+ * `started: false, enabled: false` — its timer starts it, not this resource) reports
100
+ * `ActiveState=activating` for the run's whole duration, not an instant. Written for the PVE
101
+ * node-check unit that first hit this: ~1.2s, every 60s. A plan taken mid-run must not read that
102
+ * run as drift, and a deploy must not `systemctl stop` a check that is already in flight.
103
+ * ★ systemd.service(5) §`Type=`, `oneshot` (man7.org mirror, read 2026-09-23): with no
104
+ * `RemainAfterExit=`, the service manager holds the unit `activating` for as long as
105
+ * `ExecStart=` runs, then moves it straight to `dead`/`inactive` (or `failed`) — it never passes
106
+ * through `active`. So for `started: false`, `activating` is exactly a run in progress, and
107
+ * `active` is the one state a oneshot never reaches on its own: that is the drift, and the only
108
+ * thing settle stops.
109
+ * ⛔ CRASH-LOOP GUARD, added on adversarial review: `ActiveState=activating` is not only "starting
110
+ * for the first time" — a service with `Restart=` waiting out its `RestartSec=` backoff between
111
+ * crash attempts is ALSO `activating`, with `SubState=auto-restart` (or `auto-restart-queued`).
112
+ * A unit declared `started: false` that is crash-looping sits there for nearly all of its
113
+ * wall-clock time. Without this guard the oneshot exemption above would read that loop as
114
+ * converged forever, and a deploy would never again issue the `stop` that ends it — silently
115
+ * defeating `started: false` on exactly the unit that most needs it enforced. So only a genuine
116
+ * start (`SubState` anything else — `start`, `start-pre`, `start-post`, …) gets the exemption;
117
+ * an auto-restart substate counts as running regardless of `started`, same as `active` does.
118
+ * ★ SOURCE, not measured against a live host: systemd's own `service.c`
119
+ * `state_translation_table` (github.com/systemd/systemd, read 2026-09-23) maps both
120
+ * `SERVICE_AUTO_RESTART` and `SERVICE_AUTO_RESTART_QUEUED` to `UNIT_ACTIVATING`, and
121
+ * `unit-def.c`'s `service_state_table` names their `SubState` strings `"auto-restart"` and
122
+ * `"auto-restart-queued"`. ⚠️ REASONED NOT MEASURED: no unit was actually crash-looped and read
123
+ * back with `systemctl show` for this change — the systemd source is the citation, unlike
124
+ * systemctl.ts's own header, which is a live-host trace.
125
+ * ⚠️ THE TRADE-OFF THIS ACCEPTS: a `Type=notify` (or other long-running type) unit stuck in a
126
+ * genuine `activating`/`start` with `started: false` — never reaching `active` and never
127
+ * crash-looping either — reads as converged, not drift, until it reaches `active`. A unit hung
128
+ * like that is exactly the case a human should look at, not one this predicate auto-corrects by
129
+ * stopping it out from under whatever else depends on it.
130
+ * ★ `started: true` (the default, when omitted) is unchanged: `active` or `activating` (any
131
+ * `subState`) both count as running, so a start already in flight is never started twice.
132
+ */
133
+ export const isUnitRunning = (
134
+ activeState: string,
135
+ subState: string | undefined,
136
+ started: boolean,
137
+ ): boolean => {
138
+ if (activeState === 'active') return true;
139
+ if (activeState !== 'activating') return false;
140
+ if (subState === 'auto-restart' || subState === 'auto-restart-queued') return true;
141
+ return started;
142
+ };
143
+
93
144
  /** Sections → an INI unit file. ★ Keys and values pass through untouched; see the file header. */
94
145
  export const renderUnit = (sections: readonly UnitSection[]): string =>
95
146
  `${sections
@@ -104,7 +155,8 @@ export const unitText = (props: SystemdUnitProps): string =>
104
155
  export const unitPathFor = (props: SystemdUnitProps): string =>
105
156
  `${props.directory ?? DEFAULT_UNIT_DIRECTORY}/${props.name}`;
106
157
 
107
- const NAME = /^[A-Za-z0-9][A-Za-z0-9_.@:-]*\.([a-z]+)$/;
158
+ /** ★ Exported so sudo-allowlist.ts validates a systemctl unit operand against the same pattern. */
159
+ export const NAME = /^[A-Za-z0-9][A-Za-z0-9_.@:-]*\.([a-z]+)$/;
108
160
  /** systemd's own unit types. ★ Fixed vocabulary from `systemd.unit(5)`, not a guess at directives. */
109
161
  const TYPES = new Set([
110
162
  'automount',
@@ -27,6 +27,7 @@ import {
27
27
  UNIT_WRITE,
28
28
  configDigest,
29
29
  digestOf,
30
+ isUnitRunning,
30
31
  unitPathFor,
31
32
  unitText,
32
33
  } from './unit-form.ts';
@@ -75,10 +76,16 @@ export const diffUnit = async (
75
76
  const live = await readUnit(runner, news);
76
77
  if (live === undefined || live.unitSha256 !== desired) return update();
77
78
  if (live.enabled !== (news.enabled !== false)) return update();
78
- if (live.active !== (news.started !== false)) return update();
79
79
  // ⚠️ systemd's own word for "the file on disk is newer than what I loaded" — a write that landed
80
- // without its reload. It is drift that neither digest can see.
80
+ // without its reload. It is drift that neither digest can see. ★ Also the freshest read of
81
+ // ActiveState/SubState — not `live.active`, which is a raw "active or activating" reading with
82
+ // no SubState in it. Whether the current state counts as drift against `started` is the
83
+ // isUnitRunning policy (unit-form.ts), shared with settle so the two can never disagree.
81
84
  const status = await showUnit(runner, news.name);
85
+ const wantStarted = news.started !== false;
86
+ if (isUnitRunning(status.activeState, status.subState, wantStarted) !== wantStarted) {
87
+ return update();
88
+ }
82
89
  return status.needDaemonReload ? update() : { action: 'noop' };
83
90
  };
84
91
 
@@ -13,6 +13,7 @@ import {
13
13
  type SystemdUnitAttributes,
14
14
  type SystemdUnitProps,
15
15
  configDigest,
16
+ isUnitRunning,
16
17
  unitPathFor,
17
18
  } from './unit-form.ts';
18
19
  import {
@@ -81,10 +82,13 @@ export const settle = async (
81
82
  try {
82
83
  if (wantEnabled && (!isEnabled || step.changed)) await enableUnit(runner, props.name);
83
84
  if (!wantEnabled && isEnabled) await disableUnit(runner, props.name);
84
- const active = step.status.activeState === 'active' || step.status.activeState === 'activating';
85
+ // ★ isUnitRunning (unit-form.ts): the same started-aware policy diffUnit uses, so a unit this
86
+ // deploy never touches — a `started: false` oneshot mid-run — is never stopped here either.
87
+ // `subState` is what tells that mid-run apart from a crash-restart backoff, which still stops.
88
+ const running = isUnitRunning(step.status.activeState, step.status.subState, wantStarted);
85
89
  if (!wantStarted) {
86
- if (active) await stopUnit(runner, props.name);
87
- } else if (!active) await startUnit(runner, props.name);
90
+ if (running) await stopUnit(runner, props.name);
91
+ } else if (!running) await startUnit(runner, props.name);
88
92
  else if (step.changed || step.configChanged) await restartUnit(runner, props.name);
89
93
  } catch (cause) {
90
94
  return undo(cause instanceof Error ? cause.message : String(cause));
@@ -96,7 +100,7 @@ export const settle = async (
96
100
  * as drift, in either direction.
97
101
  */
98
102
  const after = await showUnit(runner, props.name);
99
- if (wantStarted && after.activeState !== 'active' && after.activeState !== 'activating') {
103
+ if (wantStarted && !isUnitRunning(after.activeState, after.subState, wantStarted)) {
100
104
  return undo(`systemctl reported success but the unit is ${after.activeState}.`);
101
105
  }
102
106
  const settled = attributesOf(props, step.desired, after);
@@ -48,6 +48,8 @@ export const startFakeLitellm = (options?: {
48
48
  new Response(JSON.stringify(body), { headers: { 'content-type': 'application/json' }, status });
49
49
 
50
50
  const server = Bun.serve({
51
+ // ⚠️ Loopback, not the wildcard default — see proxmox/fake-pve-lxc.ts for the race.
52
+ hostname: '127.0.0.1',
51
53
  port: 0,
52
54
  fetch: async (req) => {
53
55
  const url = new URL(req.url);
@@ -12,7 +12,11 @@ import { PveError, pveWith } from './client.ts';
12
12
  import type { PveCredential, PveTarget } from './credentials.ts';
13
13
  import { orderedMembers, resetLastGoodForTest } from './members.ts';
14
14
 
15
- type ServeOptions = { fetch(request: Request): Response | Promise<Response>; port: number };
15
+ type ServeOptions = {
16
+ fetch(request: Request): Response | Promise<Response>;
17
+ hostname: string;
18
+ port: number;
19
+ };
16
20
  const { Bun } = globalThis as unknown as {
17
21
  Bun: { serve(options: ServeOptions): { port: number; stop(closeActive: boolean): void } };
18
22
  };
@@ -84,6 +88,8 @@ const counting = (data: unknown) => {
84
88
  hits += 1;
85
89
  return Response.json({ data });
86
90
  },
91
+ // ⚠️ Loopback, not the wildcard default — see fake-pve-lxc.ts for the measured race.
92
+ hostname: '127.0.0.1',
87
93
  port: 0,
88
94
  });
89
95
  return { hits: () => hits, port: server.port, stop: () => server.stop(true) };
@@ -106,7 +112,11 @@ describe('cluster member failover', () => {
106
112
 
107
113
  it('does not fail over on HTTP 500 from the first member', async () => {
108
114
  resetLastGoodForTest();
109
- const bad = Bun.serve({ fetch: () => new Response('fail', { status: 500 }), port: 0 });
115
+ const bad = Bun.serve({
116
+ fetch: () => new Response('fail', { status: 500 }),
117
+ hostname: '127.0.0.1',
118
+ port: 0,
119
+ });
110
120
  const good = counting([]);
111
121
  try {
112
122
  const error = await run(pveWith(target([A, B]), CRED, 'GET', 'pools').pipe(Effect.flip), {
@@ -144,7 +154,11 @@ describe('cluster member failover', () => {
144
154
 
145
155
  it('does not re-send a write after a transport timeout', async () => {
146
156
  resetLastGoodForTest();
147
- const hang = Bun.serve({ fetch: () => new Promise<Response>(() => {}), port: 0 });
157
+ const hang = Bun.serve({
158
+ fetch: () => new Promise<Response>(() => {}),
159
+ hostname: '127.0.0.1',
160
+ port: 0,
161
+ });
148
162
  const backup = counting('UPID:1');
149
163
  try {
150
164
  await run(
@@ -185,7 +185,16 @@ export const fakePve = (): FakePve => {
185
185
  return json({ data: null, message: 'unhandled\n' }, 501);
186
186
  };
187
187
 
188
- const server = Bun.serve({ fetch: handle, port: 0 });
188
+ // 🔴 LOOPBACK, NOT THE DEFAULT WILDCARD — AND THAT WAS THE FLAKE. Measured 2026-09-23 on
189
+ // macOS: `Bun.serve({ port: 0 })` binds 0.0.0.0, and the kernel will hand a wildcard
190
+ // port-0 bind a port some OTHER socket already holds on 127.0.0.1 (16,373 binds in, it
191
+ // did). Loopback traffic then goes to the more specific listener, so this fake's own
192
+ // requests reached another process's server — another test suite's fake, when several
193
+ // agents run `bun test` at once — and a plan failed with "Transport error" on a GET to a
194
+ // server that was up. A 127.0.0.1 port-0 bind is never handed a port in use on
195
+ // 127.0.0.1, and nothing more specific can shadow it. tests/loopback-servers.test.ts
196
+ // keeps every test server this way.
197
+ const server = Bun.serve({ fetch: handle, hostname: '127.0.0.1', port: 0 });
189
198
  const port = String(server.port);
190
199
  const remapped = (input: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => {
191
200
  const url = new URL(input instanceof Request ? input.url : String(input));