Preflight validation + destroy teardown (open-source lifecycle) - #6
Merged
Conversation
Complete the create-lifecycle with the two bookends a stranger cloning this hits first: 'will it work for me' and 'how do I undo it'. preflight.sh (make preflight; auto-run by provision): validates local CLIs, Hetzner token (401 vs unreachable), TS authkey format, tailscale up + MagicDNS, and a free server name — failing in seconds instead of a 15-min blind timeout after a billable box exists. Replaces provision's inline existing-server check. destroy.sh (make destroy; FORCE=/DRY_RUN=): deletes the Hetzner server and clears local SSH host-key state; prints the manual tailnet-node step. Adversarial-audit fixes before ship: destroy distinguishes API/auth error from '0 servers' (a REVOKED token — which the example tells you to revoke — no longer reads as 'nothing to delete' on a billing box); DRY_RUN/FORCE normalized so DRY_RUN=true can't delete; preflight name-check validates HTTP status (no fail-open free-name); refuses ambiguous duplicate names. CI now runs 'make check' as the single source of truth for the file list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Open-sourcing means strangers will clone this. The two things they hit that I never did (I had all the context): 'will this even work for me?' and 'how do I cleanly undo it?'. Today I personally hit the first — a stopped Tailscale client surfaced only as a cryptic
Could not resolve hostname, 15 minutes into a provision that had already created a billable server.What
Two lifecycle bookends, small shell, no new deps:
make preflight, auto-run by provision) — validates CLIs, Hetzner token (401 vs unreachable), authkey format, tailscale up + MagicDNS, free name. Fails in seconds, before spending money. Replaces provision's inline existing-server check.make destroy,FORCE=1/DRY_RUN=1) — deletes the server (billing stops), clears local host key, prints the one manual tailnet step.Deliberately NOT added (kept the repo's single purpose): multi-cloud, CONTRIBUTING scaffolding, optional-Claude, monitoring stacks.
Verified
preflight run live: 9 ✓ + correct ✗ on the taken name. destroy DRY_RUN: found the server, deleted nothing, box untouched. Adversarial review caught a money-losing false-safe (revoked token → 'nothing to delete') — fixed and reproduced: a bad token in secrets.env now makes destroy abort (HTTP 401, exit 1) and preflight ✗, verified with the real API then restored.
make checkgreen (shellcheck+bash -n+residue over all scripts); cloud-init schema + devproxy compile in CI.🤖 Generated with Claude Code