mirror of
https://github.com/github/spec-kit.git
synced 2026-08-03 06:26:30 +08:00
fix: handle tags containing / in GitHub release asset URL resolution (#3767)
The tag extraction in resolve_github_release_asset_api_url split the URL path on / and assumed the tag was a single segment at index 4. Tags containing literal / (e.g. feature/v1) would be split across multiple segments, causing the tag to be truncated to only the first part and the asset name to include leftover tag segments. Fix by reconstructing the tag as all segments between 'download' and the final asset segment: tag = '/'.join(parts[4:-1]), asset = parts[-1].
This commit is contained in:
@@ -159,8 +159,9 @@ def resolve_github_release_asset_api_url(
|
||||
if len(parts) < 6 or parts[2:4] != ["releases", "download"]:
|
||||
return None
|
||||
|
||||
owner, repo, tag = parts[0], parts[1], parts[4]
|
||||
asset_name = "/".join(parts[5:])
|
||||
owner, repo = parts[0], parts[1]
|
||||
tag = "/".join(parts[4:-1])
|
||||
asset_name = parts[-1]
|
||||
encoded_tag = quote(tag, safe="")
|
||||
release_url = f"{api_base}/repos/{owner}/{repo}/releases/tags/{encoded_tag}"
|
||||
|
||||
|
||||
@@ -379,6 +379,31 @@ class TestResolveGitHubReleaseAssetApiUrl:
|
||||
assert result == "https://api.github.com/repos/org/repo/releases/assets/99"
|
||||
assert captured == ["https://api.github.com/repos/org/repo/releases/tags/v1.0"]
|
||||
|
||||
def test_tag_with_literal_slash_in_path(self):
|
||||
"""A tag containing a literal '/' (e.g. feature/v1.0.0) splits across
|
||||
multiple URL path segments. The implementation must join all segments
|
||||
between 'download/' and the asset name to reconstruct the full tag."""
|
||||
captured_urls = []
|
||||
asset_url = "https://api.github.com/repos/org/repo/releases/assets/77"
|
||||
|
||||
@contextmanager
|
||||
def capturing_open(url, timeout=None, extra_headers=None):
|
||||
captured_urls.append(url)
|
||||
resp = MagicMock()
|
||||
resp.read.side_effect = io.BytesIO(json.dumps({
|
||||
"assets": [{"name": "asset.zip", "url": asset_url}]
|
||||
}).encode()).read
|
||||
yield resp
|
||||
|
||||
result = resolve_github_release_asset_api_url(
|
||||
"https://github.com/org/repo/releases/download/feature/v1.0.0/asset.zip",
|
||||
capturing_open,
|
||||
)
|
||||
assert result == asset_url
|
||||
# Tag must be the full "feature/v1.0.0", not just "v1.0.0"
|
||||
assert len(captured_urls) == 1
|
||||
assert "releases/tags/feature%2Fv1.0.0" in captured_urls[0]
|
||||
|
||||
|
||||
class TestGitHubRedirectAuth:
|
||||
"""Tests for GitHub-owned redirect auth handling."""
|
||||
|
||||
Reference in New Issue
Block a user