From e8a32787aa7fc0e59785e93ccca257aa474f4cbf Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Mon, 24 Aug 2026 10:12:05 -0400 Subject: [PATCH 1/6] Add files via upload --- .github/workflows/update-merlin-sha256.yml | 116 +++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 .github/workflows/update-merlin-sha256.yml diff --git a/.github/workflows/update-merlin-sha256.yml b/.github/workflows/update-merlin-sha256.yml new file mode 100644 index 00000000..21af39e5 --- /dev/null +++ b/.github/workflows/update-merlin-sha256.yml @@ -0,0 +1,116 @@ +name: Update Merlin SHA256 Checksums + +on: + schedule: + # Every 15 minutes, offset from the top of the hour to reduce scheduler congestion. + - cron: '7,22,37,52 * * * *' + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: update-merlin-sha256 + cancel-in-progress: false + +jobs: + scrape-and-commit: + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - name: Checkout repository + uses: actions/checkout@v7 + + - name: Fetch, parse, and validate SHA256 signatures + shell: bash + run: | + set -euo pipefail + + readonly SOURCE_URL='https://www.asuswrt-merlin.net/download' + readonly TARGET_FILE='merlin-sha256.txt' + readonly MIN_EXPECTED_ENTRIES=5 + + page_file="$(mktemp)" + candidate_file="$(mktemp)" + trap 'rm -f "$page_file" "$candidate_file"' EXIT + + echo "Fetching SHA256 signatures from ${SOURCE_URL}..." + curl --fail --location --silent --show-error \ + --retry 4 --retry-delay 5 --retry-connrefused \ + --connect-timeout 15 --max-time 60 \ + --user-agent 'MerlinAutoUpdate checksum mirror (+https://github.com/ExtremeFiretop/MerlinAutoUpdate-Router)' \ + --output "$page_file" \ + "$SOURCE_URL" + + # Keep the same source section MerlinAU consumes today, but write to a + # temporary candidate so a scrape/parser failure cannot destroy the + # last-known-good mirror in the repository. + sed -n '/<.*>SHA256 signatures:<\/.*>/,/<\/pre>/p' "$page_file" | \ + sed -n '/]*>/,/<\/pre>/p' | \ + sed -e 's/<[^>]*>//g; s/^[[:space:]]*//; s/[[:space:]]*$//' | \ + tr -d '\r' | \ + sed '/^[[:space:]]*$/d' > "$candidate_file" + + echo "Validating candidate checksum list..." + awk -v min_entries="$MIN_EXPECTED_ENTRIES" ' + BEGIN { + valid = 1 + count = 0 + } + { + count++ + + if (NF != 2) { + printf "Invalid field count on line %d: %s\n", NR, $0 > "/dev/stderr" + valid = 0 + next + } + + if (length($1) != 64 || $1 ~ /[^0-9A-Fa-f]/) { + printf "Invalid SHA256 on line %d: %s\n", NR, $1 > "/dev/stderr" + valid = 0 + } + + if (seen[$2]++) { + printf "Duplicate firmware filename on line %d: %s\n", NR, $2 > "/dev/stderr" + valid = 0 + } + } + END { + if (count < min_entries) { + printf "Only %d checksum entries were parsed; expected at least %d.\n", count, min_entries > "/dev/stderr" + valid = 0 + } + + if (!valid) + exit 1 + } + ' "$candidate_file" + + echo "Validated $(wc -l < "$candidate_file") checksum entries." + echo "Candidate preview:" + head -n 5 "$candidate_file" + + # Replace the working-tree copy only after the candidate has passed + # every validation check. A failed run therefore leaves the repository + # and its last-known-good checksum mirror unchanged. + mv -f "$candidate_file" "$TARGET_FILE" + + - name: Commit and push changes + shell: bash + run: | + set -euo pipefail + + git config user.name 'github-actions[bot]' + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + + git add merlin-sha256.txt + + if git diff --cached --quiet; then + echo 'No checksum changes detected. Nothing to commit.' + exit 0 + fi + + git commit -m 'Automated update: refresh Merlin SHA256 checksums' + git push From a05b021e242c4c2f9710d3de7682dd0d86be2e42 Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Mon, 24 Aug 2026 10:19:28 -0400 Subject: [PATCH 2/6] Add files via upload --- .github/workflows/update-merlin-sha256.yml | 32 ++++++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/.github/workflows/update-merlin-sha256.yml b/.github/workflows/update-merlin-sha256.yml index 21af39e5..838531a2 100644 --- a/.github/workflows/update-merlin-sha256.yml +++ b/.github/workflows/update-merlin-sha256.yml @@ -36,12 +36,32 @@ jobs: trap 'rm -f "$page_file" "$candidate_file"' EXIT echo "Fetching SHA256 signatures from ${SOURCE_URL}..." - curl --fail --location --silent --show-error \ - --retry 4 --retry-delay 5 --retry-connrefused \ - --connect-timeout 15 --max-time 60 \ - --user-agent 'MerlinAutoUpdate checksum mirror (+https://github.com/ExtremeFiretop/MerlinAutoUpdate-Router)' \ - --output "$page_file" \ - "$SOURCE_URL" + + http_code="$( + curl --location --silent --show-error \ + --retry 4 --retry-delay 5 --retry-connrefused \ + --connect-timeout 15 --max-time 60 \ + --user-agent 'MerlinAutoUpdate checksum mirror (+https://github.com/ExtremeFiretop/MerlinAutoUpdate-Router)' \ + --output "$page_file" \ + --write-out '%{http_code}' \ + "$SOURCE_URL" + )" + + echo "HTTP response code: ${http_code}" + echo "Downloaded page size: $(wc -c < "$page_file") bytes" + + echo "Relevant response markers:" + grep -iE 'SHA256|signature|forbidden|blocked|access denied|cloudflare|captcha|wix|error' \ + "$page_file" | head -n 30 || true + + echo "First 5000 bytes of returned document:" + head -c 5000 "$page_file" + echo + + if [[ ! "$http_code" =~ ^2[0-9][0-9]$ ]]; then + echo "ERROR: Source returned HTTP ${http_code}." >&2 + exit 1 + fi # Keep the same source section MerlinAU consumes today, but write to a # temporary candidate so a scrape/parser failure cannot destroy the From 5999d3f3aeb22c47e55368b9d04377a72152881d Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Mon, 24 Aug 2026 10:31:48 -0400 Subject: [PATCH 3/6] Add files via upload --- .github/workflows/update-merlin-sha256.yml | 37 ++++++---------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/.github/workflows/update-merlin-sha256.yml b/.github/workflows/update-merlin-sha256.yml index 838531a2..d1261e53 100644 --- a/.github/workflows/update-merlin-sha256.yml +++ b/.github/workflows/update-merlin-sha256.yml @@ -36,39 +36,22 @@ jobs: trap 'rm -f "$page_file" "$candidate_file"' EXIT echo "Fetching SHA256 signatures from ${SOURCE_URL}..." - - http_code="$( - curl --location --silent --show-error \ - --retry 4 --retry-delay 5 --retry-connrefused \ - --connect-timeout 15 --max-time 60 \ - --user-agent 'MerlinAutoUpdate checksum mirror (+https://github.com/ExtremeFiretop/MerlinAutoUpdate-Router)' \ - --output "$page_file" \ - --write-out '%{http_code}' \ - "$SOURCE_URL" - )" - - echo "HTTP response code: ${http_code}" - echo "Downloaded page size: $(wc -c < "$page_file") bytes" - - echo "Relevant response markers:" - grep -iE 'SHA256|signature|forbidden|blocked|access denied|cloudflare|captcha|wix|error' \ - "$page_file" | head -n 30 || true - - echo "First 5000 bytes of returned document:" - head -c 5000 "$page_file" - echo - - if [[ ! "$http_code" =~ ^2[0-9][0-9]$ ]]; then - echo "ERROR: Source returned HTTP ${http_code}." >&2 - exit 1 - fi + curl --fail --location --silent --show-error \ + --retry 4 --retry-delay 5 --retry-connrefused \ + --connect-timeout 15 --max-time 60 \ + --user-agent 'MerlinAutoUpdate checksum mirror (+https://github.com/ExtremeFiretop/MerlinAutoUpdate-Router)' \ + --output "$page_file" \ + "$SOURCE_URL" # Keep the same source section MerlinAU consumes today, but write to a # temporary candidate so a scrape/parser failure cannot destroy the # last-known-good mirror in the repository. sed -n '/<.*>SHA256 signatures:<\/.*>/,/<\/pre>/p' "$page_file" | \ sed -n '/]*>/,/<\/pre>/p' | \ - sed -e 's/<[^>]*>//g; s/^[[:space:]]*//; s/[[:space:]]*$//' | \ + sed -e 's/^.*]*>//' \ + -e 's/<[^>]*>//g' \ + -e 's/^[[:space:]]*//' \ + -e 's/[[:space:]]*$//' | \ tr -d '\r' | \ sed '/^[[:space:]]*$/d' > "$candidate_file" From 64e71327684372ffc9c8928c309ea10e9febdfc6 Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Mon, 24 Aug 2026 10:35:43 -0400 Subject: [PATCH 4/6] Add files via upload --- .github/workflows/update-merlin-sha256.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/update-merlin-sha256.yml b/.github/workflows/update-merlin-sha256.yml index d1261e53..7bf939be 100644 --- a/.github/workflows/update-merlin-sha256.yml +++ b/.github/workflows/update-merlin-sha256.yml @@ -21,6 +21,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v7 + with: + ssh-key: ${{ secrets.DEPLOY_KEY }} - name: Fetch, parse, and validate SHA256 signatures shell: bash From 5f2c051838357f1bdbd1a268e0b5d4a5673cc719 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 14:36:12 +0000 Subject: [PATCH 5/6] Automated update: refresh Merlin SHA256 checksums --- merlin-sha256.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 merlin-sha256.txt diff --git a/merlin-sha256.txt b/merlin-sha256.txt new file mode 100644 index 00000000..2eed75ce --- /dev/null +++ b/merlin-sha256.txt @@ -0,0 +1,21 @@ +a04d65e566b70a2533f1dcde9e0e1e66133438268f66165caeb973a2aaa8e065 GT-AX11000_3004_388.12_2_rog_ubi.w +24f8679af3726386321aea8ae49af2e7a560f46a8f1fca5a93e31a31d72e43d2 GT-AX11000_3004_388.12_2_ubi.w +b78b365ec8060351c5143782ad9a438f67ab39f37b454fbe06113e99a62c6c25 GT-AXE11000_3004_388.12_2_pureubi.w +c4ef1675ecd772f381c6e5a696d643db89e28f64451d140f53bb8fea62d0089d GT-AXE11000_3004_388.12_2_rog_pureubi.w +352f4a89e86f02deb89d5569db0e354c89956f28225458f8e14f4fe6bacc2123 RT-AX58U_3004_388.12_2_puresqubi.w +936e04cccc6da05b94c19c3cb9c6d8b9fbb0a6542adc7b953aea3c0c7c068903 RT-AX68U_3004_388.12_2_pureubi.w +864cb94504bd0f036f730089c779aafbf5827721af10d5533924f94d3c20982a RT-AX86U_3004_388.12_2_pureubi.w +a902d77915c609cf5ee6ac6069c52e3ab460cd4b915f0febcb269175cc842a6d RT-AX88U_3004_388.12_2_ubi.w +5dc2284ac99bcb280b8f57c98d817ae17c1ae5e60102b8cb581680894739f467 GT-AX11000_PRO_3006_102.8_4_nand_squashfs.pkgtb +9497ab9a5956da9b6c9b86a1c0172e0eef9d8e02c9531598332f0a911a92e925 GT-AX6000_3006_102.8_4_nand_squashfs.pkgtb +ea266310a61dc9018fed850e1dba38b37335740fd5e0053683a1133d69837f4a GT-AXE16000_3006_102.8_4_nand_squashfs.pkgtb +f9e896c3b46a2913e60ea2ac638b4ca624d4d239b3a5416864da95f8b4ed1873 GT-BE19000AI_3006_102.8_4_emmc_squashfs.pkgtb +11932c048a9ecc2be8de93a19af985d685bb21999091d70a1b946fbfa57b7960 GT-BE98_PRO_3006_102.8_4_nand_squashfs.pkgtb +78f296e30bde73b842f3e211b3205bdab7e9b947f1b0b40d43a248cc86badaa7 RT-AX86U_PRO_3006_102.8_4_nand_squashfs.pkgtb +8eca0813db27ef8518535cd00060475c58c7928d8878e87d34df4476dde05550 RT-AX88U_PRO_3006_102.8_4_nand_squashfs.pkgtb +566bb3a9a6331293d7a28b2dbb0676dfa846a5f11bafa3a99c848b894c087606 RT-BE58_GO_3006_102.8_4_nand_squashfs.pkgtb +7cf298f161aca6de3ad4ff3840f08eae3c11a39c067da825e444439aac67dabc RT-BE86U_3006_102.8_4_nand_squashfs.pkgtb +28954e19157261fe97adcb266591de839c202d188d485484a87089149c61dea3 RT-BE88U_3006_102.8_4_nand_squashfs.pkgtb +1fc818b504f51a378fcbd1b8acde0d1e7950d28527c364cc8c4937c9a4072fbe RT-BE92U_3006_102.8_4_nand_squashfs.pkgtb +f4483a27071d4bc074b2e42760e736a8d079a5f0fb9cab1684553de11ce5f453 RT-BE96U_3006_102.8_4_nand_squashfs.pkgtb +12b00d614e5073e78c8e87ae84c688c2d93e7afcb4d0f36d479731b1cbb9f54e XT12_3006_102.8_4_nand_squashfs.pkgtb From 5911b2de85d2a66be8e14145826d4418187dcbd7 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 4 Sep 2026 12:51:58 +0000 Subject: [PATCH 6/6] Update SCRIPT_BRANCH to master in MerlinAU.sh and version to 1.6.7 --- MerlinAU.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MerlinAU.sh b/MerlinAU.sh index 531b3793..08ccce56 100644 --- a/MerlinAU.sh +++ b/MerlinAU.sh @@ -23,7 +23,7 @@ readonly SCRIPT_VERSION=1.6.7 readonly SCRIPT_VERSTAG="26090309" readonly SCRIPT_NAME="MerlinAU" ## Set to "master" for Production Releases ## -SCRIPT_BRANCH="dev" +SCRIPT_BRANCH="master" ##----------------------------------------## ## Modified by Martinski W. [2024-Jul-03] ##