Skip to content

Answer a github ref with an archive of that ref - #34

Merged
oscarvalenzuelab merged 2 commits into
mainfrom
fix/github-versioned-purl-resolves-to-archive
Sep 1, 2026
Merged

Answer a github ref with an archive of that ref#34
oscarvalenzuelab merged 2 commits into
mainfrom
fix/github-versioned-purl-resolves-to-archive

Conversation

@oscarvalenzuelab

Copy link
Copy Markdown
Collaborator

Closes #33.

The bug

>>> purl2src.get_download_url("pkg:github/expressjs/express@v99.99.99", validate=True)
HandlerResult(download_url='https://github.com/expressjs/express.git',
              validated=True, method='direct', status='success')

There is no such tag. build_download_url ignored the version and returned the
clone URL, which resolves whatever ref you name, so validation passed. The
git checkout v99.99.99 in fallback_command would then fail, and a consumer
handing the URL to tarfile.open extracts zero files without an error. suphm
already carries a workaround for this, dropping any download URL ending in
.git.

The decision

A ref that was asked for is answered with an archive of that ref. With no ref to
archive, the clone URL is the honest answer, so a versionless PURL is unchanged.

The archive form

Changed from /archive/refs/tags/{ref}.tar.gz to /archive/{ref}.tar.gz.
Checked live:

URL result
/archive/refs/tags/4.18.2.tar.gz 200
/archive/4.18.2.tar.gz 200
/archive/refs/tags/main.tar.gz 404
/archive/main.tar.gz 200
/archive/{commit sha}.tar.gz 200
/archive/v99.99.99.tar.gz 404

So the old form was a second, quieter bug: it only resolves tags, meaning it
404'd for a branch that is really there and could never resolve a commit sha.

Live results

pkg:github/expressjs/express@v99.99.99      failed   None
pkg:github/expressjs/express@no-such-branch failed   None
pkg:github/expressjs/express@4.18.2         success  .../archive/4.18.2.tar.gz
pkg:github/rails/rails@main                 success  .../archive/main.tar.gz
pkg:github/rails/rails@v7.0.0               success  .../archive/v7.0.0.tar.gz
pkg:github/expressjs/express                success  .../express.git

Downloaded and extracted the express archive to confirm it is a real source
tarball rather than the empty result the clone URL produced: 304 members,
including express-4.18.2/package.json and express-4.18.2/LICENSE.

Known limit

A tag and a branch sharing a name leaves the resolution order to GitHub. That
ambiguity is in the coordinate rather than the lookup, and disambiguating would
need the ref class spelled in the PURL, so it is left alone.

Tests

328 pass, 5 new.

Six existing tests changed. One asserted the clone URL for a versioned PURL,
which is the behaviour being removed. Five asserted the refs/tags form, and
two of those asserted archive/refs/tags/main.tar.gz, a URL that 404s in
reality.

A versioned github PURL was answered with the repository clone URL. That URL
resolves whatever ref you name, so a tag that does not exist came back
validated=True and status=success, and the git checkout in fallback_command
would then fail. A consumer handing the URL to tarfile.open extracts zero files
without an error, which is why suphm already drops any download URL ending
in .git.

A ref that was asked for is now answered with an archive of that ref. With no
ref to archive, the clone URL remains the honest answer, so a versionless PURL
is unchanged.

The archive URL is built as /archive/{ref}.tar.gz rather than
/archive/refs/tags/{ref}.tar.gz. The refs/tags form resolves tags only, so it
404d for main, a branch that is really there, and it cannot resolve a commit
sha. The plain form resolves a tag, a branch or a sha, and 404s for a ref that
does not exist, which is what lets a missing ref report failure.

A tag and a branch sharing a name leaves the resolution order to GitHub. That
ambiguity exists in the coordinate rather than in the lookup, and naming the
ref class would need it spelled in the PURL, so it is left alone here.

Six existing tests changed. One asserted the clone URL for a versioned PURL,
which is the behaviour being removed. Five asserted the refs/tags form, and two
of those asserted archive/refs/tags/main.tar.gz, a URL that 404s.

Closes #33
@cla-bot cla-bot Bot added the cla-signed label Sep 1, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

License Check Report

ℹ️ No licenses detected in changed files.

The e2e test asserted the clone URL for pkg:github/facebook/react@v18.2.0,
which is the behaviour this branch removes. It passed locally off a cached
pre-change answer and failed in CI, which has no cache.
@oscarvalenzuelab
oscarvalenzuelab merged commit e7bf59b into main Sep 1, 2026
10 checks passed
@oscarvalenzuelab
oscarvalenzuelab deleted the fix/github-versioned-purl-resolves-to-archive branch September 1, 2026 07:09
@oscarvalenzuelab oscarvalenzuelab mentioned this pull request Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A github PURL with a tag that does not exist returns the clone URL, validated

1 participant