Use datestamp as agent version

This commit is contained in:
Graham McIntire 2026-02-09 13:51:32 -06:00
parent ae9b393137
commit a50c8e6314
No known key found for this signature in database
2 changed files with 68 additions and 6 deletions

View file

@ -191,15 +191,28 @@ defmodule Towerops.Agent.Validator do
{:error, {:decode_error, "Invalid protobuf message format"}}
end
# Validate semantic version format (empty string allowed for backward compat)
# Validate version format - accepts either semantic version or RFC 3339 timestamp
# Empty string allowed for backward compat
defp validate_version(""), do: :ok
defp validate_version(version) when is_binary(version) do
if String.match?(version, ~r/^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$/) and
String.length(version) <= @max_short_string_length do
:ok
else
{:error, {:invalid_version, "Version must be semver format (e.g., 1.2.3)"}}
cond do
# Semantic version format (backward compatibility with old agents)
# Pattern: X.Y.Z or X.Y.Z-suffix
String.match?(version, ~r/^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$/) ->
if String.length(version) <= @max_short_string_length,
do: :ok,
else: {:error, {:invalid_version, "Version too long"}}
# RFC 3339 timestamp format (new agents with compile timestamp)
# Pattern: YYYY-MM-DDTHH:MM:SSZ
String.match?(version, ~r/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/) ->
if String.length(version) <= @max_short_string_length,
do: :ok,
else: {:error, {:invalid_version, "Version too long"}}
true ->
{:error, {:invalid_version, "Version must be semver format (e.g., 1.2.3) or RFC 3339 timestamp"}}
end
end

View file

@ -535,6 +535,55 @@ defmodule Towerops.Agent.ValidatorTest do
assert {:ok, _} = Validator.validate_heartbeat(binary)
end
test "accepts RFC 3339 timestamp version format" do
heartbeat = %AgentHeartbeat{
version: "2025-02-09T15:30:45Z",
hostname: "agent01",
uptime_seconds: 100,
ip_address: ""
}
binary = AgentHeartbeat.encode(heartbeat)
assert {:ok, validated} = Validator.validate_heartbeat(binary)
assert validated.version == "2025-02-09T15:30:45Z"
end
test "accepts RFC 3339 timestamp with different date/time" do
heartbeat = %AgentHeartbeat{
version: "2026-12-31T23:59:59Z",
hostname: "agent02",
uptime_seconds: 200,
ip_address: ""
}
binary = AgentHeartbeat.encode(heartbeat)
assert {:ok, _} = Validator.validate_heartbeat(binary)
end
test "rejects RFC 3339 timestamp without Z suffix" do
heartbeat = %AgentHeartbeat{
version: "2025-02-09T15:30:45",
hostname: "agent01",
uptime_seconds: 100,
ip_address: ""
}
binary = AgentHeartbeat.encode(heartbeat)
assert {:error, {:invalid_version, _}} = Validator.validate_heartbeat(binary)
end
test "rejects RFC 3339 timestamp with offset instead of Z" do
heartbeat = %AgentHeartbeat{
version: "2025-02-09T15:30:45+00:00",
hostname: "agent01",
uptime_seconds: 100,
ip_address: ""
}
binary = AgentHeartbeat.encode(heartbeat)
assert {:error, {:invalid_version, _}} = Validator.validate_heartbeat(binary)
end
test "rejects version with spaces" do
heartbeat = %AgentHeartbeat{
version: "1.2 .3",