Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,39 @@ jobs:
command -v socket-patch
socket-patch --version

- name: Shell — run the installer against an alternate origin
# Exercises SOCKET_PATCH_BASE_URL (and SOCKET_PATCH_INSTALL_DIR) with a
# base that is not the default. Uses GitHub's own releases base, which
# is the same URL shape install.socket.dev serves, so the template the
# script builds is covered regardless of whether the Socket relay is
# deployed yet. The dedicated Socket-origin check is the next step.
run: |
SOCKET_PATCH_BASE_URL=https://github.com/SocketDev/socket-patch/releases \
SOCKET_PATCH_INSTALL_DIR="$RUNNER_TEMP/alt-origin" \
sh scripts/install.sh
"$RUNNER_TEMP/alt-origin/socket-patch" --version

- name: Shell — install through install.socket.dev, once it exists
# The whole point of the relay is that a client never has to reach
# github.com. That is only assertable against the deployed host, so this
# step skips itself until the host resolves rather than being red from
# the day it merges (same posture as the installer-drift workflow).
run: |
if ! curl -sfI -m 20 https://install.socket.dev/patch/latest >/dev/null 2>&1; then
echo "::notice::install.socket.dev/patch/latest does not answer yet — skipping the Socket-origin install."
exit 0
fi
latest=$(curl -fsSL -m 20 https://install.socket.dev/patch/latest)
echo "install.socket.dev reports latest=$latest"
SOCKET_PATCH_BASE_URL=https://install.socket.dev/SocketDev/socket-patch/releases \
SOCKET_PATCH_INSTALL_DIR="$RUNNER_TEMP/socket-origin" \
sh scripts/install.sh
installed=$("$RUNNER_TEMP/socket-origin/socket-patch" --version | awk '{print $NF}')
if [ "$installed" != "$latest" ]; then
echo "::error::install.socket.dev says latest is $latest but installed $installed" >&2
exit 1
fi

- name: Shell — the installer URL is consistent across the docs
# The README, the script's own usage comment, and the hosting runbook
# all name the canonical URL. Keeping them in lockstep is the whole
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,18 @@ into the new version's section — see docs/releasing.md.

### Changed

- **`install.sh` can install without reaching github.com.** New
`SOCKET_PATCH_BASE_URL` points the archive downloads at any releases base that
answers GitHub's two asset paths — notably
`https://install.socket.dev/SocketDev/socket-patch/releases`, which relays them
from the GitHub release, so one URL template covers either origin. A new
release needs no publish for this: the origin resolves "latest" per request.
`socket-patch --update` can use the same host today through the
`SOCKET_UPDATE_BASE_URL` override it already has. Also new:
`SOCKET_PATCH_INSTALL_DIR` to choose the install directory explicitly instead
of taking `/usr/local/bin` or `~/.local/bin`. The default download origin is
still GitHub — see `docs/installer-hosting.md`.

- **The documented one-liner installs from `https://install.socket.dev/patch`.**
The previous URL was `raw.githubusercontent.com`, which asks users to trust a
third-party CDN for a script they pipe into a shell and is the first URL a
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ against the release's `SHA256SUMS`, and installs to `/usr/local/bin` or `~/.loca
Use `sudo sh` instead of `sh` if `/usr/local/bin` requires root. Pin a version with
`SOCKET_PATCH_VERSION=3.3.0 sh` instead of plain `sh`.

On a network that blocks or distrusts `github.com`, set `SOCKET_PATCH_BASE_URL` so the
archives come from Socket too — `install.socket.dev` relays them from the GitHub release,
checksums included:

```bash
curl -fsSL https://install.socket.dev/patch \
| SOCKET_PATCH_BASE_URL=https://install.socket.dev/SocketDev/socket-patch/releases sh
```

`install.socket.dev` serves a copy of [`scripts/install.sh`](scripts/install.sh) from
this repository — read it before you run it, either there or at
[install.socket.dev/patch](https://install.socket.dev/patch). If you would rather not
Expand Down
53 changes: 49 additions & 4 deletions docs/installer-hosting.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,45 @@ it stays stable if the artifacts ever move.
The GitHub URL still works and still serves the same bytes. Anyone who would
rather not add a dependency on the Socket domain can keep using it.

## Installing without reaching github.com

By default the script downloads archives from the GitHub release. Point it
somewhere else with `SOCKET_PATCH_BASE_URL` — a releases base that answers
GitHub's two asset paths, `<base>/latest/download/<file>` and
`<base>/download/v<ver>/<file>`:

```sh
curl -fsSL https://install.socket.dev/patch \
| SOCKET_PATCH_BASE_URL=https://install.socket.dev/SocketDev/socket-patch/releases sh
```

`install.socket.dev` relays those exact paths from the GitHub release, which is
why one template covers both origins and the script needs no branching. It also
exposes a cleaner shape for humans and for scripts that want the version:

| Endpoint | Serves |
|---|---|
| `install.socket.dev/patch/latest` | the latest version as plain text (`3.4.0`) |
| `install.socket.dev/patch/dl/v3.4.0/<asset>` | that release's asset, immutably cached |
| `install.socket.dev/patch/dl/latest/<asset>` | the same asset from whatever is latest |

**A new release needs no publish for any of this.** "Latest" is resolved per
request against the upstream release, so cutting 3.4.0 makes it installable from
`install.socket.dev` immediately — nothing runs at release time.

`socket-patch --update` can use the same host today, with no changes to the CLI,
via the endpoint override it already has:

```sh
SOCKET_UPDATE_BASE_URL=https://install.socket.dev socket-patch --update
```

One caveat worth knowing before standardizing on that: a non-default
`SOCKET_UPDATE_BASE_URL` intentionally downgrades the downloaded binary's
version self-check from hard-fail to a warning, because the override is meant
for mirrors that may repackage. Making Socket's host a first-class endpoint set
that keeps the strict check is a CLI change, not a hosting one.

## What the trust model actually is

Unchanged by the hosting move, and worth being precise about:
Expand Down Expand Up @@ -83,9 +122,15 @@ mangled publish is caught even when the hash somehow matches expectations.
through a package manager or a release archive. A `patch.ps1` object on the
same host would be the natural addition — the hosting side already supports
it, nothing here does yet.
- **Objects must stay flat.** `gcs-bucket-server` interpolates the object name
into the GCS JSON API URL unencoded, so only bucket-root keys resolve
(`patch`, `patch.sha256`, `index.html`). A nested path like
`/patch/3.3.0/install.sh` would 404 until that is fixed on the depscan side.
- **Objects must stay flat** — for the *bucket-backed* paths only (`patch`,
`patch.sha256`, `index.html`). `gcs-bucket-server` interpolates the object name
into the GCS JSON API URL unencoded, so only bucket-root keys resolve. This
does not affect `/patch/dl/**`, which is relayed by a separate service and
never touches the bucket.
- **The default download origin is still GitHub.** The `SOCKET_PATCH_BASE_URL`
mechanism ships first; flipping the default to `install.socket.dev` is a
one-line change, deliberately held until the relay is verified in prod. A
script that defaults to a host which does not answer yet is a broken installer
for everyone running it from a git checkout or the raw GitHub URL.

[depscan]: https://github.com/SocketDev/depscan
42 changes: 36 additions & 6 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,33 @@ set -eu
#
# Override the version that gets installed by exporting SOCKET_PATCH_VERSION:
# curl -fsSL https://install.socket.dev/patch | SOCKET_PATCH_VERSION=3.0.0 sh
#
# Override where the archives come from with SOCKET_PATCH_BASE_URL — a releases
# base that answers GitHub's two asset paths, `<base>/latest/download/<file>`
# and `<base>/download/v<ver>/<file>`. Use it to install without reaching
# github.com at all:
#
# … | SOCKET_PATCH_BASE_URL=https://install.socket.dev/SocketDev/socket-patch/releases sh
#
# install.socket.dev relays those exact paths from the GitHub release, which is
# why one template covers both origins. Whichever origin is used, the archive is
# still verified against the SHA256SUMS fetched from that same origin.
#
# Override where the binary is installed with SOCKET_PATCH_INSTALL_DIR.

REPO="SocketDev/socket-patch"
BINARY="socket-patch"
VERSION="${SOCKET_PATCH_VERSION:-latest}"
# Releases base. Default is GitHub; see the SOCKET_PATCH_BASE_URL note above for
# installing through install.socket.dev instead. Trailing slashes are trimmed so
# a base with one does not produce `//download`.
RELEASES_BASE="${SOCKET_PATCH_BASE_URL:-https://github.com/${REPO}/releases}"
while :; do
case "$RELEASES_BASE" in
*/) RELEASES_BASE="${RELEASES_BASE%/}" ;;
*) break ;;
esac
done

