@crvouga/dev-fleet 0.3.0 → 0.5.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 (97) hide show
  1. package/README.md +25 -17
  2. package/ansible/github/git.yml +66 -0
  3. package/ansible/macos/policy.json +12 -1
  4. package/ansible/monitoring/compose.yml +10 -0
  5. package/ansible/monitoring/container-watchdog.py +118 -0
  6. package/ansible/monitoring/hub-darwin.yml +146 -0
  7. package/ansible/net/remote-probe.sh +5 -0
  8. package/ansible/platforms.json +111 -0
  9. package/ansible/ubuntu/authorize-sudo.sh +7 -16
  10. package/ansible/ubuntu/baseline.yml +6 -28
  11. package/ansible/ubuntu/disk-gc.py +211 -7
  12. package/ansible/ubuntu/disk-guard.py +24 -5
  13. package/ansible/ubuntu/policy.json +68 -4
  14. package/ansible/ubuntu/t3-desktop.yml +2 -2
  15. package/ansible/ubuntu/tailscale.yml +20 -9
  16. package/ansible/ubuntu/tasks/browser.yml +56 -0
  17. package/ansible/ubuntu/tasks/docker.yml +52 -0
  18. package/ansible/ubuntu/tasks/dpkg.yml +46 -0
  19. package/ansible/ubuntu/tasks/install.yml +38 -0
  20. package/ansible/ubuntu/tasks/packages.yml +4 -55
  21. package/ansible/ubuntu/tasks/release.yml +25 -0
  22. package/ansible/ubuntu/tasks/resources.yml +7 -6
  23. package/ansible/ubuntu/tasks/services.yml +13 -0
  24. package/ansible/ubuntu/tasks/snapshot.yml +50 -0
  25. package/ansible/ubuntu/tasks/unattended-upgrades.yml +24 -0
  26. package/bootstrap/doctor.ts +32 -6
  27. package/bootstrap/fleet-remote-bootstrap.sh +49 -45
  28. package/bootstrap/setup.ts +23 -8
  29. package/bootstrap/worker-tools.ts +118 -0
  30. package/cliproxy/README.md +1 -1
  31. package/cliproxy/compose.yaml +4 -0
  32. package/cliproxy/scripts/checkpoint.py +1 -1
  33. package/docs/authentication.md +90 -0
  34. package/docs/consumer-setup.md +32 -30
  35. package/docs/declared.md +6 -5
  36. package/docs/machine-setup.md +22 -12
  37. package/docs/operations.md +87 -31
  38. package/docs/runbooks.md +377 -0
  39. package/docs/state.md +13 -7
  40. package/docs/support-matrix.md +36 -0
  41. package/docs/ubuntu-sync.md +16 -13
  42. package/docs/worker-contract.md +28 -1
  43. package/examples/fleet.json +19 -1
  44. package/llms.txt +2 -0
  45. package/mise.toml +7 -0
  46. package/package.json +2 -2
  47. package/schema/check-ids.json +526 -0
  48. package/schema/fleet.schema.json +185 -4
  49. package/schema/output/check.schema.json +23 -0
  50. package/schema/output/error.schema.json +14 -0
  51. package/schema/output/fleet-report.schema.json +79 -0
  52. package/schema/output/fleet-sync.schema.json +112 -0
  53. package/schema/output/report.schema.json +38 -0
  54. package/src/auth-checks.ts +3 -0
  55. package/src/cli/agent-guide.ts +5 -3
  56. package/src/cli/fleet-report.ts +126 -0
  57. package/src/cli/fleet-sync-manager.ts +11 -0
  58. package/src/cli/fleet-sync-plan.ts +200 -0
  59. package/src/cli/fleet-sync-remote.ts +4 -2
  60. package/src/cli/fleet-sync-schedule.ts +142 -35
  61. package/src/cli/fleet-sync.ts +90 -8
  62. package/src/cli/fleet-watch.ts +198 -0
  63. package/src/cli/fleet.ts +4 -0
  64. package/src/cli/register-fleet.ts +51 -0
  65. package/src/cli/registry.ts +13 -0
  66. package/src/cli/schedule-logs.ts +36 -0
  67. package/src/clock.ts +63 -0
  68. package/src/definition.ts +160 -12
  69. package/src/git-identity.ts +160 -0
  70. package/src/machine/platform.ts +48 -28
  71. package/src/machine/support-matrix.ts +76 -0
  72. package/src/machine-health.ts +51 -4
  73. package/src/manager-health.ts +205 -0
  74. package/src/manager-sync.ts +27 -9
  75. package/src/monitoring/hub-backup.ts +63 -17
  76. package/src/monitoring/manager-hub.ts +44 -2
  77. package/src/network-definition.ts +1 -1
  78. package/src/node-converge-linux.ts +16 -5
  79. package/src/node-converge.ts +1 -1
  80. package/src/notify.ts +239 -0
  81. package/src/platform/debian-version.ts +62 -0
  82. package/src/platform/ubuntu-audit.ts +11 -4
  83. package/src/platform/ubuntu-release.ts +41 -0
  84. package/src/remote-bootstrap.ts +89 -25
  85. package/src/remote-operation.ts +213 -0
  86. package/src/schedule-check.ts +40 -0
  87. package/src/secrets.ts +26 -8
  88. package/src/ssh.ts +10 -2
  89. package/src/state/history.ts +172 -0
  90. package/src/state/store.ts +11 -4
  91. package/src/tailscale.ts +51 -0
  92. package/src/toolchain-checks.ts +8 -3
  93. package/src/worker-capability-checks.ts +167 -0
  94. package/src/worker-capacity.ts +19 -7
  95. package/src/worker-host-checks.ts +68 -10
  96. package/src/worker-policy.ts +33 -0
  97. package/src/worker-readiness.ts +10 -1
@@ -0,0 +1,36 @@
1
+ # Support matrix
2
+
3
+ Which platforms dev-fleet runs on, in which role, and what happens to the
4
+ rest. The default is one macOS manager and Ubuntu workers treated as cattle.
5
+
6
+ - **supported**: converged, measured and tested on every pull request.
7
+ - **best effort**: works and is not tested as a fleet role.
8
+ - **refused**: stopped with the named reason before anything is installed.
9
+
10
+ <!-- Generated by `bun src/machine/support-matrix.ts` from ansible/macos/policy.json, ansible/ubuntu/policy.json and ansible/platforms.json; features/rules/support-matrix.feature fails when it differs. -->
11
+
12
+ | Role | Platform | Versions | Architectures | Status | Note |
13
+ | -------------- | --------- | ------------------- | --------------- | ----------- | ----------------------------------------------------------------------------------------- |
14
+ | manager | macOS | 14 or newer | arm64, x86_64 | supported | ansible/macos/policy.json |
15
+ | worker | Ubuntu | 26.04 (resolute) | amd64, arm64 | supported | ansible/ubuntu/policy.json; a machine of its own, physical or virtual |
16
+ | manager | any other | any | any | refused | The fleet configuration accepts only a macOS manager. |
17
+ | worker | Ubuntu | any other release | any | refused | UBUNTU_BASELINE_MISMATCH |
18
+ | worker | Ubuntu | an accepted release | any other | refused | UBUNTU_BASELINE_MISMATCH |
19
+ | worker | Debian | any | any | refused | UBUNTU_BASELINE_MISMATCH |
20
+ | worker | macOS | any | any | refused | The fleet configuration accepts only Linux workers. |
21
+ | worker | Windows | any | any | refused | The fleet configuration accepts only Linux workers. |
22
+ | worker | WSL2 | any | any | refused | WORKER_ENVIRONMENT_UNSUPPORTED |
23
+ | worker | container | any | any | refused | WORKER_ENVIRONMENT_UNSUPPORTED |
24
+ | toolchain only | macOS | any | arm64, x86_64 | best effort | No fleet role: devfleet bootstrap installs the pinned tools (docs/machine-setup.md). |
25
+ | toolchain only | Linux | any | x86_64, aarch64 | best effort | No fleet role: devfleet bootstrap installs the pinned tools (docs/machine-setup.md). |
26
+ | toolchain only | WSL2 | any | x86_64 | best effort | Treated as Linux: devfleet bootstrap installs the pinned tools (docs/machine-setup.md). |
27
+ | toolchain only | Windows | any | x64 | best effort | No fleet role: bootstrap/bootstrap.ps1 installs the pinned tools (docs/machine-setup.md). |
28
+ | toolchain only | Alpine | any | any | refused | musl: the pinned mise build needs glibc. |
29
+
30
+ A worker is refused by the first check that can tell: the fleet configuration
31
+ refuses a worker that is not Linux, the platform probe refuses another
32
+ release, CPU or environment (`ubuntu:release`, `platform:environment`), and
33
+ the bootstrap and the Ubuntu baseline refuse them again on the machine.
34
+
35
+ Supporting another platform means adding it to the policy that names it, with
36
+ its package pins, a fresh-box job and its row here.
@@ -61,10 +61,9 @@ resolve enrolled fleet
61
61
 
