@crvouga/dev-fleet 0.1.0 → 0.3.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 (159) hide show
  1. package/README.md +265 -37
  2. package/agents/setup.md +42 -12
  3. package/ansible/macos/manager.yml +10 -7
  4. package/ansible/macos/policy.json +2 -10
  5. package/ansible/macos/t3-policy.yml +49 -0
  6. package/ansible/monitoring/README.md +86 -25
  7. package/ansible/monitoring/agent.yml +40 -2
  8. package/ansible/monitoring/hub-route-darwin.yml +51 -0
  9. package/ansible/monitoring/lock.json +5 -0
  10. package/ansible/pyproject.toml +12 -0
  11. package/ansible/ubuntu/baseline.yml +1 -1
  12. package/ansible/ubuntu/disk-gc.py +336 -0
  13. package/ansible/ubuntu/policy.json +13 -3
  14. package/ansible/ubuntu/t3-desktop.yml +19 -0
  15. package/ansible/ubuntu/t3-health.sh +93 -22
  16. package/ansible/ubuntu/t3-idle.py +42 -0
  17. package/ansible/ubuntu/t3-policy.yml +4 -11
  18. package/ansible/ubuntu/tailscale.yml +8 -5
  19. package/ansible/ubuntu/tasks/recovery.yml +60 -1
  20. package/ansible/ubuntu/tasks/resources.yml +61 -1
  21. package/ansible/ubuntu/tasks/t3-restart.yml +37 -0
  22. package/ansible/ubuntu/wip-guard.py +121 -0
  23. package/ansible/uv.lock +190 -0
  24. package/bootstrap/bootstrap.sh +25 -18
  25. package/bootstrap/doctor.ts +46 -1
  26. package/bootstrap/fleet-manager-run.sh +42 -15
  27. package/bootstrap/fleet-remote-bootstrap.sh +85 -12
  28. package/bootstrap/global-config.ts +64 -6
  29. package/bootstrap/install-launcher.sh +3 -0
  30. package/bootstrap/native-t3.ts +22 -11
  31. package/bootstrap/npm.ts +10 -2
  32. package/bootstrap/release-version.ts +157 -0
  33. package/cliproxy/README.md +3 -3
  34. package/cliproxy/scripts/accounts.py +216 -0
  35. package/cliproxy/scripts/checkpoint.py +29 -1
  36. package/cliproxy/scripts/cli.py +1 -1
  37. package/cliproxy/scripts/clientkeys.py +99 -0
  38. package/cliproxy/scripts/lease.py +80 -0
  39. package/cliproxy/scripts/ops +137 -25
  40. package/cliproxy/scripts/restore-verify +15 -0
  41. package/docs/accounts.md +154 -0
  42. package/docs/consumer-setup.md +408 -0
  43. package/docs/declared.md +91 -0
  44. package/docs/durability.md +26 -0
  45. package/docs/machine-setup.md +400 -0
  46. package/docs/operations.md +276 -0
  47. package/docs/releasing.md +103 -0
  48. package/docs/state.md +254 -0
  49. package/docs/topology.md +69 -0
  50. package/docs/ubuntu-sync.md +357 -0
  51. package/docs/worker-contract.md +67 -0
  52. package/examples/fleet.json +5 -0
  53. package/llms.txt +36 -0
  54. package/mise.lock +29 -0
  55. package/mise.toml +15 -2
  56. package/package.json +11 -2
  57. package/schema/fleet.schema.json +137 -15
  58. package/src/accounts/checks.ts +220 -0
  59. package/src/accounts/context.ts +76 -0
  60. package/src/accounts/propagate.ts +62 -0
  61. package/src/accounts/roster.ts +85 -0
  62. package/src/accounts/selection.ts +67 -0
  63. package/src/accounts/sessions.ts +120 -0
  64. package/src/agents/account-relay.ts +176 -26
  65. package/src/agents/fleet-verify.ts +9 -0
  66. package/src/agents/launch.ts +84 -5
  67. package/src/agents/native-verify.ts +293 -22
  68. package/src/agents/provider-errors.ts +9 -2
  69. package/src/agents/registry.ts +7 -1
  70. package/src/cli/agent-guide.ts +39 -5
  71. package/src/cli/app.ts +11 -4
  72. package/src/cli/cli.ts +7 -0
  73. package/src/cli/command-index.ts +7 -0
  74. package/src/cli/fleet-accounts.ts +253 -0
  75. package/src/cli/fleet-state.ts +499 -0
  76. package/src/cli/fleet-sync-accounts.ts +58 -0
  77. package/src/cli/fleet-sync-checkout.ts +56 -17
  78. package/src/cli/fleet-sync-enrollment.ts +19 -23
  79. package/src/cli/fleet-sync-forward.ts +1 -1
  80. package/src/cli/fleet-sync-manager.ts +84 -12
  81. package/src/cli/fleet-sync-monitoring.ts +5 -5
  82. package/src/cli/fleet-sync-output.ts +7 -3
  83. package/src/cli/fleet-sync-remote.ts +31 -18
  84. package/src/cli/fleet-sync-state.ts +86 -0
  85. package/src/cli/fleet-sync.ts +159 -57
  86. package/src/cli/fleet.ts +4 -2
  87. package/src/cli/managed-health.ts +4 -4
  88. package/src/cli/node-sync.ts +7 -0
  89. package/src/cli/program.ts +20 -4
  90. package/src/cli/project.ts +51 -0
  91. package/src/cli/register-fleet.ts +86 -1
  92. package/src/cli/registry.ts +41 -1
  93. package/src/cli/roster.ts +46 -30
  94. package/src/cli/settings.ts +15 -12
  95. package/src/cli/source-operations.ts +27 -3
  96. package/src/cli/tailnet.ts +2 -2
  97. package/src/definition.ts +116 -4
  98. package/src/diagnostics.ts +1 -1
  99. package/src/fleet-config.ts +105 -19
  100. package/src/ide/definition.ts +86 -0
  101. package/src/ide/ide.ts +43 -0
  102. package/src/ide/index.ts +5 -0
  103. package/src/ide/orchestrate.ts +50 -0
  104. package/src/ide/t3.ts +111 -0
  105. package/src/machine/source.ts +3 -3
  106. package/src/machine/state.ts +15 -27
  107. package/src/manager-sync.ts +9 -18
  108. package/src/monitoring/agent-evidence.ts +146 -0
  109. package/src/monitoring/apply.ts +15 -3
  110. package/src/monitoring/beszel.ts +11 -4
  111. package/src/monitoring/enroll.ts +2 -1
  112. package/src/monitoring/hub-access.ts +4 -3
  113. package/src/monitoring/hub-backup.ts +121 -0
  114. package/src/monitoring/hub-viewer.ts +8 -8
  115. package/src/monitoring/hub.ts +3 -3
  116. package/src/monitoring/manager-hub.ts +30 -14
  117. package/src/node-converge-linux.ts +30 -7
  118. package/src/package-info.ts +45 -0
  119. package/src/platform/ansible.ts +19 -15
  120. package/src/platform/darwin.ts +0 -13
  121. package/src/platform/fallback.ts +0 -8
  122. package/src/platform/linux.ts +0 -10
  123. package/src/platform/resource-verify.ts +8 -4
  124. package/src/platform/t3-policy.ts +33 -6
  125. package/src/platform/t3-service.ts +104 -0
  126. package/src/platform/types.ts +0 -4
  127. package/src/platform/ubuntu-audit.ts +5 -2
  128. package/src/platform/windows.ts +0 -14
  129. package/src/remote-bootstrap.ts +17 -19
  130. package/src/remote-entry.ts +15 -1
  131. package/src/repair-catalog.ts +1 -1
  132. package/src/runner.ts +1 -1
  133. package/src/service-auth.ts +15 -5
  134. package/src/state/bucket.ts +208 -0
  135. package/src/state/check.ts +74 -0
  136. package/src/state/connection.ts +92 -0
  137. package/src/state/enrollment.ts +45 -0
  138. package/src/state/legacy.ts +89 -0
  139. package/src/state/litestream.ts +143 -0
  140. package/src/state/operator.ts +20 -0
  141. package/src/state/paths.ts +40 -0
  142. package/src/state/roster.ts +62 -0
  143. package/src/state/store.ts +169 -0
  144. package/src/state/sync.ts +352 -0
  145. package/src/t3/accounts.ts +7 -1
  146. package/src/t3/models.ts +133 -0
  147. package/src/t3/pairing.ts +31 -0
  148. package/src/t3/profile.ts +203 -0
  149. package/src/t3/version.ts +119 -0
  150. package/src/t3-endpoint.ts +64 -8
  151. package/src/t3-linked-check.ts +24 -2
  152. package/src/toolchain-checks.ts +25 -0
  153. package/src/transport.ts +3 -2
  154. package/src/types.ts +4 -0
  155. package/src/worker-access-checks.ts +56 -3
  156. package/src/worker-host-checks.ts +41 -13
  157. package/src/workstation-checks.ts +1 -1
  158. package/src/index.ts +0 -6
  159. package/src/test-fixtures.ts +0 -36
