FEAT - LAUNCHER: wire Engine access roles
This commit is contained in:
parent
ec91821fdc
commit
55ab952ae8
|
|
@ -6,7 +6,14 @@ const platformGroups = {
|
||||||
launcherUser: "nodedc:launcher:user",
|
launcherUser: "nodedc:launcher:user",
|
||||||
taskManagerAdmin: "nodedc:taskmanager:admin",
|
taskManagerAdmin: "nodedc:taskmanager:admin",
|
||||||
taskManagerUser: "nodedc:taskmanager:user",
|
taskManagerUser: "nodedc:taskmanager:user",
|
||||||
|
engineAdmin: "nodedc:engine:admin",
|
||||||
|
engineEditor: "nodedc:engine:editor",
|
||||||
|
engineViewer: "nodedc:engine:viewer",
|
||||||
|
engineLegacyAdmin: "nodedc_admin",
|
||||||
|
engineLegacyEditor: "nodedc_editor",
|
||||||
|
engineLegacyViewer: "nodedc_viewer",
|
||||||
};
|
};
|
||||||
|
const engineServiceSlugs = new Set(["nodedc", "engine", "nodedc-engine"]);
|
||||||
const publicPoolClientId = "client_public_pool";
|
const publicPoolClientId = "client_public_pool";
|
||||||
const publicPoolClient = {
|
const publicPoolClient = {
|
||||||
id: publicPoolClientId,
|
id: publicPoolClientId,
|
||||||
|
|
@ -200,6 +207,7 @@ export function resolveRequiredGroups(data, user) {
|
||||||
groupNames.add(platformGroups.launcherAdmin);
|
groupNames.add(platformGroups.launcherAdmin);
|
||||||
groupNames.add(platformGroups.taskManagerAdmin);
|
groupNames.add(platformGroups.taskManagerAdmin);
|
||||||
groupNames.add(platformGroups.taskManagerUser);
|
groupNames.add(platformGroups.taskManagerUser);
|
||||||
|
addGroups(groupNames, resolveEngineRoleGroups("admin"));
|
||||||
return [...groupNames];
|
return [...groupNames];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -219,7 +227,9 @@ export function resolveRequiredGroups(data, user) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (service.slug === "task-manager") {
|
if (isEngineService(service)) {
|
||||||
|
addGroups(groupNames, resolveEngineRoleGroups(access.appRole));
|
||||||
|
} else if (service.slug === "task-manager") {
|
||||||
groupNames.add(platformGroups.taskManagerUser);
|
groupNames.add(platformGroups.taskManagerUser);
|
||||||
|
|
||||||
if (access.appRole === "admin" || access.appRole === "owner") {
|
if (access.appRole === "admin" || access.appRole === "owner") {
|
||||||
|
|
@ -234,6 +244,32 @@ export function resolveRequiredGroups(data, user) {
|
||||||
return [...groupNames];
|
return [...groupNames];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isEngineService(service) {
|
||||||
|
return (
|
||||||
|
engineServiceSlugs.has(service.slug) ||
|
||||||
|
engineServiceSlugs.has(service.authentikApplicationSlug) ||
|
||||||
|
service.id === "service_nodedc"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveEngineRoleGroups(appRole) {
|
||||||
|
if (appRole === "admin" || appRole === "owner") {
|
||||||
|
return [platformGroups.engineAdmin, platformGroups.engineLegacyAdmin];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appRole === "viewer") {
|
||||||
|
return [platformGroups.engineViewer, platformGroups.engineLegacyViewer];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [platformGroups.engineEditor, platformGroups.engineLegacyEditor];
|
||||||
|
}
|
||||||
|
|
||||||
|
function addGroups(target, groups) {
|
||||||
|
for (const group of groups) {
|
||||||
|
target.add(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getUserRuntimeClients(data, userId) {
|
function getUserRuntimeClients(data, userId) {
|
||||||
const clients = [...data.clients];
|
const clients = [...data.clients];
|
||||||
const hasPublicPoolMembership = data.memberships.some(
|
const hasPublicPoolMembership = data.memberships.some(
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,14 @@ const accessRequestStatuses = new Set(["new", "approved", "rejected"]);
|
||||||
const taskerInviteRequestStatuses = new Set(["new", "approved", "rejected", "cancelled"]);
|
const taskerInviteRequestStatuses = new Set(["new", "approved", "rejected", "cancelled"]);
|
||||||
const taskManagerInviteRoles = new Set(["guest", "member", "admin"]);
|
const taskManagerInviteRoles = new Set(["guest", "member", "admin"]);
|
||||||
const publicPoolClientId = "client_public_pool";
|
const publicPoolClientId = "client_public_pool";
|
||||||
|
const engineAuthentikGroups = [
|
||||||
|
"nodedc:engine:admin",
|
||||||
|
"nodedc:engine:editor",
|
||||||
|
"nodedc:engine:viewer",
|
||||||
|
"nodedc_admin",
|
||||||
|
"nodedc_editor",
|
||||||
|
"nodedc_viewer",
|
||||||
|
];
|
||||||
const publicPoolClient = {
|
const publicPoolClient = {
|
||||||
id: publicPoolClientId,
|
id: publicPoolClientId,
|
||||||
type: "person",
|
type: "person",
|
||||||
|
|
@ -1811,6 +1819,7 @@ export function createControlPlaneStore({ projectRoot }) {
|
||||||
"nodedc:superadmin",
|
"nodedc:superadmin",
|
||||||
"nodedc:launcher:admin",
|
"nodedc:launcher:admin",
|
||||||
"nodedc:launcher:user",
|
"nodedc:launcher:user",
|
||||||
|
...engineAuthentikGroups,
|
||||||
...data.services.flatMap((service) => (service.authentikGroupName ? [service.authentikGroupName] : [])),
|
...data.services.flatMap((service) => (service.authentikGroupName ? [service.authentikGroupName] : [])),
|
||||||
...data.groups.map((group) => `client:${group.clientId}:group:${slugify(group.name)}`),
|
...data.groups.map((group) => `client:${group.clientId}:group:${slugify(group.name)}`),
|
||||||
],
|
],
|
||||||
|
|
@ -1931,6 +1940,7 @@ function normalizeData(payload) {
|
||||||
...client,
|
...client,
|
||||||
integrations: normalizeClientIntegrations(client.integrations),
|
integrations: normalizeClientIntegrations(client.integrations),
|
||||||
}));
|
}));
|
||||||
|
data.services = data.services.map(normalizeService);
|
||||||
data.accessRequests = data.accessRequests.map(normalizeAccessRequest).filter(Boolean);
|
data.accessRequests = data.accessRequests.map(normalizeAccessRequest).filter(Boolean);
|
||||||
data.revokedAccounts = data.revokedAccounts.map(normalizeRevokedAccount).filter(Boolean);
|
data.revokedAccounts = data.revokedAccounts.map(normalizeRevokedAccount).filter(Boolean);
|
||||||
data.serviceModuleEntitlements = data.serviceModuleEntitlements.map(normalizeServiceModuleEntitlement).filter(Boolean);
|
data.serviceModuleEntitlements = data.serviceModuleEntitlements.map(normalizeServiceModuleEntitlement).filter(Boolean);
|
||||||
|
|
@ -1938,6 +1948,23 @@ function normalizeData(payload) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeService(service) {
|
||||||
|
if (typeof service !== "object" || service === null) return service;
|
||||||
|
if (service.id !== "service_nodedc" && service.slug !== "nodedc" && service.authentikApplicationSlug !== "nodedc") return service;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...service,
|
||||||
|
title: service.title === "AGENT CORE" || service.title === "NodeDC" ? "ENGINE" : service.title,
|
||||||
|
url: service.url === "https://nodedc.ru/" || service.url === "https://dev.handhdc.ru/sso/launch" ? "https://engine.nodedc.ru/" : service.url,
|
||||||
|
launchUrl:
|
||||||
|
service.launchUrl === "https://nodedc.ru/" || service.launchUrl === "https://dev.handhdc.ru/sso/launch"
|
||||||
|
? "https://engine.nodedc.ru/"
|
||||||
|
: service.launchUrl,
|
||||||
|
authentikApplicationSlug: service.authentikApplicationSlug === "nodedc" ? "nodedc-engine" : service.authentikApplicationSlug,
|
||||||
|
authentikGroupName: service.authentikGroupName === "service-nodedc" ? "nodedc:engine:viewer" : service.authentikGroupName,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeServiceModuleEntitlement(payload) {
|
function normalizeServiceModuleEntitlement(payload) {
|
||||||
if (typeof payload !== "object" || payload === null) return null;
|
if (typeof payload !== "object" || payload === null) return null;
|
||||||
const clientId = nullableString(payload.clientId);
|
const clientId = nullableString(payload.clientId);
|
||||||
|
|
|
||||||
|
|
@ -2134,7 +2134,7 @@ function getAppCatalog() {
|
||||||
const launcherData = readLauncherData();
|
const launcherData = readLauncherData();
|
||||||
const services = Array.isArray(launcherData?.services) ? launcherData.services : [];
|
const services = Array.isArray(launcherData?.services) ? launcherData.services : [];
|
||||||
const serviceCatalog = services.map((service) => {
|
const serviceCatalog = services.map((service) => {
|
||||||
const specialGroups = specialRequiredGroups(service.slug);
|
const specialGroups = specialRequiredGroups(service);
|
||||||
const requiredGroups = specialGroups.length
|
const requiredGroups = specialGroups.length
|
||||||
? specialGroups
|
? specialGroups
|
||||||
: service.authentikGroupName
|
: service.authentikGroupName
|
||||||
|
|
@ -2175,9 +2175,26 @@ function getAppCatalog() {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function specialRequiredGroups(slug) {
|
const engineRequiredGroups = [
|
||||||
|
"nodedc:engine:admin",
|
||||||
|
"nodedc:engine:editor",
|
||||||
|
"nodedc:engine:viewer",
|
||||||
|
"nodedc_admin",
|
||||||
|
"nodedc_editor",
|
||||||
|
"nodedc_viewer",
|
||||||
|
];
|
||||||
|
|
||||||
|
function specialRequiredGroups(serviceOrSlug) {
|
||||||
|
const slug = typeof serviceOrSlug === "string" ? serviceOrSlug : serviceOrSlug?.slug;
|
||||||
|
const applicationSlug = typeof serviceOrSlug === "string" ? null : serviceOrSlug?.authentikApplicationSlug;
|
||||||
|
const serviceId = typeof serviceOrSlug === "string" ? null : serviceOrSlug?.id;
|
||||||
|
|
||||||
if (slug === "launcher") return ["nodedc:launcher:admin", "nodedc:launcher:user"];
|
if (slug === "launcher") return ["nodedc:launcher:admin", "nodedc:launcher:user"];
|
||||||
if (slug === "task-manager") return ["nodedc:taskmanager:admin", "nodedc:taskmanager:user"];
|
if (slug === "task-manager") return ["nodedc:taskmanager:admin", "nodedc:taskmanager:user"];
|
||||||
|
if (slug === "nodedc" || slug === "engine" || slug === "nodedc-engine" || applicationSlug === "nodedc-engine" || serviceId === "service_nodedc") {
|
||||||
|
return engineRequiredGroups;
|
||||||
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,19 +77,19 @@ export const mockServices: Service[] = [
|
||||||
{
|
{
|
||||||
id: "service_nodedc",
|
id: "service_nodedc",
|
||||||
slug: "nodedc",
|
slug: "nodedc",
|
||||||
title: "NodeDC",
|
title: "ENGINE",
|
||||||
subtitle: "Агентная платформа",
|
subtitle: "Агентная платформа",
|
||||||
description: "Сборка, запуск и мониторинг агентных workflow.",
|
description: "Сборка, запуск и мониторинг агентных workflow.",
|
||||||
fullDescription:
|
fullDescription:
|
||||||
"NodeDC используется для настройки агентных процессов, визуальной оркестрации, интеграций и runtime-мониторинга.",
|
"NodeDC используется для настройки агентных процессов, визуальной оркестрации, интеграций и runtime-мониторинга.",
|
||||||
url: "https://dev.handhdc.ru/sso/launch",
|
url: "https://engine.nodedc.ru/",
|
||||||
launchUrl: "https://dev.handhdc.ru/sso/launch",
|
launchUrl: "https://engine.nodedc.ru/",
|
||||||
accentColor: "#B5FF5A",
|
accentColor: "#B5FF5A",
|
||||||
fallbackGradient: "linear-gradient(128deg, rgba(181, 255, 90, 0.84), rgba(37, 58, 36, 0.86) 42%, #0A0D10 82%)",
|
fallbackGradient: "linear-gradient(128deg, rgba(181, 255, 90, 0.84), rgba(37, 58, 36, 0.86) 42%, #0A0D10 82%)",
|
||||||
status: "active",
|
status: "active",
|
||||||
order: 10,
|
order: 10,
|
||||||
authentikApplicationSlug: "nodedc",
|
authentikApplicationSlug: "nodedc-engine",
|
||||||
authentikGroupName: "service-nodedc",
|
authentikGroupName: "nodedc:engine:viewer",
|
||||||
createdAt: "2026-04-01T10:00:00Z",
|
createdAt: "2026-04-01T10:00:00Z",
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
},
|
},
|
||||||
|
|
@ -207,6 +207,8 @@ export const mockGrants: ServiceGrant[] = [
|
||||||
grant("grant_dctouch_task_admins", "service_task_manager", "group", "group_dctouch_admins", "admin"),
|
grant("grant_dctouch_task_admins", "service_task_manager", "group", "group_dctouch_admins", "admin"),
|
||||||
grant("grant_dctouch_task_managers", "service_task_manager", "group", "group_dctouch_managers", "member"),
|
grant("grant_dctouch_task_managers", "service_task_manager", "group", "group_dctouch_managers", "member"),
|
||||||
grant("grant_dctouch_nodedc_admins", "service_nodedc", "group", "group_dctouch_admins", "admin"),
|
grant("grant_dctouch_nodedc_admins", "service_nodedc", "group", "group_dctouch_admins", "admin"),
|
||||||
|
grant("grant_engine_user_silver_psih_yahoo_com", "service_nodedc", "user", "user_silver_psih", "member"),
|
||||||
|
grant("grant_engine_user_constr_dc_yahoo_com", "service_nodedc", "user", "user_constr_dc_yahoo_com", "viewer"),
|
||||||
];
|
];
|
||||||
|
|
||||||
export const mockExceptions: ServiceAccessException[] = [];
|
export const mockExceptions: ServiceAccessException[] = [];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue