enable galactic admin to delete global analyze rules

This commit is contained in:
Oliver Kieselbach
2026-02-17 13:15:03 +01:00
parent 93169575ba
commit 878abaf72a
3 changed files with 40 additions and 9 deletions
@@ -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;
}
}
}
}
@@ -121,13 +121,22 @@ namespace AutopilotMonitor.Functions.Services
}
/// <summary>
/// Deletes a custom analyze rule (cannot delete built-in rules)
/// Deletes a custom analyze rule for a tenant
/// </summary>
public async Task<bool> DeleteRuleAsync(string tenantId, string ruleId)
{
return await _storageService.DeleteAnalyzeRuleAsync(tenantId, ruleId);
}
/// <summary>
/// Deletes a global built-in analyze rule (Galactic Admin only)
/// </summary>
public async Task<bool> DeleteGlobalRuleAsync(string ruleId)
{
_logger.LogInformation($"Deleting global analyze rule: {ruleId}");
return await _storageService.DeleteAnalyzeRuleAsync("global", ruleId);
}
/// <summary>
/// Re-imports all built-in analyze rules into the global partition.
/// Deletes old global built-in rules and writes current code definitions.
@@ -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() {
<span>{rule.isBuiltIn ? "Edit (Global)" : "Edit"}</span>
</button>
)}
{!rule.isBuiltIn && (
<button onClick={() => handleDeleteRule(rule)} disabled={deletingRuleId === rule.ruleId} className="px-4 py-2 text-sm bg-red-600 text-white rounded-lg hover:bg-red-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center space-x-2">
{deletingRuleId === rule.ruleId ? (<><div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div><span>Deleting...</span></>) : (<><svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg><span>Delete</span></>)}
{(!rule.isBuiltIn || isGalacticAdmin) && (
<button onClick={() => handleDeleteRule(rule)} disabled={deletingRuleId === rule.ruleId} className="px-4 py-2 text-sm bg-red-600 text-white rounded-lg hover:bg-red-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center space-x-2" title={rule.isBuiltIn ? "Delete global rule (Galactic Admin)" : "Delete rule"}>
{deletingRuleId === rule.ruleId ? (<><div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div><span>Deleting...</span></>) : (<><svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg><span>{rule.isBuiltIn ? "Delete (Global)" : "Delete"}</span></>)}
</button>
)}
</div>