blog: remove liquid tags #6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Upgrade and redesign of the original hashes.yml workflow by 00-matt, plowsof, binaryFate | |
| # Remade by: redsh4de for the Monero site redesign project | |
| # Purpose: Validate Monero download hashes, torrents, and webseeds + create PRs to update download info | |
| name: "Download Hashes" | |
| on: | |
| push: | |
| paths: | |
| - "downloads/hashes.txt" | |
| pull_request: | |
| paths: | |
| - "downloads/hashes.txt" | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| validate-download-hashes: | |
| name: "Validate signed hashes and downloads" | |
| runs-on: ubuntu-22.04 | |
| env: | |
| HASH_FILE: ${{ github.workspace }}/downloads/hashes.txt | |
| outputs: | |
| magnet_gui: ${{ steps.verify-torrents.outputs.magnet_gui }} | |
| magnet_cli: ${{ steps.verify-torrents.outputs.magnet_cli }} | |
| version_gui: ${{ steps.verify-filenames.outputs.version_gui }} | |
| version_cli: ${{ steps.verify-filenames.outputs.version_cli }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install dependencies | |
| run: | | |
| set -euo pipefail | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| ca-certificates \ | |
| coreutils \ | |
| curl \ | |
| gnupg \ | |
| git \ | |
| bzip2 \ | |
| diffutils \ | |
| bash \ | |
| tar \ | |
| transmission-cli \ | |
| jq | |
| - name: Verify hashes.txt signature | |
| run: | | |
| set -euo pipefail | |
| export GNUPGHOME="$(mktemp -d)" | |
| curl -sSfL --proto '=https' --tlsv1.2 \ | |
| "https://raw.githubusercontent.com/monero-project/monero/master/utils/gpg_keys/binaryfate.asc" | | |
| gpg --import | |
| gpg --batch --verify "$HASH_FILE" | |
| - name: Verify filenames | |
| id: verify-filenames | |
| run: | | |
| set -euo pipefail | |
| lines="$(grep -v ^# "$HASH_FILE")" | |
| SAVEIFS=$IFS | |
| IFS=$'\n' | |
| lines=($lines) | |
| IFS=$SAVEIFS | |
| version_gui=$(awk '/monero-gui-source-v/ {print $2}' "$HASH_FILE" | awk -F".tar.bz2" '{print $1}' | awk -F"-" '{print $4}') | |
| version_cli=$(awk '/monero-source-v/ {print $2}' "$HASH_FILE" | awk -F".tar.bz2" '{print $1}' | awk -F"-" '{print $3}') | |
| echo "version_gui=$version_gui" >> $GITHUB_OUTPUT | |
| echo "version_cli=$version_cli" >> $GITHUB_OUTPUT | |
| filenames_cli=() | |
| filenames_gui=() | |
| get_filename(){ | |
| line=$1 | |
| the_line=($line) | |
| length="${#the_line[@]}" | |
| ((length-=1)) | |
| filename="${the_line[$length]}" | |
| echo "${filename}" | |
| } | |
| # expects cli files between lines 2-14 and gui 15-19 (comments do not count, 1st line = 0) | |
| # to add a new file to the cli, $num must be -gt 1 and -lt 16. | |
| # gui $num is now -gt 15 and -lt 21 (new line has been added above) | |
| # a new gui file will only increase the -lt number by 1 | |
| # changes to extensions / new files must be reflected in the cli_files / gui_files lists below | |
| num=0 | |
| for line in "${lines[@]}"; do | |
| if [ $num -gt 1 ] && [ $num -lt 15 ] ; then | |
| #CLI | |
| filename=$(get_filename "${line}") | |
| filenames_cli+=("${filename}") | |
| elif [ $num -gt 14 ] && [ $num -lt 21 ] ; then | |
| #GUI | |
| filename=$(get_filename "${line}") | |
| filenames_gui+=("${filename}") | |
| fi | |
| ((num+=1)) | |
| done | |
| # edit/add/remove filenames below | |
| cli_files=(\ | |
| "monero-android-armv7-${version_cli}.tar.bz2" \ | |
| "monero-android-armv8-${version_cli}.tar.bz2" \ | |
| "monero-freebsd-x64-${version_cli}.tar.bz2" \ | |
| "monero-linux-armv7-${version_cli}.tar.bz2" \ | |
| "monero-linux-armv8-${version_cli}.tar.bz2" \ | |
| "monero-linux-riscv64-${version_cli}.tar.bz2" \ | |
| "monero-linux-x64-${version_cli}.tar.bz2" \ | |
| "monero-linux-x86-${version_cli}.tar.bz2" \ | |
| "monero-mac-armv8-${version_cli}.tar.bz2" \ | |
| "monero-mac-x64-${version_cli}.tar.bz2" \ | |
| "monero-win-x64-${version_cli}.zip" \ | |
| "monero-win-x86-${version_cli}.zip" \ | |
| "monero-source-${version_cli}.tar.bz2") | |
| gui_files=(\ | |
| "monero-gui-install-win-x64-${version_gui}.exe" \ | |
| "monero-gui-linux-x64-${version_gui}.tar.bz2" \ | |
| "monero-gui-mac-x64-${version_gui}.dmg" \ | |
| "monero-gui-mac-armv8-${version_gui}.dmg" \ | |
| "monero-gui-win-x64-${version_gui}.zip" \ | |
| "monero-gui-source-${version_gui}.tar.bz2") | |
| check_filenames(){ | |
| local -n file_list=$1 | |
| local -n hardcoded=$2 | |
| for f in "${file_list[@]}"; do | |
| if [[ "${hardcoded[*]}" =~ "${f}" ]]; then | |
| echo "Filename OK: ${f}" | |
| else | |
| echo "Filename BAD: ${f}" | |
| exit 1 | |
| fi | |
| done | |
| } | |
| check_filenames filenames_cli cli_files | |
| check_filenames filenames_gui gui_files | |
| - name: Download releases and verify hashes | |
| run: | | |
| set -euo pipefail | |
| for file in $(awk '/monero-/ {print $2}' "$HASH_FILE"); do | |
| [ -f "$file" ] && continue | |
| dir="cli" | |
| if [[ $file =~ gui ]]; then | |
| dir="gui" | |
| fi | |
| url="https://dlsrc.getmonero.org/${dir}/${file}" | |
| echo "Downloading $file from $url..." | |
| curl --retry 3 --retry-delay 2 -sSfL --proto '=https' --tlsv1.2 "$url" -o "$file" | |
| sleep 0.5 | |
| done | |
| grep monero- "$HASH_FILE" | sha256sum -c | |
| - name: Validate source integrity | |
| id: validate-sources | |
| run: | | |
| set -euo pipefail | |
| version_gui="${{ steps.verify-filenames.outputs.version_gui }}" | |
| version_cli="${{ steps.verify-filenames.outputs.version_cli }}" | |
| echo -e "\n--> GUI version: $version_gui \n--> CLI version: $version_cli" | |
| mkdir validate_sources | |
| cd validate_sources | |
| # Download / verify git-archive-all.sh | |
| curl -O https://raw.githubusercontent.com/fabacab/git-archive-all.sh/fc86194f00b678438f9210859597f6eead28e765/git-archive-all.sh | |
| echo "db62e9a824866989c9d080f008ec06d81421cf94bed3762acba3b9148607af2d git-archive-all.sh" | sha256sum -c | |
| chmod +x git-archive-all.sh | |
| echo -e "--> Generating tarballs..." | |
| # CLI | |
| git clone --recursive -b "$version_cli" --depth 1 --shallow-submodules https://github.com/monero-project/monero.git monero.git && cd monero.git && ../git-archive-all.sh --prefix monero-source-${version_cli}/ --format tar --tree-ish $version_cli ../monero-source-${version_cli}.tar && cd .. && bzip2 monero-source-${version_cli}.tar | |
| # GUI | |
| git clone --recursive -b "$version_gui" --depth 1 --shallow-submodules https://github.com/monero-project/monero-gui.git monero-gui.git && cd monero-gui.git && ../git-archive-all.sh --prefix monero-gui-source-${version_gui}/ --format tar --tree-ish $version_gui ../monero-gui-source-${version_gui}.tar && cd .. && bzip2 monero-gui-source-${version_gui}.tar | |
| mkdir yours | |
| cp monero-gui-source-${version_gui}.tar.bz2 yours/. | |
| cp monero-source-${version_cli}.tar.bz2 yours/. | |
| mkdir from_website | |
| echo -e "\n--> Move tarballs from getmonero..." | |
| cp ../monero-gui-source-${version_gui}.tar.bz2 from_website/. | |
| cp ../monero-source-${version_cli}.tar.bz2 from_website/. | |
| echo -e "\n--> Unpacking all..." | |
| bunzip2 yours/*.bz2 | |
| bunzip2 from_website/*.bz2 | |
| tar xf yours/monero-source-${version_cli}.tar -C yours/ | |
| tar xf yours/monero-gui-source-${version_gui}.tar -C yours/ | |
| tar xf from_website/monero-source-${version_cli}.tar -C from_website/ | |
| tar xf from_website/monero-gui-source-${version_gui}.tar -C from_website | |
| # Compare directories | |
| echo -e "\n--> Comparing CLI directories" | |
| diff -r yours/monero-source-$version_cli from_website/monero-source-$version_cli | |
| echo -e "\n--> Comparing GUI directories" | |
| diff -r yours/monero-gui-source-$version_gui from_website/monero-gui-source-$version_gui | |
| - name: Verify torrent + magnet links | |
| id: verify-torrents | |
| run: | | |
| set -euo pipefail | |
| version_gui="${{ steps.verify-filenames.outputs.version_gui }}" | |
| version_cli="${{ steps.verify-filenames.outputs.version_cli }}" | |
| # Clone and pin the monero-torrent repo | |
| git clone --recurse-submodules https://github.com/plowsof/monero-torrent.git | |
| cd monero-torrent | |
| git reset --hard 4727b8fd44b9e9b0adfa8d2dc8ed5edef517814a | |
| cd .. | |
| # Move the already-downloaded monero-* files into cdn | |
| mkdir monero-torrent/cdn | |
| awk '/monero-/ {print $2}' "$HASH_FILE" | while read -r f; do | |
| [ -z "$f" ] && continue | |
| mv "$f" monero-torrent/cdn/ | |
| done | |
| # Add GPG key and hashes.txt into cdn | |
| wget -q \ | |
| https://raw.githubusercontent.com/monero-project/monero/master/utils/gpg_keys/binaryfate.asc \ | |
| -O monero-torrent/cdn/binaryfate.asc | |
| cp "$HASH_FILE" monero-torrent/cdn/hashes.txt | |
| # Build torrents locally | |
| cd monero-torrent | |
| docker compose --profile local up --build | |
| # Paths to locally-built torrents | |
| local_cli_torrent="watch/monero-${version_cli}.torrent" | |
| local_gui_torrent="watch/monero-gui-${version_gui}.torrent" | |
| if [ ! -f "$local_cli_torrent" ] || [ ! -f "$local_gui_torrent" ]; then | |
| echo "Local torrent files were not created as expected" >&2 | |
| ls -R | |
| exit 1 | |
| fi | |
| # Extract magnet links from locally built torrents | |
| MAGNET_LINK_CLI="$(transmission-show -m "$local_cli_torrent")" | |
| MAGNET_LINK_GUI="$(transmission-show -m "$local_gui_torrent")" | |
| # Download torrents from CDN (replace with the monero URLs) | |
| CDN_CLI_URL="https://github.com/plowsof/monero-torrent/releases/download/${version_cli}/monero-${version_cli}.torrent" | |
| CDN_GUI_URL="https://github.com/plowsof/monero-torrent/releases/download/${version_gui}/monero-gui-${version_gui}.torrent" | |
| CDN_AVAILABLE=true | |
| if ! wget --spider -q "$CDN_CLI_URL" || ! wget --spider -q "$CDN_GUI_URL"; then | |
| echo "::warning title=CDN-Torrents::CDN torrent files not available yet, skipping comparison" | |
| CDN_AVAILABLE=false | |
| fi | |
| if [ "$CDN_AVAILABLE" = true ]; then | |
| wget -q "$CDN_CLI_URL" -O "monero-${version_cli}.torrent" | |
| wget -q "$CDN_GUI_URL" -O "monero-gui-${version_gui}.torrent" | |
| CDN_MAGNET_LINK_CLI="$(transmission-show -m "monero-${version_cli}.torrent")" | |
| CDN_MAGNET_LINK_GUI="$(transmission-show -m "monero-gui-${version_gui}.torrent")" | |
| # Compare local vs CDN magnets | |
| if [ "$MAGNET_LINK_CLI" != "$CDN_MAGNET_LINK_CLI" ]; then | |
| echo "CLI torrent magnet mismatch between local build and CDN version" >&2 | |
| echo "Local: $MAGNET_LINK_CLI" >&2 | |
| echo "CDN : $CDN_MAGNET_LINK_CLI" >&2 | |
| exit 1 | |
| fi | |
| if [ "$MAGNET_LINK_GUI" != "$CDN_MAGNET_LINK_GUI" ]; then | |
| echo "GUI torrent magnet mismatch between local build and CDN version" >&2 | |
| echo "Local: $MAGNET_LINK_GUI" >&2 | |
| echo "CDN : $CDN_MAGNET_LINK_GUI" >&2 | |
| exit 1 | |
| fi | |
| echo "Torrent files and magnet links match local build and CDN." | |
| fi | |
| echo "magnet_gui=$MAGNET_LINK_GUI" >> $GITHUB_OUTPUT | |
| echo "magnet_cli=$MAGNET_LINK_CLI" >> $GITHUB_OUTPUT | |
| # Check webseed URLs | |
| CDN_URL="https://downloads.getmonero.org" | |
| if ! wget --spider -q "$CDN_URL/hashes-$version_cli.txt"; then | |
| echo "::warning title=Webseed-URLs::Webseed URL unreachable: $CDN_URL/hashes-$version_cli.txt" | |
| fi | |
| if ! wget --spider -q "$CDN_URL/hashes-$version_gui.txt"; then | |
| echo "::warning title=Webseed-URLs::Webseed URL unreachable: $CDN_URL/hashes-$version_gui.txt" | |
| fi | |
| for file in $(awk '/monero-/ {print $2}' "$HASH_FILE"); do | |
| dir="cli" | |
| part="monero-$version_cli" | |
| if [[ $file =~ gui ]]; then | |
| dir="gui" | |
| part="monero-gui-$version_gui" | |
| fi | |
| url="$CDN_URL/${part}/${dir}/${file}" | |
| if ! wget --spider -q "$url"; then | |
| echo "::warning title=Webseed-URLs::Webseed URL unreachable: $url" | |
| fi | |
| done | |
| update-repo: | |
| needs: validate-download-hashes | |
| name: "Update static data with new download info" | |
| runs-on: ubuntu-22.04 | |
| if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch) | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| - uses: pnpm/action-setup@v4 | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y jq gh | |
| - name: Update magnet links | |
| run: | | |
| set -euo pipefail | |
| MAGNET_LINK_GUI="${{ needs.validate-download-hashes.outputs.magnet_gui }}" | |
| MAGNET_LINK_CLI="${{ needs.validate-download-hashes.outputs.magnet_cli }}" | |
| # Update magnet links in core.json only if different | |
| CURRENT_GUI_MAGNET=$(jq -r '.gui.torrent.magnet' src/data/downloads/core.json) | |
| if [ "$CURRENT_GUI_MAGNET" != "$MAGNET_LINK_GUI" ]; then | |
| jq --arg m "$MAGNET_LINK_GUI" '.gui.torrent.magnet = $m' src/data/downloads/core.json > tmp.json && mv tmp.json src/data/downloads/core.json | |
| fi | |
| CURRENT_CLI_MAGNET=$(jq -r '.cli.torrent.magnet' src/data/downloads/core.json) | |
| if [ "$CURRENT_CLI_MAGNET" != "$MAGNET_LINK_CLI" ]; then | |
| jq --arg m "$MAGNET_LINK_CLI" '.cli.torrent.magnet = $m' src/data/downloads/core.json > tmp.json && mv tmp.json src/data/downloads/core.json | |
| fi | |
| - name: Update Core download metadata | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| version_gui="${{ needs.validate-download-hashes.outputs.version_gui }}" | |
| version_cli="${{ needs.validate-download-hashes.outputs.version_cli }}" | |
| current_gui_version=$(jq -r '.gui.version' src/data/downloads/core.json) | |
| current_cli_version=$(jq -r '.cli.version' src/data/downloads/core.json) | |
| if [ "$current_gui_version" != "$version_gui" ] || [ "$current_cli_version" != "$version_cli" ]; then | |
| echo "Versions differ, updating core downloads" | |
| # Get release names from GitHub | |
| first_release_cli=$(echo "${version_cli}" | sed 's/\.[0-9]\+\.[0-9]\+$/.0.0/') | |
| first_release_gui=$(echo "${version_gui}" | sed 's/\.[0-9]\+\.[0-9]\+$/.0.0/') | |
| cli_name="$(gh release view "${first_release_cli}" --repo monero-project/monero --json name --jq '.name | sub("[^A-Za-z ]+.*$"; "") | sub(" +$"; "")' || echo '')" | |
| gui_name="$(gh release view "${first_release_gui}" --repo monero-project/monero-gui --json name --jq '.name | sub("[^A-Za-z ]+.*$"; "") | sub(" +$"; "")' || echo '')" | |
| # Update version numbers and names | |
| jq --arg v "$version_cli" --arg n "$cli_name" '.cli.version = $v | .cli.name = $n' src/data/downloads/core.json > tmp.json && mv tmp.json src/data/downloads/core.json | |
| jq --arg v "$version_gui" --arg n "$gui_name" '.gui.version = $v | .gui.name = $n' src/data/downloads/core.json > tmp.json && mv tmp.json src/data/downloads/core.json | |
| # Update file sizes | |
| for section in cli gui; do | |
| jq -r ".$section.downloads[] | objects | select(.href) | .href" src/data/downloads/core.json | while read -r url; do | |
| if [ -n "$url" ]; then | |
| echo "Fetching size for $url" | |
| size=$(curl -sIL "$url" | grep -i content-length | awk '{print $2}' | tr -d '\r\n') | |
| if [ -n "$size" ] && [ "$size" -gt 0 ]; then | |
| mb=$(awk -v s="$size" 'BEGIN { printf "%.2f", s/1048576 }') | |
| jq --arg u "$url" --arg s "$mb MB" "(.${section}.downloads[] | objects | select(.href == \$u) | .size) = \$s" src/data/downloads/core.json > tmp.json && mv tmp.json src/data/downloads/core.json | |
| fi | |
| sleep 0.5 | |
| fi | |
| done | |
| done | |
| else | |
| echo "Versions match, skipping" | |
| fi | |
| - name: Format metadata file | |
| run: | | |
| set -euo pipefail | |
| pnpm install --frozen-lockfile | |
| pnpm exec prettier --write src/data/downloads/core.json | |
| - name: Create pull request | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} | |
| run: | | |
| set -euo pipefail | |
| # If core.json hasn't changed, bail out early | |
| if git diff --quiet src/data/downloads/core.json; then | |
| echo "No changes to commit" | |
| exit 0 | |
| fi | |
| PREFIX="actions/core-downloads-" | |
| # List existing core.json update PRs | |
| prs=$(gh pr list \ | |
| --state open \ | |
| --base "$DEFAULT_BRANCH" \ | |
| --json number,headRefName \ | |
| --jq '.[] | select(.headRefName | startswith("'"$PREFIX"'")) | .number') | |
| version_gui="${{ needs.validate-download-hashes.outputs.version_gui }}" | |
| version_cli="${{ needs.validate-download-hashes.outputs.version_cli }}" | |
| BRANCH_NAME="${PREFIX}${version_cli}-$(date +%Y%m%d%H%M%S)" | |
| git config user.name 'github-actions[bot]' | |
| git config user.email 'github-actions[bot]@users.noreply.github.com' | |
| git checkout -b "$BRANCH_NAME" | |
| git add src/data/downloads/core.json | |
| git commit -m "Update Core download information (CLI ${version_cli}, GUI ${version_gui})" | |
| git push --set-upstream origin "$BRANCH_NAME" | |
| gh pr create \ | |
| --base "$DEFAULT_BRANCH" \ | |
| --head "$BRANCH_NAME" \ | |
| --title "Update Core download information (CLI ${version_cli}, GUI ${version_gui})" \ | |
| --body "This PR was automatically generated by the Download Hashes workflow to update **src/data/downloads/core.json** based on the latest downloads/hashes.txt." | |
| # Close outdated PRs | |
| if [ -n "$prs" ]; then | |
| for pr in $prs; do | |
| echo "Closing existing PR #$pr" | |
| gh pr close "$pr" --comment "Closed by Actions: superseded by a newer PR." | |
| done | |
| fi |