From 26d2f1fddafc5f6d165eeb4512b38c2f2c8e7840 Mon Sep 17 00:00:00 2001 From: ecamli <107792368+erkancamli@users.noreply.github.com> Date: Sun, 13 Sep 2026 13:54:32 +0300 Subject: [PATCH 1/4] fix(arcup): accept a checksum file with no trailing newline --- arcup/arcup | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arcup/arcup b/arcup/arcup index 3590cd36..9d8f2042 100755 --- a/arcup/arcup +++ b/arcup/arcup @@ -656,7 +656,16 @@ verify_checksum_file() { local archive_name="$3" local expected_checksum expected_name actual_checksum - if ! read -r expected_checksum expected_name < "$checksum_path"; then + if [[ ! -r "$checksum_path" ]]; then + error "Checksum file is missing or unreadable: $checksum_path" + fi + + # `read` reports failure at EOF even when it populated the variables, which is + # what happens when the checksum file has no trailing newline. Inspect the parsed + # value rather than the exit status so a valid single-line file is still accepted. + read -r expected_checksum expected_name < "$checksum_path" || true + + if [[ -z "$expected_checksum" ]]; then error "Checksum file is empty: $checksum_path" fi From 00c4319515bad14c53c677b82a37395d7201449b Mon Sep 17 00:00:00 2001 From: ecamli <107792368+erkancamli@users.noreply.github.com> Date: Sun, 13 Sep 2026 13:54:34 +0300 Subject: [PATCH 2/4] fix(arcup): accept a checksum file with no trailing newline --- arcup/test_arcup.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arcup/test_arcup.sh b/arcup/test_arcup.sh index 49021191..23525a0c 100755 --- a/arcup/test_arcup.sh +++ b/arcup/test_arcup.sh @@ -119,6 +119,24 @@ test_checksum_validation() { printf '%s other-asset.tar.gz\n' "$checksum" > "$checksum_file" expect_fail "checksum filename mismatch fails" verify_checksum_file "$archive" "$checksum_file" "$archive_name" + + # A checksum file with no trailing newline is still a valid single-line file; + # `read` reports EOF for it even though the fields parsed fine. + printf '%s %s' "$checksum" "$archive_name" > "$checksum_file" + verify_checksum_file "$archive" "$checksum_file" "$archive_name" + pass "checksum file without trailing newline passes" + + printf '%s' "$checksum" > "$checksum_file" + verify_checksum_file "$archive" "$checksum_file" "$archive_name" + pass "bare checksum without filename or newline passes" + + : > "$checksum_file" + expect_fail "empty checksum file fails" verify_checksum_file "$archive" "$checksum_file" "$archive_name" + + printf '\n' > "$checksum_file" + expect_fail "blank-line checksum file fails" verify_checksum_file "$archive" "$checksum_file" "$archive_name" + + expect_fail "missing checksum file fails" verify_checksum_file "$archive" "$TEST_TMP/absent.sha256" "$archive_name" } test_download_error_lists_assets() { From 936bff20a79434b1754c38a5897b091eacb1cbaa Mon Sep 17 00:00:00 2001 From: ecamli <107792368+erkancamli@users.noreply.github.com> Date: Wed, 16 Sep 2026 09:41:35 +0300 Subject: [PATCH 3/4] chore(arcup): bump ARCUP_INSTALLER_VERSION to 0.2.1 The header comment asks for a bump on any change to this script, and self_update compares the two versions with version_gt, so an equal version means every existing install refuses the fix as "already up to date". Without this the checksum change would ship and reach nobody. --- arcup/arcup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcup/arcup b/arcup/arcup index 9d8f2042..1458f24a 100755 --- a/arcup/arcup +++ b/arcup/arcup @@ -6,7 +6,7 @@ set -euo pipefail # NOTE: if you make modifications to this script, please increment the version number. # WARNING: the SemVer pattern: major.minor.patch must be followed as we use it to determine if the script is up to date. -ARCUP_INSTALLER_VERSION="0.2.0" +ARCUP_INSTALLER_VERSION="0.2.1" REPO="${ARC_REPO:-circlefin/arc-node}" if [[ -n "${ARC_REPO:-}" ]] && [[ ! "$ARC_REPO" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then From e486e59aa015e0766824099e9c8985654cd0248a Mon Sep 17 00:00:00 2001 From: ecamli <107792368+erkancamli@users.noreply.github.com> Date: Wed, 16 Sep 2026 09:42:47 +0300 Subject: [PATCH 4/4] test(arcup): assert the error message, not just a non-zero exit expect_fail only checked that the call failed. The empty, blank-line and missing-file cases all failed on main too, for the wrong reason, so they were characterization tests rather than regression tests, and the new unreadable-file guard had no coverage at all. expect_fail_message pins the message. With the -r guard removed the missing-file case now fails and shows the raw bash redirection error plus an unbound-variable error from set -u, which is what the guard prevents. --- arcup/test_arcup.sh | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/arcup/test_arcup.sh b/arcup/test_arcup.sh index 23525a0c..c8c061d6 100755 --- a/arcup/test_arcup.sh +++ b/arcup/test_arcup.sh @@ -47,6 +47,25 @@ expect_fail() { pass "$name" } +# Like expect_fail, but also pins the message. Without this a test only proves the +# call exited non-zero, which it already did before the fix for the wrong reason. +expect_fail_message() { + local name="$1" + local expected="$2" + shift 2 + + if ( "$@" ) >"$TEST_TMP/expect_fail.out" 2>&1; then + cat "$TEST_TMP/expect_fail.out" >&2 + fail "$name" + fi + if ! grep -qF "$expected" "$TEST_TMP/expect_fail.out"; then + printf 'expected message: %s\nactual output:\n' "$expected" >&2 + cat "$TEST_TMP/expect_fail.out" >&2 + fail "$name" + fi + pass "$name" +} + test_version_normalization() { assert_eq "v1.2.3" "$(normalize_version "1.2.3")" "normalizes missing v prefix" assert_eq "v1.2.3" "$(normalize_version "v1.2.3")" "keeps v-prefixed version" @@ -131,12 +150,15 @@ test_checksum_validation() { pass "bare checksum without filename or newline passes" : > "$checksum_file" - expect_fail "empty checksum file fails" verify_checksum_file "$archive" "$checksum_file" "$archive_name" + expect_fail_message "empty checksum file fails" "Checksum file is empty" \ + verify_checksum_file "$archive" "$checksum_file" "$archive_name" printf '\n' > "$checksum_file" - expect_fail "blank-line checksum file fails" verify_checksum_file "$archive" "$checksum_file" "$archive_name" + expect_fail_message "blank-line checksum file fails" "Checksum file is empty" \ + verify_checksum_file "$archive" "$checksum_file" "$archive_name" - expect_fail "missing checksum file fails" verify_checksum_file "$archive" "$TEST_TMP/absent.sha256" "$archive_name" + expect_fail_message "missing checksum file fails" "Checksum file is missing or unreadable" \ + verify_checksum_file "$archive" "$TEST_TMP/absent.sha256" "$archive_name" } test_download_error_lists_assets() {