Watch
1
0
Fork
You've already forked RedFlag
0
RedFlag/server/internal/version/versions.go
Fimeg ff2f30f47a v0.2.9.3: device classification + ARM support — Pixel 3 lands
DEVICE-002: ARM machine-ID fallback — device-tree model + /etc/machine-id
combo, then /proc/cpuinfo Serial (all-zero rejected), before the weak
hostname fallback. Hardware-bound IDs on DMI-less devices.

DEVICE-001: agent detects device_type (server/desktop/phone/tablet) from
/sys signals — system battery (scope=Device peripherals excluded, UPS
excluded), DRM connector state, framebuffer min-dimension for phone/tablet
split. Reports device_type/device_model/os_distro in registration and
system-info paths.

SERVER-001: migration 061 — device_type, device_type_manual (operator
override, never agent-written), device_model, os_distro on agents.
effective_device_type computed into every serialized agent.

SERVER-002: PUT /admin/agents/:id/device-type — set/clear override,
enum-validated, journaled.

WEB-001: device-type icons + fleet filter, device model in list, detail
header badge with reclassify dropdown, os_distro surfaced.

INSTALL-003: arm64 install path unblocked — helper (required manifest
component) now cross-built aarch64-unknown-linux-musl via rust-lld in the
server image, signed at boot (helperArches += arm64), listed in the release
manifest. Install template already handled uname -m and pacman.

Plus in-flight: desktop tray wiring, enrollment page polish, CI workflow
updates, RAF session-broker/pacman-scanner docs, native installer scaffold.
2026-07-06 18:21:23 -04:00

118 lines
3.2 KiB
Go

package version
import (
"fmt"
"strconv"
"strings"
"time"
)
// Version coordination for Server Authority model
// The server is the single source of truth for all version information
// Version information (SERVER AUTHORITY).
// Values are maintained by scripts/bump-version.sh and must match the release
// tag — the release gate enforces this. ldflags may override at build time;
// the release pipeline injects the tag so binaries and source agree.
var (
AgentVersion = "0.2.9.3"
ConfigVersion = "0.2.9.3"
MinAgentVersion = "0.1.22"
)
// CurrentVersions holds the authoritative version information
type CurrentVersions struct {
AgentVersion string `json:"agent_version"`
ConfigVersion string `json:"config_version"`
MinAgentVersion string `json:"min_agent_version"`
BuildTime time.Time `json:"build_time"`
}
// GetCurrentVersions returns the current version information
func GetCurrentVersions() CurrentVersions {
return CurrentVersions{
AgentVersion: AgentVersion,
ConfigVersion: ConfigVersion,
MinAgentVersion: MinAgentVersion,
BuildTime: time.Now(),
}
}
// CompareVersions compares two version strings using octet-based comparison.
// Returns -1 if a < b, 0 if a == b, 1 if a > b.
// Handles "dev" as always older than any release version.
// Version format: "0.1.26.0" (up to 4 octets, padded with zeros).
func CompareVersions(a, b string) int {
a = strings.TrimPrefix(a, "v")
b = strings.TrimPrefix(b, "v")
if a == b {
return 0
}
if a == "dev" || a == "" {
return -1
}
if b == "dev" || b == "" {
return 1
}
aParts := strings.Split(a, ".")
bParts := strings.Split(b, ".")
maxLen := len(aParts)
if len(bParts) > maxLen {
maxLen = len(bParts)
}
for i := 0; i < maxLen; i++ {
aVal := 0
bVal := 0
if i < len(aParts) {
if n, err := strconv.Atoi(aParts[i]); err == nil {
aVal = n
}
}
if i < len(bParts) {
if n, err := strconv.Atoi(bParts[i]); err == nil {
bVal = n
}
}
if aVal < bVal {
return -1
}
if aVal > bVal {
return 1
}
}
return 0
}
// ExtractConfigVersionFromAgent extracts config version from agent version.
// Agent version format: "0.1.23.6" where the last octet is the config version.
func ExtractConfigVersionFromAgent(agentVersion string) string {
cleanVersion := strings.TrimPrefix(agentVersion, "v")
parts := strings.Split(cleanVersion, ".")
if len(parts) >= 1 {
return parts[len(parts)-1]
}
return "3"
}
// ValidateAgentVersion checks if an agent version is compatible
func ValidateAgentVersion(agentVersion string) error {
current := GetCurrentVersions()
if CompareVersions(agentVersion, current.MinAgentVersion) < 0 {
return fmt.Errorf("agent version %s is below minimum %s", agentVersion, current.MinAgentVersion)
}
return nil
}
// GetBuildFlags returns the ldflags to inject versions into agent builds
func GetBuildFlags() []string {
versions := GetCurrentVersions()
return []string{
fmt.Sprintf("-X github.com/Fimeg/RedFlag/agent/internal/version.Version=%s", versions.AgentVersion),
fmt.Sprintf("-X github.com/Fimeg/RedFlag/agent/internal/version.ConfigVersion=%s", versions.ConfigVersion),
fmt.Sprintf("-X github.com/Fimeg/RedFlag/agent/internal/version.BuildTime=%s", versions.BuildTime.Format(time.RFC3339)),
}
}