diff --git a/src/Backend/AutopilotMonitor.Functions.Tests/GetAgentConfigFunctionTests.cs b/src/Backend/AutopilotMonitor.Functions.Tests/GetAgentConfigFunctionTests.cs index b1b54778..e2ecaadd 100644 --- a/src/Backend/AutopilotMonitor.Functions.Tests/GetAgentConfigFunctionTests.cs +++ b/src/Backend/AutopilotMonitor.Functions.Tests/GetAgentConfigFunctionTests.cs @@ -31,4 +31,27 @@ public class GetAgentConfigFunctionTests var actual = GetAgentConfigFunction.ParseAgentMajor(agentVersion); Assert.Equal(expectedMajor, actual); } + + [Theory] + // CustomerSas: gated on the per-tenant SAS URL being present. + [InlineData("https://acct.blob.core.windows.net/c?sv=...", "CustomerSas", true)] + [InlineData(null, "CustomerSas", false)] + [InlineData("", "CustomerSas", false)] + // Hosted: platform owns the storage, no per-tenant SAS URL — must still enable uploads. + // Regression guard for the bug where Hosted-destination tenants silently never uploaded. + [InlineData(null, "Hosted", true)] + [InlineData("", "Hosted", true)] + [InlineData(null, "hosted", true)] // case-insensitive + // Hosted with a SAS also set (belt-and-braces) stays enabled. + [InlineData("https://acct.blob.core.windows.net/c?sv=...", "Hosted", true)] + // Unknown/empty destination with no SAS → disabled (no silent uploads to nowhere). + [InlineData(null, null, false)] + [InlineData(null, "", false)] + [InlineData(null, "Bogus", false)] + public void ResolveDiagnosticsUploadEnabled_GatesOnSasOrHosted( + string? diagnosticsBlobSasUrl, string? destination, bool expected) + { + var actual = GetAgentConfigFunction.ResolveDiagnosticsUploadEnabled(diagnosticsBlobSasUrl, destination); + Assert.Equal(expected, actual); + } } diff --git a/src/Backend/AutopilotMonitor.Functions/Functions/Config/GetAgentConfigFunction.cs b/src/Backend/AutopilotMonitor.Functions/Functions/Config/GetAgentConfigFunction.cs index 4eeccf80..6ace3c77 100644 --- a/src/Backend/AutopilotMonitor.Functions/Functions/Config/GetAgentConfigFunction.cs +++ b/src/Backend/AutopilotMonitor.Functions/Functions/Config/GetAgentConfigFunction.cs @@ -117,6 +117,19 @@ namespace AutopilotMonitor.Functions.Functions.Config return int.TryParse(majorStr, out var major) ? major : 1; } + /// + /// Decides whether the agent should perform diagnostics uploads at all. + /// The CustomerSas destination is gated on a per-tenant SAS URL being present, but the + /// Hosted destination has no such URL (the platform owns the storage) — so gating purely + /// on the SAS URL silently disabled uploads for every Hosted-destination tenant. Enable + /// when either a customer SAS is configured OR the destination is Hosted. + /// + internal static bool ResolveDiagnosticsUploadEnabled(string? diagnosticsBlobSasUrl, string? destination) + { + return !string.IsNullOrEmpty(diagnosticsBlobSasUrl) + || string.Equals(destination, "Hosted", StringComparison.OrdinalIgnoreCase); + } + /// /// Returns the (ZipSha256, ExeSha256) pair appropriate for the calling agent. /// Reads the X-Agent-Version header, parses the major, and dispatches to the @@ -197,7 +210,8 @@ namespace AutopilotMonitor.Functions.Functions.Config EnrollmentSummaryBrandingImageUrl = tenantConfig.EnrollmentSummaryBrandingImageUrl, EnrollmentSummaryLaunchRetrySeconds = tenantConfig.EnrollmentSummaryLaunchRetrySeconds ?? 120, MaxBatchSize = tenantConfig.MaxBatchSize ?? 100, - DiagnosticsUploadEnabled = !string.IsNullOrEmpty(tenantConfig.DiagnosticsBlobSasUrl), + DiagnosticsUploadEnabled = ResolveDiagnosticsUploadEnabled( + tenantConfig.DiagnosticsBlobSasUrl, tenantConfig.DiagnosticsUploadDestination), DiagnosticsUploadMode = tenantConfig.DiagnosticsUploadMode ?? "Off", DiagnosticsLogPaths = diagLogPaths, Collectors = collectors,