Fix Launcher Engine access role handling

This commit is contained in:
DCCONSTRUCTIONS
2026-05-25 19:09:32 +03:00
parent 03f4044e35
commit de446c1879
5 changed files with 131 additions and 15 deletions
+81 -7
View File
@@ -1212,6 +1212,7 @@ export function createControlPlaneStore({ projectRoot }) {
}
const targetUser = findById(data.users, request.targetUserId, "user");
const membership = ensureEngineWorkflowPublicPoolMembership(data, targetUser, request, actor, now);
const grant = ensureEngineWorkflowServiceAccess(data, targetUser, request.role, now);
request.status = "approved";
@@ -1230,7 +1231,7 @@ export function createControlPlaneStore({ projectRoot }) {
});
await writeData(data);
return { engineWorkflowAccessRequest: request, grant, targetUser, data };
return { engineWorkflowAccessRequest: request, grant, membership, targetUser, data };
}
async function rejectEngineWorkflowAccessRequest(engineWorkflowAccessRequestId, payload, identity) {
@@ -1647,6 +1648,11 @@ export function createControlPlaneStore({ projectRoot }) {
const value = requireString(payload?.value, "value");
const user = findById(data.users, userId, "user");
const service = findById(data.services, serviceId, "service");
const engineService = isEngineService(service);
if (engineService && (value === "admin" || value === "owner")) {
throw new Error("Для Engine доступны только роли guest, member или блокировка");
}
const directGrant = data.grants.find(
(grant) => grant.serviceId === serviceId && grant.targetType === "user" && grant.targetId === userId
@@ -1677,6 +1683,9 @@ export function createControlPlaneStore({ projectRoot }) {
createdAt: directGrant?.createdAt ?? now,
updatedAt: now,
});
if (engineService) {
ensurePublicPoolMembershipActiveForServiceAccess(data, user, actor, now);
}
} else if (value !== "unset") {
throw new Error(`Unsupported access value: ${value}`);
}
@@ -2662,13 +2671,78 @@ function ensureEngineWorkflowServiceAccess(data, user, workflowRole, now) {
return grant;
}
function ensureEngineWorkflowPublicPoolMembership(data, user, request, actor, now) {
const invitedByUserId = request.requesterUserId || actor?.id || null;
let membership = data.memberships.find(
(candidate) => candidate.clientId === publicPoolClientId && candidate.userId === user.id
);
if (membership) {
const wasActive = membership.status === "active";
membership.status = "active";
if (!wasActive) {
membership.role = "member";
membership.source = "engine_workflow_access_request";
membership.sourceEngineWorkflowAccessRequestId = request.id;
} else {
membership.sourceEngineWorkflowAccessRequestId =
membership.sourceEngineWorkflowAccessRequestId ?? request.id;
}
membership.invitedByUserId = membership.invitedByUserId ?? invitedByUserId;
membership.updatedAt = now;
markPendingSync(data, user, "user", user.email);
return membership;
}
membership = {
id: uniqueId(data.memberships, "mem", `${publicPoolClientId}-${user.email}`),
clientId: publicPoolClientId,
userId: user.id,
role: "member",
status: "active",
invitedByUserId,
inviteId: null,
source: "engine_workflow_access_request",
sourceTaskerInviteRequestId: null,
sourceEngineWorkflowAccessRequestId: request.id,
createdAt: now,
updatedAt: now,
};
data.memberships.push(membership);
markPendingSync(data, user, "user", user.email);
return membership;
}
function ensurePublicPoolMembershipActiveForServiceAccess(data, user, actor, now) {
const membership = data.memberships.find(
(candidate) => candidate.clientId === publicPoolClientId && candidate.userId === user.id
);
if (!membership || membership.status === "active") {
return null;
}
membership.role = "member";
membership.status = "active";
membership.invitedByUserId = membership.invitedByUserId ?? actor?.id ?? null;
membership.source = membership.source ?? "launcher";
membership.updatedAt = now;
markPendingSync(data, user, "user", user.email);
return membership;
}
function findEngineService(data) {
return data.services.find(
(candidate) =>
candidate.id === "service_nodedc" ||
candidate.slug === "nodedc" ||
candidate.slug === "engine" ||
candidate.authentikApplicationSlug === "nodedc-engine"
return data.services.find(isEngineService);
}
function isEngineService(candidate) {
return Boolean(
candidate &&
(
candidate.id === "service_nodedc" ||
candidate.slug === "nodedc" ||
candidate.slug === "engine" ||
candidate.authentikApplicationSlug === "nodedc-engine"
)
);
}