@crvouga/dev-fleet 0.0.0-stage → 0.2.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.
- package/.mise/locks/aws-cdk/2.1146.1/aube-lock.yaml +24 -0
- package/.mise/locks/aws-cdk/2.1146.1/package.json +7 -0
- package/.mise/locks/azure-cli/2.91.0~a837e014/pyproject.toml +5 -0
- package/.mise/locks/azure-cli/2.91.0~a837e014/uv.lock +2794 -0
- package/.mise/locks/gemini/0.66.0~84aac8e6/aube-lock.yaml +123 -0
- package/.mise/locks/gemini/0.66.0~84aac8e6/package.json +12 -0
- package/.mise/locks/npm-devcontainers-cli/0.90.0/aube-lock.yaml +24 -0
- package/.mise/locks/npm-devcontainers-cli/0.90.0/package.json +7 -0
- package/.mise/locks/npm-modelcontextprotocol-inspector/2.13.0~4c109bea/aube-lock.yaml +1432 -0
- package/.mise/locks/npm-modelcontextprotocol-inspector/2.13.0~4c109bea/package.json +7 -0
- package/.mise/locks/npm-vercel/65.8.0/aube-lock.yaml +3595 -0
- package/.mise/locks/npm-vercel/65.8.0/package.json +7 -0
- package/.mise/locks/npm-wrangler/4.156.0/aube-lock.yaml +895 -0
- package/.mise/locks/npm-wrangler/4.156.0/package.json +7 -0
- package/.mise/locks/npm-yarnpkg-cli-dist/4.18.1/aube-lock.yaml +24 -0
- package/.mise/locks/npm-yarnpkg-cli-dist/4.18.1/package.json +7 -0
- package/LICENSE +21 -0
- package/README.md +357 -2
- package/agents/antigravity-proxy.ts +3 -0
- package/agents/audit.md +89 -0
- package/agents/claude-proxy +5 -0
- package/agents/claude-proxy.ts +3 -0
- package/agents/codex-proxy.ts +3 -0
- package/agents/grok-proxy.ts +3 -0
- package/agents/managed-proxy.ts +55 -0
- package/agents/opencode-proxy.ts +3 -0
- package/agents/registry.json +209 -0
- package/agents/registry.schema.json +149 -0
- package/agents/setup.md +158 -0
- package/agents/t3.json +40 -0
- package/ansible/macos/manager.yml +30 -0
- package/ansible/macos/policy.json +9 -0
- package/ansible/monitoring/README.md +215 -0
- package/ansible/monitoring/agent-darwin.yml +198 -0
- package/ansible/monitoring/agent.yml +172 -0
- package/ansible/monitoring/beszel-agent.service +42 -0
- package/ansible/monitoring/compose.yml +74 -0
- package/ansible/monitoring/hub-darwin.yml +102 -0
- package/ansible/monitoring/hub-route-darwin.yml +51 -0
- package/ansible/monitoring/lock.json +16 -0
- package/ansible/net/remote-probe.sh +13 -0
- package/ansible/pyproject.toml +12 -0
- package/ansible/ubuntu/authorize-sudo.sh +51 -0
- package/ansible/ubuntu/baseline.yml +89 -0
- package/ansible/ubuntu/disk-gc.py +336 -0
- package/ansible/ubuntu/disk-guard.py +104 -0
- package/ansible/ubuntu/policy.json +52 -0
- package/ansible/ubuntu/recovery.yml +15 -0
- package/ansible/ubuntu/t3/policy.json +7 -0
- package/ansible/ubuntu/t3-desktop.yml +220 -0
- package/ansible/ubuntu/t3-health.sh +33 -0
- package/ansible/ubuntu/t3-policy.yml +76 -0
- package/ansible/ubuntu/t3-route.yml +28 -0
- package/ansible/ubuntu/tailscale.yml +78 -0
- package/ansible/ubuntu/tasks/credentials.yml +47 -0
- package/ansible/ubuntu/tasks/docker.yml +31 -0
- package/ansible/ubuntu/tasks/packages.yml +56 -0
- package/ansible/ubuntu/tasks/power.yml +51 -0
- package/ansible/ubuntu/tasks/recovery.yml +39 -0
- package/ansible/ubuntu/tasks/resources.yml +312 -0
- package/ansible/ubuntu/tasks/services.yml +31 -0
- package/ansible/ubuntu/tasks/ssh.yml +71 -0
- package/ansible/ubuntu/tasks/user.yml +120 -0
- package/ansible/uv.lock +190 -0
- package/bin/devfleet.mjs +36 -0
- package/bootstrap/bootstrap.ps1 +50 -0
- package/bootstrap/bootstrap.sh +80 -0
- package/bootstrap/devfleet +7 -0
- package/bootstrap/docker-desktop.sh +33 -0
- package/bootstrap/doctor.ts +234 -0
- package/bootstrap/fleet-manager-run.sh +103 -0
- package/bootstrap/fleet-remote-bootstrap.sh +258 -0
- package/bootstrap/global-config.ts +171 -0
- package/bootstrap/install-launcher.sh +10 -0
- package/bootstrap/native-aws.ts +86 -0
- package/bootstrap/native-t3.ts +154 -0
- package/bootstrap/npm.ts +358 -0
- package/bootstrap/release-version.ts +157 -0
- package/bootstrap/setup-status.ts +51 -0
- package/bootstrap/setup.ts +88 -0
- package/bootstrap/shell-path.ts +105 -0
- package/bootstrap/verify-t3-archive.py +49 -0
- package/bootstrap/worker-auth.ts +65 -0
- package/bootstrap/worker-github.ts +47 -0
- package/bootstrap/worker-tools.ts +24 -0
- package/cliproxy/AGENTS.md +11 -0
- package/cliproxy/README.md +269 -0
- package/cliproxy/clients/bootstrap.py +143 -0
- package/cliproxy/clients/launcher.py +57 -0
- package/cliproxy/compose.yaml +90 -0
- package/cliproxy/config.template.yaml +70 -0
- package/cliproxy/docs/cloud-adoption.md +16 -0
- package/cliproxy/docs/deployment.png +0 -0
- package/cliproxy/docs/deployment.svg +109 -0
- package/cliproxy/docs/health-workflow.example.yml +185 -0
- package/cliproxy/docs/migration.md +131 -0
- package/cliproxy/docs/model-health-report.schema.json +364 -0
- package/cliproxy/docs/model-health.md +393 -0
- package/cliproxy/image.lock.json +5 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-backup-check.plist +38 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-backup.plist +48 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-fleet.plist +32 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-gc.plist +38 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-monitor.plist +29 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-vault-renew.plist +31 -0
- package/cliproxy/models.json +1618 -0
- package/cliproxy/requirements.lock +78 -0
- package/cliproxy/scripts/accounts.py +38 -0
- package/cliproxy/scripts/audit.py +123 -0
- package/cliproxy/scripts/backup +234 -0
- package/cliproxy/scripts/check.py +34 -0
- package/cliproxy/scripts/checkpoint.py +226 -0
- package/cliproxy/scripts/cli.py +64 -0
- package/cliproxy/scripts/cliproxy_host.py +257 -0
- package/cliproxy/scripts/cloud_state.py +150 -0
- package/cliproxy/scripts/container-health +6 -0
- package/cliproxy/scripts/docker +24 -0
- package/cliproxy/scripts/external-health.py +79 -0
- package/cliproxy/scripts/fleet_config.py +43 -0
- package/cliproxy/scripts/fleet_sync.py +274 -0
- package/cliproxy/scripts/initialize +84 -0
- package/cliproxy/scripts/install-dependencies +48 -0
- package/cliproxy/scripts/install.py +406 -0
- package/cliproxy/scripts/model_health.py +16 -0
- package/cliproxy/scripts/modelhealth/__init__.py +5 -0
- package/cliproxy/scripts/modelhealth/checks.py +429 -0
- package/cliproxy/scripts/modelhealth/cli.py +117 -0
- package/cliproxy/scripts/modelhealth/config.py +186 -0
- package/cliproxy/scripts/modelhealth/emulator.py +536 -0
- package/cliproxy/scripts/modelhealth/expect.py +88 -0
- package/cliproxy/scripts/modelhealth/findings.py +183 -0
- package/cliproxy/scripts/modelhealth/protocol.py +330 -0
- package/cliproxy/scripts/modelhealth/redact.py +28 -0
- package/cliproxy/scripts/modelhealth/report.py +150 -0
- package/cliproxy/scripts/modelhealth/runner.py +390 -0
- package/cliproxy/scripts/modelhealth/scenario.py +131 -0
- package/cliproxy/scripts/modelhealth/schema.py +63 -0
- package/cliproxy/scripts/modelhealth/simulate.py +111 -0
- package/cliproxy/scripts/modelhealth/transport.py +213 -0
- package/cliproxy/scripts/monitor +68 -0
- package/cliproxy/scripts/ops +527 -0
- package/cliproxy/scripts/public-endpoint +127 -0
- package/cliproxy/scripts/recover_node.py +177 -0
- package/cliproxy/scripts/restore-verify +60 -0
- package/cliproxy/scripts/retention.py +144 -0
- package/cliproxy/scripts/service-start +7 -0
- package/cliproxy/scripts/validate-config +56 -0
- package/cliproxy/scripts/vault-access.py +57 -0
- package/cliproxy/scripts/vault-backup-login +55 -0
- package/cliproxy/scripts/vault-recovery +56 -0
- package/cliproxy/scripts/vault-renew +30 -0
- package/cliproxy/systemd/cliproxy-backup-check.service +10 -0
- package/cliproxy/systemd/cliproxy-backup-check.timer +8 -0
- package/cliproxy/systemd/cliproxy-backup.service +13 -0
- package/cliproxy/systemd/cliproxy-backup.timer +8 -0
- package/cliproxy/systemd/cliproxy-fleet.service +17 -0
- package/cliproxy/systemd/cliproxy-gc.service +13 -0
- package/cliproxy/systemd/cliproxy-gc.timer +8 -0
- package/cliproxy/systemd/cliproxy-monitor.service +8 -0
- package/cliproxy/systemd/cliproxy-monitor.timer +7 -0
- package/cliproxy/systemd/cliproxy-vault-renew.service +8 -0
- package/cliproxy/systemd/cliproxy-vault-renew.timer +7 -0
- package/cliproxy/vendor/LICENSE +22 -0
- package/cliproxy/vendor/config.upstream.yaml +1349 -0
- package/docs/consumer-setup.md +408 -0
- package/docs/declared.md +89 -0
- package/docs/machine-setup.md +399 -0
- package/docs/operations.md +276 -0
- package/docs/releasing.md +103 -0
- package/docs/state.md +254 -0
- package/docs/topology.md +67 -0
- package/docs/ubuntu-sync.md +351 -0
- package/docs/worker-contract.md +67 -0
- package/examples/fleet.json +100 -0
- package/examples/roster.json +13 -0
- package/llms.txt +35 -0
- package/mise.lock +1521 -0
- package/mise.toml +110 -0
- package/package.json +74 -4
- package/schema/fleet.schema.json +420 -0
- package/schema/roster.schema.json +77 -0
- package/src/agents/account-relay.ts +111 -0
- package/src/agents/accounts.ts +85 -0
- package/src/agents/audit.ts +77 -0
- package/src/agents/cli.ts +13 -0
- package/src/agents/command.ts +204 -0
- package/src/agents/converge.ts +123 -0
- package/src/agents/doctor.ts +107 -0
- package/src/agents/errors.ts +2 -0
- package/src/agents/files.ts +73 -0
- package/src/agents/fleet-verify.ts +165 -0
- package/src/agents/launch.ts +290 -0
- package/src/agents/native-verify.ts +371 -0
- package/src/agents/provider-errors.ts +57 -0
- package/src/agents/registry.ts +61 -0
- package/src/agents/render.ts +110 -0
- package/src/agents/round-trip.ts +192 -0
- package/src/agents/secrets.ts +13 -0
- package/src/agents/toolchain.ts +34 -0
- package/src/agents/verify-cache.ts +103 -0
- package/src/agents/verify.ts +127 -0
- package/src/auth-checks.ts +163 -0
- package/src/cli/agent-guide.ts +129 -0
- package/src/cli/app.ts +122 -0
- package/src/cli/cli.ts +28 -0
- package/src/cli/command-index.ts +57 -0
- package/src/cli/contracts.ts +25 -0
- package/src/cli/fleet-reference.ts +17 -0
- package/src/cli/fleet-state.ts +499 -0
- package/src/cli/fleet-sync-checkout.ts +130 -0
- package/src/cli/fleet-sync-enrollment.ts +140 -0
- package/src/cli/fleet-sync-forward.ts +134 -0
- package/src/cli/fleet-sync-manager.ts +249 -0
- package/src/cli/fleet-sync-monitoring.ts +185 -0
- package/src/cli/fleet-sync-output.ts +317 -0
- package/src/cli/fleet-sync-privilege.ts +27 -0
- package/src/cli/fleet-sync-progress.ts +109 -0
- package/src/cli/fleet-sync-remote.ts +242 -0
- package/src/cli/fleet-sync-report.ts +26 -0
- package/src/cli/fleet-sync-schedule.ts +138 -0
- package/src/cli/fleet-sync-state.ts +86 -0
- package/src/cli/fleet-sync-vault.ts +166 -0
- package/src/cli/fleet-sync.ts +375 -0
- package/src/cli/fleet.ts +165 -0
- package/src/cli/managed-health.ts +219 -0
- package/src/cli/node-deployment.ts +34 -0
- package/src/cli/node-sync.ts +121 -0
- package/src/cli/node-t3.ts +31 -0
- package/src/cli/options.ts +141 -0
- package/src/cli/probe-source.ts +7 -0
- package/src/cli/program.ts +185 -0
- package/src/cli/project.ts +51 -0
- package/src/cli/register-fleet.ts +296 -0
- package/src/cli/registry.ts +185 -0
- package/src/cli/repair-apply.ts +67 -0
- package/src/cli/repair-guard.ts +11 -0
- package/src/cli/repair-inspect.ts +150 -0
- package/src/cli/repair-script.ts +76 -0
- package/src/cli/repair.ts +209 -0
- package/src/cli/roster.ts +105 -0
- package/src/cli/search.ts +35 -0
- package/src/cli/settings.ts +67 -0
- package/src/cli/source-operations.ts +102 -0
- package/src/cli/t3/command.ts +90 -0
- package/src/cli/t3/register.ts +55 -0
- package/src/cli/tailnet.ts +127 -0
- package/src/cli/ui-actions.ts +133 -0
- package/src/cli/ui-controller.ts +113 -0
- package/src/cli/ui-data.ts +106 -0
- package/src/cli/ui-execute.ts +163 -0
- package/src/cli/ui-repairs.ts +34 -0
- package/src/cli/ui-reports.ts +211 -0
- package/src/cli/ui-targets.ts +100 -0
- package/src/cli/ui-terminal.ts +109 -0
- package/src/cli/ui-types.ts +49 -0
- package/src/cli/ui-wizard.ts +101 -0
- package/src/cli/ui.ts +9 -0
- package/src/cli/worker-health-output.ts +37 -0
- package/src/config.ts +186 -0
- package/src/configure.ts +255 -0
- package/src/definition.ts +290 -0
- package/src/diagnostics.ts +92 -0
- package/src/doctor-check.ts +10 -0
- package/src/errors.ts +1 -0
- package/src/fingerprint.ts +120 -0
- package/src/fleet-config.ts +174 -0
- package/src/input-hashes.ts +73 -0
- package/src/machine/local-source.ts +52 -0
- package/src/machine/lock-error.ts +2 -0
- package/src/machine/platform.ts +44 -0
- package/src/machine/source.ts +68 -0
- package/src/machine/state.ts +173 -0
- package/src/machine-health.ts +95 -0
- package/src/managed-source.ts +47 -0
- package/src/manager-failure.ts +48 -0
- package/src/manager-sync.ts +405 -0
- package/src/manager.ts +62 -0
- package/src/monitoring/agent-evidence.ts +146 -0
- package/src/monitoring/apply.ts +183 -0
- package/src/monitoring/beszel.ts +198 -0
- package/src/monitoring/enroll.ts +111 -0
- package/src/monitoring/hub-access.ts +114 -0
- package/src/monitoring/hub-backup.ts +121 -0
- package/src/monitoring/hub-viewer.ts +142 -0
- package/src/monitoring/hub.ts +93 -0
- package/src/monitoring/manager-agent.ts +73 -0
- package/src/monitoring/manager-hub.ts +248 -0
- package/src/monitoring/remote.ts +65 -0
- package/src/network-definition.ts +83 -0
- package/src/node-converge-linux.ts +374 -0
- package/src/node-converge-shared.ts +83 -0
- package/src/node-converge.ts +40 -0
- package/src/onboard.ts +35 -0
- package/src/package-info.ts +45 -0
- package/src/platform/ansible-receipt.ts +128 -0
- package/src/platform/ansible.ts +66 -0
- package/src/platform/darwin.ts +203 -0
- package/src/platform/detect.ts +11 -0
- package/src/platform/fallback.ts +110 -0
- package/src/platform/index.ts +38 -0
- package/src/platform/launchd.ts +98 -0
- package/src/platform/linux.ts +139 -0
- package/src/platform/ps.ts +45 -0
- package/src/platform/resource-verify.ts +132 -0
- package/src/platform/systemd-user.ts +95 -0
- package/src/platform/t3-policy.ts +137 -0
- package/src/platform/t3-route.ts +68 -0
- package/src/platform/t3-service.ts +75 -0
- package/src/platform/types.ts +123 -0
- package/src/platform/ubuntu-audit.ts +66 -0
- package/src/platform/ubuntu-verify.ts +105 -0
- package/src/platform/windows.ts +148 -0
- package/src/power-recovery.ts +55 -0
- package/src/probe.ts +51 -0
- package/src/protocol.ts +119 -0
- package/src/proxy-converge.ts +85 -0
- package/src/remote-bootstrap.ts +210 -0
- package/src/remote-entry.ts +89 -0
- package/src/remote-lock.ts +12 -0
- package/src/repair-catalog.ts +206 -0
- package/src/repair-plan.ts +78 -0
- package/src/repair-runner.ts +84 -0
- package/src/report.ts +71 -0
- package/src/runner.ts +104 -0
- package/src/secrets.ts +169 -0
- package/src/service-auth.ts +115 -0
- package/src/ssh.ts +135 -0
- package/src/state/bucket.ts +208 -0
- package/src/state/check.ts +74 -0
- package/src/state/connection.ts +92 -0
- package/src/state/enrollment.ts +45 -0
- package/src/state/legacy.ts +89 -0
- package/src/state/litestream.ts +143 -0
- package/src/state/operator.ts +20 -0
- package/src/state/paths.ts +40 -0
- package/src/state/roster.ts +62 -0
- package/src/state/store.ts +169 -0
- package/src/state/sync.ts +352 -0
- package/src/sync.ts +104 -0
- package/src/t3/accounts.ts +81 -0
- package/src/t3/desired.ts +165 -0
- package/src/t3/files.ts +81 -0
- package/src/t3/names-check.ts +53 -0
- package/src/t3/names.ts +155 -0
- package/src/t3/plan.ts +82 -0
- package/src/t3/providers.ts +74 -0
- package/src/t3/reconcile.ts +123 -0
- package/src/t3-endpoint.ts +104 -0
- package/src/t3-linked-check.ts +123 -0
- package/src/tailnet-health.ts +231 -0
- package/src/tailnet-matching.ts +37 -0
- package/src/tailscale.ts +141 -0
- package/src/toolchain-checks.ts +108 -0
- package/src/topology.ts +24 -0
- package/src/transport.ts +122 -0
- package/src/types.ts +99 -0
- package/src/vault-config.ts +38 -0
- package/src/worker-access-checks.ts +168 -0
- package/src/worker-capacity.ts +34 -0
- package/src/worker-host-checks.ts +181 -0
- package/src/worker-policy.ts +64 -0
- package/src/worker-readiness.ts +64 -0
- package/src/workstation-checks.ts +29 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Run on the manager only, through hub-darwin.yml from the verified checkout.
|
|
2
|
+
# Never copy the hub data to a worker or run a second copy of its identity.
|
|
3
|
+
name: personal-beszel
|
|
4
|
+
services:
|
|
5
|
+
hub:
|
|
6
|
+
image: henrygd/beszel:0.21.1@sha256:8514a69d9bbbcb74f371a3205561ee231fc0289739cea64e8131f341d695b770
|
|
7
|
+
restart: unless-stopped
|
|
8
|
+
ports:
|
|
9
|
+
- '127.0.0.1:8090:8090'
|
|
10
|
+
environment:
|
|
11
|
+
APP_URL: '${BESZEL_APP_URL:-${BESZEL_HUB_URL:?private HTTPS hub URL required}}'
|
|
12
|
+
DISABLE_SSH: 'true'
|
|
13
|
+
CHECK_UPDATES: 'false'
|
|
14
|
+
# Single-operator private hub: fleet-registered systems are visible to every login.
|
|
15
|
+
SHARE_ALL_SYSTEMS: 'true'
|
|
16
|
+
# Visitors are signed in automatically as this read-only viewer account
|
|
17
|
+
# (never the fleet admin), so the dashboard needs no login. Empty keeps
|
|
18
|
+
# the normal login page.
|
|
19
|
+
AUTO_LOGIN: '${BESZEL_AUTO_LOGIN:-}'
|
|
20
|
+
# First start only (empty data directory): Beszel creates the fleet login
|
|
21
|
+
# as a verified user and superuser. hub-darwin.yml sets these just once.
|
|
22
|
+
USER_EMAIL: '${BESZEL_BOOTSTRAP_EMAIL:-}'
|
|
23
|
+
USER_PASSWORD: '${BESZEL_BOOTSTRAP_PASSWORD:-}'
|
|
24
|
+
volumes:
|
|
25
|
+
- type: bind
|
|
26
|
+
source: '${BESZEL_DATA_DIR:?per-user hub data directory required}'
|
|
27
|
+
target: /beszel_data
|
|
28
|
+
bind:
|
|
29
|
+
create_host_path: false
|
|
30
|
+
logging:
|
|
31
|
+
driver: local
|
|
32
|
+
options:
|
|
33
|
+
max-size: '10m'
|
|
34
|
+
max-file: '3'
|
|
35
|
+
mem_limit: 512m
|
|
36
|
+
cpus: 1.0
|
|
37
|
+
pids_limit: 128
|
|
38
|
+
stop_grace_period: 30s
|
|
39
|
+
# Outbound-only Cloudflare Tunnel for the public dashboard hostname. The
|
|
40
|
+
# connector token is delivered from the manager's Vault session to a 0600
|
|
41
|
+
# per-user file by hub-darwin.yml.
|
|
42
|
+
cloudflared:
|
|
43
|
+
profiles: [public-endpoint]
|
|
44
|
+
image: cloudflare/cloudflared:2026.9.3@sha256:072c067d25ccbe61d46e18f0d0723255f2bb5304f7317caa95b27031520ff92c
|
|
45
|
+
user: '1000:1000'
|
|
46
|
+
restart: unless-stopped
|
|
47
|
+
command:
|
|
48
|
+
[
|
|
49
|
+
'tunnel',
|
|
50
|
+
'--no-autoupdate',
|
|
51
|
+
'run',
|
|
52
|
+
'--token-file',
|
|
53
|
+
'/run/secrets/tunnel-token',
|
|
54
|
+
]
|
|
55
|
+
volumes:
|
|
56
|
+
- type: bind
|
|
57
|
+
source: '${BESZEL_TUNNEL_TOKEN_FILE:?per-user connector token file required}'
|
|
58
|
+
target: /run/secrets/tunnel-token
|
|
59
|
+
read_only: true
|
|
60
|
+
bind:
|
|
61
|
+
create_host_path: false
|
|
62
|
+
depends_on:
|
|
63
|
+
- hub
|
|
64
|
+
read_only: true
|
|
65
|
+
cap_drop: [ALL]
|
|
66
|
+
security_opt: ['no-new-privileges:true']
|
|
67
|
+
mem_limit: 256m
|
|
68
|
+
cpus: 0.5
|
|
69
|
+
pids_limit: 128
|
|
70
|
+
logging:
|
|
71
|
+
driver: local
|
|
72
|
+
options:
|
|
73
|
+
max-size: '5m'
|
|
74
|
+
max-file: '2'
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
# The Beszel hub runs only on the manager (the human's macOS machine) under
|
|
3
|
+
# Docker Desktop, as that user: no become, per-user data and credential paths.
|
|
4
|
+
# Runtime variables arrive through a private 0600 variables file, never argv.
|
|
5
|
+
- name: Converge the Beszel hub on the manager
|
|
6
|
+
hosts: localhost
|
|
7
|
+
connection: local
|
|
8
|
+
become: false
|
|
9
|
+
gather_facts: true
|
|
10
|
+
vars:
|
|
11
|
+
beszel_lock: "{{ lookup('ansible.builtin.file', 'lock.json') | from_json }}"
|
|
12
|
+
beszel_compose:
|
|
13
|
+
- docker
|
|
14
|
+
- compose
|
|
15
|
+
- '-f'
|
|
16
|
+
- '{{ playbook_dir }}/compose.yml'
|
|
17
|
+
beszel_environment:
|
|
18
|
+
BESZEL_HUB_URL: '{{ beszel_hub_url }}'
|
|
19
|
+
BESZEL_APP_URL: '{{ beszel_public_url | default(beszel_hub_url) }}'
|
|
20
|
+
BESZEL_DATA_DIR: '{{ beszel_data_dir }}'
|
|
21
|
+
BESZEL_AUTO_LOGIN: '{{ beszel_auto_login | default("") }}'
|
|
22
|
+
BESZEL_TUNNEL_TOKEN_FILE: '{{ beszel_tunnel_dir }}/token'
|
|
23
|
+
tasks:
|
|
24
|
+
- name: Require the macOS manager and private dashboard policy
|
|
25
|
+
ansible.builtin.assert:
|
|
26
|
+
that:
|
|
27
|
+
- ansible_facts.os_family == 'Darwin'
|
|
28
|
+
- beszel_hub_url is match('^https://[a-z0-9.-]+\.ts\.net:8443$')
|
|
29
|
+
- beszel_data_dir is match('^/Users/[^/]+/Library/Application Support/personal-beszel$')
|
|
30
|
+
- beszel_tunnel_dir is match('^/Users/[^/]+/Library/Application Support/personal-beszel-tunnel$')
|
|
31
|
+
fail_msg: BESZEL_NOT_MANAGER; the hub runs only on the macOS manager with per-user data.
|
|
32
|
+
- name: Require a running Docker Desktop engine with Compose
|
|
33
|
+
ansible.builtin.command:
|
|
34
|
+
argv: [docker, compose, version]
|
|
35
|
+
changed_when: false
|
|
36
|
+
- name: Inspect an existing hub image before any upgrade
|
|
37
|
+
ansible.builtin.command:
|
|
38
|
+
argv:
|
|
39
|
+
[
|
|
40
|
+
docker,
|
|
41
|
+
inspect,
|
|
42
|
+
'--format',
|
|
43
|
+
'{{ "{{.Config.Image}}" }}',
|
|
44
|
+
personal-beszel-hub-1,
|
|
45
|
+
]
|
|
46
|
+
changed_when: false
|
|
47
|
+
failed_when: false
|
|
48
|
+
register: existing_hub
|
|
49
|
+
- name: Require explicit maintenance for a different existing image
|
|
50
|
+
ansible.builtin.assert:
|
|
51
|
+
that: existing_hub.rc != 0 or existing_hub.stdout == beszel_lock.image
|
|
52
|
+
fail_msg: BESZEL_HUB_UPGRADE_PENDING; take and verify a backup before an explicit maintenance upgrade.
|
|
53
|
+
- name: Create per-user hub data and connector directories without replacing data
|
|
54
|
+
ansible.builtin.file:
|
|
55
|
+
path: '{{ item }}'
|
|
56
|
+
state: directory
|
|
57
|
+
mode: '0700'
|
|
58
|
+
loop:
|
|
59
|
+
- '{{ beszel_data_dir }}'
|
|
60
|
+
- '{{ beszel_tunnel_dir }}'
|
|
61
|
+
- name: Write the public dashboard connector token for the current user only
|
|
62
|
+
ansible.builtin.copy:
|
|
63
|
+
dest: '{{ beszel_tunnel_dir }}/token'
|
|
64
|
+
content: '{{ beszel_tunnel_token }}'
|
|
65
|
+
mode: '0600'
|
|
66
|
+
when: beszel_tunnel_token | default('') | length > 0
|
|
67
|
+
no_log: true
|
|
68
|
+
- name: Detect a hub that has never started (no database yet)
|
|
69
|
+
ansible.builtin.stat:
|
|
70
|
+
path: '{{ beszel_data_dir }}/data.db'
|
|
71
|
+
register: hub_database
|
|
72
|
+
- name: Start pinned stock Compose service
|
|
73
|
+
ansible.builtin.command:
|
|
74
|
+
argv: "{{ beszel_compose + ['up', '-d', '--pull', 'missing', 'hub'] }}"
|
|
75
|
+
# A fresh hub creates the fleet login itself on first start, so no one
|
|
76
|
+
# has to create the account by hand. Existing data is never changed.
|
|
77
|
+
environment: >-
|
|
78
|
+
{{ beszel_environment | combine({
|
|
79
|
+
'BESZEL_BOOTSTRAP_EMAIL': beszel_fleet_identity,
|
|
80
|
+
'BESZEL_BOOTSTRAP_PASSWORD': beszel_fleet_password
|
|
81
|
+
} if (not hub_database.stat.exists
|
|
82
|
+
and beszel_fleet_password | default('') | length > 0)
|
|
83
|
+
else {}) }}
|
|
84
|
+
no_log: true
|
|
85
|
+
register: hub_apply
|
|
86
|
+
changed_when: "'Started' in hub_apply.stderr or 'Created' in hub_apply.stderr or 'Recreated' in hub_apply.stderr"
|
|
87
|
+
- name: Start the public connector when its credential is present
|
|
88
|
+
ansible.builtin.command:
|
|
89
|
+
argv: "{{ beszel_compose + ['--profile', 'public-endpoint', 'up', '-d', '--pull', 'missing'] }}"
|
|
90
|
+
environment: '{{ beszel_environment }}'
|
|
91
|
+
when: beszel_tunnel_token | default('') | length > 0
|
|
92
|
+
register: tunnel_apply
|
|
93
|
+
changed_when: "'Started' in tunnel_apply.stderr or 'Created' in tunnel_apply.stderr or 'Recreated' in tunnel_apply.stderr"
|
|
94
|
+
- name: Independently verify the local hub health endpoint
|
|
95
|
+
ansible.builtin.uri:
|
|
96
|
+
url: http://127.0.0.1:8090/api/health
|
|
97
|
+
status_code: 200
|
|
98
|
+
return_content: false
|
|
99
|
+
retries: 10
|
|
100
|
+
delay: 2
|
|
101
|
+
register: hub_health
|
|
102
|
+
until: hub_health.status == 200
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
# The manager's hub is reached over the tailnet only: Tailscale Serve
|
|
3
|
+
# terminates HTTPS on the declared port and proxies to the loopback hub. Never
|
|
4
|
+
# Funnel. A port that already has any owner is left alone: fleet-sync refuses
|
|
5
|
+
# a conflicting owner before this runs and reads the route back afterwards.
|
|
6
|
+
- name: Serve the manager hub privately over the tailnet
|
|
7
|
+
hosts: localhost
|
|
8
|
+
connection: local
|
|
9
|
+
gather_facts: false
|
|
10
|
+
vars:
|
|
11
|
+
beszel_serve:
|
|
12
|
+
[
|
|
13
|
+
'{{ beszel_tailscale_cli }}',
|
|
14
|
+
serve,
|
|
15
|
+
--bg,
|
|
16
|
+
'--https={{ beszel_route_port }}',
|
|
17
|
+
'{{ beszel_route_target }}',
|
|
18
|
+
]
|
|
19
|
+
tasks:
|
|
20
|
+
- name: Require the declared loopback target and port
|
|
21
|
+
ansible.builtin.assert:
|
|
22
|
+
that:
|
|
23
|
+
- "beszel_route_target is match('^http://127\\.0\\.0\\.1:[0-9]+$')"
|
|
24
|
+
- "beszel_route_port is match('^[0-9]+$')"
|
|
25
|
+
- "beszel_tailscale_cli is match('^/')"
|
|
26
|
+
|
|
27
|
+
- name: Read this node's Serve configuration
|
|
28
|
+
ansible.builtin.command:
|
|
29
|
+
argv: ['{{ beszel_tailscale_cli }}', serve, status, --json]
|
|
30
|
+
register: beszel_serve_status
|
|
31
|
+
changed_when: false
|
|
32
|
+
- name: Publish the hub on the tailnet HTTPS port as the signed-in user
|
|
33
|
+
ansible.builtin.command:
|
|
34
|
+
argv: '{{ beszel_serve }}'
|
|
35
|
+
vars:
|
|
36
|
+
serve: "{{ beszel_serve_status.stdout | default('{}', true) | from_json }}"
|
|
37
|
+
when:
|
|
38
|
+
- beszel_route_port not in (serve.TCP | default({}))
|
|
39
|
+
- "(serve.Web | default({})) | select('search', ':' ~ beszel_route_port ~ '$') | list | length == 0"
|
|
40
|
+
register: beszel_served
|
|
41
|
+
changed_when: beszel_served.rc == 0
|
|
42
|
+
failed_when: false
|
|
43
|
+
# The standalone daemon accepts Serve changes from an administrator only.
|
|
44
|
+
- name: Publish the hub with administrator rights where the daemon requires them
|
|
45
|
+
ansible.builtin.command:
|
|
46
|
+
argv: '{{ beszel_serve }}'
|
|
47
|
+
become: true
|
|
48
|
+
when:
|
|
49
|
+
- beszel_served is not skipped
|
|
50
|
+
- beszel_served.rc != 0
|
|
51
|
+
changed_when: true
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.21.1",
|
|
3
|
+
"image": "henrygd/beszel:0.21.1@sha256:8514a69d9bbbcb74f371a3205561ee231fc0289739cea64e8131f341d695b770",
|
|
4
|
+
"tunnelImage": "cloudflare/cloudflared:2026.9.3@sha256:072c067d25ccbe61d46e18f0d0723255f2bb5304f7317caa95b27031520ff92c",
|
|
5
|
+
"agents": {
|
|
6
|
+
"amd64": "3b6ee592632ec03b9a43312e99a40203a7b3d83fe40dd0c25acda1eb915ea7c0",
|
|
7
|
+
"arm64": "a6ea544976b9a74398ac88d5da5bb96813d9a2e353a37bbfdb6a903fa8ba1838",
|
|
8
|
+
"darwin-arm64": "9246065f680cdb0af2885b7bf5876dc45b754019f2c90eb28550cf45db978eb8",
|
|
9
|
+
"darwin-amd64": "21f4a03fd90ae46869cfcbb69e21e8312f0f05deff49669d4602a3dee4866981"
|
|
10
|
+
},
|
|
11
|
+
"agentBinaries": {
|
|
12
|
+
"amd64": "5c84416b63028f7ad86ebafa4c8a7a27977d485a838de357216ded3ab844b2b5",
|
|
13
|
+
"arm64": "eb4e7ac9340d380b19ab18261301b18813c1e46ebab5f0e4bf8cb6c86b4d5c20"
|
|
14
|
+
},
|
|
15
|
+
"source": "https://github.com/henrygd/beszel/releases/tag/v0.21.1"
|
|
16
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Read-only health probe that `dev-fleet net check` pipes to each host over SSH (`sh -s`).
|
|
2
|
+
# Prints key=value lines; works on macOS and Linux (including WSL).
|
|
3
|
+
if [ "$(uname)" = Darwin ]; then
|
|
4
|
+
echo "ncpu=$(sysctl -n hw.ncpu)"
|
|
5
|
+
echo "load=$(sysctl -n vm.loadavg | awk '{print $2}')"
|
|
6
|
+
echo "memfree=$(memory_pressure -Q 2>/dev/null | awk -F': ' '/percentage/{gsub("%","",$2); print $2}')"
|
|
7
|
+
sysctl -n vm.swapusage | awk '{t=$3; u=$6; gsub("M","",t); gsub("M","",u); if (t>0) print "swap=" int(u*100/t); else print "swap=0"}'
|
|
8
|
+
else
|
|
9
|
+
echo "ncpu=$(nproc)"
|
|
10
|
+
echo "load=$(cut -d' ' -f1 /proc/loadavg)"
|
|
11
|
+
awk '/MemTotal/{t=$2} /MemAvailable/{a=$2} /SwapTotal/{st=$2} /SwapFree/{sf=$2} END{print "memfree=" int(a*100/t); if (st>0) print "swap=" int((st-sf)*100/st); else print "swap=0"}' /proc/meminfo
|
|
12
|
+
fi
|
|
13
|
+
echo "diskmb=$(df -Pk "$HOME" | awk 'NR==2{print int($4/1024)}')"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# The Ansible the manager runs these playbooks with: one release, on one
|
|
2
|
+
# Python, with every dependency hash-locked in uv.lock. A worker runs the
|
|
3
|
+
# exact ansible-core package ubuntu/policy.json names instead. Change the
|
|
4
|
+
# version here, then run `uv lock` in this directory.
|
|
5
|
+
[project]
|
|
6
|
+
name = "dev-fleet-ansible"
|
|
7
|
+
version = "0"
|
|
8
|
+
requires-python = "==3.13.16"
|
|
9
|
+
dependencies = ["ansible-core==2.19.9"]
|
|
10
|
+
|
|
11
|
+
[tool.uv]
|
|
12
|
+
package = false
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Manager-led, explicitly approved initial privilege step. Run through a real
|
|
3
|
+
# SSH terminal so sudo reads the operator's password itself; never capture it.
|
|
4
|
+
set -eu
|
|
5
|
+
umask 077
|
|
6
|
+
case "$(uname -s)" in
|
|
7
|
+
Linux)
|
|
8
|
+
. /etc/os-release
|
|
9
|
+
[ "$ID" = ubuntu ] && [ "$VERSION_ID" = 26.04 ] || exit 1 ;;
|
|
10
|
+
Darwin)
|
|
11
|
+
[ "$(sw_vers -productVersion | cut -d. -f1)" -ge 14 ] || exit 1 ;;
|
|
12
|
+
*) exit 1 ;;
|
|
13
|
+
esac
|
|
14
|
+
user=$(id -un)
|
|
15
|
+
case "$user" in root|''|*[!a-z0-9_-]*) exit 1;; esac
|
|
16
|
+
command -v sudo >/dev/null 2>&1 || exit 1
|
|
17
|
+
# The same operation lock used by remote bootstrap excludes another installer.
|
|
18
|
+
root="$HOME/.local/share/personal/fleet"
|
|
19
|
+
for path in "$HOME/.local" "$HOME/.local/share" "$HOME/.local/share/personal" "$root"; do
|
|
20
|
+
[ ! -L "$path" ] || exit 1
|
|
21
|
+
done
|
|
22
|
+
mkdir -p "$root"
|
|
23
|
+
chmod 700 "$root"
|
|
24
|
+
[ ! -L "$root/remote-operation.lock" ] || exit 1
|
|
25
|
+
exec 9>"$root/remote-operation.lock"
|
|
26
|
+
if command -v flock >/dev/null 2>&1; then
|
|
27
|
+
flock -n 9 || exit 1
|
|
28
|
+
else
|
|
29
|
+
python3 -c 'import fcntl; fcntl.flock(9, fcntl.LOCK_EX | fcntl.LOCK_NB)' 9>&9 || exit 1
|
|
30
|
+
fi
|
|
31
|
+
sudo -v
|
|
32
|
+
file=$(mktemp)
|
|
33
|
+
trap 'rm -f "$file"' EXIT
|
|
34
|
+
trap 'exit 1' HUP INT TERM
|
|
35
|
+
printf '# Managed by personal Fleet: designated development user\n%s ALL=(ALL:ALL) NOPASSWD: ALL\n' "$user" >"$file"
|
|
36
|
+
sudo -n visudo -cf "$file" >/dev/null
|
|
37
|
+
# This dedicated path is owned by the same Workstation baseline. Preserve any
|
|
38
|
+
# existing fragment for recovery before installing the validated declaration.
|
|
39
|
+
target="/etc/sudoers.d/personal-fleet-$user"
|
|
40
|
+
if sudo -n test -e "$target"; then
|
|
41
|
+
sudo -n test ! -L "$target" || exit 1
|
|
42
|
+
sudo -n grep -qxF '# Managed by personal Fleet: designated development user' "$target" || {
|
|
43
|
+
printf '%s\n' 'SUDOERS_OWNERSHIP_CONFLICT: preserve the existing fragment and review its source before migration.' >&2
|
|
44
|
+
exit 1
|
|
45
|
+
}
|
|
46
|
+
sudo -n cp -p -- "$target" "$target.before-fleet-enrollment"
|
|
47
|
+
fi
|
|
48
|
+
group=root
|
|
49
|
+
[ "$(uname -s)" != Darwin ] || group=wheel
|
|
50
|
+
sudo -n install -o root -g "$group" -m 0440 -- "$file" "$target"
|
|
51
|
+
sudo -n true
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
- name: Apply reviewed Ubuntu development-server policy
|
|
3
|
+
hosts: localhost
|
|
4
|
+
connection: local
|
|
5
|
+
become: true
|
|
6
|
+
gather_facts: true
|
|
7
|
+
vars_files:
|
|
8
|
+
- policy.json
|
|
9
|
+
pre_tasks:
|
|
10
|
+
- name: Require the supported common release and an explicit non-root user
|
|
11
|
+
ansible.builtin.assert:
|
|
12
|
+
that:
|
|
13
|
+
- ansible_facts.distribution == 'Ubuntu'
|
|
14
|
+
- ansible_facts.distribution_version == release
|
|
15
|
+
- ansible_facts.architecture in ['x86_64', 'aarch64']
|
|
16
|
+
- development_user is match('^[a-z_][a-z0-9_-]{0,31}$')
|
|
17
|
+
- development_user != 'root'
|
|
18
|
+
fail_msg: Unsupported platform or user; no distribution upgrade is permitted.
|
|
19
|
+
- name: Read the designated existing account
|
|
20
|
+
ansible.builtin.getent:
|
|
21
|
+
database: passwd
|
|
22
|
+
key: '{{ development_user }}'
|
|
23
|
+
- name: Refuse a different user identity or home
|
|
24
|
+
ansible.builtin.assert:
|
|
25
|
+
that:
|
|
26
|
+
- ansible_facts.getent_passwd[development_user][1] | int == development_uid | int
|
|
27
|
+
- ansible_facts.getent_passwd[development_user][4] == development_home
|
|
28
|
+
# Memory and disk safety must land even when the disk is nearly full.
|
|
29
|
+
- ansible.builtin.import_tasks: tasks/resources.yml
|
|
30
|
+
- name: Inspect capacity before package and service changes
|
|
31
|
+
ansible.builtin.command:
|
|
32
|
+
argv:
|
|
33
|
+
- /usr/bin/python3
|
|
34
|
+
- '-c'
|
|
35
|
+
- |
|
|
36
|
+
import json, os
|
|
37
|
+
print(json.dumps([{"path": p, "freeMiB": (v.f_bavail * v.f_frsize) // (1024 * 1024), "freeInodes": v.f_favail} for p in ['/', '/var', os.environ['FLEET_HOME']] for v in [os.statvfs(p)]]))
|
|
38
|
+
environment:
|
|
39
|
+
FLEET_HOME: '{{ development_home }}'
|
|
40
|
+
changed_when: false
|
|
41
|
+
register: capacity
|
|
42
|
+
- name: Preserve management capacity instead of installing into an exhausted disk
|
|
43
|
+
ansible.builtin.assert:
|
|
44
|
+
that:
|
|
45
|
+
- item.freeMiB >= minimumFreeDiskMiB
|
|
46
|
+
- item.freeInodes >= minimumFreeInodes
|
|
47
|
+
fail_msg: RESOURCE_CAPACITY_REQUIRED; inspect disk space and inodes on the reported filesystem. Preserve developer work; the disk GC removes only build output and caches, so what remains needs a person.
|
|
48
|
+
loop: '{{ capacity.stdout | from_json }}'
|
|
49
|
+
- name: Inspect installed packages
|
|
50
|
+
ansible.builtin.package_facts:
|
|
51
|
+
manager: apt
|
|
52
|
+
- name: Preserve Docker installations owned by a different distribution
|
|
53
|
+
ansible.builtin.assert:
|
|
54
|
+
that: "'docker-ce' not in ansible_facts.packages and 'containerd.io' not in ansible_facts.packages"
|
|
55
|
+
fail_msg: DOCKER_OWNER_CONFLICT; migrate the existing Docker owner explicitly before applying the Ubuntu-native baseline.
|
|
56
|
+
- name: Inspect existing service ownership
|
|
57
|
+
ansible.builtin.service_facts:
|
|
58
|
+
- name: Wait for legitimate package transactions before inspecting dpkg
|
|
59
|
+
ansible.builtin.command:
|
|
60
|
+
argv:
|
|
61
|
+
- /usr/bin/python3
|
|
62
|
+
- '-c'
|
|
63
|
+
- |
|
|
64
|
+
import fcntl
|
|
65
|
+
files = [open(path, 'a') for path in ['/var/lib/dpkg/lock-frontend', '/var/lib/dpkg/lock']]
|
|
66
|
+
for handle in files:
|
|
67
|
+
fcntl.lockf(handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
68
|
+
register: apt_idle
|
|
69
|
+
changed_when: false
|
|
70
|
+
retries: 24
|
|
71
|
+
delay: 5
|
|
72
|
+
until: apt_idle.rc == 0
|
|
73
|
+
- name: Inspect package database consistency
|
|
74
|
+
ansible.builtin.command: dpkg --audit
|
|
75
|
+
changed_when: false
|
|
76
|
+
register: dpkg_audit
|
|
77
|
+
- name: Require package database recovery before modifying packages
|
|
78
|
+
ansible.builtin.assert:
|
|
79
|
+
that: dpkg_audit.stdout | trim == ''
|
|
80
|
+
fail_msg: APT_STATE_BROKEN; inspect dpkg --audit and use reviewed package recovery. Never remove package lock files.
|
|
81
|
+
tasks:
|
|
82
|
+
- ansible.builtin.import_tasks: tasks/packages.yml
|
|
83
|
+
- ansible.builtin.import_tasks: tasks/docker.yml
|
|
84
|
+
- ansible.builtin.import_tasks: tasks/services.yml
|
|
85
|
+
- ansible.builtin.import_tasks: tasks/power.yml
|
|
86
|
+
- ansible.builtin.import_tasks: tasks/user.yml
|
|
87
|
+
- ansible.builtin.import_tasks: tasks/ssh.yml
|
|
88
|
+
- ansible.builtin.import_tasks: tasks/credentials.yml
|
|
89
|
+
when: development_source is defined
|