62
62
  Bare invocation selects every canonical Linux and macOS node. It does not mean
63
63
  “this computer,” and the manager is not implicitly a deployment target. Its own
64
- node is targeted only if explicitly declared in Fleet membership. Ubuntu 26.04 is
65
- the accepted worker platform; a node declared `"os": "macOS"` runs the same phases
66
- best effort through `ansible/macos` (see the platform matrix below).
67
- Windows machines stay declared for diagnostics and are never converged.
64
+ node is targeted only if explicitly declared in Fleet membership. Workers are the
65
+ Ubuntu releases the [support matrix](support-matrix.md) lists; it also says what
66
+ is refused (macOS and Windows workers, WSL2, containers) and why.
68
67
  `--node ID` filters troubleshooting/rollout. `--all` is an explicit spelling of the
69
68
  default. Neither flag authorizes managing arbitrary Tailscale peers.
70
69
 
@@ -117,9 +116,8 @@ included, to the exact version in `ansible/ubuntu/policy.json`. The interactive
117
116
  roster in the [fleet state](state.md), using the existing roster schema.
118
117
  Preserve workspace/runtime paths, capabilities and explicit `tailscaleId`
119
118
  bindings.
120
- - Workstation network consumers derive their inventory from Fleet. The old file
121
- is retained only as `packages/fleet/migrations/workstation-network-v1.json` for
122
- lossless identity-path migration; conflicts fail rather than silently winning.
119
+ - Workstation network consumers derive their inventory from the fleet
120
+ configuration; conflicts fail rather than silently winning.
123
121
  - Manager approval: the `enrollment` document in the [fleet state](state.md).
124
122
  Manager deployment lock: `~/.local/share/personal/fleet/manager/sync.lock`.
125
123
  - Remote source: `~/.local/share/personal/fleet/revisions/FULL_SHA`.
@@ -211,14 +209,19 @@ vault kv get -field=FLEET_WORKER_TOKEN_WORKER_ONE secret/personal/prd \
211
209
  | ssh worker-one 'vault login -address=https://vault.example.com -no-print -'
212
210
  ```
213
211
 
214
- From then on the node's `personal-worker-auth` timer renews that token and its
215
- GitHub login, and renders provider configuration from Vault through Workstation.
212
+ From then on the node's `personal-worker-auth` timer renews that token and
213
+ restores its GitHub login from it (`bootstrap/worker-auth.ts`). It renders no
214
+ provider configuration: agent profiles are applied by `fleet-sync`. See
215
+ [Authentication and accounts](authentication.md).
216
216
 
217
217
  ## Ubuntu and remote-work safety
218
218
 
219
- The declared common baseline is Ubuntu **26.04 LTS**, amd64/arm64. Other releases
220
- receive `UBUNTU_BASELINE_MISMATCH`; there is no automatic release upgrade or
221
- package downgrade. Fleet audits release, packages, service state and dpkg
219
+ The accepted releases are named once, in `ansible/ubuntu/policy.json`, and
220
+ listed in the [support matrix](support-matrix.md). Other releases receive
221
+ `UBUNTU_BASELINE_MISMATCH`, and WSL2 and containers
222
+ `WORKER_ENVIRONMENT_UNSUPPORTED`; there is no automatic release upgrade or
223
+ package downgrade. Package pins are minimums: see the
224
+ [worker contract](worker-contract.md#package-pins-and-security-updates). Fleet audits release, packages, service state and dpkg
222
225
  consistency, declares snapshot sources for managed transactions, and pins its
223
226
  selected APT packages. Unrelated applications and package sources are preserved.
224
227
 
@@ -268,7 +271,7 @@ promise. Inspect disk/inodes, swap/memory pressure, `systemctl --failed`, and pr
268
271
  boot journal evidence locally; sanitize it before sharing. Do not enable automatic
269
272
  reboot-on-pressure or kill active work to obtain a green report.
270
273
 
271
- T3 0.1.7's supported administrator policy at `/etc/t3code/policy.json`
274
+ The pinned T3's (`t3_version` in `mise.toml`) supported administrator policy at `/etc/t3code/policy.json`
272
275
  disables independent updates and declares the existing managed Codex instance
273
276
  plus an OpenCode instance for all five gateway models. Fleet reuses the
274
277
  existing `agents/t3.json` renderer; it does not edit the live settings database.
@@ -12,7 +12,8 @@ devfleet fleet-status --workers
12
12
  ```
