@openparachute/hub 0.6.4-rc.8 → 0.6.4

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.
@@ -86,6 +86,13 @@ describe("init", () => {
86
86
  const logs: string[] = [];
87
87
  const code = await init({
88
88
  configDir: h.configDir,
89
+ // #590: keep the version-check a no-op in init tests — NEVER let the
90
+ // production default fire a real /health fetch + restart the live unit.
91
+ ensureHubVersion: async () => ({
92
+ outcome: "match" as const,
93
+ installedVersion: "test",
94
+ messages: [],
95
+ }),
89
96
  manifestPath: h.manifestPath,
90
97
  log: (l) => logs.push(l),
91
98
  alive: () => false,
@@ -127,6 +134,13 @@ describe("init", () => {
127
134
  const logs: string[] = [];
128
135
  const code = await init({
129
136
  configDir: h.configDir,
137
+ // #590: keep the version-check a no-op in init tests — NEVER let the
138
+ // production default fire a real /health fetch + restart the live unit.
139
+ ensureHubVersion: async () => ({
140
+ outcome: "match" as const,
141
+ installedVersion: "test",
142
+ messages: [],
143
+ }),
130
144
  manifestPath: h.manifestPath,
131
145
  log: (l) => logs.push(l),
132
146
  // No pidfile (unit-managed) → processState reports not-running.
@@ -168,6 +182,13 @@ describe("init", () => {
168
182
  const logs: string[] = [];
169
183
  const code = await init({
170
184
  configDir: h.configDir,
185
+ // #590: keep the version-check a no-op in init tests — NEVER let the
186
+ // production default fire a real /health fetch + restart the live unit.
187
+ ensureHubVersion: async () => ({
188
+ outcome: "match" as const,
189
+ installedVersion: "test",
190
+ messages: [],
191
+ }),
171
192
  manifestPath: h.manifestPath,
172
193
  log: (l) => logs.push(l),
173
194
  alive: () => true,
@@ -213,6 +234,13 @@ describe("init", () => {
213
234
  const logs: string[] = [];
214
235
  const code = await init({
215
236
  configDir: h.configDir,
237
+ // #590: keep the version-check a no-op in init tests — NEVER let the
238
+ // production default fire a real /health fetch + restart the live unit.
239
+ ensureHubVersion: async () => ({
240
+ outcome: "match" as const,
241
+ installedVersion: "test",
242
+ messages: [],
243
+ }),
216
244
  manifestPath: h.manifestPath,
217
245
  log: (l) => logs.push(l),
218
246
  alive: () => true,
@@ -237,6 +265,13 @@ describe("init", () => {
237
265
  const opened: string[] = [];
238
266
  const code = await init({
239
267
  configDir: h.configDir,
268
+ // #590: keep the version-check a no-op in init tests — NEVER let the
269
+ // production default fire a real /health fetch + restart the live unit.
270
+ ensureHubVersion: async () => ({
271
+ outcome: "match" as const,
272
+ installedVersion: "test",
273
+ messages: [],
274
+ }),
240
275
  manifestPath: h.manifestPath,
241
276
  log: () => {},
242
277
  alive: () => false,
@@ -270,6 +305,13 @@ describe("init", () => {
270
305
  const opened: string[] = [];
271
306
  const code = await init({
272
307
  configDir: h.configDir,
308
+ // #590: keep the version-check a no-op in init tests — NEVER let the
309
+ // production default fire a real /health fetch + restart the live unit.
310
+ ensureHubVersion: async () => ({
311
+ outcome: "match" as const,
312
+ installedVersion: "test",
313
+ messages: [],
314
+ }),
273
315
  manifestPath: h.manifestPath,
274
316
  log: () => {},
275
317
  alive: () => false,
@@ -306,6 +348,13 @@ describe("init", () => {
306
348
  let prompted = false;
307
349
  const code = await init({
308
350
  configDir: h.configDir,
351
+ // #590: keep the version-check a no-op in init tests — NEVER let the
352
+ // production default fire a real /health fetch + restart the live unit.
353
+ ensureHubVersion: async () => ({
354
+ outcome: "match" as const,
355
+ installedVersion: "test",
356
+ messages: [],
357
+ }),
309
358
  manifestPath: h.manifestPath,
310
359
  log: () => {},
311
360
  alive: () => false,
@@ -339,6 +388,13 @@ describe("init", () => {
339
388
  let prompted = false;
340
389
  const code = await init({
341
390
  configDir: h.configDir,
391
+ // #590: keep the version-check a no-op in init tests — NEVER let the
392
+ // production default fire a real /health fetch + restart the live unit.
393
+ ensureHubVersion: async () => ({
394
+ outcome: "match" as const,
395
+ installedVersion: "test",
396
+ messages: [],
397
+ }),
342
398
  manifestPath: h.manifestPath,
343
399
  log: () => {},
344
400
  alive: () => false,
@@ -366,6 +422,13 @@ describe("init", () => {
366
422
  const opened: string[] = [];
367
423
  const code = await init({
368
424
  configDir: h.configDir,
425
+ // #590: keep the version-check a no-op in init tests — NEVER let the
426
+ // production default fire a real /health fetch + restart the live unit.
427
+ ensureHubVersion: async () => ({
428
+ outcome: "match" as const,
429
+ installedVersion: "test",
430
+ messages: [],
431
+ }),
369
432
  manifestPath: h.manifestPath,
370
433
  log: () => {},
371
434
  alive: () => false,
@@ -400,6 +463,13 @@ describe("init", () => {
400
463
  const logs: string[] = [];
401
464
  const code = await init({
402
465
  configDir: h.configDir,
466
+ // #590: keep the version-check a no-op in init tests — NEVER let the
467
+ // production default fire a real /health fetch + restart the live unit.
468
+ ensureHubVersion: async () => ({
469
+ outcome: "match" as const,
470
+ installedVersion: "test",
471
+ messages: [],
472
+ }),
403
473
  manifestPath: h.manifestPath,
404
474
  log: (l) => logs.push(l),
405
475
  alive: () => false,
@@ -434,6 +504,13 @@ describe("init", () => {
434
504
  const opened: string[] = [];
435
505
  const code = await init({
436
506
  configDir: h.configDir,
507
+ // #590: keep the version-check a no-op in init tests — NEVER let the
508
+ // production default fire a real /health fetch + restart the live unit.
509
+ ensureHubVersion: async () => ({
510
+ outcome: "match" as const,
511
+ installedVersion: "test",
512
+ messages: [],
513
+ }),
437
514
  manifestPath: h.manifestPath,
438
515
  log: () => {},
439
516
  alive: () => false,
@@ -464,6 +541,13 @@ describe("init", () => {
464
541
  const logs: string[] = [];
465
542
  const code = await init({
466
543
  configDir: h.configDir,
544
+ // #590: keep the version-check a no-op in init tests — NEVER let the
545
+ // production default fire a real /health fetch + restart the live unit.
546
+ ensureHubVersion: async () => ({
547
+ outcome: "match" as const,
548
+ installedVersion: "test",
549
+ messages: [],
550
+ }),
467
551
  manifestPath: h.manifestPath,
468
552
  log: (l) => logs.push(l),
469
553
  alive: () => false,
@@ -485,6 +569,176 @@ describe("init", () => {
485
569
  });
486
570
  });
487
571
 
572
+ describe("init — version-check-and-restart at the hub adoption point (#590)", () => {
573
+ test("invokes the version check with the resolved hub port after the hub is up", async () => {
574
+ const h = makeHarness();
575
+ try {
576
+ const logs: string[] = [];
577
+ let seenPort: number | undefined;
578
+ const code = await init({
579
+ configDir: h.configDir,
580
+ manifestPath: h.manifestPath,
581
+ log: (l) => logs.push(l),
582
+ alive: () => false,
583
+ ensureHub: async () => {
584
+ writeHubPort(1939, h.configDir);
585
+ return { pid: 0, port: 1939, started: false };
586
+ },
587
+ ensureHubVersion: async ({ port, log }) => {
588
+ seenPort = port;
589
+ log(
590
+ "⚠ the running hub is 0.5.14-rc.4 but 0.6.4-rc.9 is installed — restarting the hub unit to pick up the new code.",
591
+ );
592
+ return {
593
+ outcome: "restarted" as const,
594
+ runningVersion: "0.6.4-rc.9",
595
+ installedVersion: "0.6.4-rc.9",
596
+ messages: ["✓ hub unit restarted; now running 0.6.4-rc.9."],
597
+ };
598
+ },
599
+ readExposeStateFn: () => undefined,
600
+ isTty: false,
601
+ platform: "linux",
602
+ installVaultModuleImpl: noopVaultInstall,
603
+ });
604
+ expect(code).toBe(0);
605
+ expect(seenPort).toBe(1939);
606
+ const joined = logs.join("\n");
607
+ // The mismatch notice + the restart confirmation both surface.
608
+ expect(joined).toContain("restarting the hub unit to pick up the new code");
609
+ expect(joined).toContain("now running 0.6.4-rc.9");
610
+ } finally {
611
+ h.cleanup();
612
+ }
613
+ });
614
+
615
+ test("a not-unit-managed mismatch bails init with exit 1 (don't wire a tunnel to a zombie)", async () => {
616
+ const h = makeHarness();
617
+ try {
618
+ const logs: string[] = [];
619
+ let exposeRan = false;
620
+ const code = await init({
621
+ configDir: h.configDir,
622
+ manifestPath: h.manifestPath,
623
+ log: (l) => logs.push(l),
624
+ alive: () => false,
625
+ ensureHub: async () => {
626
+ writeHubPort(1939, h.configDir);
627
+ return { pid: 0, port: 1939, started: false };
628
+ },
629
+ ensureHubVersion: async () => ({
630
+ outcome: "not-unit-managed" as const,
631
+ runningVersion: "0.5.14-rc.4",
632
+ installedVersion: "0.6.4-rc.9",
633
+ messages: [
634
+ "⚠ the running hub is 0.5.14-rc.4 but 0.6.4-rc.9 is installed.",
635
+ " The running hub is NOT managed by a Parachute service unit (a detached process or a foreground `parachute serve`), so it won't be restarted automatically.",
636
+ ],
637
+ }),
638
+ // If init wrongly continued, this would run — assert it does NOT.
639
+ exposeChoice: "tailnet",
640
+ exposeTailnetImpl: async () => {
641
+ exposeRan = true;
642
+ return 0;
643
+ },
644
+ readExposeStateFn: () => undefined,
645
+ isTty: false,
646
+ platform: "linux",
647
+ installVaultModuleImpl: noopVaultInstall,
648
+ });
649
+ expect(code).toBe(1);
650
+ expect(exposeRan).toBe(false);
651
+ const joined = logs.join("\n");
652
+ expect(joined).toContain("NOT managed by a Parachute service unit");
653
+ expect(joined).toContain("re-run `parachute init`");
654
+ } finally {
655
+ h.cleanup();
656
+ }
657
+ });
658
+
659
+ test("a restart-failed outcome bails init with exit 1 + an orienting line (don't continue past a failed restart)", async () => {
660
+ const h = makeHarness();
661
+ try {
662
+ const logs: string[] = [];
663
+ let exposeRan = false;
664
+ const code = await init({
665
+ configDir: h.configDir,
666
+ manifestPath: h.manifestPath,
667
+ log: (l) => logs.push(l),
668
+ alive: () => false,
669
+ ensureHub: async () => {
670
+ writeHubPort(1939, h.configDir);
671
+ return { pid: 0, port: 1939, started: false };
672
+ },
673
+ ensureHubVersion: async () => ({
674
+ outcome: "restart-failed" as const,
675
+ runningVersion: "0.5.14-rc.4",
676
+ installedVersion: "0.6.4-rc.9",
677
+ messages: [
678
+ "⚠ the running hub is 0.5.14-rc.4 but 0.6.4-rc.9 is installed, and the hub unit restart failed.",
679
+ "failed to restart the hub unit via the service manager (Unit parachute-hub.service not found.)",
680
+ ],
681
+ }),
682
+ // If init wrongly continued past the failed restart, this would run.
683
+ exposeChoice: "tailnet",
684
+ exposeTailnetImpl: async () => {
685
+ exposeRan = true;
686
+ return 0;
687
+ },
688
+ readExposeStateFn: () => undefined,
689
+ isTty: false,
690
+ platform: "linux",
691
+ installVaultModuleImpl: noopVaultInstall,
692
+ });
693
+ expect(code).toBe(1);
694
+ expect(exposeRan).toBe(false);
695
+ const joined = logs.join("\n");
696
+ // The version-check messages + the orienting line + the logs hint surface.
697
+ expect(joined).toContain("the hub unit restart failed");
698
+ expect(joined).toContain("The hub service manager rejected the restart command.");
699
+ expect(joined).toContain("parachute logs hub");
700
+ } finally {
701
+ h.cleanup();
702
+ }
703
+ });
704
+
705
+ test("a still-mismatched outcome warns but continues (bun-linked branch)", async () => {
706
+ const h = makeHarness();
707
+ try {
708
+ const logs: string[] = [];
709
+ const code = await init({
710
+ configDir: h.configDir,
711
+ manifestPath: h.manifestPath,
712
+ log: (l) => logs.push(l),
713
+ alive: () => false,
714
+ ensureHub: async () => {
715
+ writeHubPort(1939, h.configDir);
716
+ return { pid: 0, port: 1939, started: false };
717
+ },
718
+ ensureHubVersion: async () => ({
719
+ outcome: "still-mismatched" as const,
720
+ runningVersion: "0.6.4-rc.8",
721
+ installedVersion: "0.6.4-rc.9",
722
+ messages: [
723
+ "⚠ restarted the hub unit, but it is still not reporting 0.6.4-rc.9 (reports 0.6.4-rc.8).",
724
+ ],
725
+ }),
726
+ readExposeStateFn: () => undefined,
727
+ isTty: false,
728
+ platform: "linux",
729
+ installVaultModuleImpl: noopVaultInstall,
730
+ });
731
+ // Continues (does NOT bail) — the warning surfaces but init reaches the URL.
732
+ expect(code).toBe(0);
733
+ const joined = logs.join("\n");
734
+ expect(joined).toContain("still not reporting 0.6.4-rc.9");
735
+ expect(joined).toContain("http://127.0.0.1:1939/admin/");
736
+ } finally {
737
+ h.cleanup();
738
+ }
739
+ });
740
+ });
741
+
488
742
  describe("init bootstrap-token first-claim (hub#576)", () => {
489
743
  function publicState(): ExposeState {
490
744
  return {
@@ -507,6 +761,13 @@ describe("init bootstrap-token first-claim (hub#576)", () => {
507
761
  const logs: string[] = [];
508
762
  const code = await init({
509
763
  configDir: h.configDir,
764
+ // #590: keep the version-check a no-op in init tests — NEVER let the
765
+ // production default fire a real /health fetch + restart the live unit.
766
+ ensureHubVersion: async () => ({
767
+ outcome: "match" as const,
768
+ installedVersion: "test",
769
+ messages: [],
770
+ }),
510
771
  manifestPath: h.manifestPath,
511
772
  log: (l) => logs.push(l),
512
773
  alive: () => true,
@@ -541,6 +802,13 @@ describe("init bootstrap-token first-claim (hub#576)", () => {
541
802
  const logs: string[] = [];
542
803
  const code = await init({
543
804
  configDir: h.configDir,
805
+ // #590: keep the version-check a no-op in init tests — NEVER let the
806
+ // production default fire a real /health fetch + restart the live unit.
807
+ ensureHubVersion: async () => ({
808
+ outcome: "match" as const,
809
+ installedVersion: "test",
810
+ messages: [],
811
+ }),
544
812
  manifestPath: h.manifestPath,
545
813
  log: (l) => logs.push(l),
546
814
  alive: () => true,
@@ -569,6 +837,13 @@ describe("init bootstrap-token first-claim (hub#576)", () => {
569
837
  const logs: string[] = [];
570
838
  const code = await init({
571
839
  configDir: h.configDir,
840
+ // #590: keep the version-check a no-op in init tests — NEVER let the
841
+ // production default fire a real /health fetch + restart the live unit.
842
+ ensureHubVersion: async () => ({
843
+ outcome: "match" as const,
844
+ installedVersion: "test",
845
+ messages: [],
846
+ }),
572
847
  manifestPath: h.manifestPath,
573
848
  log: (l) => logs.push(l),
574
849
  alive: () => true,
@@ -596,6 +871,13 @@ describe("init bootstrap-token first-claim (hub#576)", () => {
596
871
  const wizardUrls: string[] = [];
597
872
  const code = await init({
598
873
  configDir: h.configDir,
874
+ // #590: keep the version-check a no-op in init tests — NEVER let the
875
+ // production default fire a real /health fetch + restart the live unit.
876
+ ensureHubVersion: async () => ({
877
+ outcome: "match" as const,
878
+ installedVersion: "test",
879
+ messages: [],
880
+ }),
599
881
  manifestPath: h.manifestPath,
600
882
  log: () => {},
601
883
  alive: () => true,
@@ -686,6 +968,13 @@ describe("init exposure chain", () => {
686
968
  const promptCalls: string[] = [];
687
969
  const code = await init({
688
970
  configDir: h.configDir,
971
+ // #590: keep the version-check a no-op in init tests — NEVER let the
972
+ // production default fire a real /health fetch + restart the live unit.
973
+ ensureHubVersion: async () => ({
974
+ outcome: "match" as const,
975
+ installedVersion: "test",
976
+ messages: [],
977
+ }),
689
978
  manifestPath: h.manifestPath,
690
979
  log: () => {},
691
980
  alive: () => false,
@@ -719,6 +1008,13 @@ describe("init exposure chain", () => {
719
1008
  const promptCalls: string[] = [];
720
1009
  const code = await init({
721
1010
  configDir: h.configDir,
1011
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1012
+ // production default fire a real /health fetch + restart the live unit.
1013
+ ensureHubVersion: async () => ({
1014
+ outcome: "match" as const,
1015
+ installedVersion: "test",
1016
+ messages: [],
1017
+ }),
722
1018
  manifestPath: h.manifestPath,
723
1019
  log: () => {},
724
1020
  alive: () => false,
@@ -765,6 +1061,13 @@ describe("init exposure chain", () => {
765
1061
  const promptCalls: string[] = [];
766
1062
  const code = await init({
767
1063
  configDir: h.configDir,
1064
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1065
+ // production default fire a real /health fetch + restart the live unit.
1066
+ ensureHubVersion: async () => ({
1067
+ outcome: "match" as const,
1068
+ installedVersion: "test",
1069
+ messages: [],
1070
+ }),
768
1071
  manifestPath: h.manifestPath,
769
1072
  log: () => {},
770
1073
  alive: () => false,
@@ -808,6 +1111,13 @@ describe("init exposure chain", () => {
808
1111
  let cloudflareCalls = 0;
809
1112
  const code = await init({
810
1113
  configDir: h.configDir,
1114
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1115
+ // production default fire a real /health fetch + restart the live unit.
1116
+ ensureHubVersion: async () => ({
1117
+ outcome: "match" as const,
1118
+ installedVersion: "test",
1119
+ messages: [],
1120
+ }),
811
1121
  manifestPath: h.manifestPath,
812
1122
  log: () => {},
813
1123
  alive: () => false,
@@ -842,6 +1152,13 @@ describe("init exposure chain", () => {
842
1152
  let cloudflareCalls = 0;
843
1153
  const code = await init({
844
1154
  configDir: h.configDir,
1155
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1156
+ // production default fire a real /health fetch + restart the live unit.
1157
+ ensureHubVersion: async () => ({
1158
+ outcome: "match" as const,
1159
+ installedVersion: "test",
1160
+ messages: [],
1161
+ }),
845
1162
  manifestPath: h.manifestPath,
846
1163
  log: () => {},
847
1164
  alive: () => false,
@@ -884,6 +1201,13 @@ describe("init exposure chain", () => {
884
1201
  };
885
1202
  await init({
886
1203
  configDir: h.configDir,
1204
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1205
+ // production default fire a real /health fetch + restart the live unit.
1206
+ ensureHubVersion: async () => ({
1207
+ outcome: "match" as const,
1208
+ installedVersion: "test",
1209
+ messages: [],
1210
+ }),
887
1211
  manifestPath: h.manifestPath,
888
1212
  log: (l) => promptLog.push(l),
889
1213
  alive: () => false,
@@ -918,6 +1242,13 @@ describe("init exposure chain", () => {
918
1242
  setChained("none");
919
1243
  await init({
920
1244
  configDir: h.configDir,
1245
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1246
+ // production default fire a real /health fetch + restart the live unit.
1247
+ ensureHubVersion: async () => ({
1248
+ outcome: "match" as const,
1249
+ installedVersion: "test",
1250
+ messages: [],
1251
+ }),
921
1252
  manifestPath: h.manifestPath,
922
1253
  log: (l) => promptLog.push(l),
923
1254
  alive: () => true,
@@ -967,6 +1298,13 @@ describe("init exposure chain", () => {
967
1298
  const logs: string[] = [];
968
1299
  const code = await init({
969
1300
  configDir: h.configDir,
1301
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1302
+ // production default fire a real /health fetch + restart the live unit.
1303
+ ensureHubVersion: async () => ({
1304
+ outcome: "match" as const,
1305
+ installedVersion: "test",
1306
+ messages: [],
1307
+ }),
970
1308
  manifestPath: h.manifestPath,
971
1309
  log: (l) => logs.push(l),
972
1310
  alive: () => false,
@@ -1010,6 +1348,13 @@ describe("init exposure chain", () => {
1010
1348
  let chained = false;
1011
1349
  const code = await init({
1012
1350
  configDir: h.configDir,
1351
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1352
+ // production default fire a real /health fetch + restart the live unit.
1353
+ ensureHubVersion: async () => ({
1354
+ outcome: "match" as const,
1355
+ installedVersion: "test",
1356
+ messages: [],
1357
+ }),
1013
1358
  manifestPath: h.manifestPath,
1014
1359
  log: () => {},
1015
1360
  alive: () => false,
@@ -1041,6 +1386,13 @@ describe("init exposure chain", () => {
1041
1386
  const logs: string[] = [];
1042
1387
  const code = await init({
1043
1388
  configDir: h.configDir,
1389
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1390
+ // production default fire a real /health fetch + restart the live unit.
1391
+ ensureHubVersion: async () => ({
1392
+ outcome: "match" as const,
1393
+ installedVersion: "test",
1394
+ messages: [],
1395
+ }),
1044
1396
  manifestPath: h.manifestPath,
1045
1397
  log: (l) => logs.push(l),
1046
1398
  alive: () => false,
@@ -1077,6 +1429,13 @@ describe("init exposure chain", () => {
1077
1429
  const logs: string[] = [];
1078
1430
  const code = await init({
1079
1431
  configDir: h.configDir,
1432
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1433
+ // production default fire a real /health fetch + restart the live unit.
1434
+ ensureHubVersion: async () => ({
1435
+ outcome: "match" as const,
1436
+ installedVersion: "test",
1437
+ messages: [],
1438
+ }),
1080
1439
  manifestPath: h.manifestPath,
1081
1440
  log: (l) => logs.push(l),
1082
1441
  alive: () => false,
@@ -1111,6 +1470,13 @@ describe("init exposure chain", () => {
1111
1470
  const order: string[] = [];
1112
1471
  const code = await init({
1113
1472
  configDir: h.configDir,
1473
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1474
+ // production default fire a real /health fetch + restart the live unit.
1475
+ ensureHubVersion: async () => ({
1476
+ outcome: "match" as const,
1477
+ installedVersion: "test",
1478
+ messages: [],
1479
+ }),
1114
1480
  manifestPath: h.manifestPath,
1115
1481
  log: () => {},
1116
1482
  alive: () => false,
@@ -1156,6 +1522,13 @@ describe("init exposure chain", () => {
1156
1522
 
1157
1523
  const code = await init({
1158
1524
  configDir: h.configDir,
1525
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1526
+ // production default fire a real /health fetch + restart the live unit.
1527
+ ensureHubVersion: async () => ({
1528
+ outcome: "match" as const,
1529
+ installedVersion: "test",
1530
+ messages: [],
1531
+ }),
1159
1532
  manifestPath: h.manifestPath,
1160
1533
  log: () => {},
1161
1534
  alive: () => false,
@@ -1193,6 +1566,13 @@ describe("init exposure chain", () => {
1193
1566
 
1194
1567
  const code = await init({
1195
1568
  configDir: h.configDir,
1569
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1570
+ // production default fire a real /health fetch + restart the live unit.
1571
+ ensureHubVersion: async () => ({
1572
+ outcome: "match" as const,
1573
+ installedVersion: "test",
1574
+ messages: [],
1575
+ }),
1196
1576
  manifestPath: h.manifestPath,
1197
1577
  log: () => {},
1198
1578
  alive: () => false,
@@ -1221,6 +1601,13 @@ describe("init exposure chain", () => {
1221
1601
  // wizard creates first-admin.
1222
1602
  const code = await init({
1223
1603
  configDir: h.configDir,
1604
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1605
+ // production default fire a real /health fetch + restart the live unit.
1606
+ ensureHubVersion: async () => ({
1607
+ outcome: "match" as const,
1608
+ installedVersion: "test",
1609
+ messages: [],
1610
+ }),
1224
1611
  manifestPath: h.manifestPath,
1225
1612
  log: () => {},
1226
1613
  alive: () => false,
@@ -1247,6 +1634,13 @@ describe("init exposure chain", () => {
1247
1634
  const logs: string[] = [];
1248
1635
  const code = await init({
1249
1636
  configDir: h.configDir,
1637
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1638
+ // production default fire a real /health fetch + restart the live unit.
1639
+ ensureHubVersion: async () => ({
1640
+ outcome: "match" as const,
1641
+ installedVersion: "test",
1642
+ messages: [],
1643
+ }),
1250
1644
  manifestPath: h.manifestPath,
1251
1645
  log: (l) => logs.push(l),
1252
1646
  alive: () => false,
@@ -1289,6 +1683,13 @@ describe("init exposure chain", () => {
1289
1683
  const logs: string[] = [];
1290
1684
  const code = await init({
1291
1685
  configDir: h.configDir,
1686
+ // #590: keep the version-check a no-op in init tests — NEVER let the
1687
+ // production default fire a real /health fetch + restart the live unit.
1688
+ ensureHubVersion: async () => ({
1689
+ outcome: "match" as const,
1690
+ installedVersion: "test",
1691
+ messages: [],
1692
+ }),
1292
1693
  manifestPath: h.manifestPath,
1293
1694
  log: (l) => logs.push(l),
1294
1695
  alive: () => false,