refactor(deploy): rewrite install.sh in POSIX sh with systemd + OpenRC support#132
Merged
Merged
Conversation
…C support - Convert from bash 4+ (assoc arrays, [[ ]], read -rp, echo -e, C-style for, process substitution) to POSIX sh that runs under dash and busybox ash. - i18n and capability tables collapse from declare -A into single case functions. - k3s-style init abstraction: detect_init sets INIT (openrc|systemd|none); svc_* dispatch layer; systemd unit + OpenRC supervise-daemon generators. - OpenRC service writes output_log/error_log + logrotate (no journald there). - sha256 verification of downloaded binaries (warn-and-continue for releases without sha256sums.txt). - doas/sudo privilege handling via re-exec when not root. - apk Caddy branch + init-aware Caddy enable/start for Alpine. - Verified: dash -n, busybox ash -n, shellcheck --severity=warning all clean.
uninstall --purge relied on a best-effort rmdir of the base directory, which silently failed whenever a prior non-purge uninstall of the other component left files behind, leaving /opt/serverbee in place. When purge is requested and no components remain, remove the base directory recursively; the non-purge path still only drops already-empty dirs so kept config and data are preserved.
Add an install-script lint job to ci.yml running dash -n and shellcheck --shell=dash on deploy/install.sh, so bashisms and POSIX syntax regressions are caught in CI. Rename the release checksum asset from checksums.txt to sha256sums.txt: install.sh fetches the sha256sums.txt name for binary verification, so the old name meant the checksum step could never find its file and always fell through to the warn-and-skip path. Also hash only serverbee-* to avoid self-including the sums file in the glob.
systemd uses RestartPreventExitStatus=78 to stop the agent when enrollment fails permanently (exit 78), so it does not burn the registration rate limit in a tight respawn loop. OpenRC's supervise-daemon has no per-exit-code equivalent, so a bad enrollment code would respawn-loop forever. Add respawn_max=5 + respawn_period=300 to the OpenRC agent init script, mirroring the systemd unit's StartLimitBurst=5 / StartLimitIntervalSec=300: more than 5 respawns within 300s and supervise-daemon gives up. Verified end-to-end on a privileged Alpine OpenRC container: a bogus enrollment code produces exactly 5 'Permanent registration failure' log lines, then supervise-daemon stops respawning and the service reports stopped (no infinite loop). Full OpenRC install/agent/lifecycle/ uninstall e2e recorded in tests/manual/agent-recover-e2e.md section 11.
The installer is now POSIX sh, so the bootstrap pipe should invoke sh instead of bash — on minimal systems (e.g. Alpine) bash may be absent, which is exactly the case the rewrite targets. Updates both READMEs, all docs install snippets (en/zh), and the landing page command.
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.
Summary
Rewrites
deploy/install.shfrom a bash script into portable POSIXsh, adding first-class OpenRC support alongside systemd so the installer works on Alpine and other non-systemd distros. Adds a CI lint gate and release checksum verification, plus an end-to-end VPS test runbook.What changed
deploy/install.sh(POSIX rewrite, ~2200 net lines)dash -nandshellcheck --shell=dash.svc_*) with three backends: systemd, OpenRC (supervise-daemon + logrotate), and none (manual-start fallback).sudo/doasinstead of prefixing every command..install-metatracking, and theserverbeemanagement CLI.CI / release
ci.yml: newinstall-scriptjob runsdash -n+shellcheck --shell=dash --severity=warning.release.yml: emitsha256sums.txt; the installer verifies downloaded binaries against it (older releases without the file warn-and-continue).Docs / tests
docs/superpowers/.tests/manual/agent-recover-e2e.mde2e runbook.Review follow-ups (included as separate commits)
A code review of the rewrite surfaced these, each fixed in its own commit:
fix(deploy): matchsha256sumson the exact filename field (no substring/regex match on the security-verification path)fix(deploy): print(no logs)when service/docker log output is genuinely empty (sedexits 0 on empty input, so the prior||fallback was dead code)fix(deploy): preserve the section separator whentoml_setappends a key into an existing sectionfix(deploy): forwardSERVERBEE_*/LANG_CODEenv acrossdoaselevation (doas has nosudo -Eequivalent)fix(deploy):--purgeremoves the snap Docker config dir so no empty husk lingersdocs(deploy): clarify the OpenRC respawn bound is a weaker guarantee than systemd'sRestartPreventExitStatus=78Testing
dash -n deploy/install.sh— cleanshellcheck --shell=dash --severity=warning deploy/install.sh— clean (matches the new CI gate)toml_setkey-insertion (mid-section and end-of-file), checksum exact-match, anddoas envargv assembly verified locally with standalone harnesses.Full VPS end-to-end (
tests/manual/full-deploy-e2e.md) not yet run on this branch.