Self-Updating Script with Safe Replace Prompt
Add a secure self-update mechanism to a CLI script: version check against a release source, checksum/signature verification, atomic in-place replacement, and rollback — without leaving a half-written binary if the network drops mid-update.
- Target user
- Authors of distributed CLI tools that need to update in the field
- Difficulty
- Advanced
- Tools
- Claude, ChatGPT
The prompt
You are a senior tooling engineer who has shipped self-updating CLIs and knows the failure mode that matters most: never brick the tool you're updating. I will provide: - Where releases live (GitHub Releases, an internal URL, an artifact store) - The current version string and how it's embedded - Who runs the tool and how it's installed (single file, PATH location) Your job: 1. **Version check** — embed a `VERSION` constant. Fetch the latest version from the release source (GitHub API `/releases/latest`, a `VERSION` file, or tags). Compare with proper semver ordering (not string compare). Support `--check` (report only) vs `--update` (apply). Cache the check to avoid hammering the source every run; respect an opt-out env var. 2. **Download to temp, never in place** — download the new artifact to a temp file in the SAME filesystem as the target (so the final move is atomic). Use `curl -fsSL`/`wget` with a timeout and follow redirects; fail loudly on non-2xx. 3. **Verify before trusting** — REQUIRE a checksum (`sha256sum -c`) from the release, and verify a GPG/cosign signature if available. Refuse to install an artifact that fails verification. Never pipe a remote script straight into bash. 4. **Atomic replace** — once verified, `chmod +x` the temp file and `mv` it over the running script (rename is atomic on the same FS). Back up the old version first (`script.bak` or a versioned copy) so rollback is one command. 5. **Self-replacement gotcha** — handle updating the very file that's executing: do the swap, then re-exec or simply exit with a "updated to X, re-run" message; don't try to continue running the half-replaced file. 6. **Rollback + downgrade** — provide `--rollback` to restore the backup and a `--version X` to pin. Verify the new binary actually runs (`new --version`) before discarding the backup; auto-rollback if the smoke test fails. 7. **Safety + permissions** — detect when the install path needs root and instruct rather than silently failing; never widen permissions. Make the whole thing a no-op when offline. Output: (a) the self-update function/subcommand, (b) the verification + atomic-swap logic, (c) the rollback command, (d) the release-side checklist (publish checksum + signature), (e) failure-mode table (network drop, bad checksum, no perms). Bias toward: verify-before-replace, atomic same-filesystem moves, and always keeping a working rollback.