mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-25 13:10:13 +00:00
9f7b070e80
The V1 agent line is retired: no new V1 sessions since 2026-05-09, only orphaned straggler traffic remained on /api/agent/ingest (last seen 2026-06-29, events for long-cleaned-up sessions). Bootstrap/Intune/CI have deployed V2-only since the v2 cutover. Agent: - Delete AutopilotMonitor.Agent, .Agent.Core, .Agent.Core.Tests (projects + sln entries). V2 trio, SummaryDialog, DecisionCore.Tests and V2Isolation.targets stay. Backend: - Relocate the shared statics/DTOs V2 reused from the V1 partials (StampServerFields, SanitizeEventTimestamps, IsMaxLifetimeAgentShutdown, RecalculateAppDurations, EventClassification, AppInstallAggregationState) into EventIngestProcessor; IngestEventsOutput moves next to IngestTelemetryFunction (same namespace, zero ripple). - Delete IngestEventsFunction (route agent/ingest), BootstrapIngestEvents (route bootstrap/ingest), NdjsonParser and their DI registration. EventDataNormalizer stays (used by TelemetryPayloadParser). - Drop both routes from EndpointAccessPolicyCatalog and RequestTelemetryMiddleware.TenantHeaderTrustedPaths. - Retire the V1 update-hash oracle: LatestAgentV1*/LatestBootstrapV1* fields + GetAgentLine case 1 (default arm returns empty hashes, so stragglers gracefully skip the integrity check; ParseAgentMajor keeps its default of 1 on purpose — defaulting to 2 would feed V2 hashes to V1 binaries). TableConfigRepository Store+Map updated in lockstep. - Remove ApiEndpoints.IngestEvents/.BootstrapIngestEvents constants. Tests: NdjsonParserTests deleted; timestamp/critical-path/max-lifetime tests repointed to EventIngestProcessor; the two NDJSON pipeline tests removed (coverage retained by direct-list siblings); catalog/no-store InlineData rows updated. Docs: architecture.md (endpoint tables, ingest flow diagram, solution layout, test matrix), web SectionAgentInternals endpoint tables, build.ps1 help text. Azure: no config change needed — /api/agent is not in the client-cert exclusion paths (agent/ingest was always cert-enforced) and the /api/bootstrap prefix exclusion remains for the surviving bootstrap routes (verified via ARM on autopilotmonitor-api). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
79 lines
3.4 KiB
C#
79 lines
3.4 KiB
C#
using AutopilotMonitor.Functions.Middleware;
|
|
|
|
namespace AutopilotMonitor.Functions.Tests;
|
|
|
|
public class NoStoreCacheMiddlewareTests
|
|
{
|
|
[Theory]
|
|
// Exact-match credential / identity routes
|
|
[InlineData("/api/auth/me")]
|
|
[InlineData("/api/agent/config")]
|
|
[InlineData("/api/agent/upload-url")]
|
|
[InlineData("/api/bootstrap/config")]
|
|
// Prefix-match routes — Bearer token (bootstrap/validate), tenant config, sessions
|
|
[InlineData("/api/bootstrap/validate/ABC123")]
|
|
[InlineData("/api/config/contoso-tenant-id")]
|
|
[InlineData("/api/config/contoso-tenant-id/bootstrap-tokens")]
|
|
[InlineData("/api/sessions/session-guid-here")]
|
|
[InlineData("/api/sessions/session-guid-here/events")]
|
|
// Session list + diagnostics-download surfaces — PII session payloads / proxied ZIPs
|
|
[InlineData("/api/sessions")]
|
|
[InlineData("/api/diagnostics/download-url")]
|
|
[InlineData("/api/diagnostics/download-ticket")] // short-lived signed download credential
|
|
[InlineData("/api/diagnostics/download")] // ticket-gated anonymous ZIP stream
|
|
// /api/search/* — quick, sessions, sessions-by-event, sessions-by-cve (all return session PII)
|
|
[InlineData("/api/search/quick")]
|
|
[InlineData("/api/search/sessions")]
|
|
[InlineData("/api/search/sessions-by-event")]
|
|
[InlineData("/api/search/sessions-by-cve")]
|
|
// GA cross-tenant raw + global PII surfaces
|
|
[InlineData("/api/raw/sessions")]
|
|
[InlineData("/api/raw/events")]
|
|
[InlineData("/api/global/sessions")]
|
|
[InlineData("/api/global/raw/sessions")]
|
|
[InlineData("/api/global/raw/events")]
|
|
[InlineData("/api/global/raw/tables/foo")]
|
|
[InlineData("/api/global/search/sessions")]
|
|
[InlineData("/api/global/search/sessions-by-cve")]
|
|
[InlineData("/api/global/distress-reports")]
|
|
[InlineData("/api/global/session-reports")]
|
|
[InlineData("/api/global/session-reports/download-url")] // 15-min SAS URL in response
|
|
[InlineData("/api/global/session-reports/report-id/note")]
|
|
// Case-insensitive
|
|
[InlineData("/API/Auth/Me")]
|
|
[InlineData("/api/Bootstrap/Validate/abc")]
|
|
[InlineData("/API/Diagnostics/Download-Url")]
|
|
[InlineData("/api/Global/Session-Reports/Download-Url")]
|
|
public void IsSensitive_ReturnsTrue_ForCredentialBearingRoutes(string path)
|
|
{
|
|
Assert.True(NoStoreCacheMiddleware.IsSensitive(path),
|
|
$"Expected '{path}' to be classified as sensitive.");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("/api/health")]
|
|
[InlineData("/api/stats/platform")]
|
|
[InlineData("/api/agent/telemetry")]
|
|
[InlineData("/api/agent/register-session")]
|
|
[InlineData("/api/auth/global-admins")] // returns admin list, but no Bearer/SAS
|
|
[InlineData("/api/auth/is-global-admin")]
|
|
[InlineData("/api/rules")]
|
|
[InlineData("/api/rules/gather")]
|
|
[InlineData("/api/rules/analyze")]
|
|
[InlineData("/api/notifications")] // tenant bell — no SAS / token
|
|
[InlineData("/api/audit/logs")] // not in scope: see middleware allowlist commentary
|
|
[InlineData("/")]
|
|
[InlineData("")]
|
|
public void IsSensitive_ReturnsFalse_ForNonCredentialRoutes(string path)
|
|
{
|
|
Assert.False(NoStoreCacheMiddleware.IsSensitive(path),
|
|
$"Expected '{path}' to NOT be classified as sensitive (would over-stamp no-store).");
|
|
}
|
|
|
|
[Fact]
|
|
public void IsSensitive_NullPath_ReturnsFalse()
|
|
{
|
|
Assert.False(NoStoreCacheMiddleware.IsSensitive(null!));
|
|
}
|
|
}
|