Skip to content

Commit 1263f83

Browse files
fix(agent-update): stop stripping the pre-release suffix from the bundled agent version
util.GetVersionFromBinaryPath parsed the bundled agent binary with a regex that captured only MAJOR.MINOR.PATCH, so an edge binary stamped 2.0.3-rc.116 was read as "2.0.3". That value is what ServeAgentVersion advertises as latestVersion, and CompareVersions correctly ranks a release above its pre-release, so once a host had actually installed the rc the server kept reporting hasUpdate: true and the agent re-downloaded the identical binary on every check. handler/agent_version.go already carried the corrected pattern along with a comment describing this exact failure; the util copy was never updated and the two drifted. Promote the pattern to util.AgentVersionRe and alias the handler constant to it so there is only one definition, which also means the existing TestAgentVersionRe_CapturesPreRelease now guards both call sites. alerts/agent_update.go shares the same helper, so the "Agent Files Update Available" alert was likewise comparing a truncated current version against the full DNS value. Upgrades from an older release are unaffected: the numeric core decides before the pre-release identifiers are consulted, so 2.0.2 still sees 2.0.3-rc.116 as an update.
1 parent 379225c commit 1263f83

2 files changed

Lines changed: 13 additions & 9 deletions

File tree

server-source-code/internal/handler/agent_version.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@ import (
1818

1919
const (
2020
agentDNSDomain = "agent.vcheck.patchmon.net"
21-
// The pre-release group is required, not cosmetic: edge agents are stamped
22-
// 2.0.3-rc.61, and capturing only the numeric core would report them as
23-
// "2.0.3" here while the agent itself reports the full string. The two would
24-
// never match, so every check would look like a pending update and the agent
25-
// would re-download itself forever.
26-
agentVersionRe = `(?i)(?:PatchMon Agent v|patchmon-agent v|version )?([0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?)`
21+
// Shared with util.GetVersionFromBinaryPath, which backs the agent's own
22+
// update check. Two copies drifted apart once and stripped the pre-release
23+
// suffix on the update path only; keep this an alias, not a duplicate.
24+
agentVersionRe = util.AgentVersionRe
2725
)
2826

2927
// AgentVersionHandler handles agent version routes.

server-source-code/internal/util/agent_binary.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ import (
1111
"time"
1212
)
1313

14-
const agentVersionRe = `(?i)(?:PatchMon Agent v|patchmon-agent v|version )?([0-9]+\.[0-9]+\.[0-9]+)`
14+
// AgentVersionRe parses a version out of an agent binary's own output. The
15+
// pre-release group is required, not cosmetic: edge agents are stamped
16+
// 2.0.3-rc.61, and capturing only the numeric core reports them as "2.0.3"
17+
// here while the agent itself reports the full string. The server then
18+
// advertises a latestVersion that always outranks what the agent has, so every
19+
// check looks like a pending update and the agent re-downloads itself forever.
20+
const AgentVersionRe = `(?i)(?:PatchMon Agent v|patchmon-agent v|version )?([0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?)`
1521

1622
// GetAgentsDir returns the agents binary directory from env (AGENT_BINARIES_DIR, AGENTS_DIR) or "agents".
1723
func GetAgentsDir() string {
@@ -59,7 +65,7 @@ func GetCurrentAgentVersionFromBinary(ctx context.Context, agentsDir string) str
5965
return ""
6066
}
6167

62-
versionRe := regexp.MustCompile(agentVersionRe)
68+
versionRe := regexp.MustCompile(AgentVersionRe)
6369
versionCommands := []string{"--version", "version", "--help"}
6470

6571
for _, cmd := range versionCommands {
@@ -80,7 +86,7 @@ func GetCurrentAgentVersionFromBinary(ctx context.Context, agentsDir string) str
8086
// Tries executing the binary if it matches server platform (linux/linux, freebsd/freebsd), else uses "strings".
8187
// Callers must pass binaryPath validated with SafePathUnderBase(baseDir, binaryName) to prevent command injection.
8288
func GetVersionFromBinaryPath(ctx context.Context, binaryPath string) string {
83-
versionRe := regexp.MustCompile(agentVersionRe)
89+
versionRe := regexp.MustCompile(AgentVersionRe)
8490
serverOS := runtime.GOOS
8591
binaryOS := "linux"
8692
if strings.Contains(binaryPath, "freebsd") {

0 commit comments

Comments
 (0)