fix: correct platform format in version detection

Created version package for semantic version comparison.
Fixed GetLatestVersionByTypeAndArch to use combined platform format.
Replaced inline version comparison with reusable version.Compare().
This commit is contained in:
Fimeg
2025-11-10 21:50:46 -05:00
parent c95cc7d91f
commit ddaa9ac637
3 changed files with 81 additions and 42 deletions

View File

@@ -12,6 +12,7 @@ import (
"github.com/Fimeg/RedFlag/aggregator-server/internal/database/queries" "github.com/Fimeg/RedFlag/aggregator-server/internal/database/queries"
"github.com/Fimeg/RedFlag/aggregator-server/internal/models" "github.com/Fimeg/RedFlag/aggregator-server/internal/models"
"github.com/Fimeg/RedFlag/aggregator-server/internal/services" "github.com/Fimeg/RedFlag/aggregator-server/internal/services"
"github.com/Fimeg/RedFlag/aggregator-server/internal/version"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"
) )
@@ -578,8 +579,10 @@ func (h *AgentUpdateHandler) CheckForUpdateAvailable(c *gin.Context) {
return return
} }
// Check if this is actually newer than current version // Check if this is actually newer than current version using version package
hasUpdate := isVersionUpgrade(latestVersion, agent.CurrentVersion) currentVer := version.Version(agent.CurrentVersion)
latestVer := version.Version(latestVersion)
hasUpdate := currentVer.IsUpgrade(latestVer)
log.Printf("[DEBUG] Version comparison - latest: %s, current: %s, hasUpdate: %v for platform: %s/%s", latestVersion, agent.CurrentVersion, hasUpdate, osType, osArch) log.Printf("[DEBUG] Version comparison - latest: %s, current: %s, hasUpdate: %v for platform: %s/%s", latestVersion, agent.CurrentVersion, hasUpdate, osType, osArch)
@@ -589,11 +592,12 @@ func (h *AgentUpdateHandler) CheckForUpdateAvailable(c *gin.Context) {
log.Printf("[DEBUG] Detected sub-version upgrade: %s -> %s", agent.CurrentVersion, latestVersion) log.Printf("[DEBUG] Detected sub-version upgrade: %s -> %s", agent.CurrentVersion, latestVersion)
} }
platform := version.Platform(osType + "-" + osArch)
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"hasUpdate": hasUpdate, "hasUpdate": hasUpdate,
"currentVersion": agent.CurrentVersion, "currentVersion": agent.CurrentVersion,
"latestVersion": latestVersion, "latestVersion": latestVersion,
"platform": osType + "-" + osArch, "platform": platform.String(),
}) })
} }
@@ -641,40 +645,4 @@ func (h *AgentUpdateHandler) GetUpdateStatus(c *gin.Context) {
"progress": progress, "progress": progress,
"error": errorMsg, "error": errorMsg,
}) })
}
// isVersionUpgrade returns true if new version is greater than current version
func isVersionUpgrade(newVersion string, currentVersion string) bool {
// Parse semantic versions
newParts := strings.Split(newVersion, ".")
curParts := strings.Split(currentVersion, ".")
// Pad arrays to 3 parts
for len(newParts) < 3 {
newParts = append(newParts, "0")
}
for len(curParts) < 3 {
curParts = append(curParts, "0")
}
// Convert to integers for comparison
newMajor, _ := strconv.Atoi(newParts[0])
newMinor, _ := strconv.Atoi(newParts[1])
newPatch, _ := strconv.Atoi(newParts[2])
curMajor, _ := strconv.Atoi(curParts[0])
curMinor, _ := strconv.Atoi(curParts[1])
curPatch, _ := strconv.Atoi(curParts[2])
// Check if new > current (not equal, not less)
if newMajor > curMajor {
return true
}
if newMajor == curMajor && newMinor > curMinor {
return true
}
if newMajor == curMajor && newMinor == curMinor && newPatch > curPatch {
return true
}
return false
} }

View File

@@ -240,17 +240,20 @@ func (q *AgentUpdateQueries) GetLatestVersion(platform string) (string, error) {
// GetLatestVersionByTypeAndArch retrieves the latest available version for a specific os_type and architecture // GetLatestVersionByTypeAndArch retrieves the latest available version for a specific os_type and architecture
func (q *AgentUpdateQueries) GetLatestVersionByTypeAndArch(osType, osArch string) (string, error) { func (q *AgentUpdateQueries) GetLatestVersionByTypeAndArch(osType, osArch string) (string, error) {
// Use combined platform format to match agent_update_packages storage
platformStr := osType + "-" + osArch
query := ` query := `
SELECT version FROM agent_update_packages SELECT version FROM agent_update_packages
WHERE platform = $1 AND architecture = $2 AND is_active = true WHERE (platform || '-' || architecture) = $1 AND is_active = true
ORDER BY version DESC LIMIT 1 ORDER BY version DESC LIMIT 1
` `
var latestVersion string var latestVersion string
err := q.db.Get(&latestVersion, query, osType, osArch) err := q.db.Get(&latestVersion, query, platformStr)
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return "", fmt.Errorf("no update packages available for platform %s/%s", osType, osArch) return "", fmt.Errorf("no update packages available for platform %s", platformStr)
} }
return "", fmt.Errorf("failed to get latest version: %w", err) return "", fmt.Errorf("failed to get latest version: %w", err)
} }

View File

@@ -0,0 +1,68 @@
package version
import (
"strconv"
"strings"
)
// Version represents a semantic version string
type Version string
// Platform represents combined platform-architecture format (e.g., "linux-amd64")
type Platform string
// ParsePlatform converts "linux-amd64" → platform="linux", arch="amd64"
func ParsePlatform(p Platform) (platform, architecture string) {
parts := strings.SplitN(string(p), "-", 2)
if len(parts) == 2 {
return parts[0], parts[1]
}
return string(p), ""
}
// String returns the full platform string
func (p Platform) String() string {
return string(p)
}
// Compare returns -1, 0, or 1 for v < other, v == other, v > other
func (v Version) Compare(other Version) int {
v1Parts := strings.Split(string(v), ".")
v2Parts := strings.Split(string(other), ".")
maxLen := len(v1Parts)
if len(v2Parts) > maxLen {
maxLen = len(v2Parts)
}
for i := 0; i < maxLen; i++ {
v1Num := 0
v2Num := 0
if i < len(v1Parts) {
v1Num, _ = strconv.Atoi(v1Parts[i])
}
if i < len(v2Parts) {
v2Num, _ = strconv.Atoi(v2Parts[i])
}
if v1Num < v2Num {
return -1
}
if v1Num > v2Num {
return 1
}
}
return 0
}
// IsUpgrade returns true if other is newer than v
func (v Version) IsUpgrade(other Version) bool {
return v.Compare(other) < 0
}
// IsValid returns true if version string is non-empty
func (v Version) IsValid() bool {
return string(v) != ""
}