diff --git a/src/Backend/AutopilotMonitor.Functions/Functions/AnalyzeRulesFunction.cs b/src/Backend/AutopilotMonitor.Functions/Functions/AnalyzeRulesFunction.cs
index 02bcd566..eb064f20 100644
--- a/src/Backend/AutopilotMonitor.Functions/Functions/AnalyzeRulesFunction.cs
+++ b/src/Backend/AutopilotMonitor.Functions/Functions/AnalyzeRulesFunction.cs
@@ -198,11 +198,31 @@ namespace AutopilotMonitor.Functions.Functions
return unauthorized;
}
- var success = await _ruleService.DeleteRuleAsync(tenantId, ruleId);
+ // Galactic Admins can delete built-in rules globally
+ var globalDelete = req.Url.Query.Contains("global=true", StringComparison.OrdinalIgnoreCase);
+ if (globalDelete)
+ {
+ var upn = TenantHelper.GetUserIdentifier(req);
+ var isGalactic = await _galacticAdminService.IsGalacticAdminAsync(upn);
+ if (!isGalactic)
+ {
+ var forbidden = req.CreateResponse(HttpStatusCode.Forbidden);
+ await forbidden.WriteAsJsonAsync(new { success = false, message = "Galactic Admin privileges required for global rule deletion" });
+ return forbidden;
+ }
- var response = req.CreateResponse(success ? HttpStatusCode.OK : HttpStatusCode.InternalServerError);
- await response.WriteAsJsonAsync(new { success, message = success ? "Rule deleted" : "Failed to delete rule" });
- return response;
+ var success = await _ruleService.DeleteGlobalRuleAsync(ruleId);
+ var response = req.CreateResponse(success ? HttpStatusCode.OK : HttpStatusCode.InternalServerError);
+ await response.WriteAsJsonAsync(new { success, message = success ? "Global rule deleted" : "Failed to delete global rule" });
+ return response;
+ }
+ else
+ {
+ var success = await _ruleService.DeleteRuleAsync(tenantId, ruleId);
+ var response = req.CreateResponse(success ? HttpStatusCode.OK : HttpStatusCode.InternalServerError);
+ await response.WriteAsJsonAsync(new { success, message = success ? "Rule deleted" : "Failed to delete rule" });
+ return response;
+ }
}
}
}
diff --git a/src/Backend/AutopilotMonitor.Functions/Services/AnalyzeRuleService.cs b/src/Backend/AutopilotMonitor.Functions/Services/AnalyzeRuleService.cs
index ee0eee9c..3e456a10 100644
--- a/src/Backend/AutopilotMonitor.Functions/Services/AnalyzeRuleService.cs
+++ b/src/Backend/AutopilotMonitor.Functions/Services/AnalyzeRuleService.cs
@@ -121,13 +121,22 @@ namespace AutopilotMonitor.Functions.Services
}
///
- /// Deletes a custom analyze rule (cannot delete built-in rules)
+ /// Deletes a custom analyze rule for a tenant
///
public async Task DeleteRuleAsync(string tenantId, string ruleId)
{
return await _storageService.DeleteAnalyzeRuleAsync(tenantId, ruleId);
}
+ ///
+ /// Deletes a global built-in analyze rule (Galactic Admin only)
+ ///
+ public async Task DeleteGlobalRuleAsync(string ruleId)
+ {
+ _logger.LogInformation($"Deleting global analyze rule: {ruleId}");
+ return await _storageService.DeleteAnalyzeRuleAsync("global", ruleId);
+ }
+
///
/// Re-imports all built-in analyze rules into the global partition.
/// Deletes old global built-in rules and writes current code definitions.
diff --git a/src/Web/autopilot-monitor-web/app/analyze-rules/page.tsx b/src/Web/autopilot-monitor-web/app/analyze-rules/page.tsx
index 554ce070..91fc134e 100644
--- a/src/Web/autopilot-monitor-web/app/analyze-rules/page.tsx
+++ b/src/Web/autopilot-monitor-web/app/analyze-rules/page.tsx
@@ -285,7 +285,9 @@ export default function AnalyzeRulesPage() {
throw new Error("Failed to get access token");
}
- const response = await fetch(`${API_BASE_URL}/api/analyze-rules/${encodeURIComponent(rule.ruleId)}`, {
+ const isGlobalDelete = rule.isBuiltIn && isGalacticAdmin;
+ const url = `${API_BASE_URL}/api/analyze-rules/${encodeURIComponent(rule.ruleId)}${isGlobalDelete ? "?global=true" : ""}`;
+ const response = await fetch(url, {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
@@ -955,9 +957,9 @@ export default function AnalyzeRulesPage() {
{rule.isBuiltIn ? "Edit (Global)" : "Edit"}
)}
- {!rule.isBuiltIn && (
-