UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

349 lines (348 loc) • 15.9 kB
import { a as getProcessGatewayPluginMetadataSnapshot } from "./current-plugin-metadata-state-CfLPTM0e.mjs"; import { t as GATEWAY_OWNER_PROFILE_ID } from "./user-profile-constants-DfyZS95p.mjs"; import { R as onUserProfilesChanged } from "./user-profiles-internal-DlO1LBbo.mjs"; import { a as createAdmittedRunOperatorAuthority, t as assertAdmittedRunOperatorAuthority } from "./admitted-run-context-QJnFIxUZ.mjs"; import { n as readOperatorModelPolicyMembership, t as prepareOperatorModelPolicy } from "./operator-model-policy-7XqG83Qr.mjs"; import { a as roleScopesAllow, t as intersectOperatorScopes } from "./operator-scope-compat-Ci6GBcmU.mjs"; import { o as prepareUserProfileIdentity } from "./user-profile-list-CtETKur7.mjs"; import { d as retainGatewayDeviceRevocation, l as readGatewayDeviceSourceAuthority, o as onGatewayDeviceSourceRevoked, u as readGatewayDeviceSourceIdentity } from "./device-revocation-DeateGFe.mjs"; import { a as onOperatorRolePolicyChanged, f as resolveOperatorRolePolicyForAssignment, u as resolveGatewayOperatorRoleActor } from "./operator-role-policy-Bsa4SHqC.mjs"; import { r as sourceRolePolicy } from "./operator-role-source-policy-DD1lr4qS.mjs"; import { isDeepStrictEqual } from "node:util"; //#region src/gateway/operator-run-authority.ts const operatorSources = /* @__PURE__ */ new WeakMap(); function getOperatorSources(client) { let sources = operatorSources.get(client); if (!sources) { sources = /* @__PURE__ */ new Set(); operatorSources.set(client, sources); } return sources; } /** A captured transport principal keeps its source's comparison identity, not new authority. */ function transferGatewayOperatorSourceIdentity(source, target) { operatorSources.set(target, getOperatorSources(source)); } function retainOperatorSource(client, owners, membership) { const sources = getOperatorSources(client); let source = membership === void 0 ? void 0 : [...sources].find((entry) => entry.membership === membership && entry.owners.every((owner, index) => owner === owners[index])); if (!source) { source = { owners, membership, token: Object.freeze({}), references: 0 }; sources.add(source); } const retained = source; const bucket = sources; retained.references += 1; return { token: retained.token, release: () => { if (--retained.references === 0) bucket.delete(retained); } }; } function prepareRunRolePolicy(role) { return role ? { sessionAccessCap: role.sessions.others, sandboxRequired: role.sandbox === "required", agents: role.agents } : void 0; } function intersectRunModelPolicy(original, current) { return original && current && readOperatorModelPolicyMembership(original) !== readOperatorModelPolicyMembership(current) ? Object.freeze({ models: Object.freeze(current.models.filter(original.allows)), allows: (ref) => original.allows(ref) && current.allows(ref) }) : current ?? original; } /** Bridge a prepared linked principal while retaining its exact channel admission capability. */ function captureChannelOperatorRunAuthority(input) { const params = { ...input }; params.assertCurrent(); let modelPolicyConfig = params.getRuntimeConfig(); let modelPolicyMetadata = getProcessGatewayPluginMetadataSnapshot(); const prepareModelPolicy = (cfg, metadata) => prepareOperatorModelPolicy({ cfg, policy: resolveOperatorRolePolicyForAssignment(params.profileId, params.assignedRole, cfg, params.githubLogin ?? null)?.modelPolicy, manifestPlugins: metadata ?? [] }); const originalModelPolicy = prepareModelPolicy(modelPolicyConfig, modelPolicyMetadata); let modelPolicy = originalModelPolicy; return createAdmittedRunOperatorAuthority({ profileId: params.profileId, scopes: params.scopes, rolePolicy: prepareRunRolePolicy(sourceRolePolicy(resolveOperatorRolePolicyForAssignment(params.profileId, params.assignedRole, modelPolicyConfig, params.githubLogin ?? null))), gatewayAccessGrant: params.gatewayAccessGrant, assertCurrent: params.assertCurrent, readCurrentRoleAssignment: () => { params.assertCurrent(); return params.assignedRole; }, readCurrentGithubLogin: () => { params.assertCurrent(); return params.githubLogin ?? null; }, get modelPolicy() { const cfg = params.getRuntimeConfig(); const metadata = getProcessGatewayPluginMetadataSnapshot(); if (cfg !== modelPolicyConfig || metadata !== modelPolicyMetadata) { const current = prepareModelPolicy(cfg, metadata); modelPolicy = intersectRunModelPolicy(originalModelPolicy, current); modelPolicyConfig = cfg; modelPolicyMetadata = metadata; } return modelPolicy; }, onModelPolicyChanged: (listener) => { const releaseProfile = onUserProfilesChanged(listener); const releasePolicy = onOperatorRolePolicyChanged((change) => { if (change.kind === "config" || change.profileId === params.profileId) listener(); }); params.signal?.addEventListener("abort", listener, { once: true }); return () => { releaseProfile(); releasePolicy(); params.signal?.removeEventListener("abort", listener); }; } }); } /** Transfers the original operator restriction into accepted work, independently of its request. */ async function captureGatewayOperatorRunAuthority(input) { const params = { ...input }; const inherited = params.client?.internal?.operatorRunAuthority; if (inherited !== void 0) { assertAdmittedRunOperatorAuthority(inherited); inherited.assertCurrent(); const scopes = intersectOperatorScopes(inherited.scopes, params.client?.connect.scopes ?? []); return { authority: roleScopesAllow({ role: "operator", requestedScopes: inherited.scopes, allowedScopes: scopes }) ? inherited : createAdmittedRunOperatorAuthority({ ...inherited, scopes, get modelPolicy() { return inherited.modelPolicy; } }), release: inherited.retain?.() ?? (() => {}) }; } const actor = resolveGatewayOperatorRoleActor(params.client); const client = params.client; const isAuthenticatedOwner = (currentActor) => client?.internal?.authenticatedOperator === true && (currentActor === void 0 || currentActor.kind === "system") && client.connect.role === "operator" && Boolean(client.connId) && !client.invalidated && !client.connectionSignal?.aborted && !client.internal.syntheticClient && !client.internal.agentRuntimeIdentity && !client.internal.agentToolCaller && client.authenticatedUserProfile?.profileId === "gateway-owner"; const authenticatedOwner = isAuthenticatedOwner(actor); if (!client || actor?.kind !== "operator" && !authenticatedOwner) return; const profileId = actor?.kind === "operator" ? actor.profileId : GATEWAY_OWNER_PROFILE_ID; const connectionId = client.connId; const connectionSignal = client.connectionSignal; if (params.hasCurrentClientAuthority?.() === false) throw new Error("Gateway caller authority is no longer active."); const releaseDevice = retainGatewayDeviceRevocation(params.hasCurrentClientAuthority); const isSourceCurrent = readGatewayDeviceSourceAuthority(params.hasCurrentClientAuthority); const resolveGatewayContext = params.context.resolveGatewayContext; const gatewayContext = resolveGatewayContext?.(); const getConfig = params.context.getCommittedRuntimeConfig ?? params.context.getRuntimeConfig; let modelPolicyConfig = getConfig(); let modelPolicyMetadata = getProcessGatewayPluginMetadataSnapshot(); let modelPolicy; let originalModelPolicy; const isGatewayCurrent = () => !resolveGatewayContext || gatewayContext !== void 0 && resolveGatewayContext() === gatewayContext; const sourceAuthority = params.sourceAuthority !== void 0 ? params.sourceAuthority : client.internal?.operatorAccessAuthority; const sourceAuthorities = [sourceAuthority, params.invocationAuthority]; const scopes = Object.freeze([...client.connect.scopes ?? []]); const sourceOwners = [ gatewayContext ?? params.context, resolveGatewayContext, getConfig, readGatewayDeviceSourceIdentity(params.hasCurrentClientAuthority) ?? (params.hasCurrentClientAuthority ? Object.freeze({}) : void 0), sourceAuthority, params.invocationAuthority ]; let releaseSource; let references = 1; let revoked = false; const revocation = new AbortController(); const subscriptions = []; let preparedProfile; const assertProfileCurrent = () => { try { const profile = preparedProfile?.readCurrentProfile(); if (!profile || profile.profileId !== profileId) throw new Error("operator profile is unavailable"); return profile; } catch (error) { throw new Error("operator source identity changed; start a new request", { cause: error }); } }; const resolveCurrentRole = (cfg = getConfig()) => { const profile = assertProfileCurrent(); return resolveOperatorRolePolicyForAssignment(profileId, profile.assignedRole, cfg, profile.githubLogin ?? null); }; const assertRoleCurrent = () => { const policy = resolveCurrentRole(); if (policy && !roleScopesAllow({ role: "operator", requestedScopes: scopes, allowedScopes: policy.scopes })) throw new Error("Your operator role changed; reconnect before continuing."); }; const readModelPolicy = () => { const original = originalModelPolicy; const cfg = getConfig(); const metadata = getProcessGatewayPluginMetadataSnapshot(); if (cfg !== modelPolicyConfig || metadata !== modelPolicyMetadata) { modelPolicy = intersectRunModelPolicy(original, prepareOperatorModelPolicy({ cfg, policy: resolveCurrentRole(cfg)?.modelPolicy, manifestPlugins: metadata ?? [] })); modelPolicyConfig = cfg; modelPolicyMetadata = metadata; } return modelPolicy; }; const revoke = (reason) => { if (references > 0 && isGatewayCurrent()) { revoked = true; revocation.abort(reason); } }; const recheck = (check) => { if (!revoked && references > 0 && isGatewayCurrent()) try { check(); } catch (error) { revoke(error); } }; const assertSourceCurrent = () => { if (revoked || references === 0) throw new Error("operator execution authority is no longer active"); if (isSourceCurrent?.() === false || !isGatewayCurrent()) throw new Error("operator source authority is no longer active"); for (const authority of sourceAuthorities) { authority?.signal?.throwIfAborted(); authority?.assertCurrent(); authority?.signal?.throwIfAborted(); } if (revoked || references === 0) throw new Error("operator execution authority is no longer active"); }; const assertCurrent = () => { try { assertSourceCurrent(); assertRoleCurrent(); } catch (error) { revoked = true; throw error; } }; const releaseHold = () => { let released = false; return () => { if (!released) { released = true; if (--references === 0) { releaseSource?.(); releaseSource = void 0; for (const unsubscribe of subscriptions.splice(0)) unsubscribe?.(); preparedProfile?.release(); releaseDevice?.(); } } }; }; const release = releaseHold(); try { const initialRoleConfig = { gateway: { roles: structuredClone(modelPolicyConfig.gateway?.roles) } }; const preparationConfigs = [initialRoleConfig]; let onConfigChange = () => { preparationConfigs.push({ gateway: { roles: structuredClone(getConfig().gateway?.roles) } }); }; let profileChangedDuringPreparation = false; let onProfileChange = () => { profileChangedDuringPreparation = true; }; subscriptions.push(onGatewayDeviceSourceRevoked(params.hasCurrentClientAuthority, () => revoke(/* @__PURE__ */ new Error("operator source authority is no longer active"))), onUserProfilesChanged(() => onProfileChange()), onOperatorRolePolicyChanged((change) => { if (change.kind === "assignment" && change.profileId === profileId) revoke(/* @__PURE__ */ new Error("Your operator role changed; reconnect before continuing.")); else if (change.kind === "config" && change.context === (gatewayContext ?? params.context)) onConfigChange(); })); for (const authority of sourceAuthorities) { const sourceSignal = authority?.signal; if (sourceSignal) { const onAbort = () => revoke(sourceSignal.reason); sourceSignal.addEventListener("abort", onAbort, { once: true }); subscriptions.push(() => sourceSignal.removeEventListener("abort", onAbort)); } } assertSourceCurrent(); preparedProfile = await prepareUserProfileIdentity(profileId); const currentActor = resolveGatewayOperatorRoleActor(params.client); const originalActorCurrent = authenticatedOwner ? isAuthenticatedOwner(currentActor) && client.connId === connectionId && client.connectionSignal === connectionSignal : currentActor?.kind === "operator" && currentActor.profileId === profileId; if (params.client !== client || !originalActorCurrent || params.hasCurrentClientAuthority?.() === false || !isGatewayCurrent() || !roleScopesAllow({ role: "operator", requestedScopes: scopes, allowedScopes: client.connect.scopes ?? [] })) throw new Error("Gateway caller authority is no longer active."); const capturedProfile = assertProfileCurrent(); const capturedAssignedRole = capturedProfile.assignedRole; const capturedGithubLogin = capturedProfile.githubLogin ?? null; const capturedRole = structuredClone(resolveCurrentRole()); const capturedSourcePolicy = sourceRolePolicy(capturedRole); if (preparationConfigs.some((config) => !isDeepStrictEqual(capturedSourcePolicy, sourceRolePolicy(resolveOperatorRolePolicyForAssignment(profileId, capturedAssignedRole, config, capturedGithubLogin))))) revoke(/* @__PURE__ */ new Error("Your operator role changed; reconnect before continuing.")); const assertCapturedRoleCurrent = () => { const current = assertProfileCurrent(); const policy = resolveOperatorRolePolicyForAssignment(profileId, current.assignedRole, getConfig(), current.githubLogin ?? null); if (current.assignedRole !== capturedAssignedRole || !isDeepStrictEqual(capturedSourcePolicy, sourceRolePolicy(policy))) throw new Error("Your operator role changed; reconnect before continuing."); }; onConfigChange = () => recheck(assertCapturedRoleCurrent); onProfileChange = () => recheck(assertCapturedRoleCurrent); if (profileChangedDuringPreparation) onProfileChange(); assertCurrent(); originalModelPolicy = prepareOperatorModelPolicy({ cfg: modelPolicyConfig, policy: resolveOperatorRolePolicyForAssignment(profileId, capturedAssignedRole, initialRoleConfig, capturedGithubLogin)?.modelPolicy, manifestPlugins: modelPolicyMetadata ?? [] }); modelPolicy = originalModelPolicy; preparationConfigs.length = 0; const source = retainOperatorSource(client, sourceOwners, readOperatorModelPolicyMembership(originalModelPolicy)); releaseSource = source.release; return { authority: createAdmittedRunOperatorAuthority({ profileId, scopes, rolePolicy: prepareRunRolePolicy(capturedSourcePolicy), readCurrentRoleAssignment: () => { assertCurrent(); return assertProfileCurrent().assignedRole; }, readCurrentGithubLogin: () => { assertCurrent(); return assertProfileCurrent().githubLogin ?? null; }, gatewayAccessGrant: sourceAuthority === null || sourceAuthority === void 0 && authenticatedOwner ? null : sourceAuthority?.gatewayAccessGrant, source: source.token, assertCurrent, signal: revocation.signal, retain: () => { assertCurrent(); references += 1; return releaseHold(); }, get modelPolicy() { return readModelPolicy(); }, onModelPolicyChanged: (listener) => onOperatorRolePolicyChanged((change) => { if (change.kind === "config" && change.context === (gatewayContext ?? params.context)) listener(); }) }), release }; } catch (error) { release(); throw error; } } //#endregion export { captureGatewayOperatorRunAuthority as n, transferGatewayOperatorSourceIdentity as r, captureChannelOperatorRunAuthority as t };