From 52c76090500569033c9da3bc1b801e4c09cafbe6 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 10 Sep 2026 16:51:11 +0000 Subject: [PATCH] wolf: fix GE-Proton download URL resolution (malformed URL) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ./manage.sh ge-proton failed live with: curl: (3) URL rejected: Malformed input to a URL function Root cause: the GitHub release JSON is parsed with a plain grep browser_download_url | grep '\.tar\.gz' | cut -d'"' -f4 pipeline. Once a release publishes more than one asset whose name contains ".tar.gz" (a second architecture build, a checksum-adjacent file, etc.), grep returns more than one line and $(...) glues them together with an embedded newline instead of yielding a single URL — curl then rejects the whole multi-line string outright. Reproduced synthetically with a release carrying two .tar.gz assets: the old pipeline emits two lines where exactly one is expected. Fixed all three independent copies of this same extraction (manage.sh's _cache_ge_proton() helper and its ge-proton command, plus install_wolf()'s own pre-download step) to parse the release JSON for real via python3 instead of pattern-matching the raw text — filtering by an actual ".tar.gz" suffix (not substring) and preferring an x86_64-tagged asset if more than one still matches, since every container this repo runs is x86_64. Verified against a synthetic multi-asset release JSON that the new logic picks exactly one clean URL where the old one produced two concatenated lines. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_013BWYKEERLA1a7gv86Z4W23 --- services/wolf.sh | 55 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/services/wolf.sh b/services/wolf.sh index 2db65fb..2e7c322 100644 --- a/services/wolf.sh +++ b/services/wolf.sh @@ -2024,8 +2024,27 @@ _cache_ge_proton() { url="https://github.com/GloriousEggroll/proton-ge-custom/releases/download/$version/$version.tar.gz" else echo "Fetching latest GE-Proton release info..." + # A plain grep+cut over the raw JSON used to break outright once a + # release started shipping more than one .tar.gz-suffixed asset (a + # second architecture build, a differently-named tarball, etc.) — + # grep then returns more than one line, and $(...) glues them + # together with an embedded newline instead of picking just one, + # which curl rejects outright ("URL rejected: Malformed input to a + # URL function") rather than a clean single URL. Parse the JSON for + # real instead of pattern-matching the raw text. url=$(curl -sL https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases/latest \ - | grep browser_download_url | grep '\.tar\.gz' | cut -d'"' -f4) + | python3 -c ' +import sys, json +try: + release = json.load(sys.stdin) +except Exception: + print("") + raise SystemExit +assets = [a for a in release.get("assets", []) if a.get("name", "").endswith(".tar.gz")] +x64 = [a for a in assets if "x86_64" in a.get("name", "")] +pick = x64 or assets +print(pick[0]["browser_download_url"] if pick else "") +' 2>/dev/null) if [ -z "$url" ]; then echo "Could not determine GE-Proton download URL (GitHub rate-limited or offline?)." return 1 @@ -3143,8 +3162,23 @@ PYEOF echo "Using pre-downloaded GE-Proton: $NAME" else echo "Fetching latest GE-Proton release info..." + # See _cache_ge_proton()'s own comment above for why this parses + # the JSON for real instead of grep+cut over the raw text — + # more than one matching .tar.gz asset used to glue into one + # multi-line, curl-rejected "Malformed input to a URL function". URL=$(curl -sL https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases/latest \ - | grep browser_download_url | grep '\.tar\.gz' | cut -d'"' -f4) + | python3 -c ' +import sys, json +try: + release = json.load(sys.stdin) +except Exception: + print("") + raise SystemExit +assets = [a for a in release.get("assets", []) if a.get("name", "").endswith(".tar.gz")] +x64 = [a for a in assets if "x86_64" in a.get("name", "")] +pick = x64 or assets +print(pick[0]["browser_download_url"] if pick else "") +' 2>/dev/null) if [ -z "$URL" ]; then echo "Could not determine GE-Proton download URL (GitHub rate-limited or offline?)." exit 1 @@ -6175,8 +6209,23 @@ MD ( CACHE_DIR="$WOLF_DIR/ge-proton-cache" mkdir -p "$CACHE_DIR" + # See the matching comment on manage.sh's own ge-proton command for + # why this parses the JSON for real instead of grep+cut over the raw + # text — more than one matching .tar.gz asset used to glue into one + # multi-line, curl-rejected "Malformed input to a URL function". URL=$(curl -sL https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases/latest \ - | grep browser_download_url | grep '\.tar\.gz' | cut -d'"' -f4) + | python3 -c ' +import sys, json +try: + release = json.load(sys.stdin) +except Exception: + print("") + raise SystemExit +assets = [a for a in release.get("assets", []) if a.get("name", "").endswith(".tar.gz")] +x64 = [a for a in assets if "x86_64" in a.get("name", "")] +pick = x64 or assets +print(pick[0]["browser_download_url"] if pick else "") +' 2>/dev/null) if [ -z "$URL" ]; then log_warning "Could not fetch GE-Proton URL — run './manage.sh ge-proton' later." else