@crvouga/dev-fleet 0.8.0 → 0.9.1
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 +65 -9
- package/agents/audit.md +18 -18
- package/ansible/agents/agents.yml +134 -0
- package/ansible/agents/templates/antigravity.settings.json.j2 +3 -0
- package/ansible/agents/templates/claude.settings.json.j2 +3 -0
- package/ansible/agents/templates/codex.config.toml.j2 +11 -0
- package/ansible/agents/templates/gemini.settings.json.j2 +14 -0
- package/ansible/agents/templates/grok.config.toml.j2 +19 -0
- package/ansible/agents/templates/opencode.json.j2 +24 -0
- package/ansible/agents/templates/receipt.json.j2 +10 -0
- package/ansible/ansible.cfg +14 -0
- package/ansible/github/git.yml +82 -0
- package/ansible/macos/manager-privilege.yml +55 -9
- package/ansible/macos/manager.yml +154 -7
- package/ansible/macos/policy.json +13 -0
- package/ansible/macos/t3-policy.yml +5 -3
- package/ansible/macos/vault-renew.yml +85 -0
- package/ansible/monitoring/agent-darwin.yml +3 -0
- package/ansible/monitoring/agent.yml +2 -0
- package/ansible/monitoring/hub-darwin.yml +3 -0
- package/ansible/monitoring/hub-route-darwin.yml +1 -0
- package/ansible/net/remote-probe.sh +4 -1
- package/ansible/platforms.json +2 -2
- package/ansible/pyproject.toml +5 -0
- package/ansible/ubuntu/baseline.yml +39 -13
- package/ansible/ubuntu/disk-gc.py +6 -2
- package/ansible/ubuntu/firewall.nft.j2 +50 -0
- package/ansible/ubuntu/policy.json +125 -6
- package/ansible/ubuntu/reboot.yml +89 -0
- package/ansible/ubuntu/recovery.yml +13 -3
- package/ansible/ubuntu/t3/policy.json +3 -0
- package/ansible/ubuntu/t3-desktop.yml +23 -2
- package/ansible/ubuntu/t3-headless.yml +128 -0
- package/ansible/ubuntu/t3-health.sh +24 -10
- package/ansible/ubuntu/t3-idle.py +37 -2
- package/ansible/ubuntu/t3-policy.yml +4 -1
- package/ansible/ubuntu/t3-route.yml +1 -0
- package/ansible/ubuntu/tailscale.yml +54 -8
- package/ansible/ubuntu/tasks/browser.yml +3 -0
- package/ansible/ubuntu/tasks/containers-off.yml +43 -0
- package/ansible/ubuntu/tasks/docker.yml +53 -6
- package/ansible/ubuntu/tasks/dpkg.yml +4 -0
- package/ansible/ubuntu/tasks/features.yml +22 -0
- package/ansible/ubuntu/tasks/firewall.yml +172 -0
- package/ansible/ubuntu/tasks/install.yml +2 -1
- package/ansible/ubuntu/tasks/packages.yml +4 -2
- package/ansible/ubuntu/tasks/release.yml +6 -0
- package/ansible/ubuntu/tasks/resources.yml +6 -4
- package/ansible/ubuntu/tasks/services.yml +2 -2
- package/ansible/ubuntu/tasks/sizing.yml +49 -0
- package/ansible/ubuntu/tasks/snapshot.yml +14 -3
- package/ansible/ubuntu/tasks/ssh.yml +61 -4
- package/ansible/ubuntu/tasks/t3-restart.yml +3 -1
- package/ansible/ubuntu/tasks/user.yml +1 -0
- package/ansible/ubuntu/worker-account.yml +117 -0
- package/ansible/uv.lock +265 -0
- package/bin/devfleet.mjs +42 -4
- package/bootstrap/fleet-remote-bootstrap.sh +91 -25
- package/bootstrap/global-config.ts +29 -3
- package/bootstrap/package-smoke.ts +127 -0
- package/bootstrap/pins.ts +189 -0
- package/bootstrap/release-notes.ts +88 -0
- package/bootstrap/release-version.ts +41 -7
- package/bootstrap/worker-features.ts +114 -0
- package/bootstrap/worker-seed.yaml +7 -3
- package/bootstrap/worker-tools.ts +39 -9
- package/cliproxy/README.md +1 -1
- package/cliproxy/docs/health-workflow.example.yml +20 -143
- package/docs/authentication.md +19 -11
- package/docs/consumer-setup.md +42 -27
- package/docs/convergence.md +67 -0
- package/docs/declared.md +61 -34
- package/docs/machine-setup.md +73 -7
- package/docs/manager-setup.md +10 -3
- package/docs/operations.md +64 -9
- package/docs/releasing.md +49 -1
- package/docs/runbooks.md +98 -7
- package/docs/state.md +23 -11
- package/docs/support-matrix.md +40 -4
- package/docs/topology.md +67 -6
- package/docs/ubuntu-sync.md +78 -28
- package/docs/worker-contract.md +122 -19
- package/docs/worker-requirements.md +107 -0
- package/examples/fleet.json +1 -0
- package/examples/workers-from-infrastructure/main.tf +132 -0
- package/examples/workers-from-infrastructure/worker-records.json +14 -0
- package/llms.txt +3 -1
- package/mise.lock +29 -0
- package/mise.toml +5 -3
- package/package.json +2 -2
- package/schema/check-ids.json +1967 -170
- package/schema/check-ids.schema.json +34 -0
- package/schema/fleet.schema.json +327 -8
- package/schema/output/check.schema.json +1 -1
- package/schema/output/fleet-state-definition.schema.json +14 -0
- package/schema/output/fleet-sync-schedule.schema.json +26 -0
- package/schema/output/fleet-sync.schema.json +18 -0
- package/schema/output/report.schema.json +3 -2
- package/schema/worker-record.schema.json +76 -0
- package/src/agents/converge.ts +140 -24
- package/src/agents/files.ts +2 -32
- package/src/agents/native-verify.ts +34 -3
- package/src/agents/secrets.ts +39 -4
- package/src/check-owners.ts +61 -2
- package/src/check-registry.ts +630 -0
- package/src/cli/agent-guide.ts +3 -3
- package/src/cli/cli.ts +4 -0
- package/src/cli/fleet-manifest.ts +9 -3
- package/src/cli/fleet-node-lifecycle.ts +313 -64
- package/src/cli/fleet-node-park.ts +238 -0
- package/src/cli/fleet-node-seed.ts +51 -35
- package/src/cli/fleet-state.ts +2 -1
- package/src/cli/fleet-sync-checkout.ts +7 -0
- package/src/cli/fleet-sync-enrollment.ts +193 -32
- package/src/cli/fleet-sync-forward.ts +4 -0
- package/src/cli/fleet-sync-manager.ts +103 -33
- package/src/cli/fleet-sync-output.ts +31 -11
- package/src/cli/fleet-sync-plan.ts +65 -9
- package/src/cli/fleet-sync-records.ts +113 -0
- package/src/cli/fleet-sync-remote.ts +151 -9
- package/src/cli/fleet-sync-schedule.ts +14 -4
- package/src/cli/fleet-sync-state.ts +28 -16
- package/src/cli/fleet-sync-vault.ts +77 -0
- package/src/cli/fleet-sync-worker.ts +214 -0
- package/src/cli/fleet-sync.ts +150 -19
- package/src/cli/fleet-validate.ts +59 -21
- package/src/cli/fleet-watch.ts +7 -1
- package/src/cli/fleet.ts +87 -5
- package/src/cli/managed-health.ts +25 -1
- package/src/cli/register-fleet.ts +115 -4
- package/src/cli/registry.ts +14 -0
- package/src/cli/tailnet.ts +43 -10
- package/src/cli/ui-data.ts +3 -1
- package/src/cli/worker-usage-report.ts +63 -0
- package/src/clock.ts +42 -0
- package/src/definition.ts +332 -9
- package/src/diagnostics.ts +5 -2
- package/src/exposure.ts +102 -0
- package/src/fleet-config.ts +3 -1
- package/src/git-identity.ts +76 -3
- package/src/ide/ide.ts +5 -0
- package/src/ide/t3.ts +12 -2
- package/src/input-hashes.ts +6 -0
- package/src/machine/machine-class.ts +59 -0
- package/src/machine/platform.ts +90 -11
- package/src/machine/state.ts +37 -15
- package/src/machine/support-matrix.ts +11 -9
- package/src/machine-health.ts +28 -5
- package/src/manager-health.ts +148 -2
- package/src/manager-sync.ts +65 -4
- package/src/monitoring/beszel.ts +8 -8
- package/src/monitoring/enroll.ts +8 -1
- package/src/monitoring/hub-access.ts +10 -4
- package/src/monitoring/systems.ts +138 -0
- package/src/network-definition.ts +13 -4
- package/src/node-converge-linux.ts +136 -27
- package/src/node-converge.ts +13 -3
- package/src/platform/ansible-receipt.ts +17 -2
- package/src/platform/ansible.ts +40 -4
- package/src/platform/manager-host.ts +25 -8
- package/src/platform/resource-verify.ts +18 -7
- package/src/platform/t3-policy.ts +24 -10
- package/src/platform/t3-service.ts +109 -34
- package/src/platform/ubuntu-release.ts +24 -0
- package/src/platform/ubuntu-verify.ts +31 -3
- package/src/platform/ubuntu-worker.ts +58 -0
- package/src/platform/worker-platform.ts +72 -0
- package/src/protocol.ts +1 -1
- package/src/public-reachability.ts +186 -0
- package/src/remote-bootstrap.ts +50 -12
- package/src/remote-operation.ts +18 -4
- package/src/repair-plan.ts +23 -12
- package/src/report.ts +2 -1
- package/src/schedule-check.ts +21 -2
- package/src/secrets.ts +4 -0
- package/src/service-auth.ts +55 -48
- package/src/ssh-connection.ts +141 -0
- package/src/ssh.ts +63 -24
- package/src/state/store.ts +4 -2
- package/src/state/sync.ts +35 -6
- package/src/state/workers.ts +140 -0
- package/src/t3/pairing.ts +59 -0
- package/src/t3/peer-link.ts +333 -0
- package/src/t3/version.ts +1 -1
- package/src/tailnet-cleanup.ts +185 -0
- package/src/tailnet-control.ts +346 -0
- package/src/tailscale.ts +1 -1
- package/src/toolchain-checks.ts +11 -1
- package/src/types.ts +4 -2
- package/src/worker-account.ts +63 -0
- package/src/worker-activity.ts +303 -0
- package/src/worker-capability-checks.ts +55 -16
- package/src/worker-capacity.ts +31 -0
- package/src/worker-exposure.ts +388 -0
- package/src/worker-features.ts +201 -0
- package/src/worker-host-checks.ts +71 -20
- package/src/worker-manifest.ts +27 -4
- package/src/worker-parking.ts +70 -0
- package/src/worker-policy.ts +17 -1
- package/src/worker-readiness.ts +15 -3
- package/src/worker-reboot.ts +129 -0
- package/src/worker-records.ts +305 -0
- package/src/worker-seed.ts +16 -11
- package/src/worker-sizing.ts +76 -0
- package/src/cli/schedule-logs.ts +0 -36
package/docs/authentication.md
CHANGED
|
@@ -8,14 +8,14 @@ rewrites them).
|
|
|
8
8
|
|
|
9
9
|
## Where credentials live
|
|
10
10
|
|
|
11
|
-
| Credential | Lives in
|
|
12
|
-
| ----------------------------------- |
|
|
13
|
-
| The fleet's secrets (table below) | The provider `secrets` names in `fleet.json`
|
|
14
|
-
| The bucket's two keys | The environment of the `devfleet` command; `~/.config/dev-fleet/bucket.json` (0600) on the manager after `fleet-state --init`
|
|
15
|
-
| A node's Vault token | That node's own Vault session (`~/.vault-token`)
|
|
16
|
-
| A node's GitHub login | `gh`'s own store on that node
|
|
17
|
-
| Provider accounts (Claude, Codex …) | The CLI proxy's store on the manager
|
|
18
|
-
| Tailscale and T3 pairing | Each machine, signed in by a person
|
|
11
|
+
| Credential | Lives in | Read by |
|
|
12
|
+
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------ |
|
|
13
|
+
| The fleet's secrets (table below) | The provider `secrets` names in `fleet.json` | The node that needs it, through `src/secrets.ts` |
|
|
14
|
+
| The bucket's two keys | The environment of the `devfleet` command; `~/.config/dev-fleet/bucket.json` (0600) on the manager after `fleet-state --init` | The manager only |
|
|
15
|
+
| A node's Vault token | That node's own Vault session (`~/.vault-token`) | That node only; never copied |
|
|
16
|
+
| A node's GitHub login | `gh`'s own store on that node | `gh`, and git through its credential helper |
|
|
17
|
+
| Provider accounts (Claude, Codex …) | The CLI proxy's store on the manager | The proxy; nodes hold only the proxy client key |
|
|
18
|
+
| Tailscale and T3 pairing | Each machine, signed in by a person; a replaced worker's T3 is paired by the manager with a one-time code it never writes down | That machine |
|
|
19
19
|
|
|
20
20
|
## How they reach each node
|
|
21
21
|
|
|
@@ -30,14 +30,19 @@ rewrites them).
|
|
|
30
30
|
makes `gh` git's credential helper and writes the declared identity
|
|
31
31
|
(`git` in `fleet.json`, `ansible/github/git.yml`) on every node.
|
|
32
32
|
- **The proxy client key** is read by each node from its own secrets provider
|
|
33
|
-
whenever a launcher starts an agent.
|
|
33
|
+
whenever a launcher starts an agent. The node keeps the last key it read in
|
|
34
|
+
`~/.cache/dev-fleet/proxy-client-key` (0600) and uses it only while the
|
|
35
|
+
provider cannot answer, so an unreachable Vault or an expired session leaves
|
|
36
|
+
that node's agents working until the Vault checks below are fixed.
|
|
34
37
|
- **The monitoring hub's backup storage keys** are read on the manager by
|
|
35
38
|
`fleet-sync` and handed to the hub's playbook in a private variables file.
|
|
36
39
|
|
|
37
40
|
## Rotation and failure
|
|
38
41
|
|
|
39
|
-
Rotate a secret where the provider keeps it; the next read uses it
|
|
40
|
-
|
|
42
|
+
Rotate a secret where the provider keeps it; the next read uses it. Only the
|
|
43
|
+
proxy client key is remembered, and only as a fallback; a rotated key reaches
|
|
44
|
+
every node at its next launch, and `retire-key` should wait until every node
|
|
45
|
+
has launched an agent since the rotation. A Vault token that is not renewed expires: `worker:vault-renewal`
|
|
41
46
|
fails and the fix is one login of that machine. A GitHub token that stops
|
|
42
47
|
working fails `auth:github` and `worker:git-push-auth`; store the new one in
|
|
43
48
|
Vault and the worker restores itself within ten minutes. During a proxy
|
|
@@ -60,6 +65,7 @@ Every failure code is in [the runbooks](runbooks.md).
|
|
|
60
65
|
| `notify-webhook-url` | when its feature is declared | `DEVFLEET_SECRET_NOTIFY_WEBHOOK_URL` | `~/.config/dev-fleet/secrets/notify-webhook-url` |
|
|
61
66
|
| `notify-ntfy-url` | when its feature is declared | `DEVFLEET_SECRET_NOTIFY_NTFY_URL` | `~/.config/dev-fleet/secrets/notify-ntfy-url` |
|
|
62
67
|
| `tailnet-auth-key` | when its feature is declared | `DEVFLEET_SECRET_TAILNET_AUTH_KEY` | `~/.config/dev-fleet/secrets/tailnet-auth-key` |
|
|
68
|
+
| `tailnet-admin` | when its feature is declared | `DEVFLEET_SECRET_TAILNET_ADMIN` | `~/.config/dev-fleet/secrets/tailnet-admin` |
|
|
63
69
|
|
|
64
70
|
<!-- end: secrets -->
|
|
65
71
|
|
|
@@ -72,8 +78,10 @@ Every failure code is in [the runbooks](runbooks.md).
|
|
|
72
78
|
| `auth:github` | `src/github/checks.ts` |
|
|
73
79
|
| `auth:vault` | `src/cli/fleet-sync-vault.ts` |
|
|
74
80
|
| `auth:vault-isolation` | `src/cli/fleet-sync-vault.ts` |
|
|
81
|
+
| `worker:credential-renewal` | `src/worker-host-checks.ts` |
|
|
75
82
|
| `worker:git-identity` | `src/git-identity.ts` |
|
|
76
83
|
| `worker:git-push-auth` | `src/definition.ts`, `src/git-identity.ts` |
|
|
84
|
+
| `worker:git-signing` | `src/definition.ts`, `src/git-identity.ts` |
|
|
77
85
|
| `worker:github-sync` | `src/worker-access-checks.ts` |
|
|
78
86
|
| `worker:proxy-authentication` | `src/worker-access-checks.ts` |
|
|
79
87
|
| `worker:vault-renewal` | `src/worker-access-checks.ts` |
|
package/docs/consumer-setup.md
CHANGED
|
@@ -24,13 +24,13 @@ Nothing else is needed. You never clone dev-fleet, copy its files or write a
|
|
|
24
24
|
wrapper script around a checkout of it: the npm package is the tool, and the
|
|
25
25
|
version in `package.json` is the commit every machine runs.
|
|
26
26
|
|
|
27
|
-
| Concept | Meaning
|
|
28
|
-
| ----------- |
|
|
29
|
-
| manager | The one macOS machine you run `devfleet fleet-sync` on. Hosts the CLI proxy and the monitoring hub.
|
|
30
|
-
| worker | An Ubuntu 26.04 machine the manager converges over SSH. Stateless: rebuilt from Git and your secrets.
|
|
31
|
-
| fleet state | One SQLite database (roster, approved revision, configuration last applied) replicated to your bucket.
|
|
32
|
-
| bucket | Any S3-compatible bucket you own, or a directory. The source of truth for the fleet state.
|
|
33
|
-
| revision | The dev-fleet commit the installed package was published from (`npx devfleet --version`).
|
|
27
|
+
| Concept | Meaning |
|
|
28
|
+
| ----------- | -------------------------------------------------------------------------------------------------------------- |
|
|
29
|
+
| manager | The one macOS machine you run `devfleet fleet-sync` on. Hosts the CLI proxy and the monitoring hub. |
|
|
30
|
+
| worker | An Ubuntu 26.04 or 24.04 machine the manager converges over SSH. Stateless: rebuilt from Git and your secrets. |
|
|
31
|
+
| fleet state | One SQLite database (roster, approved revision, configuration last applied) replicated to your bucket. |
|
|
32
|
+
| bucket | Any S3-compatible bucket you own, or a directory. The source of truth for the fleet state. |
|
|
33
|
+
| revision | The dev-fleet commit the installed package was published from (`npx devfleet --version`). |
|
|
34
34
|
|
|
35
35
|
## Rules for agents
|
|
36
36
|
|
|
@@ -75,25 +75,30 @@ On the manager (the Mac this project is checked out on):
|
|
|
75
75
|
| Tailscale signed in | `tailscale status --json` (look for `"BackendState":"Running"`) |
|
|
76
76
|
| An SSH alias per worker that works without a prompt | `ssh -o BatchMode=yes WORKER_ALIAS true` for each worker |
|
|
77
77
|
|
|
78
|
-
On every worker
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
`
|
|
95
|
-
|
|
96
|
-
|
|
78
|
+
On every worker, check each row of
|
|
79
|
+
[what a machine must offer to be a worker](worker-requirements.md): the
|
|
80
|
+
image, architecture and size, the access, the first-boot data and the
|
|
81
|
+
network. Each row says how to verify it. If `sudo -n true` fails, that is fine
|
|
82
|
+
for the first, interactive run, which asks for the password once and installs
|
|
83
|
+
a sudo rule for the fleet; it is not fine for unattended runs.
|
|
84
|
+
|
|
85
|
+
A worker is reached in one of two ways, always with `BatchMode=yes` and
|
|
86
|
+
`StrictHostKeyChecking=yes`; never add `StrictHostKeyChecking=no` or
|
|
87
|
+
`accept-new`.
|
|
88
|
+
|
|
89
|
+
- **From declared data (no alias).** Leave `ssh` out: dev-fleet connects as
|
|
90
|
+
`network.user` on `network.sshPort` to `network.tailscaleName`, and checks
|
|
91
|
+
the host key against a known_hosts file of its own, rendered from the key
|
|
92
|
+
the fleet state pins. The human's `~/.ssh/config` and `~/.ssh/known_hosts`
|
|
93
|
+
are neither needed nor changed. The key is pinned without trusting a first
|
|
94
|
+
connection: `npx devfleet fleet-node-seed --id ID --output PATH --apply
|
|
95
|
+
--yes` generates it for a new machine, `npx devfleet fleet-node-replace
|
|
96
|
+
--id ID --host-key "TYPE BASE64" --apply --yes` pins one the human verified
|
|
97
|
+
out of band, and a worker record (below) may carry it as `hostKey`.
|
|
98
|
+
- **Through the human's own alias.** `ssh` names a Host alias in the
|
|
99
|
+
manager's `~/.ssh/config`, and its host key must already be in their
|
|
100
|
+
`known_hosts`. **Ask** the human to verify each fingerprint out of band and
|
|
101
|
+
connect once by hand. A typical alias:
|
|
97
102
|
|
|
98
103
|
```
|
|
99
104
|
Host worker-one
|
|
@@ -302,6 +307,14 @@ An agent cannot answer those prompts, and `--json`, `--non-interactive` or a
|
|
|
302
307
|
npx devfleet fleet-sync
|
|
303
308
|
```
|
|
304
309
|
|
|
310
|
+
A worker that needs none of those prompts is enrolled without the human: a
|
|
311
|
+
run with `--json` or `--non-interactive` enrolls a declared worker when its
|
|
312
|
+
pinned host key matched, `sudo -n` works on it, and exactly one tailnet device
|
|
313
|
+
matches it (or none, when `fleet.json` declares `tailnet` and its secret
|
|
314
|
+
`tailnet-admin`, so the run joins it with a single-use key). The report lists
|
|
315
|
+
what it enrolled (`enrolled` in the JSON). A machine made with
|
|
316
|
+
`devfleet fleet-node-seed` meets all of these.
|
|
317
|
+
|
|
305
318
|
It converges the manager first, then the canary worker, then the rest. It
|
|
306
319
|
prints one table and the path of the full JSON report
|
|
307
320
|
(`~/.local/share/personal/fleet/manager/last-sync.json`, readable by the human
|
|
@@ -382,7 +395,9 @@ and codes; leave out everything private.
|
|
|
382
395
|
- **Remove a worker.** Delete its entry, commit, run `npx devfleet fleet-sync`.
|
|
383
396
|
- **Upgrade the fleet.** `npm install --save-dev --save-exact @crvouga/dev-fleet@latest`,
|
|
384
397
|
commit, `npx devfleet fleet-sync`. The canary proves the new revision first.
|
|
385
|
-
|
|
398
|
+
`npx devfleet fleet-sync --rollback` goes back to the revision applied
|
|
399
|
+
before (the revision, tools and T3; system packages roll forward only, as
|
|
400
|
+
the [README](../README.md#the-version) says).
|
|
386
401
|
- **Replace the manager.** Follow
|
|
387
402
|
[replacing the manager](manager-recovery.md).
|
|
388
403
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# What converges a machine, and what is not Ansible yet
|
|
2
|
+
|
|
3
|
+
The goal is one convergence engine: Ansible, on every platform, with the CLI
|
|
4
|
+
as an orchestrator that validates the fleet configuration, runs playbooks,
|
|
5
|
+
reads their results and reports checks. Today three mechanisms change a
|
|
6
|
+
machine: the playbooks under `ansible/`, the bootstrap scripts, and some
|
|
7
|
+
TypeScript. This page lists every step that is not an Ansible task yet, each
|
|
8
|
+
with the reason it is not, so the list can only shrink.
|
|
9
|
+
`features/rules/convergence.feature` fails when a file that changes a machine
|
|
10
|
+
is missing from it.
|
|
11
|
+
|
|
12
|
+
## Ansible
|
|
13
|
+
|
|
14
|
+
| Playbook | Converges |
|
|
15
|
+
| ----------------------------------------- | ----------------------------------------------------------------------------- |
|
|
16
|
+
| `ansible/ubuntu/baseline.yml` | A worker's packages, Docker, services, power, user, SSH, disk |
|
|
17
|
+
| `ansible/ubuntu/tailscale.yml` | Tailscale on a worker |
|
|
18
|
+
| `ansible/ubuntu/t3-desktop.yml` | The T3 desktop app on a desktop worker |
|
|
19
|
+
| `ansible/ubuntu/t3-headless.yml` | The T3 server as a lingering user service on a headless worker |
|
|
20
|
+
| `ansible/ubuntu/t3-policy.yml` | T3's administrator policy |
|
|
21
|
+
| `ansible/ubuntu/t3-route.yml` | T3's private tailnet route |
|
|
22
|
+
| `ansible/ubuntu/recovery.yml` | Recovery of a stopped T3 desktop app or server |
|
|
23
|
+
| `ansible/ubuntu/worker-account.yml` | The declared account on an image that lets only root in, from the manager |
|
|
24
|
+
| `ansible/ubuntu/reboot.yml` | One worker's first-converge or maintenance reboot, from the manager |
|
|
25
|
+
| `ansible/monitoring/agent.yml` | The Beszel agent on a worker |
|
|
26
|
+
| `ansible/monitoring/agent-darwin.yml` | The Beszel agent on the manager |
|
|
27
|
+
| `ansible/monitoring/hub-darwin.yml` | The Beszel hub and its tunnel on the manager |
|
|
28
|
+
| `ansible/monitoring/hub-route-darwin.yml` | The hub's private tailnet route |
|
|
29
|
+
| `ansible/macos/manager.yml` | The manager's power settings, network time and fleet-watch job, unattended |
|
|
30
|
+
| `ansible/macos/t3-policy.yml` | T3's administrator policy on the manager |
|
|
31
|
+
| `ansible/macos/manager-privilege.yml` | The one administrator grant: sudoers, job log rotation and the T3 policy |
|
|
32
|
+
| `ansible/macos/worker-host-key.yml` | A worker's pinned SSH host key in the manager's known_hosts |
|
|
33
|
+
| `ansible/macos/vault-renew.yml` | The launch agent that renews the manager's own Vault session |
|
|
34
|
+
| `ansible/github/git.yml` | The Git identity and GitHub credentials of every node |
|
|
35
|
+
| `ansible/agents/agents.yml` | Each agent CLI's dedicated profile, rendered from `ansible/agents/templates/` |
|
|
36
|
+
|
|
37
|
+
Every playbook passes `ansible-lint` in the production profile, every command
|
|
38
|
+
in it says when it changes something and runs, or is skipped, in a dry run
|
|
39
|
+
(`features/rules/playbooks.feature`). The Beszel agent playbook is proven on a
|
|
40
|
+
systemd machine to report no change on a second run and in `--check`, and to
|
|
41
|
+
report drift, and only that drift (`features/monitoring/agent-lifecycle.feature`).
|
|
42
|
+
|
|
43
|
+
## Not Ansible yet
|
|
44
|
+
|
|
45
|
+
| Step | Where | Why it is not a task yet |
|
|
46
|
+
| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
47
|
+
| Install Git, curl, CA certificates, Python and Ansible | `bootstrap/fleet-remote-bootstrap.sh` | It must run before Ansible exists on the machine; it is the minimal bootstrap |
|
|
48
|
+
| Create the worker account, its host key, the privilege rule and Tailscale on first boot | `bootstrap/worker-seed.yaml` (written by `fleet-node-seed`) | cloud-init runs it before the manager can reach the machine; fleet-sync converges everything else with Ansible afterwards |
|
|
49
|
+
| Install mise and the pinned toolchain | `bootstrap/bootstrap.sh`, `bootstrap/setup.ts` | mise must exist before any tool does, and `mise install --locked` already converges from a lock |
|
|
50
|
+
| Install a worker's subset of tools | `bootstrap/worker-tools.ts`, `bootstrap/worker-features.ts` | It chooses which locked tools `mise install` gets; moving it means a toolchain role |
|
|
51
|
+
| Publish the global mise configuration | `bootstrap/global-config.ts` | Derived from `mise.toml` and the agent worktree roots on every run; a `toolchain` role with a template would replace it |
|
|
52
|
+
| `PATH` lines in shell profiles | `bootstrap/shell-path.ts` | Edits files a person owns, guarded by markers; a `blockinfile` task would replace it |
|
|
53
|
+
| The `devfleet` launcher link | `bootstrap/install-launcher.sh` | Points at the fleet-owned checkout of the revision, known only during the run |
|
|
54
|
+
| The T3 server archive | `bootstrap/native-t3.ts` | Installed with the toolchain, checked against the digest in `mise.toml`; a `t3` role would replace it |
|
|
55
|
+
| The AWS CLI on Windows | `bootstrap/native-aws.ts` | Windows is not a fleet role |
|
|
56
|
+
| Docker Desktop on the manager | `bootstrap/docker-desktop.sh` | A person installs and approves it on macOS; dev-fleet only measures it |
|
|
57
|
+
| A worker's service credentials from Vault | `bootstrap/worker-github.ts`, `bootstrap/worker-auth.ts` | A login belongs to a machine and a person; it is read from a session, never declared |
|
|
58
|
+
| The manager's own convergence: proxy, profiles, hub, agent | `src/cli/fleet-sync-manager.ts` | Orchestrates the manager playbooks and the proxy's own installer; the proxy is not a playbook yet (`docs/declared.md`) |
|
|
59
|
+
| Scheduled runs | `src/cli/fleet-sync-schedule.ts`, `src/platform/launchd.ts`, `src/platform/systemd-user.ts` | Writes a launchd job or systemd timer from TypeScript; listed in `docs/declared.md` as a schedule that should be a playbook |
|
|
60
|
+
|
|
61
|
+
## Still to do
|
|
62
|
+
|
|
63
|
+
Roles with a common interface (`baseline`, `toolchain`, `agents`, `t3`,
|
|
64
|
+
`network`, `monitoring`, `recovery`, `manager`), an inventory generated from
|
|
65
|
+
the fleet configuration, and `site.yml`, `manager.yml` and `workers.yml` that
|
|
66
|
+
bring a fresh manager and worker to ready with no other mutating step. Each
|
|
67
|
+
row of the table above moves into one of those roles.
|
package/docs/declared.md
CHANGED
|
@@ -12,29 +12,33 @@ may only shrink.
|
|
|
12
12
|
|
|
13
13
|
## Declared
|
|
14
14
|
|
|
15
|
-
| What
|
|
16
|
-
|
|
|
17
|
-
| The fleet: machines, services, accounts
|
|
18
|
-
| Tools: languages, CLIs, coding agents
|
|
19
|
-
| mise itself
|
|
20
|
-
| JavaScript dependencies
|
|
21
|
-
| T3 Code, server and desktop app
|
|
22
|
-
| T3 policy on the manager (updates off)
|
|
23
|
-
| Worker work-in-progress guard
|
|
24
|
-
| Ubuntu packages
|
|
25
|
-
| Tailscale on workers
|
|
26
|
-
| Worker policy: power, SSH, sudo, memory, disk
|
|
27
|
-
| Monitoring: hub, tunnel, agents
|
|
28
|
-
| The manager's private route to the hub
|
|
29
|
-
| The manager's power settings
|
|
30
|
-
| Ansible on the manager
|
|
31
|
-
| Ansible on a worker
|
|
32
|
-
| The CLI proxy
|
|
33
|
-
| Agent profiles and T3 providers
|
|
34
|
-
| Worker time service
|
|
35
|
-
| The manager's
|
|
36
|
-
|
|
|
37
|
-
|
|
|
15
|
+
| What | Declared in | Pinned by | Applied by | Measured by |
|
|
16
|
+
| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
17
|
+
| The fleet: machines, services, accounts | Your `fleet.json` | The dev-fleet version in your `package.json`, which names one commit | `fleet-sync` | `fleet-status` |
|
|
18
|
+
| Tools: languages, CLIs, coding agents | `mise.toml` | `mise.lock`: version and checksum for each platform | `mise install --locked` | Tool and `agent:verification` checks |
|
|
19
|
+
| mise itself | `min_version` and `mise_*_sha256` in `mise.toml` | The digest of its release archive, held here | `bootstrap/bootstrap.sh` | Its version, at every toolchain setup |
|
|
20
|
+
| JavaScript dependencies | `package.json` | `bun.lock` | `bun install --frozen-lockfile` | The install fails on a difference |
|
|
21
|
+
| T3 Code, server and desktop app | `t3_*` under `[vars]` in `mise.toml` | SHA-256 of each artifact | `bootstrap/native-t3.ts`; `ansible/ubuntu/t3-desktop.yml` | T3 checks; `t3:version` on every machine |
|
|
22
|
+
| T3 policy on the manager (updates off, linked environments on) | `ansible/ubuntu/t3/policy.json`, shared with the workers | The commit | `ansible/macos/t3-policy.yml`, once, as an administrator (`manager-privilege.yml`) | `t3:updates` |
|
|
23
|
+
| Worker work-in-progress guard | `ansible/ubuntu/wip-guard.py`, `ansible/ubuntu/tasks/recovery.yml` | The commit | `fleet-sync` | `features/ide/work-in-progress.feature` |
|
|
24
|
+
| Ubuntu packages | `packages` and `snapshot` in `ansible/ubuntu/policy.json` | Exact versions from a dated archive snapshot | `ansible/ubuntu/tasks/packages.yml` | `package:*` |
|
|
25
|
+
| Tailscale on workers | `tailscale` in `ansible/ubuntu/policy.json` | Exact version; digest of the signing key | `ansible/ubuntu/tailscale.yml` | `package:tailscale` |
|
|
26
|
+
| Worker policy: power, SSH, sudo, memory, disk | `ansible/ubuntu/*.yml`, values shared with checks in `policy.json` | The commit | `fleet-sync` | Host and resource checks |
|
|
27
|
+
| Monitoring: hub, tunnel, agents | `ansible/monitoring/*.yml`, `compose.yml`, `lock.json` | Image digests; SHA-256 of each agent archive | `fleet-sync` | `beszel:*` |
|
|
28
|
+
| The manager's private route to the hub | `ansible/monitoring/hub-route-darwin.yml` | The commit | `fleet-sync` | The route, read back |
|
|
29
|
+
| The manager's power settings | `pmset` in `ansible/macos/policy.json` | The commit | `ansible/macos/manager.yml`, on every `fleet-sync`, after one grant (`manager-privilege.yml`) | `manager:power` |
|
|
30
|
+
| Ansible on the manager | `ansible/pyproject.toml` | `ansible/uv.lock`: one release, one Python, every dependency hashed | `uv run --locked --isolated` | A hash that differs stops the run |
|
|
31
|
+
| Ansible on a worker | `ansible-core` in `ansible/ubuntu/policy.json` | Exact version | `ansible/ubuntu/tasks/packages.yml` | `package:ansible-core` |
|
|
32
|
+
| The CLI proxy | `cliproxy/compose.yaml`, `image.lock.json`, `requirements.lock`, `launchd/`, `config.template.yaml` | Image digests; hashed Python dependencies | `devfleet cliproxy install`, and `fleet-sync` after it | The proxy's audit |
|
|
33
|
+
| Agent profiles and T3 providers | `agents/registry.json`, `agents/t3.json`; each CLI's configuration from `ansible/agents/templates/` | The commit | `fleet-sync` (agent profiles through `ansible/agents/agents.yml`) | Profile receipts; the plan after every apply; `agent:*:session` |
|
|
34
|
+
| Worker time service | `ansible/ubuntu/tasks/services.yml`, offsets in `clock` in `ansible/ubuntu/policy.json` | The commit | `fleet-sync` | `worker:clock` |
|
|
35
|
+
| The manager's playbook and its receipt | `ansible/macos/manager.yml` | The commit | `fleet-sync`, check mode first, then applied; re-applied at least daily | `manager:playbook` |
|
|
36
|
+
| The manager's network time | `ansible/macos/manager.yml` (an assert) | The commit | macOS | `manager:clock`, `worker:clock-offset` |
|
|
37
|
+
| fleet-watch on a schedule | `fleetWatch` in `ansible/macos/policy.json`, `manager.schedule.watchMinutes` in `fleet.json` | The commit | `fleet-sync` (`manager.yml`) | `manager:watch` |
|
|
38
|
+
| Rotation of the scheduled jobs' logs | `jobLogs` in `ansible/macos/policy.json` | The commit | `ansible/macos/manager-privilege.yml`, once, as an administrator | `manager:job-logs` |
|
|
39
|
+
| The manager's container watchdog | `ansible/monitoring/container-watchdog.py`, `containerWatchdog` in `ansible/macos/policy.json` | The commit | `fleet-sync` (`hub-darwin.yml`) | `manager:container-watchdog` |
|
|
40
|
+
| Docker Desktop on the manager | `docker_desktop_*` under `[vars]` in `mise.toml` | Version and build | You | `manager:docker` (warns) |
|
|
41
|
+
| CI | `.github/workflows/` | Each action at a commit; tools from `mise.lock` | GitHub | `features/rules/` |
|
|
38
42
|
|
|
39
43
|
A value lives in a policy file when something besides the playbook reads it,
|
|
40
44
|
so the check and the playbook cannot disagree. A value only a playbook uses
|
|
@@ -62,11 +66,11 @@ stays in the playbook: the playbook is its declaration.
|
|
|
62
66
|
scripts from the declarative files above, not by a playbook.
|
|
63
67
|
- **Files TypeScript and shell still write.** The installed `fleet.json`, the
|
|
64
68
|
`current` and `devfleet` links, the `PATH` lines in shell profiles, the
|
|
65
|
-
global mise configuration, the T3 server archive
|
|
66
|
-
settings. Each is derived
|
|
69
|
+
global mise configuration, the T3 server archive and T3 settings. Each is derived
|
|
67
70
|
from a tracked file and rewritten on every run, but by code.
|
|
68
71
|
- **Logins.** Tailscale, Vault, GitHub, each provider account and T3 pairing
|
|
69
|
-
|
|
72
|
+
(except a replaced worker's, which the manager pairs itself) belong to a
|
|
73
|
+
machine and a person. They are checked, never copied.
|
|
70
74
|
- **Windows.** `bootstrap/bootstrap.ps1` exists; Windows is not a fleet role
|
|
71
75
|
and nothing tests it.
|
|
72
76
|
|
|
@@ -80,13 +84,36 @@ moving to it entirely means NixOS workers and nix-darwin on the manager, which
|
|
|
80
84
|
replaces every unit and path that exists today. The one thing above that Nix
|
|
81
85
|
would settle and the current tools do not is the rest of a worker's packages.
|
|
82
86
|
|
|
87
|
+
## Keeping pins current
|
|
88
|
+
|
|
89
|
+
A pin that is only moved by hand goes stale and is then moved in a large
|
|
90
|
+
batch, the riskiest way to change a fleet. Each pin is moved by a machine,
|
|
91
|
+
one pull request at a time, which CI, the fresh workers and the VM test then
|
|
92
|
+
judge like any change, unless it says below why a person moves it.
|
|
93
|
+
|
|
94
|
+
| Pin | Moved by |
|
|
95
|
+
| ---------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
96
|
+
| Tools in `mise.toml` and `mise.lock` | Renovate (`mise`), one pull request per tool |
|
|
97
|
+
| JavaScript and Python dependencies | Renovate, with lock file maintenance |
|
|
98
|
+
| Actions and CI service images | Renovate, each action at a commit |
|
|
99
|
+
| mise itself | The [Pins workflow](../.github/workflows/pins.yml): `bun bootstrap/pins.ts mise`, weekly |
|
|
100
|
+
| T3 Code (nightly) | The Pins workflow: `bun bootstrap/pins.ts t3`, weekly, every artifact hashed |
|
|
101
|
+
| The tunnel image of the monitoring hub | Renovate, by tag and digest (a custom manager in `renovate.json`) |
|
|
102
|
+
| Beszel (hub image and agents) | A person, because the agents' binary digests need the archives unpacked; `pins.ts` cannot yet |
|
|
103
|
+
| Docker Desktop on the manager | A person, because a person installs it and dev-fleet only measures the version |
|
|
104
|
+
| The Ubuntu snapshot and package versions | A person, because a new snapshot moves every package at once and each needs its exact version |
|
|
105
|
+
|
|
106
|
+
The workflows never name the mise release: they install it through
|
|
107
|
+
[`.github/actions/mise`](../.github/actions/mise/action.yml), which reads
|
|
108
|
+
`min_version` from `mise.toml`.
|
|
109
|
+
|
|
83
110
|
## Changing a pin
|
|
84
111
|
|
|
85
|
-
| To change | Edit | Then
|
|
86
|
-
| ----------------------- | -------------------------------------------------------------------- |
|
|
87
|
-
| A tool | Its version in `mise.toml` | Update `mise.lock` with `mise lock`
|
|
88
|
-
| mise | `
|
|
89
|
-
| An Ubuntu package | `packages` in `ansible/ubuntu/policy.json`, and `snapshot` if needed | The VM test in `ansible/ubuntu/tests`
|
|
90
|
-
| Ansible on the manager | `ansible/pyproject.toml` | `uv lock` in `ansible/`
|
|
91
|
-
| Beszel | `ansible/monitoring/lock.json`, `compose.yml`, the agent unit | `bun test features/rules`
|
|
92
|
-
| A manager power setting | `pmset` in `ansible/macos/policy.json` | The next `fleet-sync` applies it
|
|
112
|
+
| To change | Edit | Then |
|
|
113
|
+
| ----------------------- | -------------------------------------------------------------------- | ------------------------------------- |
|
|
114
|
+
| A tool | Its version in `mise.toml` | Update `mise.lock` with `mise lock` |
|
|
115
|
+
| mise | `bun bootstrap/pins.ts mise` moves `min_version` and the digests | The fresh-box run |
|
|
116
|
+
| An Ubuntu package | `packages` in `ansible/ubuntu/policy.json`, and `snapshot` if needed | The VM test in `ansible/ubuntu/tests` |
|
|
117
|
+
| Ansible on the manager | `ansible/pyproject.toml` | `uv lock` in `ansible/` |
|
|
118
|
+
| Beszel | `ansible/monitoring/lock.json`, `compose.yml`, the agent unit | `bun test features/rules` |
|
|
119
|
+
| A manager power setting | `pmset` in `ansible/macos/policy.json` | The next `fleet-sync` applies it |
|
package/docs/machine-setup.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
> This document was written for the fleet dev-fleet was extracted from. Paths and
|
|
2
2
|
> commands were updated; some statements still describe that fleet and are being
|
|
3
|
-
> revised. The README is authoritative
|
|
3
|
+
> revised. The README is authoritative, and what a machine must offer to be a
|
|
4
|
+
> worker is listed only in [worker requirements](worker-requirements.md).
|
|
4
5
|
|
|
5
6
|
## Machine setup: macOS, Windows and Linux
|
|
6
7
|
|
|
@@ -184,7 +185,13 @@ railway login
|
|
|
184
185
|
Only sign into providers the task actually needs. On fleet machines the Git
|
|
185
186
|
identity and the GitHub credential helper come from the `git` block of
|
|
186
187
|
`fleet.json`: `fleet-sync` writes them in `~/.config/git/config` and checks
|
|
187
|
-
them as `worker:git-identity` and `worker:git-push-auth`.
|
|
188
|
+
them as `worker:git-identity` and `worker:git-push-auth`. With
|
|
189
|
+
`"signing": "ssh"` in that block every node also makes an SSH key of its own
|
|
190
|
+
(`~/.ssh/dev-fleet-git-signing`, never copied off the node) and signs every
|
|
191
|
+
commit and tag with it, checked as `worker:git-signing`; GitHub shows those
|
|
192
|
+
commits as verified once you add each node's `.pub` to the account as a
|
|
193
|
+
signing key (`gh ssh-key add ~/.ssh/dev-fleet-git-signing.pub --type signing`
|
|
194
|
+
on the node). Elsewhere set `git
|
|
188
195
|
config --global user.name` and `user.email` after confirming them; do not guess
|
|
189
196
|
an email or overwrite an existing identity. Enable Git LFS hooks when needed with `git lfs install`.
|
|
190
197
|
|
|
@@ -357,9 +364,44 @@ headless service, so environment identity and pairing are kept. A conflicting
|
|
|
357
364
|
launcher version requires reviewed maintenance; the recovery timer stops a
|
|
358
365
|
still-running headless service. Routine fleet-sync never ends a running turn
|
|
359
366
|
to load a new pin or policy: the app restarts into them at the first idle
|
|
360
|
-
check (`t3:running-version`, `t3:policy-loaded`).
|
|
361
|
-
|
|
362
|
-
|
|
367
|
+
check (`t3:running-version`, `t3:policy-loaded`). Private routing and paired
|
|
368
|
+
execution require separate evidence.
|
|
369
|
+
|
|
370
|
+
#### Headless workers
|
|
371
|
+
|
|
372
|
+
A worker whose session is `headless` (`features.session` in `fleet.json`, or
|
|
373
|
+
the `editing` preset) has no display manager, no graphical session and no
|
|
374
|
+
GPU. It runs the pinned T3 **server**, not the desktop app under a virtual
|
|
375
|
+
display: the pinned release ships the server as its own archive
|
|
376
|
+
(`t3-<version>-linux-<arch>.tar.gz`, the `t3_version` and
|
|
377
|
+
`t3_linux_*_sha256` pins, from the release's `SHA256SUMS`), which the
|
|
378
|
+
toolchain already installs on every worker for policy commands. Its
|
|
379
|
+
`t3 serve` runs the server the desktop app embeds, with no browser; the
|
|
380
|
+
subcommand and its flags were read from the pinned release itself
|
|
381
|
+
(`t3 serve --help` of `0.1.8-nightly.20261106.4262`, whose `--mode web`
|
|
382
|
+
server answered `/.well-known/t3/environment` with that `serverVersion`).
|
|
383
|
+
A virtual display would install and pin a display server and a desktop
|
|
384
|
+
toolkit for one process, which costs the memory a small worker needs.
|
|
385
|
+
|
|
386
|
+
`ansible/ubuntu/t3-headless.yml` declares `t3code-headless.service`, a user
|
|
387
|
+
unit started by `default.target`: the designated user lingers, so it starts at
|
|
388
|
+
boot with nobody logged in. It listens on `127.0.0.1:3773` like the desktop
|
|
389
|
+
app, with `T3CODE_HOME=%h/.t3`, so the private route, the policy, the provider
|
|
390
|
+
instances, `personal-worker-recovery` (which reads the release from the
|
|
391
|
+
unit's versioned server path) and the checks are the same for both session
|
|
392
|
+
types. Switching a worker between types stops and removes the other type's
|
|
393
|
+
unit and keeps `~/.t3`; GDM auto-login, if the machine had it, is left as it
|
|
394
|
+
was. A headless worker installs none of the desktop-only packages
|
|
395
|
+
(`features.desktop` in `ansible/ubuntu/policy.json`) and reports their checks
|
|
396
|
+
as not applicable. The server prints a one-time pairing token to its own
|
|
397
|
+
journal at start, as `t3 serve` does anywhere; dev-fleet never reads it.
|
|
398
|
+
Pairing is done from the manager: by a person the first time, and by
|
|
399
|
+
`fleet-node-replace` or the next `fleet-sync` for a machine that replaces a
|
|
400
|
+
worker.
|
|
401
|
+
|
|
402
|
+
The disposable Ubuntu VM test (`ansible/ubuntu/tests/vm.py`) converges each
|
|
403
|
+
session type, reboots with nobody logged in and kills the T3 process to
|
|
404
|
+
prove the recovery timer brings it back.
|
|
363
405
|
|
|
364
406
|
Normal Ubuntu fleet setup is controller-led:
|
|
365
407
|
`devfleet fleet-sync`. See the
|
|
@@ -396,7 +438,10 @@ Controller-driven remote bootstrap passes `--worker` to the shared setup owner.
|
|
|
396
438
|
It installs the `vars.worker_tools` subset from `mise.toml`, with versions and
|
|
397
439
|
artifacts taken from the same `mise.lock`; native T3 and Ubuntu Docker/service
|
|
398
440
|
policy remain source-pinned. `bun bootstrap/doctor.ts --worker --docker --json`
|
|
399
|
-
checks that profile. It does not require unrelated cloud CLIs on workers.
|
|
441
|
+
checks that profile. It does not require unrelated cloud CLIs on workers. A
|
|
442
|
+
worker whose `containers` feature is off (`features.containers: false`, or the
|
|
443
|
+
`editing` preset) leaves `docker-cli` out of its base tools, and its doctor
|
|
444
|
+
runs with `--no-containers` instead of `--docker`.
|
|
400
445
|
|
|
401
446
|
Tool profiles add locked tool sets on top of it: `worker.toolProfiles` in
|
|
402
447
|
`fleet.json` (fleet-wide) or `toolProfiles` on one worker selects `web` (pnpm,
|
|
@@ -404,7 +449,28 @@ Deno, Yarn and headless Chromium for browser tests), `go`, `rust` (with CMake
|
|
|
404
449
|
and Ninja) or `jvm` (Temurin), each a `worker_profile_<name>` under `[vars]` in
|
|
405
450
|
`mise.toml`. `worker.tools` adds single tools dev-fleet already pins. The setup
|
|
406
451
|
installs them (`--node` reads the installed configuration) and the doctor
|
|
407
|
-
checks each as `tool:<name>` (`--profiles`, `--tools`).
|
|
452
|
+
checks each as `tool:<name>` (`--profiles`, `--tools`). The base tools include
|
|
453
|
+
`tmux`, for sessions that outlive an SSH connection.
|
|
454
|
+
|
|
455
|
+
A tool dev-fleet does not ship belongs to the project that needs it: pin it in
|
|
456
|
+
the project's own `mise.toml` and lock it with `mise lock`. On every fleet
|
|
457
|
+
machine dev-fleet's global configuration sets `locked = true` for the
|
|
458
|
+
`project` scope, so mise installs a project's tools in a checkout only from
|
|
459
|
+
that project's `mise.lock` and refuses a tool the lock does not name;
|
|
460
|
+
`mise install --locked` in the checkout installs and verifies them.
|
|
461
|
+
|
|
462
|
+
There is no `mobile` profile. No mobile toolchain can be pinned with
|
|
463
|
+
checksums for both worker architectures through mise: Flutter publishes no
|
|
464
|
+
Linux arm64 release, the Android SDK's platforms and build tools are fetched
|
|
465
|
+
by `sdkmanager` at run time (outside any lock, behind a licence a person
|
|
466
|
+
accepts), and iOS builds need macOS and Xcode, which workers are not. A
|
|
467
|
+
project that builds for Android on x86_64 workers pins `flutter`, `java` and
|
|
468
|
+
`android-sdk` in its own `mise.toml` as above.
|
|
469
|
+
|
|
470
|
+
`worker.exposure` (fleet-wide) or `exposure` on one worker says what a worker
|
|
471
|
+
opens beyond loopback and the tailnet; without it, nothing. See
|
|
472
|
+
[Exposure](ubuntu-sync.md#exposure).
|
|
473
|
+
|
|
408
474
|
The source-owned `worker-auth.ts` timer renews the worker's existing Vault token
|
|
409
475
|
and can restore the declared GitHub account from its authorized Vault service
|
|
410
476
|
credential, without copying another machine's login directory.
|
package/docs/manager-setup.md
CHANGED
|
@@ -22,6 +22,13 @@ step added here must be added there too, with the check that verifies it.
|
|
|
22
22
|
|
|
23
23
|
<!-- /human-steps -->
|
|
24
24
|
|
|
25
|
-
The grant lets the manager's user run exactly `pmset -c`
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
The grant lets the manager's user run exactly `pmset -c` and
|
|
26
|
+
`systemsetup -getusingnetworktime` without a password, so later syncs never
|
|
27
|
+
prompt. The same playbook, run as an administrator, also installs what only
|
|
28
|
+
root may write: the newsyslog drop-in that keeps the logs of the scheduled
|
|
29
|
+
jobs under a fixed size (`manager:job-logs`) and T3's administrator policy
|
|
30
|
+
(`t3:updates`). Every `fleet-sync` then applies `ansible/macos/manager.yml`
|
|
31
|
+
unattended: in check mode first, then for real, with a receipt like the
|
|
32
|
+
workers' and a full re-apply at least once a day (`manager:playbook`). Run the
|
|
33
|
+
grant again when `manager:clock` or `manager:job-logs` asks for it after an
|
|
34
|
+
upgrade, or with `-e grant=absent` to remove it.
|