Skip to content

installer: sync install.sh with canonical, guard the drift in CI - #432

Merged
TeoSlayer merged 2 commits into
mainfrom
fix/sync-install-sh-canonical
Jul 28, 2026
Merged

installer: sync install.sh with canonical, guard the drift in CI#432
TeoSlayer merged 2 commits into
mainfrom
fix/sync-install-sh-canonical

Conversation

@TeoSlayer

Copy link
Copy Markdown
Collaborator

Problem

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 shellsbash -c 'pilotctl version' failed after a successful install.
  2. jq in the post-install guide — the installer never installs it. This copy mentioned jq five times, the most of the three copies in the org.
  3. 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".

Fix

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 — 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.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.

Verification

These exact bytes were run in fresh debian:12 containers as a non-root user, with and without passwordless sudo. Install exits 0 in both; bash -c 'pilotctl version' prints v1.13.7 from a new shell in both; the printed GET STARTED block contains no jq invocation.

🤖 Generated with Claude Code

teovl and others added 2 commits July 27, 2026 18:04
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
TeoSlayer enabled auto-merge (squash) July 27, 2026 15:23

@matthew-pilot matthew-pilot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All checks green. Auto-merge is already enabled.

@TeoSlayer
TeoSlayer merged commit c967c67 into main Jul 28, 2026
22 of 25 checks passed
@matthew-pilot
matthew-pilot deleted the fix/sync-install-sh-canonical branch July 28, 2026 08:58
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants