using System; using System.Net; using System.Threading.Tasks; using AutopilotMonitor.Functions.Helpers; using AutopilotMonitor.Functions.Services; using AutopilotMonitor.Shared.DataAccess; using AutopilotMonitor.Shared.Models; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.Extensions.Logging; namespace AutopilotMonitor.Functions.Functions.Admin { public class VersionBlockFunction { private readonly ILogger _logger; private readonly BlockedVersionService _blockedVersionService; private readonly IMaintenanceRepository _maintenanceRepo; private readonly OpsEventService _opsEventService; public VersionBlockFunction( ILogger logger, BlockedVersionService blockedVersionService, IMaintenanceRepository maintenanceRepo, OpsEventService opsEventService) { _logger = logger; _blockedVersionService = blockedVersionService; _maintenanceRepo = maintenanceRepo; _opsEventService = opsEventService; } /// GET /api/versions/blocked — list all active version block rules [Function("GetBlockedVersions")] public async Task GetBlockedVersions( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "versions/blocked")] HttpRequestData req) { try { // Authentication + GlobalAdminOnly authorization enforced by PolicyEnforcementMiddleware var rules = await _blockedVersionService.GetBlockedVersionsAsync(); var response = req.CreateResponse(HttpStatusCode.OK); await response.WriteAsJsonAsync(new BlockedVersionListResponse { Success = true, Rules = rules }); return response; } catch (Exception ex) { return await req.InternalServerErrorAsync(_logger, ex, "VersionBlock"); } } /// POST /api/versions/block — add a version block rule [Function("BlockVersion")] public async Task BlockVersion( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "versions/block")] HttpRequestData req) { try { // Authentication + GlobalAdminOnly authorization enforced by PolicyEnforcementMiddleware var userIdentifier = TenantHelper.GetUserIdentifier(req); var read = await req.ReadAsync(); if (read.Error != null) return read.Error; var body = read.Value!; var versionPattern = body.VersionPattern; var action = body.Action ?? "Block"; var reason = body.Reason; if (string.IsNullOrEmpty(versionPattern)) return await req.BadRequestAsync("versionPattern is required"); if (!string.Equals(action, "Block", StringComparison.OrdinalIgnoreCase) && !string.Equals(action, "Kill", StringComparison.OrdinalIgnoreCase)) return await req.BadRequestAsync("action must be 'Block' or 'Kill'"); try { await _blockedVersionService.BlockVersionAsync(versionPattern, action, userIdentifier, reason); } catch (ArgumentException ex) { return await req.BadRequestAsync(ex.Message); } var normalizedAction = string.Equals(action, "Kill", StringComparison.OrdinalIgnoreCase) ? "Kill" : "Block"; await _maintenanceRepo.LogAuditEntryAsync( AutopilotMonitor.Shared.Constants.AuditGlobalTenantId, "CREATE", "VersionBlock", versionPattern, userIdentifier, new Dictionary { { "Action", normalizedAction }, { "Reason", reason ?? string.Empty } } ); await _opsEventService.RecordVersionBlockedAsync(versionPattern, userIdentifier); _logger.LogWarning( "Global Admin {User} added version {Action} rule: Pattern={Pattern}, Reason={Reason}", userIdentifier, normalizedAction, versionPattern, reason); var response = req.CreateResponse(HttpStatusCode.OK); await response.WriteAsJsonAsync(new BlockVersionResponse { Success = true, Message = $"Version pattern '{versionPattern}' set to {normalizedAction}.", VersionPattern = versionPattern, Action = normalizedAction }); return response; } catch (Exception ex) { return await req.InternalServerErrorAsync(_logger, ex, "VersionBlock"); } } /// DELETE /api/versions/block/{encodedPattern} — remove a version block rule [Function("UnblockVersion")] public async Task UnblockVersion( [HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "versions/block/{encodedPattern}")] HttpRequestData req, string encodedPattern) { try { // Authentication + GlobalAdminOnly authorization enforced by PolicyEnforcementMiddleware var userIdentifier = TenantHelper.GetUserIdentifier(req); var versionPattern = Uri.UnescapeDataString(encodedPattern ?? string.Empty); if (string.IsNullOrEmpty(versionPattern)) return await req.BadRequestAsync("versionPattern is required"); await _blockedVersionService.UnblockVersionAsync(versionPattern); await _maintenanceRepo.LogAuditEntryAsync( AutopilotMonitor.Shared.Constants.AuditGlobalTenantId, "DELETE", "VersionBlock", versionPattern, userIdentifier ); _logger.LogInformation( "Global Admin {User} removed version block rule: Pattern={Pattern}", userIdentifier, versionPattern); var response = req.CreateResponse(HttpStatusCode.OK); await response.WriteAsJsonAsync(new SuccessMessageResponse { Success = true, Message = $"Version pattern '{versionPattern}' unblocked." }); return response; } catch (Exception ex) { return await req.InternalServerErrorAsync(_logger, ex, "VersionBlock"); } } // ----------------------------------------------------------------------- // Helpers // ----------------------------------------------------------------------- } }