mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 04:32:32 +00:00
Dead delegated-admin and repository members go: status transition, single-row reads, MCP-user flag
None of them had a production caller. DelegatedAdminService.GetAssignmentsForUpnAsync and GetAssigneesForTenantAsync, DelegatedAdminService.SetStatusAsync with IAdminRepository.SetDelegatedAdminStatusAsync (only a test called it; the operator revoke is RemoveAsync), and IAdminRepository.GetDelegatedAdminAsync and IsMcpUserAsync, which only had their own implementation. Revoke_InvalidatesCache now pins the revoke the operator route runs (RemoveAsync); Disable_InvalidatesCache covers SetEnabledAsync. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -249,13 +249,27 @@ public class DelegatedAdminServiceTests
|
||||
[Fact]
|
||||
public async Task Revoke_InvalidatesCache()
|
||||
{
|
||||
// RemoveAsync is the revoke the operator route runs (DelegatedAdminManagementFunction.RevokeCoreAsync).
|
||||
var (svc, repo) = Build();
|
||||
Returns(repo, Row(TenantA));
|
||||
repo.Setup(r => r.SetDelegatedAdminStatusAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
|
||||
.ReturnsAsync(true);
|
||||
repo.Setup(r => r.RemoveDelegatedAdminAsync(It.IsAny<string>(), It.IsAny<string>())).ReturnsAsync(true);
|
||||
|
||||
await svc.GetScopeAsync(Id(Upn));
|
||||
await svc.SetStatusAsync(Upn, TenantA, Constants.DelegatedStatus.Revoked);
|
||||
await svc.RemoveAsync(Upn, TenantA);
|
||||
await svc.GetScopeAsync(Id(Upn));
|
||||
|
||||
repo.Verify(r => r.GetDelegatedTenantsAsync(It.IsAny<string>()), Times.Exactly(2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Disable_InvalidatesCache()
|
||||
{
|
||||
var (svc, repo) = Build();
|
||||
Returns(repo, Row(TenantA));
|
||||
repo.Setup(r => r.SetDelegatedAdminEnabledAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>())).ReturnsAsync(true);
|
||||
|
||||
await svc.GetScopeAsync(Id(Upn));
|
||||
await svc.SetEnabledAsync(Upn, TenantA, false);
|
||||
await svc.GetScopeAsync(Id(Upn));
|
||||
|
||||
repo.Verify(r => r.GetDelegatedTenantsAsync(It.IsAny<string>()), Times.Exactly(2));
|
||||
|
||||
-61
@@ -152,29 +152,6 @@ namespace AutopilotMonitor.Functions.DataAccess.TableStorage
|
||||
|
||||
// --- MCP Users ---
|
||||
|
||||
public async Task<bool> IsMcpUserAsync(string upn)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(upn))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
var normalizedUpn = upn.ToLowerInvariant();
|
||||
var entity = await _mcpUsersTableClient.GetEntityAsync<McpUserEntity>(
|
||||
"McpUsers", normalizedUpn);
|
||||
return entity?.Value != null && entity.Value.IsEnabled;
|
||||
}
|
||||
catch (RequestFailedException ex) when (ex.Status == 404)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error checking MCP user status for {Upn}", upn);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<McpUserEntry?> GetMcpUserAsync(string upn)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(upn))
|
||||
@@ -338,23 +315,6 @@ namespace AutopilotMonitor.Functions.DataAccess.TableStorage
|
||||
return entries;
|
||||
}
|
||||
|
||||
public async Task<DelegatedAdminEntry?> GetDelegatedAdminAsync(string upn, string tenantId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(upn) || string.IsNullOrWhiteSpace(tenantId))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
var result = await _delegatedAdminsTableClient.GetEntityAsync<DelegatedAdminEntity>(
|
||||
upn.ToLowerInvariant(), tenantId.ToLowerInvariant());
|
||||
return result.Value == null ? null : MapToDelegatedEntry(result.Value);
|
||||
}
|
||||
catch (RequestFailedException ex) when (ex.Status == 404)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> UpsertDelegatedAdminAsync(
|
||||
string upn, string tenantId, string role, string status, string source, string grantedBy)
|
||||
{
|
||||
@@ -380,27 +340,6 @@ namespace AutopilotMonitor.Functions.DataAccess.TableStorage
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> SetDelegatedAdminStatusAsync(string upn, string tenantId, string status)
|
||||
{
|
||||
upn = upn.ToLowerInvariant();
|
||||
tenantId = tenantId.ToLowerInvariant();
|
||||
|
||||
try
|
||||
{
|
||||
var result = await _delegatedAdminsTableClient.GetEntityAsync<DelegatedAdminEntity>(upn, tenantId);
|
||||
var entity = result.Value;
|
||||
if (entity == null) return false;
|
||||
|
||||
entity.Status = status;
|
||||
await _delegatedAdminsTableClient.UpdateEntityAsync(entity, ETag.All);
|
||||
return true;
|
||||
}
|
||||
catch (RequestFailedException ex) when (ex.Status == 404)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> SetDelegatedAdminEnabledAsync(string upn, string tenantId, bool isEnabled)
|
||||
{
|
||||
upn = upn.ToLowerInvariant();
|
||||
|
||||
@@ -231,16 +231,6 @@ public class DelegatedAdminService
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>Transitions an assignment's status (e.g. PendingApproval → Active on approval, → Revoked).</summary>
|
||||
public async Task<bool> SetStatusAsync(string upn, string tenantId, string status)
|
||||
{
|
||||
upn = upn.ToLowerInvariant();
|
||||
tenantId = tenantId.ToLowerInvariant();
|
||||
var ok = await _adminRepo.SetDelegatedAdminStatusAsync(upn, tenantId, status);
|
||||
Invalidate(upn);
|
||||
return ok;
|
||||
}
|
||||
|
||||
public async Task<bool> SetEnabledAsync(string upn, string tenantId, bool isEnabled)
|
||||
{
|
||||
upn = upn.ToLowerInvariant();
|
||||
@@ -263,14 +253,6 @@ public class DelegatedAdminService
|
||||
public Task<List<DelegatedAdminEntry>> GetAllAsync()
|
||||
=> _adminRepo.GetAllDelegatedAdminsAsync();
|
||||
|
||||
/// <summary>All assignment rows for a UPN (any status) — for the operator/admin management UI.</summary>
|
||||
public Task<List<DelegatedAdminEntry>> GetAssignmentsForUpnAsync(string upn)
|
||||
=> _adminRepo.GetDelegatedTenantsAsync(upn.ToLowerInvariant());
|
||||
|
||||
/// <summary>All assignment rows targeting a tenant (any status) — for the customer "who manages me?" UI.</summary>
|
||||
public Task<List<DelegatedAdminEntry>> GetAssigneesForTenantAsync(string tenantId)
|
||||
=> _adminRepo.GetDelegatedAssigneesAsync(tenantId.ToLowerInvariant());
|
||||
|
||||
// --- Tenant Groups (app-internal tenant bundles) ---
|
||||
//
|
||||
// ALL group mutations go through the service (never the repo directly) so the delegated-scope
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace AutopilotMonitor.Shared.DataAccess
|
||||
Task<bool> DisableGlobalAdminAsync(string upn);
|
||||
|
||||
// --- MCP Users ---
|
||||
Task<bool> IsMcpUserAsync(string upn);
|
||||
Task<McpUserEntry?> GetMcpUserAsync(string upn);
|
||||
Task<List<McpUserEntry>> GetAllMcpUsersAsync();
|
||||
Task<bool> AddMcpUserAsync(string upn, string addedBy);
|
||||
@@ -41,10 +40,8 @@ namespace AutopilotMonitor.Shared.DataAccess
|
||||
/// <summary>All assignment rows targeting one tenant (cross-partition RowKey scan — admin UI, not hot path).
|
||||
/// Powers the customer's "who manages my tenant?" view including pending requests.</summary>
|
||||
Task<List<DelegatedAdminEntry>> GetDelegatedAssigneesAsync(string tenantId);
|
||||
Task<DelegatedAdminEntry?> GetDelegatedAdminAsync(string upn, string tenantId);
|
||||
/// <summary>Creates or replaces an assignment row (upsert on PK=upn, RK=tenantId).</summary>
|
||||
Task<bool> UpsertDelegatedAdminAsync(string upn, string tenantId, string role, string status, string source, string grantedBy);
|
||||
Task<bool> SetDelegatedAdminStatusAsync(string upn, string tenantId, string status);
|
||||
Task<bool> SetDelegatedAdminEnabledAsync(string upn, string tenantId, bool isEnabled);
|
||||
Task<bool> RemoveDelegatedAdminAsync(string upn, string tenantId);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user