fix: wire DeviceAssociationValidator through ValidateSecurityAsync

The DevPrep shadow validator was never executed because the
ValidateSecurityAsync extension constructed SecurityValidator without
passing DeviceAssociationValidator, so _deviceAssociationValidator was
always null and the gate at SecurityValidator.cs:370 silently skipped
the lookup — even with ValidateDeviceAssociation=true on the tenant.

Inject the validator via DI into all 9 agent-facing functions
(RegisterSession, IngestEvents, GetAgentConfig, ReportAgentError,
GetDiagnosticsUploadUrl + 4 Bootstrap variants) and thread it through
the extension to SecurityValidator.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Oliver Kieselbach
2026-04-14 18:40:45 +02:00
parent 52fcfce271
commit 54c2c80904
10 changed files with 48 additions and 11 deletions
@@ -21,6 +21,7 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
private readonly RateLimitService _rateLimitService;
private readonly AutopilotDeviceValidator _autopilotDeviceValidator;
private readonly CorporateIdentifierValidator _corporateIdentifierValidator;
private readonly DeviceAssociationValidator _deviceAssociationValidator;
private readonly BootstrapSessionService _bootstrapSessionService;
public BootstrapGetAgentConfigFunction(
@@ -30,6 +31,7 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
RateLimitService rateLimitService,
AutopilotDeviceValidator autopilotDeviceValidator,
CorporateIdentifierValidator corporateIdentifierValidator,
DeviceAssociationValidator deviceAssociationValidator,
BootstrapSessionService bootstrapSessionService)
{
_logger = logger;
@@ -38,6 +40,7 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
_rateLimitService = rateLimitService;
_autopilotDeviceValidator = autopilotDeviceValidator;
_corporateIdentifierValidator = corporateIdentifierValidator;
_deviceAssociationValidator = deviceAssociationValidator;
_bootstrapSessionService = bootstrapSessionService;
}
@@ -75,7 +78,8 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
var (validation, errorResponse) = await req.ValidateSecurityAsync(
tenantId, _configService, _rateLimitService,
_autopilotDeviceValidator, _corporateIdentifierValidator,
_logger, bootstrapSessionService: _bootstrapSessionService);
_logger, bootstrapSessionService: _bootstrapSessionService,
deviceAssociationValidator: _deviceAssociationValidator);
if (errorResponse != null)
{
@@ -22,6 +22,7 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
private readonly RateLimitService _rateLimitService;
private readonly AutopilotDeviceValidator _autopilotDeviceValidator;
private readonly CorporateIdentifierValidator _corporateIdentifierValidator;
private readonly DeviceAssociationValidator _deviceAssociationValidator;
private readonly BootstrapSessionService _bootstrapSessionService;
public BootstrapIngestEventsFunction(
@@ -31,6 +32,7 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
RateLimitService rateLimitService,
AutopilotDeviceValidator autopilotDeviceValidator,
CorporateIdentifierValidator corporateIdentifierValidator,
DeviceAssociationValidator deviceAssociationValidator,
BootstrapSessionService bootstrapSessionService)
{
_logger = logger;
@@ -39,6 +41,7 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
_rateLimitService = rateLimitService;
_autopilotDeviceValidator = autopilotDeviceValidator;
_corporateIdentifierValidator = corporateIdentifierValidator;
_deviceAssociationValidator = deviceAssociationValidator;
_bootstrapSessionService = bootstrapSessionService;
}
@@ -77,7 +80,8 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
var (validation, errorResponse) = await req.ValidateSecurityAsync(
tenantId, _configService, _rateLimitService,
_autopilotDeviceValidator, _corporateIdentifierValidator,
_logger, bootstrapSessionService: _bootstrapSessionService);
_logger, bootstrapSessionService: _bootstrapSessionService,
deviceAssociationValidator: _deviceAssociationValidator);
if (errorResponse != null)
{
@@ -24,6 +24,7 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
private readonly RateLimitService _rateLimitService;
private readonly AutopilotDeviceValidator _autopilotDeviceValidator;
private readonly CorporateIdentifierValidator _corporateIdentifierValidator;
private readonly DeviceAssociationValidator _deviceAssociationValidator;
private readonly BootstrapSessionService _bootstrapSessionService;
public BootstrapRegisterSessionFunction(
@@ -33,6 +34,7 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
RateLimitService rateLimitService,
AutopilotDeviceValidator autopilotDeviceValidator,
CorporateIdentifierValidator corporateIdentifierValidator,
DeviceAssociationValidator deviceAssociationValidator,
BootstrapSessionService bootstrapSessionService)
{
_logger = logger;
@@ -41,6 +43,7 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
_rateLimitService = rateLimitService;
_autopilotDeviceValidator = autopilotDeviceValidator;
_corporateIdentifierValidator = corporateIdentifierValidator;
_deviceAssociationValidator = deviceAssociationValidator;
_bootstrapSessionService = bootstrapSessionService;
}
@@ -91,7 +94,8 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
registration.TenantId, _configService, _rateLimitService,
_autopilotDeviceValidator, _corporateIdentifierValidator,
_logger, registration.SessionId,
bootstrapSessionService: _bootstrapSessionService);
bootstrapSessionService: _bootstrapSessionService,
deviceAssociationValidator: _deviceAssociationValidator);
if (errorResponse != null)
{
@@ -21,6 +21,7 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
private readonly RateLimitService _rateLimitService;
private readonly AutopilotDeviceValidator _autopilotDeviceValidator;
private readonly CorporateIdentifierValidator _corporateIdentifierValidator;
private readonly DeviceAssociationValidator _deviceAssociationValidator;
private readonly BootstrapSessionService _bootstrapSessionService;
public BootstrapReportAgentErrorFunction(
@@ -30,6 +31,7 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
RateLimitService rateLimitService,
AutopilotDeviceValidator autopilotDeviceValidator,
CorporateIdentifierValidator corporateIdentifierValidator,
DeviceAssociationValidator deviceAssociationValidator,
BootstrapSessionService bootstrapSessionService)
{
_logger = logger;
@@ -38,6 +40,7 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
_rateLimitService = rateLimitService;
_autopilotDeviceValidator = autopilotDeviceValidator;
_corporateIdentifierValidator = corporateIdentifierValidator;
_deviceAssociationValidator = deviceAssociationValidator;
_bootstrapSessionService = bootstrapSessionService;
}
@@ -74,7 +77,8 @@ namespace AutopilotMonitor.Functions.Functions.Bootstrap
var (_, errorResponse) = await req.ValidateSecurityAsync(
tenantId, _configService, _rateLimitService,
_autopilotDeviceValidator, _corporateIdentifierValidator,
_logger, bootstrapSessionService: _bootstrapSessionService);
_logger, bootstrapSessionService: _bootstrapSessionService,
deviceAssociationValidator: _deviceAssociationValidator);
if (errorResponse != null)
{
@@ -24,6 +24,7 @@ namespace AutopilotMonitor.Functions.Functions.Config
private readonly RateLimitService _rateLimitService;
private readonly AutopilotDeviceValidator _autopilotDeviceValidator;
private readonly CorporateIdentifierValidator _corporateIdentifierValidator;
private readonly DeviceAssociationValidator _deviceAssociationValidator;
private readonly BootstrapSessionService _bootstrapSessionService;
public GetAgentConfigFunction(
@@ -35,6 +36,7 @@ namespace AutopilotMonitor.Functions.Functions.Config
RateLimitService rateLimitService,
AutopilotDeviceValidator autopilotDeviceValidator,
CorporateIdentifierValidator corporateIdentifierValidator,
DeviceAssociationValidator deviceAssociationValidator,
BootstrapSessionService bootstrapSessionService)
{
_logger = logger;
@@ -45,6 +47,7 @@ namespace AutopilotMonitor.Functions.Functions.Config
_rateLimitService = rateLimitService;
_autopilotDeviceValidator = autopilotDeviceValidator;
_corporateIdentifierValidator = corporateIdentifierValidator;
_deviceAssociationValidator = deviceAssociationValidator;
_bootstrapSessionService = bootstrapSessionService;
}
@@ -76,7 +79,8 @@ namespace AutopilotMonitor.Functions.Functions.Config
_autopilotDeviceValidator,
_corporateIdentifierValidator,
_logger,
bootstrapSessionService: _bootstrapSessionService
bootstrapSessionService: _bootstrapSessionService,
deviceAssociationValidator: _deviceAssociationValidator
);
if (errorResponse != null)
@@ -39,6 +39,7 @@ namespace AutopilotMonitor.Functions.Functions.Diagnostics
private readonly RateLimitService _rateLimitService;
private readonly AutopilotDeviceValidator _autopilotDeviceValidator;
private readonly CorporateIdentifierValidator _corporateIdentifierValidator;
private readonly DeviceAssociationValidator _deviceAssociationValidator;
private readonly BootstrapSessionService _bootstrapSessionService;
public GetDiagnosticsUploadUrlFunction(
@@ -47,6 +48,7 @@ namespace AutopilotMonitor.Functions.Functions.Diagnostics
RateLimitService rateLimitService,
AutopilotDeviceValidator autopilotDeviceValidator,
CorporateIdentifierValidator corporateIdentifierValidator,
DeviceAssociationValidator deviceAssociationValidator,
BootstrapSessionService bootstrapSessionService)
{
_logger = logger;
@@ -54,6 +56,7 @@ namespace AutopilotMonitor.Functions.Functions.Diagnostics
_rateLimitService = rateLimitService;
_autopilotDeviceValidator = autopilotDeviceValidator;
_corporateIdentifierValidator = corporateIdentifierValidator;
_deviceAssociationValidator = deviceAssociationValidator;
_bootstrapSessionService = bootstrapSessionService;
}
@@ -101,7 +104,8 @@ namespace AutopilotMonitor.Functions.Functions.Diagnostics
_autopilotDeviceValidator,
_corporateIdentifierValidator,
_logger,
bootstrapSessionService: _bootstrapSessionService
bootstrapSessionService: _bootstrapSessionService,
deviceAssociationValidator: _deviceAssociationValidator
);
if (errorResponse != null)
@@ -24,6 +24,7 @@ namespace AutopilotMonitor.Functions.Functions.Ingest
private readonly RateLimitService _rateLimitService;
private readonly AutopilotDeviceValidator _autopilotDeviceValidator;
private readonly CorporateIdentifierValidator _corporateIdentifierValidator;
private readonly DeviceAssociationValidator _deviceAssociationValidator;
private readonly AnalyzeRuleService _analyzeRuleService;
private readonly WebhookNotificationService _webhookNotificationService;
private readonly BlockedDeviceService _blockedDeviceService;
@@ -46,6 +47,7 @@ namespace AutopilotMonitor.Functions.Functions.Ingest
RateLimitService rateLimitService,
AutopilotDeviceValidator autopilotDeviceValidator,
CorporateIdentifierValidator corporateIdentifierValidator,
DeviceAssociationValidator deviceAssociationValidator,
AnalyzeRuleService analyzeRuleService,
WebhookNotificationService webhookNotificationService,
BlockedDeviceService blockedDeviceService,
@@ -67,6 +69,7 @@ namespace AutopilotMonitor.Functions.Functions.Ingest
_rateLimitService = rateLimitService;
_autopilotDeviceValidator = autopilotDeviceValidator;
_corporateIdentifierValidator = corporateIdentifierValidator;
_deviceAssociationValidator = deviceAssociationValidator;
_analyzeRuleService = analyzeRuleService;
_webhookNotificationService = webhookNotificationService;
_blockedDeviceService = blockedDeviceService;
@@ -107,7 +110,8 @@ namespace AutopilotMonitor.Functions.Functions.Ingest
_autopilotDeviceValidator,
_corporateIdentifierValidator,
_logger,
bootstrapSessionService: _bootstrapSessionService
bootstrapSessionService: _bootstrapSessionService,
deviceAssociationValidator: _deviceAssociationValidator
);
if (errorResponse != null)
@@ -29,6 +29,7 @@ namespace AutopilotMonitor.Functions.Functions.Ingest
private readonly RateLimitService _rateLimitService;
private readonly AutopilotDeviceValidator _autopilotDeviceValidator;
private readonly CorporateIdentifierValidator _corporateIdentifierValidator;
private readonly DeviceAssociationValidator _deviceAssociationValidator;
private readonly TelemetryClient _telemetryClient;
private readonly BootstrapSessionService _bootstrapSessionService;
@@ -38,6 +39,7 @@ namespace AutopilotMonitor.Functions.Functions.Ingest
RateLimitService rateLimitService,
AutopilotDeviceValidator autopilotDeviceValidator,
CorporateIdentifierValidator corporateIdentifierValidator,
DeviceAssociationValidator deviceAssociationValidator,
TelemetryClient telemetryClient,
BootstrapSessionService bootstrapSessionService)
{
@@ -46,6 +48,7 @@ namespace AutopilotMonitor.Functions.Functions.Ingest
_rateLimitService = rateLimitService;
_autopilotDeviceValidator = autopilotDeviceValidator;
_corporateIdentifierValidator = corporateIdentifierValidator;
_deviceAssociationValidator = deviceAssociationValidator;
_telemetryClient = telemetryClient;
_bootstrapSessionService = bootstrapSessionService;
}
@@ -77,7 +80,8 @@ namespace AutopilotMonitor.Functions.Functions.Ingest
_autopilotDeviceValidator,
_corporateIdentifierValidator,
_logger,
bootstrapSessionService: _bootstrapSessionService
bootstrapSessionService: _bootstrapSessionService,
deviceAssociationValidator: _deviceAssociationValidator
);
if (errorResponse != null)
@@ -20,6 +20,7 @@ namespace AutopilotMonitor.Functions.Functions.Sessions
private readonly RateLimitService _rateLimitService;
private readonly AutopilotDeviceValidator _autopilotDeviceValidator;
private readonly CorporateIdentifierValidator _corporateIdentifierValidator;
private readonly DeviceAssociationValidator _deviceAssociationValidator;
private readonly BootstrapSessionService _bootstrapSessionService;
public RegisterSessionFunction(
@@ -30,6 +31,7 @@ namespace AutopilotMonitor.Functions.Functions.Sessions
RateLimitService rateLimitService,
AutopilotDeviceValidator autopilotDeviceValidator,
CorporateIdentifierValidator corporateIdentifierValidator,
DeviceAssociationValidator deviceAssociationValidator,
BootstrapSessionService bootstrapSessionService)
{
_logger = logger;
@@ -39,6 +41,7 @@ namespace AutopilotMonitor.Functions.Functions.Sessions
_rateLimitService = rateLimitService;
_autopilotDeviceValidator = autopilotDeviceValidator;
_corporateIdentifierValidator = corporateIdentifierValidator;
_deviceAssociationValidator = deviceAssociationValidator;
_bootstrapSessionService = bootstrapSessionService;
}
@@ -78,7 +81,8 @@ namespace AutopilotMonitor.Functions.Functions.Sessions
_corporateIdentifierValidator,
_logger,
registration.SessionId,
bootstrapSessionService: _bootstrapSessionService
bootstrapSessionService: _bootstrapSessionService,
deviceAssociationValidator: _deviceAssociationValidator
);
if (errorResponse2 != null)
@@ -31,9 +31,10 @@ namespace AutopilotMonitor.Functions.Security
CorporateIdentifierValidator corporateIdentifierValidator,
ILogger logger,
string? sessionId = null,
BootstrapSessionService? bootstrapSessionService = null)
BootstrapSessionService? bootstrapSessionService = null,
DeviceAssociationValidator? deviceAssociationValidator = null)
{
var validator = new SecurityValidator(configService, rateLimitService, autopilotDeviceValidator, corporateIdentifierValidator, logger, bootstrapSessionService);
var validator = new SecurityValidator(configService, rateLimitService, autopilotDeviceValidator, corporateIdentifierValidator, logger, bootstrapSessionService, deviceAssociationValidator);
var validation = await validator.ValidateRequestAsync(req, tenantId, sessionId);
if (!validation.IsValid)