From 2ecbefce73c0789efc49ac4b6eb8f6dd76747c4e Mon Sep 17 00:00:00 2001 From: Oliver Kieselbach Date: Wed, 22 Apr 2026 17:51:12 +0200 Subject: [PATCH] backend route fix and v2 agent version check fix --- .../Monitoring/Runtime/SelfUpdater.cs | 32 ++++++++++--------- .../buildcounter.txt | 2 +- .../AutopilotMonitor.Agent/buildcounter.txt | 2 +- .../Middleware/AuthenticationMiddleware.cs | 1 + .../AutopilotMonitor.Shared/Constants.cs | 16 ++++++++-- 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/Agent/AutopilotMonitor.Agent.V2.Core/Monitoring/Runtime/SelfUpdater.cs b/src/Agent/AutopilotMonitor.Agent.V2.Core/Monitoring/Runtime/SelfUpdater.cs index d9ce3c92..0b489591 100644 --- a/src/Agent/AutopilotMonitor.Agent.V2.Core/Monitoring/Runtime/SelfUpdater.cs +++ b/src/Agent/AutopilotMonitor.Agent.V2.Core/Monitoring/Runtime/SelfUpdater.cs @@ -13,11 +13,13 @@ using Newtonsoft.Json.Linq; namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Runtime { /// - /// Fast self-update at agent startup: checks version.json in blob storage, - /// downloads the ZIP if newer, swaps files (rename-trick for locked binaries), + /// Fast self-update at agent startup: checks version-v2.json in blob storage, + /// downloads the V2 ZIP if newer, swaps files (rename-trick for locked binaries), /// and restarts via PowerShell Wait-Process. /// /// Design priority: speed over update — better to run the old version than delay startup. + /// V2 uses its own manifest (version-v2.json) + ZIP (AutopilotMonitor-Agent-V2.zip) to + /// stay isolated from the legacy V1 release line. /// static class SelfUpdater { @@ -82,7 +84,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Runtime /// /// Optional: backend-provided SHA-256 hash of the latest agent ZIP. /// Set from the last AgentConfigResponse before calling CheckAndApplyUpdateAsync. - /// Takes priority over the hash in version.json (separate trust channel). + /// Takes priority over the hash in version-v2.json (separate trust channel). /// public static string BackendExpectedSha256 { get; set; } @@ -107,7 +109,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Runtime /// /// When false (default), a latest version strictly lower than /// is rejected even when is true — prevents the production - /// version.json from silently overwriting a higher-versioned dev/pre-release agent via + /// version-v2.json from silently overwriting a higher-versioned dev/pre-release agent via /// the runtime hash-mismatch path. Set to true only for controlled rollback scenarios. /// public static async Task CheckAndApplyUpdateAsync( @@ -134,7 +136,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Runtime try { - // Step 1: Fetch version.json (1s timeout) + // Step 1: Fetch version-v2.json (2.5s timeout) var versionSw = Stopwatch.StartNew(); string manifestSha256; (latestVersion, manifestSha256) = await GetLatestVersionAsync(log); @@ -144,7 +146,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Runtime if (latestVersion == null) { if (isStartupTrigger) - WriteSkipMarker("version_check_failed", currentVersion, null, "version.json fetch failed or timed out", log); + WriteSkipMarker("version_check_failed", currentVersion, null, "version-v2.json fetch failed or timed out", log); return; // Could not determine latest version — continue with current } @@ -211,7 +213,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Runtime } try { zipSizeBytes = new FileInfo(zipPath).Length; } catch { /* best-effort */ } - // Step 3b: Verify SHA-256 integrity (backend hash has priority over version.json hash) + // Step 3b: Verify SHA-256 integrity (backend hash has priority over version-v2.json hash) string expectedSha256; if (!string.IsNullOrEmpty(BackendExpectedSha256)) { @@ -221,7 +223,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Runtime else if (!string.IsNullOrEmpty(manifestSha256)) { expectedSha256 = manifestSha256; - log("Self-update: using version.json hash for integrity verification (blob storage)"); + log("Self-update: using version-v2.json hash for integrity verification (blob storage)"); } else { @@ -313,14 +315,14 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Runtime } /// - /// Fetches version.json from blob storage and returns the version string and optional SHA-256 hash. + /// Fetches version-v2.json from blob storage and returns the version string and optional SHA-256 hash. /// Returns (null, null) if the check fails or times out. /// private static async Task<(string version, string sha256)> GetLatestVersionAsync(Action log) { try { - var versionUrl = $"{Constants.AgentBlobBaseUrl}/{Constants.AgentVersionFileName}"; + var versionUrl = $"{Constants.AgentBlobBaseUrl}/{Constants.AgentVersionFileNameV2}"; using (var handler = new HttpClientHandler()) using (var client = new HttpClient(handler) { Timeout = TimeSpan.FromMilliseconds(VersionCheckTimeoutMs) }) @@ -331,13 +333,13 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Runtime if (string.IsNullOrWhiteSpace(version)) { - log("Self-update: version.json has no 'version' field"); + log("Self-update: version-v2.json has no 'version' field"); return (null, null); } var sha256 = obj["sha256"]?.ToString(); if (!string.IsNullOrWhiteSpace(sha256)) - log($"Self-update: version.json has SHA-256 hash for integrity verification"); + log($"Self-update: version-v2.json has SHA-256 hash for integrity verification"); return (version.Trim(), sha256?.Trim()); } @@ -349,7 +351,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Runtime } catch (HttpRequestException ex) when (ex.Message.Contains("404")) { - log("Self-update: version.json not found (404) — skipping update"); + log("Self-update: version-v2.json not found (404) — skipping update"); return (null, null); } catch (Exception ex) @@ -447,7 +449,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Runtime { try { - var zipUrl = $"{Constants.AgentBlobBaseUrl}/{Constants.AgentZipFileName}"; + var zipUrl = $"{Constants.AgentBlobBaseUrl}/{Constants.AgentZipFileNameV2}"; // Clean up any previous download if (File.Exists(zipPath)) @@ -664,7 +666,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Runtime /// /// Writes a small JSON marker so the next agent startup can emit an agent_version_check event - /// with outcome=skipped (or check_failed if the version.json fetch itself failed). Only called + /// with outcome=skipped (or check_failed if the version-v2.json fetch itself failed). Only called /// on the startup trigger path (runtime-triggered failures are logged normally because the full /// logger is already up). Best-effort — never throws. /// diff --git a/src/Agent/AutopilotMonitor.Agent.V2/buildcounter.txt b/src/Agent/AutopilotMonitor.Agent.V2/buildcounter.txt index e34885bb..bc6298e8 100644 --- a/src/Agent/AutopilotMonitor.Agent.V2/buildcounter.txt +++ b/src/Agent/AutopilotMonitor.Agent.V2/buildcounter.txt @@ -1 +1 @@ -107 +110 diff --git a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt index 69559761..6d0c1073 100644 --- a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt +++ b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt @@ -1 +1 @@ -1075 +1077 diff --git a/src/Backend/AutopilotMonitor.Functions/Middleware/AuthenticationMiddleware.cs b/src/Backend/AutopilotMonitor.Functions/Middleware/AuthenticationMiddleware.cs index c30e30a1..0a2fb914 100644 --- a/src/Backend/AutopilotMonitor.Functions/Middleware/AuthenticationMiddleware.cs +++ b/src/Backend/AutopilotMonitor.Functions/Middleware/AuthenticationMiddleware.cs @@ -44,6 +44,7 @@ public class AuthenticationMiddleware : IFunctionsWorkerMiddleware "/api/stats/platform", "/api/agent/register-session", "/api/agent/ingest", + "/api/agent/telemetry", "/api/agent/config", "/api/agent/upload-url", "/api/agent/error", diff --git a/src/Shared/AutopilotMonitor.Shared/Constants.cs b/src/Shared/AutopilotMonitor.Shared/Constants.cs index 83694baa..e1e09d77 100644 --- a/src/Shared/AutopilotMonitor.Shared/Constants.cs +++ b/src/Shared/AutopilotMonitor.Shared/Constants.cs @@ -82,15 +82,27 @@ namespace AutopilotMonitor.Shared public const string AgentBlobBaseUrl = "https://autopilotmonitor.blob.core.windows.net/agent"; /// - /// Version manifest filename in blob storage (JSON: { "version": "1.0.350" }) + /// Version manifest filename in blob storage (JSON: { "version": "1.0.350" }) — Legacy V1 agent only. /// public const string AgentVersionFileName = "version.json"; /// - /// Agent ZIP filename in blob storage + /// Agent ZIP filename in blob storage — Legacy V1 agent only. /// public const string AgentZipFileName = "AutopilotMonitor-Agent.zip"; + /// + /// V2 version manifest filename — separate release line from V1 to prevent + /// the V2 agent from being downgrade-blocked against V1 versions. + /// Matches what the V2 bootstrapper downloads (Install-AutopilotMonitor-v2.ps1). + /// + public const string AgentVersionFileNameV2 = "version-v2.json"; + + /// + /// V2 agent ZIP filename — paired with . + /// + public const string AgentZipFileNameV2 = "AutopilotMonitor-Agent-V2.zip"; + /// /// Staging directory for self-update extraction ///