@@ -4,6 +4,7 @@ import { verifyUbuntuBoot } from './platform/ubuntu-verify';
4
4
  import { verifyResourceSafety } from './platform/resource-verify';
5
5
  import policy from '../ansible/ubuntu/policy.json';
6
6
  import { userInfo } from 'node:os';
7
+ import { T3_HEALTH_SCRIPT, runningVersionCheck } from './platform/t3-service';
7
8
  import type { Check, Runner } from './types';
8
9
 
9
10
  function check(id: string, ok: boolean, summary: string): Check {
@@ -62,6 +63,11 @@ export async function workerHostChecks(
62
63
  'Exact declarative Ubuntu package version.'
63
64
  )
64
65
  ),
66
+ check(
67
+ 'package:tailscale',
68
+ audit.packages['tailscale'] === policy.tailscale.version,
69
+ 'Exact declarative Tailscale version.'
70
+ ),
65
71
  ];
66
72
  for (const name of policy.alwaysOnServices) {
67
73
  const unit = await run([
@@ -115,18 +121,13 @@ async function recoveryChecks(run: Runner): Promise<Check[]> {
115
121
  )
116
122
  );
117
123
  checks.push(await t3HealthCheck(run));
124
+ checks.push(await runningVersionCheck(run, userInfo().uid));
118
125
  const renewal = await run([
119
126
  'systemctl',
120
127
  '--user',
121
128
  'is-active',
122
129
  'personal-worker-auth.timer',
123
130
  ]);
124
- const recovery = await run([
125
- 'systemctl',
126
- '--user',
127
- 'is-active',
128
- 'personal-worker-recovery.timer',
129
- ]);
130
131
  checks.push(
131
132
  check(
132
133
  'credential-renewal',
@@ -134,17 +135,44 @@ async function recoveryChecks(run: Runner): Promise<Check[]> {
134
135
  'Worker credential renewal timer is active.'
135
136
  )
136
137
  );
137
- checks.push(
138
- check(
139
- 'service-recovery',
140
- recovery.ok,
141
- 'Worker service recovery timer is active.'
142
- )
143
- );
138
+ checks.push(await serviceRecoveryCheck(run));
144
139
  checks.push(await powerRecoveryCheck(run));
145
140
  return checks;
146
141
  }
147
142
 
143
+ /** The recovery timer is active, the script its unit runs exists, and the
144
+ * last run of the unit succeeded: a watchdog that fails on every tick is not
145
+ * recovery. */
146
+ export async function serviceRecoveryCheck(run: Runner): Promise<Check> {
147
+ const timer = await run([
148
+ 'systemctl',
149
+ '--user',
150
+ 'is-active',
151
+ 'personal-worker-recovery.timer',
152
+ ]);
153
+ const script = await run(['test', '-r', T3_HEALTH_SCRIPT]);
154
+ const unit = await run([
155
+ 'systemctl',
156
+ '--user',
157
+ 'show',
158
+ 'personal-worker-recovery.service',
159
+ '--property=Result',
160
+ ]);
161
+ const result = /^Result=(.*)$/m.exec(unit.stdout)?.[1] ?? 'unknown';
162
+ const summary = !timer.ok
163
+ ? 'WORKER_RECOVERY_TIMER_INACTIVE'
164
+ : !script.ok
165
+ ? 'WORKER_RECOVERY_SCRIPT_MISSING'
166
+ : !unit.ok || result !== 'success'
167
+ ? `WORKER_RECOVERY_LAST_RUN_FAILED (${/^[\w-]+$/.test(result) ? result : 'unknown'})`
168
+ : 'Worker service recovery timer is active and its last run succeeded.';
169
+ return check(
170
+ 'service-recovery',
171
+ timer.ok && script.ok && unit.ok && result === 'success',
172
+ summary
173
+ );
174
+ }
175
+
148
176
  /** The server answers its local API now, not merely that a process exists. */
149
177
  async function t3HealthCheck(run: Runner): Promise<Check> {
150
178
  const probe = await run(
@@ -22,7 +22,7 @@ export async function workstationChecks(
22
22
  summary: 'The devfleet launcher is missing.',
23
23
  remedy: {
24
24
  action:
25
- 'Run fleet-sync from the manager, or sh bootstrap/install-launcher.sh in the dev-fleet checkout on this computer.',
25
+ 'Run fleet-sync from the manager: it links the launcher to the checkout of the revision it applies.',
26
26
  },
27
27
  },
28
28
  ];
package/src/index.ts DELETED
@@ -1,6 +0,0 @@
1
- export { parseConfig, loadConfig, selectNodes } from './config';
2
- export { doctor } from './manager';
3
- export { probe } from './probe';
4
- export { makeReport, reportExitCode, renderReport } from './report';
5
- export { syncPlan, syncWorkspace } from './sync';
6
- export type * from './types';
@@ -1,36 +0,0 @@
1
- import { mkdir, mkdtemp, writeFile } from 'node:fs/promises';
2
- import { tmpdir } from 'node:os';
3
- import { join } from 'node:path';
4
- import type { CommandResult, Runner, FleetNode } from './types';
5
-
6
- export const HEAD = 'a'.repeat(40);
7
- export const NODE: FleetNode = {
8
- id: 'dev-one',
9
- ssh: 'dev-one',
10
- workspace: '/home/dev/workspace',
11
- required: [],
12
- };
13
- export const success = (stdout = ''): CommandResult => ({
14
- ok: true,
15
- stdout,
16
- stderr: '',
17
- reason: 'exit',
18
- });
19
- export const failure = (stderr = ''): CommandResult => ({
20
- ok: false,
21
- stdout: '',
22
- stderr,
23
- reason: 'exit',
24
- });
25
- export const gitRunner: Runner = async (command) =>
26
- success(command.includes('rev-parse') ? HEAD : '');
27
-
28
- export async function workspace(): Promise<string> {
29
- const root = await mkdtemp(join(tmpdir(), "fleet test's "));
30
- for (const file of ['package.json', 'bun.lock', 'mise.toml', 'mise.lock'])
31
- await writeFile(join(root, file), '{}');
32
- await mkdir(join(root, 'packages/example'), { recursive: true });
33
- await writeFile(join(root, 'packages/example/package.json'), '{}');
34
- await mkdir(join(root, '.mise/locks'), { recursive: true });
35
- return root;
36
- }