Skip to content

downloader: fix SAS token corruption in constructDatastoreContext#5715

Open
jsfakian wants to merge 1 commit intolf-edge:masterfrom
jsfakian:Fix-download-image-when-we-include-SAS-token-in-the-url
Open

downloader: fix SAS token corruption in constructDatastoreContext#5715
jsfakian wants to merge 1 commit intolf-edge:masterfrom
jsfakian:Fix-download-image-when-we-include-SAS-token-in-the-url

Conversation

@jsfakian
Copy link
Copy Markdown
Contributor

@jsfakian jsfakian commented Mar 30, 2026

Description

url.JoinPath() percent-encodes ? to %3F when it appears inside
a path segment argument. When configName contains a query string
(e.g. an Azure SAS token: ?st=...&se=...&sig=...), the entire query
string is mangled into the path, causing Azure Blob Storage to return
HTTP 409 on the resulting URL, leaving the app instance permanently
stuck in DOWNLOADING state.

Split configName on the first ? before calling url.JoinPath,
apply the path join only to the clean path portion, then reattach the
raw query string after assembly. This preserves SAS tokens and any
other query-string credentials embedded in the relative URL.

The regression was introduced when simple string concatenation was
replaced with url.JoinPath (13.4-stable → 16.7.0). The old
concatenation preserved ? literally; url.JoinPath correctly
encodes it as a path character, breaking datastores configured as HTTP
type with a SAS-bearing relative URL.

How to test and validate this PR

Prerequisites:

  • A device running EVE 16.x
  • A Zededa controller with an application configured to use an HTTP
    datastore pointing to Azure Blob Storage, where the relative URL
    contains a SAS token (i.e., the URL contains ?st=...&sig=...)

Steps to verify the fix:

  1. Apply this patch and build EVE
  2. Run the device with EVE that includes the patch
  3. Onboard the device on a controller with an application configured to use an HTTP
    datastore pointing to Azure Blob Storage, where the relative URL
    contains a SAS token (i.e., the URL contains ?st=...&sig=...)
  4. The download should proceed successfully — no HTTP 409, no %3F in
    the logged URL, CurrentSize increments in the downloader status
  5. The app instance should progress past DOWNLOADING to RUNNING.

Changelog notes

Fixed a regression introduced in 16.0, where application image downloads
from HTTP datastores using Azure SAS tokens (query string credentials
in the relative URL field) failed with HTTP 409, leaving the application
permanently stuck in the DOWNLOADING state. The fix correctly
preserves the SAS query string when constructing the download URL.

PR Backports

  • 16.0-stable: No.
  • 14.5-stable: No, the regression is not present — the affected
    url.JoinPath change was not in this branch.
  • 13.4-stable: No, same reason as 14.5-stable.

Checklist

  • I've provided a proper description
  • I've added the proper documentation
  • I've tested my PR on amd64 device
  • I've tested my PR on arm64 device
  • I've written the test verification instructions
  • I've set the proper labels to this PR
  • I've checked the boxes above, or I've provided a good reason why I didn't
    check them.

url.JoinPath() percent-encodes '?' to '%3F' when it appears inside
a path segment argument. When configName contains a query string
(e.g. an Azure SAS token: ?st=...&se=...&sig=...), the entire query
string is mangled into the path, causing Azure Blob Storage to return
HTTP 409 on the resulting URL.

Split configName on the first '?' before calling url.JoinPath, apply
the path join only to the clean path portion, then reattach the raw
query string after assembly. This preserves SAS tokens and any other
query-string credentials embedded in the relative URL.

The regression was introduced when simple string concatenation was
replaced with url.JoinPath (13.4-stable -> 16.7.0). The old concat
preserved '?' literally; url.JoinPath correctly encodes it as a path
character, breaking datastores configured with HTTP type and a
SAS-bearing relative URL.

Fixes: app instances stuck in DOWNLOADING state with HTTP 409 from
Azure Blob Storage when datastore is configured as HTTP type with a
SAS token in the relative URL field.

Signed-off-by: Ioannis Sfakianakis <jsfakas@gmail.com>
@github-actions github-actions bot requested a review from eriknordmark March 30, 2026 13:17
@jsfakian jsfakian added the bug Something isn't working label Mar 30, 2026
Copy link
Copy Markdown
Contributor

@rene rene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM


// Reattach the raw query string after the path has been assembled.
// We do not re-encode it: the caller is responsible for passing a
// correctly percent-encoded query string in configName.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caller is responsible for passing a correctly percent-encoded query string in configName.

Is the caller here the controller or the user? In the latter case, we should make sure this requirement is documented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants