Fix nightly SSH remote daemon checksum mismatch (#2225)

* Fix nightly SSH remote daemon checksum mismatch

Each nightly build overwrites the shared cmuxd-remote-* assets on the
nightly release, but older nightly DMGs have manifests with checksums
from their build time. When a user's nightly is even one build behind,
the downloaded binary doesn't match their embedded manifest.

Two-layer fix:

1. CI: version nightly remote daemon asset names with the build number
   (e.g. cmuxd-remote-darwin-arm64-2362248028801) so each nightly's
   manifest points to immutable files. Unsuffixed "latest" copies are
   still uploaded for tooling compatibility.

2. Client: on checksum mismatch, fetch the live manifest from the
   release and verify against that. This handles users on older
   nightlies that predate the CI fix.

Fixes https://github.com/manaflow-ai/cmux/issues/1745

* Fix unsuffixed checksums file to use generic filenames

Regenerate cmuxd-remote-checksums.txt from the unsuffixed alias
binaries so `shasum -c` works against the generic asset names.
Also document that unsuffixed manifest intentionally keeps versioned
downloadURLs and that aliases don't carry attestation.

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
This commit is contained in:
Lawrence Chen 2026-03-26 17:24:37 -07:00 committed by GitHub
parent 1b03d23fee
commit ccd84bd578
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 148 additions and 34 deletions

View file

@ -7,12 +7,17 @@ Usage: scripts/build_remote_daemon_release_assets.sh \
--version <app-version> \
--release-tag <tag> \
--repo <owner/repo> \
--output-dir <dir>
--output-dir <dir> \
[--asset-suffix <suffix>]
Builds cmuxd-remote release assets for the supported remote platforms and emits:
cmuxd-remote-<goos>-<goarch>
cmuxd-remote-checksums.txt
cmuxd-remote-manifest.json
cmuxd-remote-<goos>-<goarch>[-<suffix>]
cmuxd-remote-checksums[-<suffix>].txt
cmuxd-remote-manifest[-<suffix>].json
When --asset-suffix is provided, all output filenames and manifest download URLs
include the suffix, making each build's assets immutable (used by nightly builds
to avoid checksum mismatches when assets are overwritten by later builds).
EOF
}
@ -20,6 +25,7 @@ VERSION=""
RELEASE_TAG=""
REPO=""
OUTPUT_DIR=""
ASSET_SUFFIX=""
while [[ $# -gt 0 ]]; do
case "$1" in
@ -39,6 +45,10 @@ while [[ $# -gt 0 ]]; do
OUTPUT_DIR="${2:-}"
shift 2
;;
--asset-suffix)
ASSET_SUFFIX="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
@ -77,9 +87,14 @@ DAEMON_GO_BUILD_ARGS=(
-ldflags "$DAEMON_GO_LDFLAGS"
)
CHECKSUMS_ASSET_NAME="cmuxd-remote-checksums.txt"
SUFFIX_TAG=""
if [[ -n "$ASSET_SUFFIX" ]]; then
SUFFIX_TAG="-${ASSET_SUFFIX}"
fi
CHECKSUMS_ASSET_NAME="cmuxd-remote-checksums${SUFFIX_TAG}.txt"
CHECKSUMS_PATH="${OUTPUT_DIR}/${CHECKSUMS_ASSET_NAME}"
MANIFEST_PATH="${OUTPUT_DIR}/cmuxd-remote-manifest.json"
MANIFEST_PATH="${OUTPUT_DIR}/cmuxd-remote-manifest${SUFFIX_TAG}.json"
TARGETS=(
"darwin arm64"
@ -95,18 +110,22 @@ trap 'rm -f "$ENTRIES_FILE"' EXIT
for target in "${TARGETS[@]}"; do
read -r GOOS GOARCH <<<"$target"
ASSET_NAME="cmuxd-remote-${GOOS}-${GOARCH}"
ASSET_NAME="cmuxd-remote-${GOOS}-${GOARCH}${SUFFIX_TAG}"
OUTPUT_PATH="${OUTPUT_DIR}/${ASSET_NAME}"
# Build into a temp path first, then rename (the binary content is the same
# regardless of suffix, so we build once and move).
BUILD_PATH="${OUTPUT_DIR}/cmuxd-remote-${GOOS}-${GOARCH}.build"
(
cd "$DAEMON_ROOT"
GOOS="$GOOS" \
GOARCH="$GOARCH" \
CGO_ENABLED=0 \
go "${DAEMON_GO_BUILD_ARGS[@]}" \
-o "$OUTPUT_PATH" \
-o "$BUILD_PATH" \
./cmd/cmuxd-remote
)
mv "$BUILD_PATH" "$OUTPUT_PATH"
chmod 755 "$OUTPUT_PATH"
SHA256="$(shasum -a 256 "$OUTPUT_PATH" | awk '{print $1}')"