diff --git a/README.md b/README.md index aef43d0591d..1e058880686 100644 --- a/README.md +++ b/README.md @@ -314,7 +314,9 @@ bash install.sh The installer ensures Node.js 20 or newer is available, installs a managed Paperclip CLI under `~/.paperclip/cli`, and starts interactive onboarding. It can also install Paperclip as a background service on supported Linux and -macOS systems. +macOS systems. The checksum detects transfer or publishing mistakes, but it is +served from the same origin as the script; use a release-tag or commit-pinned +GitHub copy when you need an independently hosted source. For a non-interactive managed install: @@ -323,6 +325,11 @@ curl -fsSL https://paperclip.ing/install.sh | bash -s -- --no-prompt --no-onboar paperclipai onboard --yes ``` +The piped form requires supported Node.js, npm, and npx to already be present. +If Node.js bootstrap is required, download and review `install.sh` before +running it so no privileged dependency-install command is accepted through a +pipe. + To try Paperclip without installing anything permanently: ```bash diff --git a/doc/CLI.md b/doc/CLI.md index 1898819c012..5b36f799589 100644 --- a/doc/CLI.md +++ b/doc/CLI.md @@ -27,6 +27,12 @@ fi bash install.sh ``` +The checksum detects transfer or publishing mistakes but is served from the +same origin as the installer. Use a release-tag or commit-pinned GitHub copy +when you need an independently hosted source. Piped installs require supported +Node.js, npm, and npx to already be installed; download the script first before +allowing it to bootstrap Node.js with privileged package-manager commands. + First-time local bootstrap from a source checkout: ```sh diff --git a/doc/INSTALLING.md b/doc/INSTALLING.md index 1222e1cb3dc..791910daf1e 100644 --- a/doc/INSTALLING.md +++ b/doc/INSTALLING.md @@ -30,7 +30,15 @@ The bootstrap script: The script prints and confirms any command that requires elevated privileges. Third-party Node.js bootstrap scripts are pinned and SHA-256 verified before execution; the installer stops if a published script changes unexpectedly. -Use `--no-prompt` for automation and `--no-onboard` to stop after installing: +The `paperclip.ing` checksum detects transfer or publishing mistakes, but it is +served from the same origin as the script and is not an independent +authenticity proof. For an independently hosted source, download a release-tag +or commit-pinned copy from GitHub, review it, and run that local file. + +Use `--no-prompt` for automation and `--no-onboard` to stop after installing. +The piped form only proceeds when supported Node.js, npm, and npx are already +installed; if Node.js bootstrap is required, download the script first so the +privileged commands are inspectable before execution: ```sh curl -fsSL https://paperclip.ing/install.sh | bash -s -- --no-prompt --no-onboard @@ -45,9 +53,10 @@ raw_base=https://raw.githubusercontent.com/paperclipai/paperclip curl -fsSL "$raw_base/master/scripts/install.sh" | bash ``` -For audits or incident response, pin the raw URL to a release tag or commit -SHA instead of `master`, download it first, and compare it with the published -checksum at `https://paperclip.ing/install.sh.sha256`. +For audits or incident response, pin the raw URL to a release tag or commit SHA +instead of `master` and download it first. That immutable GitHub URL provides a +separate delivery path from `paperclip.ing`; do not treat a checksum served by +the same origin as the artifact as an independent trust anchor. Each installer flag also has a `PAPERCLIP_INSTALL_*` environment-variable equivalent. This helps where passing arguments through a pipe is awkward. diff --git a/scripts/install.sh b/scripts/install.sh index 0220ec22273..2eceb01031e 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -20,6 +20,11 @@ INSTALL_SERVICE=0 DRY_RUN=0 VERBOSE=0 TEMP_DIR="" +PIPED_INSTALL=0 + +if [ -z "${BASH_SOURCE[0]:-}" ] || [ ! -f "${BASH_SOURCE[0]}" ]; then + PIPED_INSTALL=1 +fi usage() { cat <<'EOF' @@ -335,6 +340,9 @@ else else log "Node.js was not found" fi + if [ "$PIPED_INSTALL" = "1" ]; then + fail "Node.js bootstrap is disabled for piped installs; download install.sh, review it, and run 'bash install.sh --no-prompt'" + fi check_version_manager log "Installing Node.js $DEFAULT_NODE_MAJOR" if [ "$OS_NAME" = "macos" ]; then diff --git a/scripts/test-install-sh-docker.sh b/scripts/test-install-sh-docker.sh index 7b80b0233ad..741c138cf9f 100755 --- a/scripts/test-install-sh-docker.sh +++ b/scripts/test-install-sh-docker.sh @@ -111,6 +111,18 @@ echo "==> piped --no-prompt" run_with_node piped bash -c 'cat /paperclip-scripts/install.sh | bash -s -- --no-prompt --no-onboard' assert_line "$RESULTS_DIR/piped.args" "--yes" +echo "==> piped mode refuses privileged Node bootstrap" +if docker run --rm \ + -v "$REPO_ROOT/scripts:/paperclip-scripts:ro" \ + -e PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \ + ubuntu:24.04 \ + bash -c 'cat /paperclip-scripts/install.sh | bash -s -- --no-prompt --no-onboard' \ + >"$RESULTS_DIR/piped-no-node.out" 2>&1; then + echo "Expected piped install without Node.js to fail before privileged bootstrap" >&2 + exit 1 +fi +assert_line "$RESULTS_DIR/piped-no-node.out" "[paperclip] error: Node.js bootstrap is disabled for piped installs; download install.sh, review it, and run 'bash install.sh --no-prompt'" + echo "==> dry run" run_with_node dry-run bash /paperclip-scripts/install.sh --no-prompt --dry-run --no-onboard [ ! -e "$RESULTS_DIR/dry-run.args" ] || {