From 95227713c1d031d28513e01156111f5f9fd19801 Mon Sep 17 00:00:00 2001 From: "nelson.parente" Date: Mon, 17 Aug 2026 09:38:05 +0100 Subject: [PATCH 1/4] feat: route install script downloads through the Dapr download gateway Artifact downloads in install.sh and install.ps1 now default to the Dapr download gateway (Scarf), which redirects to GitHub Releases and provides the project with anonymous download counts. Both scripts fall back to GitHub Releases automatically if the gateway is unreachable, and the download base is overridable (DAPR_DOWNLOAD_BASE / -DownloadBase). Version discovery and the darwin-arm64 availability probe remain on GitHub so existence checks are not counted as downloads. Signed-off-by: nelson.parente --- install/install.ps1 | 32 ++++++++++++++++++++++++++++---- install/install.sh | 45 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/install/install.ps1 b/install/install.ps1 index 2cffaa2fad..18491375f9 100755 --- a/install/install.ps1 +++ b/install/install.ps1 @@ -14,7 +14,11 @@ param ( [string]$Version, [string]$DaprRoot = "$Env:SystemDrive\dapr", [string]$DaprReleaseJsonUrl = "", - [scriptblock]$CustomAssetFactory = $null + [scriptblock]$CustomAssetFactory = $null, + # Artifact download base URL. Defaults to the Dapr download gateway (Scarf), + # which redirects to GitHub Releases and provides the project with anonymous + # download counts. Pass an empty string to download from GitHub directly. + [string]$DownloadBase = "https://downloads.dapr.io/cli" ) Write-Output "" @@ -126,12 +130,32 @@ $zipFileUrl = $asset.url $assetName = $asset.name $zipFilePath = $DaprRoot + "\" + $assetName -Write-Output "Downloading $zipFileUrl ..." -$githubHeader.Accept = "application/octet-stream" $oldProgressPreference = $progressPreference; $progressPreference = 'SilentlyContinue'; -Invoke-WebRequest -Headers $githubHeader -Uri $zipFileUrl -OutFile $zipFilePath +$downloaded = $false + +# Download via the Dapr download gateway first (redirects to GitHub Releases and +# provides the project with anonymous download counts). Skipped when a +# CustomAssetFactory is used, since its asset URL may not exist on the gateway. +if (!$CustomAssetFactory -and $DownloadBase) { + $gatewayUrl = "$DownloadBase/$($release.tag_name)/$assetName" + Write-Output "Downloading $gatewayUrl ..." + try { + # Note: no GitHub auth header here - this request does not go to GitHub. + Invoke-WebRequest -Uri $gatewayUrl -OutFile $zipFilePath + $downloaded = $true + } + catch { + Write-Output "Download from $DownloadBase failed, falling back to GitHub..." + } +} + +if (!$downloaded) { + Write-Output "Downloading $zipFileUrl ..." + $githubHeader.Accept = "application/octet-stream" + Invoke-WebRequest -Headers $githubHeader -Uri $zipFileUrl -OutFile $zipFilePath +} $progressPreference = $oldProgressPreference; if (!(Test-Path $zipFilePath -PathType Leaf)) { throw "Failed to download Dapr Cli binary - $zipFilePath" diff --git a/install/install.sh b/install/install.sh index d59abe223d..c7c7d3d418 100755 --- a/install/install.sh +++ b/install/install.sh @@ -26,6 +26,16 @@ DAPR_HTTP_REQUEST_CLI=curl GITHUB_ORG=dapr GITHUB_REPO=cli +# Canonical GitHub Releases download base. Used for release probing and as a +# fallback if the download gateway is unavailable. +GITHUB_DOWNLOAD_BASE="https://github.com/${GITHUB_ORG}/${GITHUB_REPO}/releases/download" + +# Artifact download base URL. Defaults to the Dapr download gateway (Scarf), +# which redirects to GitHub Releases and provides the project with anonymous +# download counts. Set DAPR_DOWNLOAD_BASE to bypass the gateway, e.g.: +# DAPR_DOWNLOAD_BASE="https://github.com/dapr/cli/releases/download" ./install.sh +: ${DAPR_DOWNLOAD_BASE:="https://downloads.dapr.io/cli"} + # Dapr CLI filename DAPR_CLI_FILENAME=dapr @@ -127,32 +137,47 @@ downloadFile() { LATEST_RELEASE_TAG=$1 DAPR_CLI_ARTIFACT="${DAPR_CLI_FILENAME}_${OS}_${ARCH}.tar.gz" - DOWNLOAD_BASE="https://github.com/${GITHUB_ORG}/${GITHUB_REPO}/releases/download" - DOWNLOAD_URL="${DOWNLOAD_BASE}/${LATEST_RELEASE_TAG}/${DAPR_CLI_ARTIFACT}" + DOWNLOAD_URL="${DAPR_DOWNLOAD_BASE}/${LATEST_RELEASE_TAG}/${DAPR_CLI_ARTIFACT}" # Create the temp directory DAPR_TMP_ROOT=$(mktemp -dt dapr-install-XXXXXX) ARTIFACT_TMP_FILE="$DAPR_TMP_ROOT/$DAPR_CLI_ARTIFACT" - echo "Downloading $DOWNLOAD_URL ..." - if [ "$DAPR_HTTP_REQUEST_CLI" == "curl" ]; then - curl -SsL "$DOWNLOAD_URL" -o "$ARTIFACT_TMP_FILE" - else - wget -q -O "$ARTIFACT_TMP_FILE" "$DOWNLOAD_URL" + if ! fetchArtifact "$DOWNLOAD_URL" "$ARTIFACT_TMP_FILE"; then + if [ "$DAPR_DOWNLOAD_BASE" != "$GITHUB_DOWNLOAD_BASE" ]; then + echo "Download from ${DAPR_DOWNLOAD_BASE} failed, falling back to GitHub Releases..." + DOWNLOAD_URL="${GITHUB_DOWNLOAD_BASE}/${LATEST_RELEASE_TAG}/${DAPR_CLI_ARTIFACT}" + fetchArtifact "$DOWNLOAD_URL" "$ARTIFACT_TMP_FILE" + fi fi - if [ ! -f "$ARTIFACT_TMP_FILE" ]; then + if [ ! -s "$ARTIFACT_TMP_FILE" ]; then echo "failed to download $DOWNLOAD_URL ..." exit 1 fi } +fetchArtifact() { + local url=$1 + local dest=$2 + + echo "Downloading $url ..." + if [ "$DAPR_HTTP_REQUEST_CLI" == "curl" ]; then + curl -SsLf "$url" -o "$dest" || return 1 + else + wget -q -O "$dest" "$url" || return 1 + fi + + [ -s "$dest" ] +} + isReleaseAvailable() { LATEST_RELEASE_TAG=$1 DAPR_CLI_ARTIFACT="${DAPR_CLI_FILENAME}_${OS}_${ARCH}.tar.gz" - DOWNLOAD_BASE="https://github.com/${GITHUB_ORG}/${GITHUB_REPO}/releases/download" - DOWNLOAD_URL="${DOWNLOAD_BASE}/${LATEST_RELEASE_TAG}/${DAPR_CLI_ARTIFACT}" + # Probe GitHub Releases directly: this is an existence check, not a download, + # so it should not go through (and be counted by) the download gateway. + DOWNLOAD_URL="${GITHUB_DOWNLOAD_BASE}/${LATEST_RELEASE_TAG}/${DAPR_CLI_ARTIFACT}" if [ "$DAPR_HTTP_REQUEST_CLI" == "curl" ]; then httpstatus=$(curl -sSLI -o /dev/null -w "%{http_code}" "$DOWNLOAD_URL") From f21e6a8413fdc0374165323f39ccf6e6da1fd260 Mon Sep 17 00:00:00 2001 From: "nelson.parente" Date: Tue, 18 Aug 2026 20:34:04 +0100 Subject: [PATCH 2/4] fix: default the download base to the Scarf-hosted gateway domain downloads.dapr.io has no DNS record, so the gateway attempt always failed and fell through to GitHub. Use the Scarf-provided subdomain, which resolves today and needs no dapr.io DNS change. Behaviour is otherwise unchanged: GitHub Releases remains the fallback, and DAPR_DOWNLOAD_BASE / -DownloadBase still bypass the gateway entirely. Signed-off-by: nelson.parente --- install/install.ps1 | 2 +- install/install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install/install.ps1 b/install/install.ps1 index 18491375f9..266bbe2e72 100755 --- a/install/install.ps1 +++ b/install/install.ps1 @@ -18,7 +18,7 @@ param ( # Artifact download base URL. Defaults to the Dapr download gateway (Scarf), # which redirects to GitHub Releases and provides the project with anonymous # download counts. Pass an empty string to download from GitHub directly. - [string]$DownloadBase = "https://downloads.dapr.io/cli" + [string]$DownloadBase = "https://dapr.gateway.scarf.sh/cli" ) Write-Output "" diff --git a/install/install.sh b/install/install.sh index c7c7d3d418..5854426978 100755 --- a/install/install.sh +++ b/install/install.sh @@ -34,7 +34,7 @@ GITHUB_DOWNLOAD_BASE="https://github.com/${GITHUB_ORG}/${GITHUB_REPO}/releases/d # which redirects to GitHub Releases and provides the project with anonymous # download counts. Set DAPR_DOWNLOAD_BASE to bypass the gateway, e.g.: # DAPR_DOWNLOAD_BASE="https://github.com/dapr/cli/releases/download" ./install.sh -: ${DAPR_DOWNLOAD_BASE:="https://downloads.dapr.io/cli"} +: ${DAPR_DOWNLOAD_BASE:="https://dapr.gateway.scarf.sh/cli"} # Dapr CLI filename DAPR_CLI_FILENAME=dapr From 0fb8865d25ad26b5706e1901699da60d5eeeab5b Mon Sep 17 00:00:00 2001 From: "nelson.parente" Date: Wed, 19 Aug 2026 10:14:57 +0100 Subject: [PATCH 3/4] fix: match the gateway's /{version}/{platform}/{arch} route format The provisioned Scarf route resolves the artifact name itself from the platform and arch path segments; it does not accept a filename. The previous URLs (/{version}/{filename}) 404'd, so every install fell back to GitHub and nothing was counted. install.sh now builds the gateway URL from OS/ARCH, while any override of DAPR_DOWNLOAD_BASE keeps the GitHub-shaped /{version}/{filename} form, so the documented bypass is unchanged. install.ps1 defaults the gateway off: the route template resolves to .tar.gz, but the Windows artifact is a .zip, so every Windows request would 404 and print a fallback warning. It can be turned on by setting -DownloadBase once a Windows route exists in Scarf. Signed-off-by: nelson.parente --- install/install.ps1 | 17 ++++++++++++----- install/install.sh | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/install/install.ps1 b/install/install.ps1 index 266bbe2e72..68099f0707 100755 --- a/install/install.ps1 +++ b/install/install.ps1 @@ -15,10 +15,15 @@ param ( [string]$DaprRoot = "$Env:SystemDrive\dapr", [string]$DaprReleaseJsonUrl = "", [scriptblock]$CustomAssetFactory = $null, - # Artifact download base URL. Defaults to the Dapr download gateway (Scarf), - # which redirects to GitHub Releases and provides the project with anonymous - # download counts. Pass an empty string to download from GitHub directly. - [string]$DownloadBase = "https://dapr.gateway.scarf.sh/cli" + # Artifact download base URL. When set, downloads are routed through the Dapr + # download gateway (Scarf), which redirects to GitHub Releases and provides the + # project with anonymous download counts. + # + # Empty by default: the gateway's route resolves {platform}/{arch} to a + # `.tar.gz`, but the Windows artifact is a `.zip`, so every Windows request + # would 404 and fall back to GitHub with a warning. Set this to + # "https://dapr.gateway.scarf.sh/cli" once a Windows route exists. + [string]$DownloadBase = "" ) Write-Output "" @@ -139,7 +144,9 @@ $downloaded = $false # provides the project with anonymous download counts). Skipped when a # CustomAssetFactory is used, since its asset URL may not exist on the gateway. if (!$CustomAssetFactory -and $DownloadBase) { - $gatewayUrl = "$DownloadBase/$($release.tag_name)/$assetName" + # The gateway routes on /{version}/{platform}/{arch} and resolves the + # artifact name itself. + $gatewayUrl = "$DownloadBase/$($release.tag_name)/windows/amd64" Write-Output "Downloading $gatewayUrl ..." try { # Note: no GitHub auth header here - this request does not go to GitHub. diff --git a/install/install.sh b/install/install.sh index 5854426978..698d87616b 100755 --- a/install/install.sh +++ b/install/install.sh @@ -30,11 +30,17 @@ GITHUB_REPO=cli # fallback if the download gateway is unavailable. GITHUB_DOWNLOAD_BASE="https://github.com/${GITHUB_ORG}/${GITHUB_REPO}/releases/download" +# The download gateway routes on /{version}/{platform}/{arch} and resolves the +# artifact name itself, so its URLs are shaped differently from GitHub's. +DAPR_GATEWAY_DOWNLOAD_BASE="https://dapr.gateway.scarf.sh/cli" + # Artifact download base URL. Defaults to the Dapr download gateway (Scarf), # which redirects to GitHub Releases and provides the project with anonymous # download counts. Set DAPR_DOWNLOAD_BASE to bypass the gateway, e.g.: # DAPR_DOWNLOAD_BASE="https://github.com/dapr/cli/releases/download" ./install.sh -: ${DAPR_DOWNLOAD_BASE:="https://dapr.gateway.scarf.sh/cli"} +# Any base other than the gateway is treated as GitHub-shaped +# (//). +: ${DAPR_DOWNLOAD_BASE:="$DAPR_GATEWAY_DOWNLOAD_BASE"} # Dapr CLI filename DAPR_CLI_FILENAME=dapr @@ -137,7 +143,11 @@ downloadFile() { LATEST_RELEASE_TAG=$1 DAPR_CLI_ARTIFACT="${DAPR_CLI_FILENAME}_${OS}_${ARCH}.tar.gz" - DOWNLOAD_URL="${DAPR_DOWNLOAD_BASE}/${LATEST_RELEASE_TAG}/${DAPR_CLI_ARTIFACT}" + if [ "$DAPR_DOWNLOAD_BASE" = "$DAPR_GATEWAY_DOWNLOAD_BASE" ]; then + DOWNLOAD_URL="${DAPR_DOWNLOAD_BASE}/${LATEST_RELEASE_TAG}/${OS}/${ARCH}" + else + DOWNLOAD_URL="${DAPR_DOWNLOAD_BASE}/${LATEST_RELEASE_TAG}/${DAPR_CLI_ARTIFACT}" + fi # Create the temp directory DAPR_TMP_ROOT=$(mktemp -dt dapr-install-XXXXXX) From 235a65f68cd940df15b84078bc94b5915c57a84f Mon Sep 17 00:00:00 2001 From: "nelson.parente" Date: Wed, 19 Aug 2026 10:22:42 +0100 Subject: [PATCH 4/4] feat: enable the download gateway for Windows installs The Scarf package now carries a Windows route resolving /cli/{version}/windows/{arch} to the .zip artifact, so install.ps1 can use the gateway like install.sh does. Verified end-to-end across v1.15.0 and v1.14.1 for windows/amd64 plus all linux and darwin targets: the gateway returns 307 and the redirect target returns 200 in every case. GitHub Releases remains the automatic fallback and -DownloadBase '' still bypasses the gateway entirely. Signed-off-by: nelson.parente --- install/install.ps1 | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/install/install.ps1 b/install/install.ps1 index 68099f0707..bff2ae1a57 100755 --- a/install/install.ps1 +++ b/install/install.ps1 @@ -15,15 +15,10 @@ param ( [string]$DaprRoot = "$Env:SystemDrive\dapr", [string]$DaprReleaseJsonUrl = "", [scriptblock]$CustomAssetFactory = $null, - # Artifact download base URL. When set, downloads are routed through the Dapr - # download gateway (Scarf), which redirects to GitHub Releases and provides the - # project with anonymous download counts. - # - # Empty by default: the gateway's route resolves {platform}/{arch} to a - # `.tar.gz`, but the Windows artifact is a `.zip`, so every Windows request - # would 404 and fall back to GitHub with a warning. Set this to - # "https://dapr.gateway.scarf.sh/cli" once a Windows route exists. - [string]$DownloadBase = "" + # Artifact download base URL. Defaults to the Dapr download gateway (Scarf), + # which redirects to GitHub Releases and provides the project with anonymous + # download counts. Pass an empty string to download from GitHub directly. + [string]$DownloadBase = "https://dapr.gateway.scarf.sh/cli" ) Write-Output ""