UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

178 lines (177 loc) • 8.39 kB
import { l as normalizeOptionalString } from "./string-coerce-1VuiLaaR.mjs"; import { n as normalizeAgentId } from "./agent-id-D1-Q6vR4.mjs"; import { T as tryResolveLegacyCompatibilityAgentId } from "./agent-scope-config-CDYpzA0r.mjs"; import { M as parseAgentSessionKey } from "./session-key-C09ow4h0.mjs"; import { i as listAgentIds } from "./agent-roster-BXD1uMJD.mjs"; import { l as resolveSessionStorePathCore } from "./paths-dpReqUI8.mjs"; import { S as listConfiguredSessionStoreAgentIds } from "./openclaw-state-db-D1jWDzK3.mjs"; import { t as isPerAgentSessionStoreConfig } from "./session-store-config-dGf2LeNv.mjs"; import { t as resolvePersistedSessionStoreOwner } from "./session-store-owner-CnfJSmam.mjs"; import { n as resolveSessionStoreCompatibilityAgentId } from "./legacy.default-agent-owner-CiZjlN5C.mjs"; import { o as resolveSessionRoutingContract } from "./main-session-00MgEWj5.mjs"; import { a as onOperatorRolePolicyChanged, g as readGatewayAccessRevision, u as resolveGatewayOperatorRoleActor } from "./operator-role-policy-Bsa4SHqC.mjs"; import { n as authorizeOperatorScopesForMethod } from "./method-scopes-BrMPjfvW.mjs"; import { i as resolveSessionStoreIdentity } from "./session-store-key-Ci099tm9.mjs"; import { r as isGatewayAuthPolicyCurrent, t as captureGatewayAuthPolicy } from "./auth-policy-C-9ITIHT.mjs"; import { a as readGatewayRequestMutationAuthority } from "./session-mutation-guards-Cw1VPolZ.mjs"; import { n as canResolveOperatorApproval, r as canReviewOperatorApproval } from "./operator-approval-authorization-BCjW3avN.mjs"; import { isDeepStrictEqual } from "node:util"; //#region src/gateway/server-methods/approval-request-authority.ts /** Pure policy/locator facts used by approval visibility; no row or registry discovery. */ function captureApprovalConfigPolicy(config) { const agents = listAgentIds(config).toSorted(); const configuredStores = listConfiguredSessionStoreAgentIds(config).toSorted(); const compatibilityAgent = resolveSessionStoreCompatibilityAgentId(config); const storeAgents = [.../* @__PURE__ */ new Set([...configuredStores, compatibilityAgent])].toSorted(); return { routing: resolveSessionRoutingContract(config), storeOwner: resolvePersistedSessionStoreOwner(config), compatibilityAgent, legacyAgent: tryResolveLegacyCompatibilityAgentId(config), agents, configuredStores, perAgentStore: isPerAgentSessionStoreConfig(config.session?.store), stores: storeAgents.map((agentId) => ({ agentId, path: resolveSessionStorePathCore(config.session?.store, { agentId }) })) }; } /** * Commit facts for one resolved approval source: its route and the stores it resolves through. * Shared fixed stores select an owner among co-tenants, and unconfigured owners discover * through every configured store root, so those keep the matching inventory. */ function captureApprovalSourcePolicy(config, source) { const { agents, configuredStores, stores, ...policy } = captureApprovalConfigPolicy(config); const { sessionKey, agentId } = source; if (!sessionKey) return policy; let identity; try { identity = resolveSessionStoreIdentity({ cfg: config, sessionKey, ...agentId ? { agentId } : {} }); } catch { identity = null; } const owners = new Set([ parseAgentSessionKey(sessionKey)?.agentId, agentId, identity?.agentId ].flatMap((owner) => owner ? [normalizeAgentId(owner)] : [])); return { ...policy, identity, owners: [...owners].toSorted().map((owner) => { const path = resolveSessionStorePathCore(config.session?.store, { agentId: owner }); const configured = configuredStores.includes(owner); return { agentId: owner, listed: agents.includes(owner), configured, path, stores: configured ? stores.filter((store) => store.path === path) : stores }; }) }; } /** Retain the original invocation; copying options loses its request-owner binding. */ function createApprovalRequestAuthority(options) { const authority = readGatewayRequestMutationAuthority(options); const { client } = options; const method = options.req.method; const profileId = client?.authenticatedUserProfile?.profileId; const userId = client?.authenticatedUserId; const role = client?.connect.role; const deviceId = client?.connect.device?.id; const approvalRuntime = client?.internal?.approvalRuntime; const runtimeIdentity = client?.internal?.agentRuntimeIdentity; const actor = resolveGatewayOperatorRoleActor(client); const actorKind = actor?.kind; const actorProfileId = actor?.kind === "operator" ? actor.profileId : void 0; const readRuntimeConfig = options.context.getRuntimeConfig; const readCommittedConfig = options.context.getCommittedRuntimeConfig; const resolveGatewayContext = options.context.resolveGatewayContext; const gatewayContext = resolveGatewayContext?.() ?? options.context; const getConfig = readCommittedConfig ?? readRuntimeConfig; const config = getConfig(); const authPolicy = client?.authPolicy ?? captureGatewayAuthPolicy(config, null); let captureConfigPolicy = captureApprovalConfigPolicy; let configPolicy = captureConfigPolicy(config); let boundSource; const accessRevision = readGatewayAccessRevision(); let configRevoked = false; let closed = false; const observeConfig = () => { try { const current = getConfig(); configRevoked = !isGatewayAuthPolicyCurrent(authPolicy, current) || !isDeepStrictEqual(configPolicy, captureConfigPolicy(current)); } catch { configRevoked = true; } }; const releaseConfig = onOperatorRolePolicyChanged((change) => { if (change.kind !== "config" || change.context !== gatewayContext || configRevoked) return; observeConfig(); }); const bindSource = (record) => { const source = { sessionKey: normalizeOptionalString(record.sessionKey) ?? null, agentId: normalizeOptionalString(record.agentId) ?? null }; if (boundSource) { configRevoked ||= !isDeepStrictEqual(boundSource, source); return; } if (configRevoked) return; observeConfig(); if (configRevoked) return; boundSource = source; captureConfigPolicy = (current) => captureApprovalSourcePolicy(current, source); try { configPolicy = captureConfigPolicy(getConfig()); } catch { configRevoked = true; } }; const assertPolicyCurrent = () => { const currentActor = resolveGatewayOperatorRoleActor(client); const allowed = method.startsWith("exec.approval.") || method.startsWith("plugin.approval.") ? authority.family === "native-compatibility" || authorizeOperatorScopesForMethod(method, client?.connect.scopes ?? []).allowed : method === "approval.resolve" ? canResolveOperatorApproval(client) : method === "approval.history" ? authorizeOperatorScopesForMethod(method, client?.connect.scopes ?? []).allowed : canReviewOperatorApproval(client); if (closed || !allowed || client?.invalidated || client?.connect.role !== role || client?.connect.device?.id !== deviceId || client?.internal?.approvalRuntime !== approvalRuntime || client?.internal?.agentRuntimeIdentity !== runtimeIdentity || currentActor?.kind !== actorKind || (currentActor?.kind === "operator" ? currentActor.profileId : void 0) !== actorProfileId || client?.authenticatedUserProfile?.profileId !== profileId || client?.authenticatedUserId !== userId || options.context.getRuntimeConfig !== readRuntimeConfig || options.context.getCommittedRuntimeConfig !== readCommittedConfig || options.context.resolveGatewayContext !== resolveGatewayContext || (resolveGatewayContext?.() ?? options.context) !== gatewayContext || configRevoked || readGatewayAccessRevision() !== accessRevision) throw new Error("Approval requester authority changed"); }; const assertCurrent = () => { authority.assertCurrent(); authority.expectedProfileBinding?.assertCurrent(); assertPolicyCurrent(); }; const guard = { family: authority.family, assertCurrent: authority.family === "native-compatibility" ? assertCurrent : () => { authority.assertWorkerCurrent(); authority.expectedProfileBinding?.assertCurrent(); assertPolicyCurrent(); } }; return { guard, bindSource, assertCurrent, assertCommitCurrent: guard.assertCurrent, isCurrent: () => { try { assertCurrent(); return true; } catch { return false; } }, [Symbol.dispose]() { closed = true; releaseConfig(); } }; } //#endregion export { createApprovalRequestAuthority as t };