Skip to content

Add an idempotent Bash installer for CI fleet hosts #21

Description

@Nickfost

Goal

Replace the manual host deployment sequence with a repository-owned Bash installer so a prepared generic Docker host can be enrolled, verified, upgraded, repaired, or replaced consistently.

Required interface

Provide a command such as:

sudo ./scripts/install-host.sh --config /etc/ci-fleet/ci-fleet.env

The script must use strict Bash mode, provide useful errors, and be safe to rerun.

Responsibilities

  • verify supported Linux, root privileges, Docker Engine, Compose v2, Git, curl, jq, CA certificates, disk capacity, and Docker socket access;
  • validate the host-local configuration without printing secrets;
  • create root-owned directories and enforce required permissions;
  • require the GitHub App PEM to already exist at the configured host-local path;
  • run the existing preflight checks;
  • build the pinned runner and controller images;
  • install or update healthcheck and scoped-cleanup systemd units/timers;
  • start the controller at the configured minimum/maximum capacity;
  • verify controller health, image identity, and managed-container state;
  • support --check, --install, --upgrade, and --uninstall or equivalent explicit modes;
  • never use global Docker prune;
  • never create, display, copy, or commit GitHub credentials;
  • never modify GitHub runner-group repository access;
  • never install project-specific runtimes;
  • leave existing project runners and unrelated Docker workloads untouched;
  • stop with a precise error if GitHub-side prerequisites are missing.

Operational requirements

  • Idempotent: a successful second run makes no unnecessary changes.
  • Transactional where practical: do not replace a healthy controller until the new image/configuration passes validation.
  • Rollback-capable: retain or identify the previously working image/configuration.
  • Pinned: record the deployed ci-fleet commit and image identifiers.
  • Noninteractive by default after the config and PEM exist.
  • Produce a concise final report suitable for an operator or automation agent.
  • Document the one-command fresh-install, upgrade, repair, validation, and removal procedures.

Acceptance

On a fresh Debian Docker VM, an operator should only need to:

  1. install/checkout a reviewed ci-fleet commit;
  2. place the host-local configuration and GitHub App PEM;
  3. run one Bash command;
  4. receive a verified controller, maintenance timers, and an actionable final report.

The same command must safely converge an already-installed host without duplicate controllers, scale sets, timers, or unmanaged residue.

Target-host and phone-first experience

The complete setup must be runnable directly on the target Linux Docker host without OpenClaw, another agent, or a separate workstation. An automation agent may invoke the same command, but it must not be part of the architecture.

Expected operator experience:

  1. connect to the new VM or bare-metal host using a terminal;
  2. checkout a reviewed release or commit;
  3. run one Bash setup command;
  4. open at most the required safe GitHub approval links on a phone;
  5. return to the terminal and receive a verified completed installation.

The target host should serve any short-lived registration/callback endpoint itself, receive and exchange temporary codes locally, store its own PEM directly, and destroy the temporary endpoint and state afterward. No credential or temporary code may need to pass through chat, clipboard, email, an agent, or another machine.

The script should print phone-friendly HTTPS/GitHub links and may optionally render a QR code. It must clearly distinguish safe approval links from secrets. It must work on a VM or bare-metal Linux Docker host reachable from the operator's phone over an explicitly selected LAN or private-network interface.

Rerunning the same command later must check, repair, upgrade, or safely converge the existing installation rather than requiring a separate undocumented recovery process.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions