From 557f5a8d982cb0c0447948defd65b03f76f6b6f3 Mon Sep 17 00:00:00 2001 From: Lrifton92 Date: Tue, 9 Jun 2026 15:56:45 +0200 Subject: [PATCH 1/3] fix: resolve version from build info when not set via ldflags When oauth2-proxy is built without the Makefile/dist.sh ldflags (for example via `go install github.com/oauth2-proxy/oauth2-proxy/v7@latest`), the VERSION variable kept its default "undefined" value, so `oauth2-proxy --version` reported "oauth2-proxy undefined (built with ...)". Fall back to the module version recorded in runtime/debug build info when VERSION has not been overridden at build time. The ldflags-injected value still takes precedence, so official release builds are unchanged. Closes #3451 Signed-off-by: Lrifton92 --- pkg/version/version.go | 28 ++++++++++++++++- pkg/version/version_test.go | 63 +++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 pkg/version/version_test.go diff --git a/pkg/version/version.go b/pkg/version/version.go index 8635c8ba..628036be 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -1,4 +1,30 @@ package version -// VERSION contains version information +import "runtime/debug" + +// VERSION contains version information. It is set at build time via +// -ldflags "-X github.com/oauth2-proxy/oauth2-proxy/v7/pkg/version.VERSION=". +// When the binary is built without those flags (for example via +// `go install github.com/oauth2-proxy/oauth2-proxy/v7@latest`), it falls back +// to the module version recorded in the build info so that `--version` still +// reports a meaningful value instead of "undefined". var VERSION = "undefined" + +func init() { + VERSION = resolveVersion(VERSION, debug.ReadBuildInfo) +} + +// resolveVersion returns ldflagsVersion when it has been explicitly set at +// build time. Otherwise it derives the version from the module build info, +// allowing `go install`-ed binaries to report a meaningful version. +func resolveVersion(ldflagsVersion string, readBuildInfo func() (*debug.BuildInfo, bool)) string { + if ldflagsVersion != "" && ldflagsVersion != "undefined" { + return ldflagsVersion + } + if info, ok := readBuildInfo(); ok && info != nil { + if v := info.Main.Version; v != "" && v != "(devel)" { + return v + } + } + return ldflagsVersion +} diff --git a/pkg/version/version_test.go b/pkg/version/version_test.go new file mode 100644 index 00000000..9629a485 --- /dev/null +++ b/pkg/version/version_test.go @@ -0,0 +1,63 @@ +package version + +import ( + "runtime/debug" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestResolveVersion(t *testing.T) { + testCases := []struct { + name string + ldflagsVersion string + buildInfo *debug.BuildInfo + buildInfoOK bool + expected string + }{ + { + name: "ldflags version takes precedence over build info", + ldflagsVersion: "v7.15.3", + buildInfo: &debug.BuildInfo{Main: debug.Module{Version: "v7.15.0"}}, + buildInfoOK: true, + expected: "v7.15.3", + }, + { + name: "falls back to build info version when undefined", + ldflagsVersion: "undefined", + buildInfo: &debug.BuildInfo{Main: debug.Module{Version: "v7.15.3"}}, + buildInfoOK: true, + expected: "v7.15.3", + }, + { + name: "keeps undefined when build info is unavailable", + ldflagsVersion: "undefined", + buildInfo: nil, + buildInfoOK: false, + expected: "undefined", + }, + { + name: "keeps undefined for a (devel) build info version", + ldflagsVersion: "undefined", + buildInfo: &debug.BuildInfo{Main: debug.Module{Version: "(devel)"}}, + buildInfoOK: true, + expected: "undefined", + }, + { + name: "keeps undefined for an empty build info version", + ldflagsVersion: "undefined", + buildInfo: &debug.BuildInfo{Main: debug.Module{Version: ""}}, + buildInfoOK: true, + expected: "undefined", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := resolveVersion(tc.ldflagsVersion, func() (*debug.BuildInfo, bool) { + return tc.buildInfo, tc.buildInfoOK + }) + assert.Equal(t, tc.expected, result) + }) + } +} From b03d5127b31ec3742fcda84a47ecb5fcbd1c9061 Mon Sep 17 00:00:00 2001 From: Lrifton92 Date: Tue, 9 Jun 2026 15:57:52 +0200 Subject: [PATCH 2/3] docs: add CHANGELOG entry for #3452 Signed-off-by: Lrifton92 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 788e82c2..44e44bb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ ## Changes since v7.15.3 +- [#3452](https://github.com/oauth2-proxy/oauth2-proxy/pull/3452) fix: resolve version from build info when not set via ldflags (so `go install`-ed binaries report a real version instead of `undefined`) (@Lrifton92) + # V7.15.3 ## Release Highlights From fc2d4e81f15674511fc71304cd707ecb96e5a288 Mon Sep 17 00:00:00 2001 From: Lrifton92 Date: Wed, 24 Jun 2026 11:57:01 +0200 Subject: [PATCH 3/3] version: document (devel) and pseudo-version build-info behavior Clarify in resolveVersion why "(devel)" is skipped and what info.Main.Version carries for tagged installs vs. builds on top of a release, per review feedback on #3452. Signed-off-by: Lrifton92 --- pkg/version/version.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/version/version.go b/pkg/version/version.go index 628036be..8b1dab87 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -22,6 +22,14 @@ func resolveVersion(ldflagsVersion string, readBuildInfo func() (*debug.BuildInf return ldflagsVersion } if info, ok := readBuildInfo(); ok && info != nil { + // info.Main.Version is populated by the Go toolchain only for + // module-aware builds: it is the clean tag for an exact + // `@vX.Y.Z` install, or a synthesized pseudo-version + // (e.g. v7.15.4-0.20240115123456-abcdef123456) carrying the + // base version, commit timestamp and hash when built from + // commits on top of a release. A plain `go build` from a source + // checkout reports "(devel)", which we skip so release builds + // keep deferring to the ldflags value below. if v := info.Main.Version; v != "" && v != "(devel)" { return v }