13
13
 
14
14
  The manager needs Node/npm, Git, SSH, Tailscale, and its own authorized T3 link.
15
- Initially each Ubuntu 26.04 worker (or best-effort macOS 14+ node) needs a
15
+ Initially each worker (an Ubuntu release the [support matrix](support-matrix.md)
16
+ lists) needs a
16
17
  designated non-root account, trusted SSH access and administrator authorization. Standard Ubuntu cloud-image users
17
18
  already commonly have noninteractive sudo; otherwise establish the repository's
18
19
  `authorize-sudo.sh` policy once during administrator enrollment. Routine commands
@@ -39,6 +40,32 @@ HEAD. Private rosters contain connection paths and identities, not weaker policy
39
40
  | No routine password prompts | Verified BatchMode SSH, `sudo -n`, source-owned NOPASSWD policy; missing initial authorization is a failure |
40
41
  | Keep service authorization alive | Native service credentials stay per-node; Vault self-renewal timer and GitHub recovery from authorized Vault credentials; expiring T3 links are reported before expiry |
41
42
 
43
+ ## Package pins and security updates
44
+
45
+ A pin in `ansible/ubuntu/policy.json` is a **minimum**, never a hold. Ubuntu
46
+ keeps installing security updates by itself, and a worker is not turned red by
47
+ one:
48
+
49
+ - The Ubuntu baseline installs a pinned package from the snapshot only when it
50
+ is absent or older than its pin, and never downgrades
51
+ (`ansible/ubuntu/tasks/install.yml`; every pinned package, `systemd-oomd`
52
+ included, goes through it).
53
+ - What Ubuntu installs unattended is declared in
54
+ `/etc/apt/apt.conf.d/52personal-fleet-unattended-upgrades`: security updates
55
+ only, no automatic reboot, no removals.
56
+ - `worker:package:NAME` passes at the pin, **warns** with
57
+ `PACKAGE_NEWER_THAN_PIN` above it, and fails with `PACKAGE_BELOW_PIN` below
58
+ it or when the package is missing. A warning does not block convergence or
59
+ readiness; it says the pin can be raised when the snapshot moves.
60
+ - Tailscale follows the same rule: a newer Tailscale is kept; an older one
61
+ stops with `TAILSCALE_UPGRADE_PENDING`, because upgrading an active VPN can
62
+ drop SSH.
63
+
64
+ A package run cut off by a power loss is finished by the next sync: the
65
+ baseline waits for the APT lock, runs `dpkg --configure -a` once (bounded to
66
+ ten minutes) and audits again; only a database still inconsistent stops with
67
+ `APT_STATE_BROKEN`.
68
+
42
69
  Health does not mutate configuration, renew tokens, log in, install software, or
43
70
  make billable inference requests. It audits the immutable desired worker deployment,
44
71
  not an unrelated developer branch. Every declared worker must be enrolled and
@@ -29,6 +29,14 @@
29
29
  "proxy-tunnel-token": {
30
30
  "path": "cliproxy-fleet/tunnel",
31
31
  "field": "TUNNEL_TOKEN"
32
+ },
33
+ "monitoring-backup-access-key": {
34
+ "path": "beszel/backups",
35
+ "field": "ACCESS_KEY_ID"
36
+ },
37
+ "monitoring-backup-secret-key": {
38
+ "path": "beszel/backups",
39
+ "field": "SECRET_ACCESS_KEY"
32
40
  }
33
41
  }
34
42
  },
@@ -73,7 +81,16 @@
73
81
  "hubPort": 8443,
74
82
  "publicUrl": "https://beszel.example.com",
75
83
  "managerAccount": "fleet-manager@example.com",
76
- "viewerAccount": "public-viewer@example.com"
84
+ "viewerAccount": "public-viewer@example.com",
85
+ "backups": {
86
+ "schedule": "0 3 * * *",
87
+ "keep": 7,
88
+ "storage": {
89
+ "bucket": "my-fleet-hub-backups",
90
+ "endpoint": "https://s3.example.com",
91
+ "region": "auto"
92
+ }
93
+ }
77
94
  }
78
95
  },
79
96
  "ubuntu": {
@@ -92,6 +109,7 @@
92
109
  "githubLogin": "example-user",
93
110
  "vaultUser": "example-user",
94
111
  "toolchain": "mise.lock",
112
+ "toolProfiles": ["go"],
95
113
  "agentProfile": "proxy",
96
114
  "unattendedSudo": true,
97
115
  "persistentT3": true,
package/llms.txt CHANGED
@@ -31,6 +31,8 @@ Rules for an agent working in a project that uses dev-fleet:
31
31
  - [Ubuntu fleet-sync reference](https://github.com/crvouga/dev-fleet/blob/main/docs/ubuntu-sync.md): enrollment, approval, machine policy by platform, remote-work safety
32
32
  - [Worker contract](https://github.com/crvouga/dev-fleet/blob/main/docs/worker-contract.md): what a worker guarantees and how readiness is scoped
33
33
  - [Operations](https://github.com/crvouga/dev-fleet/blob/main/docs/operations.md): roster, diagnostics and repairs
34
+ - [Runbooks](https://github.com/crvouga/dev-fleet/blob/main/docs/runbooks.md): every failure code, how to confirm it, the fix and when to escalate
35
+ - [Authentication and accounts](https://github.com/crvouga/dev-fleet/blob/main/docs/authentication.md): where each credential lives, how it reaches each node and how it rotates
34
36
  - [Coding agents on every node](https://github.com/crvouga/dev-fleet/blob/main/agents/setup.md): agent launchers and the T3 providers
35
37
  - [Releasing](https://github.com/crvouga/dev-fleet/blob/main/docs/releasing.md): how a version is published from one commit (for dev-fleet developers)
36
38
  - [Features](https://github.com/crvouga/dev-fleet/blob/main/features/README.md): the behaviour specified in Gherkin (for dev-fleet developers)
package/mise.toml CHANGED
@@ -110,3 +110,10 @@ docker_desktop_amd64_sha256 = "96b53f9a4a807b6be6207d18f360b9778ff481e1d94b5027b
110
110
 
111
111
  # Minimal remote development baseline; versions are resolved exclusively by tools + mise.lock.
112
112
  worker_tools = "bun,node,gh,python,uv,docker-cli,vault,jq,codex,claude,aqua:anomalyco/opencode,gemini,copilot,http:grok,http:antigravity"
113
+ # Tool profiles a fleet adds to its workers (`worker.toolProfiles` in
114
+ # fleet.json, fleet-wide or per worker): one `worker_profile_<name>` each,
115
+ # naming tools pinned above. bootstrap/worker-tools.ts lists the names.
116
+ worker_profile_web = "pnpm,deno,npm:@yarnpkg/cli-dist"
117
+ worker_profile_go = "go"
118
+ worker_profile_rust = "rust,cmake,ninja"
119
+ worker_profile_jvm = "java"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crvouga/dev-fleet",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Keeps a set of development machines in sync: one manager and many workers",
5
5
  "license": "MIT",
6
6
  "repository": "github:crvouga/dev-fleet",
@@ -72,5 +72,5 @@
72
72
  "engines": {
73
73
  "node": ">=22"
74
74
  },
75
- "gitHead": "0c583e40a0c32c0db355e9c0bca6903894945310"
75
+ "gitHead": "620b8de05d662b4dc9072457580ca4b4eab54242"
76
76
  }