import type { ActionRunContext } from "../action.js"; import type { DbExec } from "../db/client.js"; /** * Enforcement helpers over the service-principal policy store. MCP admission, * MCP tool dispatch, and inbound A2A all ask these instead of reading * `evaluateServicePrincipal` themselves, so a refusal means the same thing * (status, message, audit row) on every entry point. */ export declare const SERVICE_PRINCIPAL_UNAVAILABLE_MESSAGE = "The service principal's status could not be verified. Retry shortly."; export type ServicePrincipalRefusalCode = "service_principal_inactive" | "service_principal_unavailable" | "service_principal_action_denied" | "service_principal_handoff_unsupported"; /** 403 is a refusal (audited as `denied`); 503 is retryable and never a denial. */ export declare class ServicePrincipalRefusedError extends Error { readonly errorCode: ServicePrincipalRefusalCode; readonly statusCode: 403 | 503; constructor(code: ServicePrincipalRefusalCode, message: string); } export declare function servicePrincipalActionDeniedError(actionName: string): ServicePrincipalRefusedError; /** * Throws `ServicePrincipalRefusedError` when `email` is a service identity that * is suspended or retired, or whose policy could not be read. Otherwise returns * its action grant: `null` is unrestricted (not a service identity, or a legacy * principal with no policy row), a list is the only set of actions it may call. * Non-service callers return without touching the database. */ export declare function assertServicePrincipalMayRun(email: string | null | undefined, orgId?: string | null, db?: Pick): Promise<{ allowedActions: string[] | null; }>; /** * Serialize a persisted run start with lifecycle changes, then recheck the * verified principal state before the run row is inserted. */ export declare function lockAndAssertServicePrincipalMayStartRun(db: DbExec, input: { email: string; orgId?: string | null; }): Promise; export declare function prepareServicePrincipalRunStart(input: { email: string; orgId?: string | null; }): Promise; /** Throws a 403 refusal unless the grant covers `actionName`. */ export declare function assertServicePrincipalMayCall(allowedActions: string[] | null, actionName: string): void; /** * Whose call was refused. `defineAction`'s own grant check passes the refused * call's run context as `ownInvocation`: the call is the invocation running * now, so its row keeps that call's attribution and its frame's approval. * Every other refusal is about another call, so it passes only the source it * knows and its row takes nothing from the invocation running now. */ export type ServicePrincipalDenialSource = { ownInvocation: ActionRunContext; caller?: never; } | { caller: string; ownInvocation?: never; }; /** * Writes a `denied` audit row when a refused service-principal call has a * verified org scope. Visible to org admins only; the recorder is best-effort. */ export declare function recordServicePrincipalDenial(input: { email: string | null | undefined; orgId?: string | null; actionName: string; error: ServicePrincipalRefusedError; } & ServicePrincipalDenialSource): Promise; /** * The action-execution check: refuse a service identity's call to `actionName` * when it is suspended, unverifiable, or outside its grant, and record one * `denied` row for a 403. Evaluated on every call, never cached, so a suspend * or re-scope takes effect on the next action of a run already in flight. * Non-service callers return without touching the database. */ export declare function enforceServicePrincipalActionGrant(input: { email: string | null | undefined; orgId?: string | null; actionName: string; } & ServicePrincipalDenialSource): Promise;