1
0
forked from baron/baron-sso

권한부여 및 정합성 검사 추가

This commit is contained in:
2026-05-14 08:45:48 +09:00
parent f6f8e88342
commit 9ca73e8774
36 changed files with 1772 additions and 105 deletions

View File

@@ -129,6 +129,7 @@ export type RPUsageDailyResponse = {
export type AdminOverviewStats = {
totalTenants: number;
totalUsers: number;
oidcClients: number;
auditEvents24h: number;
};
@@ -149,6 +150,36 @@ export type UserProjectionActionResult = {
updatedAt: string;
};
export type DataIntegrityStatus = "pass" | "warning" | "fail";
export type DataIntegrityCheck = {
key: string;
label: string;
description: string;
status: DataIntegrityStatus;
severity: "info" | "warning" | "error" | string;
count: number;
};
export type DataIntegritySection = {
key: string;
label: string;
status: DataIntegrityStatus;
checks: DataIntegrityCheck[];
};
export type DataIntegrityReport = {
status: DataIntegrityStatus;
checkedAt: string;
summary: {
totalChecks: number;
passed: number;
warnings: number;
failures: number;
};
sections: DataIntegritySection[];
};
export async function fetchAuditLogs(limit = 50, cursor?: string) {
const { data } = await apiClient.get<AuditLogListResponse>("/v1/audit", {
params: { limit, cursor },
@@ -161,6 +192,13 @@ export async function fetchAdminOverviewStats() {
return data;
}
export async function fetchDataIntegrityReport() {
const { data } = await apiClient.get<DataIntegrityReport>(
"/v1/admin/integrity",
);
return data;
}
export async function fetchUserProjectionStatus() {
const { data } = await apiClient.get<UserProjectionStatus>(
"/v1/admin/projections/users",

View File

@@ -0,0 +1,37 @@
import { describe, expect, it } from "vitest";
import {
ROLE_RP_ADMIN,
ROLE_SUPER_ADMIN,
ROLE_TENANT_ADMIN,
ROLE_USER,
isSuperAdminRole,
normalizeAdminRole,
} from "./roles";
describe("admin role helpers", () => {
it.each([
["super_admin", ROLE_SUPER_ADMIN],
["superadmin", ROLE_SUPER_ADMIN],
["super-admin", ROLE_SUPER_ADMIN],
[" SUPER-ADMIN ", ROLE_SUPER_ADMIN],
["tenant_admin", ROLE_TENANT_ADMIN],
["tenantadmin", ROLE_TENANT_ADMIN],
["tenant-admin", ROLE_TENANT_ADMIN],
["admin", ROLE_TENANT_ADMIN],
["rp_admin", ROLE_RP_ADMIN],
["rpadmin", ROLE_RP_ADMIN],
["rp-admin", ROLE_RP_ADMIN],
["tenant_member", ROLE_USER],
["member", ROLE_USER],
["custom", ROLE_USER],
["", ROLE_USER],
])("normalizes %s to %s", (input, expected) => {
expect(normalizeAdminRole(input)).toBe(expected);
});
it("detects super admin aliases", () => {
expect(isSuperAdminRole("super-admin")).toBe(true);
expect(isSuperAdminRole("admin")).toBe(false);
expect(isSuperAdminRole(undefined)).toBe(false);
});
});

View File

@@ -0,0 +1,40 @@
export const ROLE_SUPER_ADMIN = "super_admin";
export const ROLE_TENANT_ADMIN = "tenant_admin";
export const ROLE_RP_ADMIN = "rp_admin";
export const ROLE_USER = "user";
export type AdminRole =
| typeof ROLE_SUPER_ADMIN
| typeof ROLE_TENANT_ADMIN
| typeof ROLE_RP_ADMIN
| typeof ROLE_USER;
export function normalizeAdminRole(role?: string | null): AdminRole {
const normalized = role?.trim().toLowerCase() ?? "";
switch (normalized) {
case ROLE_SUPER_ADMIN:
case "superadmin":
case "super-admin":
return ROLE_SUPER_ADMIN;
case ROLE_TENANT_ADMIN:
case "tenantadmin":
case "tenant-admin":
case "admin":
return ROLE_TENANT_ADMIN;
case ROLE_RP_ADMIN:
case "rpadmin":
case "rp-admin":
return ROLE_RP_ADMIN;
case ROLE_USER:
case "tenant_member":
case "member":
return ROLE_USER;
default:
return ROLE_USER;
}
}
export function isSuperAdminRole(role?: string | null) {
return normalizeAdminRole(role) === ROLE_SUPER_ADMIN;
}