Skip to content

feat: serve plugins with dependencies at the commit pinned by the Go module proxy - #83

Merged
traefiker merged 5 commits into
traefik:masterfrom
mmatur:feat/serve-pinned-commit
Oct 27, 2026
Merged

traefiker merged 5 commits into
traefik:masterfrom
mmatur:feat/serve-pinned-commit

Conversation

@mmatur

@mmatur mmatur commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Plugins with dependencies are served from the GitHub zipball of their tag. If a tag moves after publication, the same version serves different code and no longer matches its recorded hash.

The download now reads the commit pinned by proxy.golang.org (/@v/<version>.info, Origin.Hash):

  • the tag still points at that commit: download the tag, as today. An annotated tag zipball is named after the tag object, so switching to the commit would change the bytes of every annotated version.
  • the tag moved or was deleted: download the pinned commit, and log it.
  • no Origin (version unknown to the proxy, or published before Origin existed): download the tag.
  • proxy error or timeout: download the tag, as before. GitHub error: fail the download.

The pinned commit is cached in memory per version. An empty --pin-proxy-url turns pinning off.

The tag check uses a conditional request on the pinned commit. A 304 does not count against the GitHub rate limit, so stable tags cost no extra quota.

Hashes that no longer match the bytes served (moved annotated tags, hashes recorded after a tag moved) are realigned with piceus realign --only on the -next catalog.

New flag --pin-proxy-url (default https://proxy.golang.org).

Tested locally against GitHub and proxy.golang.org with maxlerebourg/crowdsec-bouncer-traefik-plugin:

  • v1.1.5 (moved tag) serves a2fe60c and matches its recorded hash again
  • v1.8.0 and v1.8.1 (annotated tags) serve the same bytes as plugins.traefik.io

Part of traefik/hub-issues#3124

Comment thread pkg/handlers/pinned.go Resolved
Comment thread pkg/handlers/pinned.go Resolved

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Mutable-tag resolution still permits unpinned downloads, and moved annotated tags can produce archives incompatible with recorded hashes.

2 open issues
What changed in this PR

This PR uses Go module proxy metadata to select GitHub archives for plugins with dependencies, aiming to preserve published code when tags move or disappear.

Changes:

  • Adds proxy-pinned commit lookup and tag verification, retaining tag downloads when unchanged.
  • Introduces --pin-proxy-url, defaulting to https://proxy.golang.org.
  • Adds reference-selection tests and updates handler construction.
File Description
pkg/​handlers/​pinned.go Resolves archive references using proxy metadata and GitHub tag checks.
pkg/​handlers/​pinned_test.go Tests stable, moved, deleted, unknown, and error cases.
pkg/​handlers/​module.go Uses the resolved reference for archive downloads.
pkg/​handlers/​handlers.go Adds pinning configuration and an HTTP client with a timeout.
pkg/​handlers/​handlers_test.go Updates constructor calls.
pkg/​handlers/​blacklist_test.go Updates constructor calls.
go.mod Promotes golang.org/x/mod to a direct dependency.
cmd/​serve/​serve.go Passes the pinning proxy URL to handlers.
cmd/​serve/​config.go Adds the pinning proxy configuration field.
cmd/​serve/​command.go Registers and reads the new proxy flag.

Review effort: Balanced

Comment thread pkg/handlers/pinned.go Resolved
Comment thread pkg/handlers/pinned.go Resolved
Comment thread pkg/handlers/pinned.go Outdated
// It is the tag while the tag still points at the commit pinned by the Go module proxy at publication,
// and the pinned commit once the tag moved or was deleted.
// Requesting the tag keeps the archive bytes: the zipball of an annotated tag is named after the tag object, not the commit.
// The pinned commit of a moved annotated tag cannot give those bytes back, its hash is realigned instead.

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.

Where does this realign happen? Not in this PR. If it's piceus realign --only, please say so here. Otherwise moved annotated tags fail validate as soon as this is deployed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It's piceus realign --only <module>@<version> (traefik/piceus#163), run on the -next catalog and reviewed one by one before the switch. The comment now says so.

Comment thread pkg/handlers/pinned.go
return version, nil
}

if err != nil {

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 description says a proxy error fails the download, but here we serve the tag. Please update the description.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Right, it changed after the first review. Description updated.

Comment thread pkg/handlers/pinned.go
Str("tag_commit", sha).Str("pinned_commit", pinned).
Msg("Tag moved after publication, serving the pinned commit")

return pinned, nil

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.

If a version was first downloaded after its tag moved, its recorded hash is the moved one, and this now breaks it. How many versions are in that case?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

10 of the 2,159 public versions. They will be realigned with piceus realign --only on -next before the switch, which changes the code served for them. We'll test each one there and tell the authors.

Comment thread pkg/handlers/pinned.go
return version, nil
}

pinned, err := h.pinnedCommit(ctx, moduleName, version)

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.

nit: the pinned commit never changes, but we look it up on every download. Could we store it? It will also reduce number of proxy calls.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done, cached in memory per module@version. Only successful lookups are cached, as the proxy may learn a version later.

"github.com/stretchr/testify/require"
)

func TestArchiveRef(t *testing.T) {

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.

nit: missing cases for a GitHub 404 and a proxy 410.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Added both.

Comment thread cmd/serve/command.go
Required: true,
},
&cli.StringFlag{
Name: flagPinProxyURL,

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.

Please add --pin-proxy-url to the readme.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Added.

mmatur and others added 5 commits October 26, 2026 19:23
…module proxy

When a tag moved after publication, download the GitHub zipball at the
commit proxy.golang.org pinned for that version instead of the tag.

Part of traefik/hub-issues#3124, closes traefik/infra#12142.
Co-authored-by: aikido-pr-checks[bot] <169896070+aikido-pr-checks[bot]@users.noreply.github.com>
@mmatur
mmatur force-pushed the feat/serve-pinned-commit branch from 7ce8bdc to 801d327 Compare October 26, 2026 18:23

@darkweaver87 darkweaver87 left a comment

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.

LGTM

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

Labels

kind/enhancement a new or improved feature.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants