installer: sync install.sh with canonical, guard the drift in CI - #432
Merged
Conversation
This repo's install.sh is a COPY. The script users actually run is served from https://pilotprotocol.network/install.sh by the pilot-release Worker out of R2, sourced from pilot-protocol/release:install.sh. This copy had drifted 3 days and ~16KB behind canonical (38,150 vs 53,917 bytes) and still carried three defects already fixed upstream: 1. PATH invisible to non-interactive shells — `bash -c 'pilotctl version'` failed after a successful install. 2. The post-install guide piped replies through `jq`, which the installer never installs. This copy mentioned jq five times, the most of the three copies in the org. 3. It emitted `pilotctl gateway start ...`. Gateway is extras-only in the core CLI — cmd/pilotctl/main.go:1737 hard-errors on the bare form with "gateway commands are not in the core CLI". install.sh is now byte-identical to release@c8fcaa9 (sha256 4c0babf9…), which is also exactly what the live URL serves. README fixes for the same drift: - The demo showed `sudo pilotctl gateway start` — the form that hard-errors. Now `pilotctl extras gateway start`. - "What the installer does" claimed it installs pilot-gateway. Release tarballs ship daemon/pilotctl/updater only; I confirmed against the v1.13.7 artifacts. Reworded so nobody re-derives the dependency that broke fresh installs for ~6 weeks. The CI gap: install-test.yml only asserted that the updater got enabled, so it passed green throughout the drift, while the canonical script had no installer CI at all. Added a canonical-drift job that diffs this copy against the release repo and fails on any difference. Testing a copy that no user runs is theatre. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The two install-test jobs on this PR failed, and correctly so: syncing to
canonical would have regressed this repo's auto-updater activation.
The canonical script writes the systemd unit / LaunchAgent but never enables
or loads it, so `systemctl is-enabled pilot-updater` reported `disabled` and
launchctl had no job — while ~/.pilot/auto-update.json said {"enabled": true}
and the consent block promised auto-updates were on.
That gap is now fixed at the source in pilot-protocol/release#42, and this
commit picks up the fixed canonical script. install.sh here is byte-identical
to that branch, so the canonical-drift job will go green once release#42
merges.
This is exactly the regression install-test.yml was built to catch, and it
caught it. The reason it never fired before is that it only ever guarded this
repo's copy — which no user runs — while the canonical script served at
https://pilotprotocol.network/install.sh had no installer CI at all. The
canonical-drift job added in the previous commit closes that hole permanently.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
TeoSlayer
added a commit
to pilot-protocol/release
that referenced
this pull request
Jul 27, 2026
The installer writes /etc/systemd/system/pilot-updater.service (Linux) and
~/Library/LaunchAgents/network.pilotprotocol.pilot-updater.plist (macOS), and
it writes ~/.pilot/auto-update.json with {"enabled": true} while printing
"Auto-updates ENABLED (opt-out)". The consent block goes further and promises:
AUTO-UPDATES (on by default)
The pilot-updater service checks GitHub for new stable releases and
installs them automatically.
None of that was true. The unit and the plist were written but never
activated, so on a fresh install `systemctl is-enabled pilot-updater` reports
`disabled` / `inactive (dead)` and launchctl has no such job. Every install
from https://pilotprotocol.network/install.sh stays pinned on whatever release
shipped at install time and never receives a security or perf fix — silently,
while telling the operator the opposite.
This is not a recent regression: `git log -S` finds no commit in this repo that
ever added the activation. The fix exists in pilot-protocol/pilotprotocol's
copy of install.sh (added specifically to close this gap, and guarded there by
install-test.yml), but the two scripts had forked, and the copy served to users
is this one — the one that never got it. The guard never covered the canonical
script, so CI stayed green while the live installer shipped the defect.
Ported both branches verbatim from the working copy:
- Linux: `sudo systemctl enable --now pilot-updater`, non-fatal on failure.
- macOS: unload-then-`launchctl load -w` on the updater plist, which keeps
re-running install.sh (the upgrade path) idempotent.
The daemon is deliberately left opt-in on both platforms — it has
operator-tunable flags (-public, -hostname, registry overrides) that an
operator may want to set before first start. Only the updater is auto-started.
Verified on real GitHub-hosted ubuntu-latest and macos-latest runners via
pilot-protocol/pilotprotocol#432, which asserts the updater is enabled+active
(Linux) and loaded (macOS) after a non-interactive install.
Co-authored-by: Teodor Calin <teodor@vulturelabs.io>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
TeoSlayer
enabled auto-merge (squash)
July 27, 2026 15:23
matthew-pilot
approved these changes
Jul 28, 2026
matthew-pilot
left a comment
Collaborator
There was a problem hiding this comment.
All checks green. Auto-merge is already enabled.
TeoSlayer
added a commit
that referenced
this pull request
Jul 28, 2026
The canonical-drift job added in #432 went red on main immediately after that PR merged, which is the guard doing exactly its job on its first real run. pilot-protocol/release#43 landed overnight — "fix empty -email flag breaking the default install, and make re-runs safe" — so canonical moved from 988ddeb to 906deea while this repo's copy stayed at 988ddeb. That follow-up is a direct consequence of #432/release#42: once the installer actually started the services instead of only writing the unit files, a unit generated with an empty `-email ` flag became a real failure rather than dead config. release#43 adds a privilege gate (CAN_PRIV / PILOT_SUDO, never prompting), recovers an existing email from account.json/config.json on every run so re-runs don't drop the operator's address, and skips synthesised @nodes.pilotprotocol.network placeholders so they can't harden into an override that defeats a later `pilotctl set-email`. install.sh here is now byte-identical to release@51894f1 (sha256 906deea1…), which is also what the live URL serves. Co-authored-by: Teodor Calin <teodor@vulturelabs.io> Co-authored-by: Claude Opus 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.
Problem
This repo's
install.shis a copy. The script users actually run is served fromhttps://pilotprotocol.network/install.shby the pilot-release Worker out of R2, sourced frompilot-protocol/release:install.sh.This copy had drifted 3 days and ~16KB behind canonical (38,150 vs 53,917 bytes) and still carried three defects already fixed upstream:
bash -c 'pilotctl version'failed after a successful install.jqin the post-install guide — the installer never installs it. This copy mentionedjqfive times, the most of the three copies in the org.pilotctl gateway start ...— gateway is extras-only in the core CLI.cmd/pilotctl/main.go:1737hard-errors on the bare form with "gateway commands are not in the core CLI".Fix
install.shis now byte-identical torelease@c8fcaa9(sha2564c0babf9…), which is also exactly what the live URL serves.README fixes for the same drift:
sudo pilotctl gateway start— the form that hard-errors. Nowpilotctl extras gateway start.pilot-gateway. Release tarballs shipdaemon/pilotctl/updateronly — confirmed by unpacking the v1.13.7 artifacts. Reworded so nobody re-derives the dependency that broke fresh installs for ~6 weeks.The CI gap
install-test.ymlonly asserted that the updater got enabled, so it passed green throughout the drift — while the canonical script had no installer CI at all.Added a
canonical-driftjob that diffs this copy against the release repo and fails on any difference. Testing a copy that no user runs is theatre.Verification
These exact bytes were run in fresh
debian:12containers as a non-root user, with and without passwordless sudo. Install exits 0 in both;bash -c 'pilotctl version'printsv1.13.7from a new shell in both; the printed GET STARTED block contains nojqinvocation.🤖 Generated with Claude Code