import type { Client } from "@connectrpc/connect"; import type { grackle } from "@grackle-ai/common"; import type { AuthContext } from "@grackle-ai/auth"; import type { GrackleClients, ToolDefinition } from "./tool-registry.js"; /** * Assert that the caller (identified by scoped auth) is an ancestor of the target task. * * - No-op for non-scoped auth (api-key, oauth, undefined). * - Rejects if targetTaskId equals the caller's own taskId. * - Walks up from target via getTask().parentTaskId until it finds the caller's taskId (pass) * or reaches a root task (reject with PERMISSION_DENIED). */ export declare function assertCallerIsAncestor(client: Client, authContext: AuthContext | undefined, targetTaskId: string): Promise; /** * Central, fail-closed authorization for a resolved MCP tool call * (GHSA-f9ff-5x35-7gfw). Enforces a tool's declarative {@link ToolDefinition.scope} * for scoped (agent) callers so that destructive task/session tools cannot be * invoked against tasks/sessions the caller does not own. This is the single * choke point that keeps new task/session-targeting tools from silently failing * open the way the per-tool inline checks used to. * * - No-op for non-scoped auth (api-key, oauth) — they have full access. * - No-op for the root/system task (the central orchestrator), mirroring * `hasFullAccess` in tool-scoping.ts. * - No-op for tools without a `scope` descriptor (a tool opts in by declaring * one — a task/session-targeting tool that needs protection MUST set it). * - For a `taskIdArg` tool: the caller must be an ancestor of the target task. * - For a `sessionIdArg` tool: the session is resolved to its task (a taskless * session is rejected for scoped callers) and the caller must be its ancestor. * * A descriptor that is present but malformed (neither or both arg fields set) * **fails closed** — it throws rather than silently skipping the check — so a * misconfigured new tool surfaces immediately instead of becoming a bypass. * * A missing or empty target *value* is left to the tool's Zod validation, which * runs after this check and returns INVALID_ARGUMENT. * * @throws ConnectError with `Code.PermissionDenied` when the caller is not * authorized for the target, or when the tool's `scope` descriptor is malformed. */ export declare function enforceToolScope(clients: GrackleClients, tool: ToolDefinition, authContext: AuthContext | undefined, args: Record): Promise; /** * Workspace-membership gate for ID-resolving *read* tools (GHSA-f9ff-5x35-7gfw * F7). A scoped, non-root caller may read a task/schedule only when the record's * workspace matches the caller's own. This runs even when the caller has *no* * workspace — such a caller is a member of *no* workspace and may read only * workspaceless records. The previous inline check skipped whenever the caller's * `workspaceId` was falsy, so a workspaceless scoped token could read any record * (fail-open). The `scope` descriptor (enforceToolScope) covers mutations; new * ID-resolving read tools must be added here. * * - No-op for non-scoped auth and for the root/system task. * - No-op for tools that are not membership-gated reads. * * @throws ConnectError with `Code.PermissionDenied` when the record's workspace * does not match the caller's. */ export declare function enforceReadMembership(clients: GrackleClients, toolName: string, authContext: AuthContext | undefined, args: Record): Promise; /** * Assert that the caller is either the target task itself OR an ancestor of it. * * Used by workpad tools where an agent needs to operate on its own task (self) * or inspect/write a child task's workpad (ancestor). * * - No-op for non-scoped auth (api-key, oauth, undefined). * - Allows targetTaskId === callerTaskId (self). * - Otherwise walks up the parent chain like assertCallerIsAncestor. */ export declare function assertCallerIsSelfOrAncestor(client: Client, authContext: AuthContext | undefined, targetTaskId: string): Promise; //# sourceMappingURL=scope-enforcement.d.ts.map