mcp user mgmt, vul report re-scan logging

This commit is contained in:
Oliver Kieselbach
2026-03-29 12:57:36 +02:00
parent dd2ee928b0
commit cdba7f2cb4
7 changed files with 49 additions and 12 deletions
@@ -1 +1 @@
679
680
@@ -23,6 +23,7 @@ public class AuthFunction
private readonly PreviewWhitelistService _previewWhitelistService;
private readonly TelegramNotificationService _telegramNotificationService;
private readonly GlobalNotificationService _globalNotificationService;
private readonly McpUserService _mcpUserService;
public AuthFunction(
ILogger<AuthFunction> logger,
@@ -32,7 +33,8 @@ public class AuthFunction
IMetricsRepository metricsRepo,
PreviewWhitelistService previewWhitelistService,
TelegramNotificationService telegramNotificationService,
GlobalNotificationService globalNotificationService)
GlobalNotificationService globalNotificationService,
McpUserService mcpUserService)
{
_logger = logger;
_globalAdminService = globalAdminService;
@@ -42,6 +44,7 @@ public class AuthFunction
_previewWhitelistService = previewWhitelistService;
_telegramNotificationService = telegramNotificationService;
_globalNotificationService = globalNotificationService;
_mcpUserService = mcpUserService;
}
/// <summary>
@@ -176,6 +179,9 @@ public class AuthFunction
_ = _metricsRepo.RecordUserLoginAsync(tenantId, upn, displayName, objectId)
.ContinueWith(t => _logger.LogWarning(t.Exception?.InnerException, "Fire-and-forget RecordUserLoginAsync failed"), TaskContinuationOptions.OnlyOnFaulted);
// Check MCP access (cached, lightweight)
var mcpCheck = await _mcpUserService.IsAllowedAsync(upn);
var userInfo = new
{
tenantId,
@@ -185,7 +191,8 @@ public class AuthFunction
isGlobalAdmin,
isTenantAdmin,
role,
canManageBootstrapTokens
canManageBootstrapTokens,
hasMcpAccess = mcpCheck.IsAllowed
};
var response = req.CreateResponse(HttpStatusCode.OK);
@@ -38,18 +38,23 @@ export function useSessionAnalysis(
}, [sessionId, sessionTenantId, getAccessToken]);
const fetchVulnerabilityReport = useCallback(async (rescan = false) => {
if (!sessionTenantId || !GUID_REGEX.test(sessionTenantId)) return;
if (!sessionTenantId || !GUID_REGEX.test(sessionTenantId)) {
console.warn("[VulnReport] Skipped fetch: sessionTenantId missing or invalid", { sessionTenantId, rescan });
return;
}
const url = api.sessions.vulnerabilityReport(sessionId, sessionTenantId, rescan || undefined);
console.info(`[VulnReport] Fetching: rescan=${rescan}, url=${url}`);
try {
const response = await authenticatedFetch(
api.sessions.vulnerabilityReport(sessionId, sessionTenantId, rescan || undefined),
getAccessToken
);
const response = await authenticatedFetch(url, getAccessToken);
if (response.ok) {
const data = await response.json();
console.info(`[VulnReport] Response OK: rescan=${rescan}, hasReport=${data.report != null}, rescanned=${data.rescanned ?? false}`);
setVulnerabilityReport(data.report ?? null);
} else {
console.warn(`[VulnReport] Response not OK: status=${response.status}, rescan=${rescan}`);
}
} catch (error) {
console.error("Failed to fetch vulnerability report:", error);
console.error("[VulnReport] Failed to fetch vulnerability report:", error);
}
}, [sessionId, sessionTenantId, getAccessToken]);
@@ -175,8 +175,21 @@ export function GlobalSidebar({ children }: { children: ReactNode }) {
}
};
// Visible expandable groups
const visibleExpandableGroups = EXPANDABLE_NAV_GROUPS.filter(isGroupVisible);
// Visible expandable groups (with item-level filtering for feature-gated items)
const hasMcpAccess = user?.hasMcpAccess ?? false;
const visibleExpandableGroups = useMemo(() => {
return EXPANDABLE_NAV_GROUPS
.filter(isGroupVisible)
.map((group) => {
// Filter out MCP item if user doesn't have MCP access
const filteredItems = group.items.filter((item) => {
if (item.id === "cfg-mcp") return hasMcpAccess;
return true;
});
return { ...group, items: filteredItems };
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isAdminOrOperator, isGlobalAdmin, globalAdminMode, hasMcpAccess]);
// Auto-expand the group containing the current pathname
useEffect(() => {
@@ -68,6 +68,7 @@ interface UserInfo {
isTenantAdmin: boolean;
role: 'Admin' | 'Operator' | 'Viewer' | null;
canManageBootstrapTokens: boolean;
hasMcpAccess: boolean;
}
interface AuthContextType {
@@ -157,6 +158,7 @@ function AuthProviderInternal({ children }: { children: React.ReactNode }) {
isTenantAdmin: false,
role: null,
canManageBootstrapTokens: false,
hasMcpAccess: false,
};
}
}
@@ -174,6 +176,7 @@ function AuthProviderInternal({ children }: { children: React.ReactNode }) {
isTenantAdmin: data.isTenantAdmin || false,
role: data.role || null,
canManageBootstrapTokens: data.canManageBootstrapTokens || false,
hasMcpAccess: data.hasMcpAccess || false,
};
} catch (error) {
// If the refresh token is expired or consent is required, redirect to
@@ -203,6 +206,7 @@ function AuthProviderInternal({ children }: { children: React.ReactNode }) {
isTenantAdmin: false,
role: null,
canManageBootstrapTokens: false,
hasMcpAccess: false,
};
}
}, [instance]);
@@ -200,6 +200,12 @@ export const EXPANDABLE_NAV_GROUPS: ExpandableNavGroup[] = [
{ id: "cfg-offboarding", label: "Offboarding", href: "/settings/management/offboarding" },
],
},
{
id: "cfg-mcp", label: "MCP", icon: <ChartBarIcon />,
items: [
{ id: "cfg-mcp-usage", label: "Usage", href: "/settings/mcp/usage" },
],
},
],
},
{
@@ -220,6 +226,7 @@ export const EXPANDABLE_NAV_GROUPS: ExpandableNavGroup[] = [
items: [
{ id: "ga-agent-metrics", label: "Agent Metrics", href: "/admin/metrics/agent-metrics" },
{ id: "ga-usage", label: "Platform Usage", href: "/admin/metrics/usage" },
{ id: "ga-mcp-usage", label: "MCP Usage", href: "/admin/metrics/mcp-usage" },
],
},
{
@@ -245,6 +252,7 @@ export const EXPANDABLE_NAV_GROUPS: ExpandableNavGroup[] = [
{ id: "ga-diag-paths", label: "Diagnostics Log Paths", href: "/admin/settings/diagnostics-log-paths" },
{ id: "ga-mcp-users", label: "MCP Users", href: "/admin/settings/mcp-users" },
{ id: "ga-config-reseed", label: "Config Reseed", href: "/admin/settings/config-reseed" },
{ id: "ga-usage-plans", label: "Usage Plans", href: "/admin/settings/usage-plans" },
],
},
{
File diff suppressed because one or more lines are too long