# Detect platform
OS="$(uname -s)"
Expand Down Expand Up @@ -88,8 +111,13 @@ else
exit 1
fi

# Pick install directory
if [ -w /usr/local/bin ]; then
# Pick install directory. An explicit SOCKET_PATCH_INSTALL_DIR wins over both
# defaults — needed for unprivileged installs into a toolchain-managed prefix,
# and for testing the script without writing to a system path.
if [ -n "${SOCKET_PATCH_INSTALL_DIR:-}" ]; then
INSTALL_DIR="$SOCKET_PATCH_INSTALL_DIR"
mkdir -p "$INSTALL_DIR"
elif [ -w /usr/local/bin ]; then
INSTALL_DIR="/usr/local/bin"
else
INSTALL_DIR="${HOME}/.local/bin"
Expand All @@ -100,12 +128,14 @@ fi
TMPDIR="$(mktemp -d)"
trap 'rm -rf "$TMPDIR"' EXIT

# Pick the release path. "latest" resolves on GitHub's side; tagged versions are
# served from /releases/download/v<version>/.
# Pick the release path. "latest" is resolved by the origin (GitHub redirects;
# install.socket.dev resolves it against the upstream release), so the script
# never has to know the version number. Tagged versions are served from
# <base>/download/v<version>/.
if [ "$VERSION" = "latest" ]; then
BASE_URL="https://github.com/${REPO}/releases/latest/download"
BASE_URL="${RELEASES_BASE}/latest/download"
else
BASE_URL="https://github.com/${REPO}/releases/download/v${VERSION#v}"
BASE_URL="${RELEASES_BASE}/download/v${VERSION#v}"
fi

ARCHIVE="${BINARY}-${TARGET}.tar.gz"
Expand Down
Loading