/** * Shared test utilities for Ory agent plugin integration tests. * * These helpers provide mock Ory API responses, error factories, and * common assertion patterns so that harness plugin tests focus on * harness-specific behavior rather than duplicating boilerplate. */ import { vi } from "vitest"; import { OryAgentClient } from "./client.js"; import type { ActivityEntry } from "./logger.js"; import type { PermissionMode } from "./config.js"; export { runHarnessContractSuite, type HarnessContractAdapter, type ContractContext, type ContractGates, type ContractOutcome, } from "./contract-suite.js"; /** * Create an OryAgentClient with session caching disabled. * Pass overrides to customize (e.g. a different harness name). */ export declare function createMockClient(overrides?: Partial[0]>): OryAgentClient; /** * Spy on {@link OryAgentClient.recordDelegation} (the agent-security broker * call the delegation writers use). Resolves to `result` (a stub node by * default). Returns the spy so callers assert the broker inputs or * `.mockRejectedValue(...)` a broker failure. */ export declare function spyRecordDelegation(client: OryAgentClient, result?: { nodeId: string; delegationChain: string[]; }): import("vitest").Mock<(input: import("./client.js").RecordDelegationInput, options?: { fetchImpl?: typeof fetch; activityAttributes?: Record; agentToken?: string; runtimeCredential?: import("./runtime-credential.js").RuntimeCredential; signal?: AbortSignal; }) => Promise>; /** * Stub an internal API instance method on the client. * Returns a vi.fn mock so callers can assert on calls. */ export declare function stubApi(client: OryAgentClient, api: K, method: string, impl: (...args: unknown[]) => unknown): ReturnType; /** Successful session verification response (wraps Ory API shape). */ export declare const MOCK_SESSION_RESPONSE: { data: { id: string; active: boolean; authenticated_at: string; expires_at: string; authenticator_assurance_level: string; authentication_methods: { method: string; completed_at: string; }[]; identity: { id: string; traits: { email: string; }; }; }; }; /** Inactive session (same shape, active: false). */ export declare const MOCK_INACTIVE_SESSION_RESPONSE: { data: { active: boolean; id: string; authenticated_at: string; expires_at: string; authenticator_assurance_level: string; authentication_methods: { method: string; completed_at: string; }[]; identity: { id: string; traits: { email: string; }; }; }; }; /** Successful OAuth2 token introspection response. */ export declare const MOCK_OAUTH2_RESPONSE: { data: { active: boolean; client_id: string; sub: string; scope: string; aud: string[]; exp: number; iat: number; }; }; /** Inactive OAuth2 token response. */ export declare const MOCK_INACTIVE_OAUTH2_RESPONSE: { data: { active: boolean; }; }; /** Permission check allowed response. */ export declare const PERMISSION_ALLOWED: { data: { allowed: boolean; }; }; /** Permission check denied response. */ export declare const PERMISSION_DENIED: { data: { allowed: boolean; }; }; /** Batch permission check: both results allowed. */ export declare const BATCH_BOTH_ALLOWED: { data: { results: { allowed: boolean; }[]; }; }; /** Batch permission check: server allowed, tool denied. */ export declare const BATCH_SERVER_ALLOWED_TOOL_DENIED: { data: { results: { allowed: boolean; }[]; }; }; /** Batch permission check: server denied. */ export declare const BATCH_SERVER_DENIED: { data: { results: { allowed: boolean; }[]; }; }; /** Create an Axios-shaped error with a response. */ export declare function makeAxiosError(status: number, body?: unknown, code?: string): Record; /** Create a Node.js network error (ECONNREFUSED, ETIMEDOUT, etc.). */ export declare function makeNetworkError(code?: string): NodeJS.ErrnoException; /** Axios 429 rate-limit error. */ export declare function makeRateLimitError(): Record; /** Axios 403 with session_aal2_required error id. */ export declare function makeMfaRequiredError(): Record; /** Axios 401 with session_inactive error id. */ export declare function makeSessionInactiveError(): Record; /** * Get all recorded activity events from a client, optionally filtered by event. */ export declare function getActivityEvents(client: OryAgentClient, event?: string): ActivityEntry[]; /** * Assert the activity log recorded the expected tool names for an event type. */ export declare function expectActivityTools(client: OryAgentClient, event: string, expectedTools: string[]): void; /** * Set standard Ory env vars for a configured + authenticated test. * Returns a cleanup function that restores the previous state. */ export declare function setOryEnv(overrides?: Partial<{ projectUrl: string; agentSecurityUrl: string; /** * Public OAuth2 client id. Together with `projectUrl` this is what makes * Agent Security connected — pass `undefined` for either to exercise the * not-connected path. */ oauth2ClientId: string; /** * Pre-supplied user OAuth2 access token (`ORY_USER_OAUTH2_TOKEN`) — the one * accepted env credential. Pass `undefined` so the login gate does not * short-circuit on it. */ userToken: string; subjectId: string; namespace: string; /** * Permission mode for the test. Defaults to `"enforce"` so existing * test assertions that exercise the deny path still see a block. The mode * is now a server-read Keto permission, so this sets the value the * {@link stubPermissionAllowed}/`Denied` stubs report for the mode check — * it is NOT an env var (there is no `ORY_PERMISSION_MODE` anymore). */ permissionMode: "observe" | "enforce"; }>): () => void; /** * Point `XDG_CONFIG_HOME` at a fresh temp directory so `resolveConfig()` * reads from a known-empty state instead of the developer's real * `~/.config/ory-agent-plugins/config.json`. Returns a cleanup function * that restores the env var and removes the temp directory. * * Use `saveConfig(...)` from `./config.js` inside the test to shape the * isolated config (e.g. `saveConfig({ projectUrl, oauth2ClientId })`). */ export declare function useTempConfigDir(): () => void; /** Placeholder values `connectSecurity` / `disconnectSecurity` write. */ export declare const TEST_PROJECT_URL = "https://test.projects.oryapis.com"; export declare const TEST_AGENT_SECURITY_URL = "https://agents.console.ory.com"; export declare const TEST_OAUTH2_CLIENT_ID = "test-login-client"; /** * Put the isolated config into the **connected** state so the auth gates and * permission checks actually run. * * Agent Security is connected exactly when a project URL and an OAuth2 client * id both resolve — there is no flag to set. Tests that exercise checks need * both, and writing them through one named call keeps that requirement in one * place instead of two literals in every `beforeEach`. * * Call after `useTempConfigDir()` so it writes to the temp config. */ export declare function connectSecurity(overrides?: { projectUrl?: string; agentSecurityUrl?: string; oauth2ClientId?: string; }): void; /** * Put the isolated config into a partial connection state for contract tests. * * `which` selects which connection values are absent. The `no-client-id` case * now exercises the reserved client default rather than a disconnected state. * The `neither` and `no-project-url` forms remain disconnected. */ export declare function disconnectSecurity(which?: "neither" | "no-client-id" | "no-project-url"): void; /** * Clear all Ory env vars (simulate unconfigured state). */ export declare function clearOryEnv(): void; /** Stub verifySession to succeed. */ export declare function stubSessionSuccess(client: OryAgentClient): import("vitest").Mock; /** Stub verifySession to return inactive. */ export declare function stubSessionInactive(client: OryAgentClient): import("vitest").Mock; /** Stub verifySession to throw a network error. */ export declare function stubSessionNetworkError(client: OryAgentClient): import("vitest").Mock; /** Stub verifySession to throw MFA required. */ export declare function stubSessionMfaRequired(client: OryAgentClient): import("vitest").Mock; /** Stub verifySession to throw session_inactive. */ export declare function stubSessionExpired(client: OryAgentClient): import("vitest").Mock; /** Stub introspectToken to succeed. */ export declare function stubOAuth2Success(client: OryAgentClient): import("vitest").Mock; /** Stub introspectToken to return inactive. */ export declare function stubOAuth2Inactive(client: OryAgentClient): import("vitest").Mock; /** * Set the mode the server-read stub reports. Also clears the in-memory * permission-mode cache so the new value takes effect immediately (tests run * with `ORY_PERMISSION_MODE_TTL_MS=0`, but resetting is belt-and-suspenders). */ export declare function setTestPermissionMode(mode: PermissionMode): void; /** Stub checkPermission to allow. */ export declare function stubPermissionAllowed(client: OryAgentClient): import("vitest").Mock & { batch: import("vitest").Mock; }; /** Stub checkPermission to deny (the tool check; the mode check still answers `currentTestMode`). */ export declare function stubPermissionDenied(client: OryAgentClient): import("vitest").Mock & { batch: import("vitest").Mock; }; /** Stub checkPermission to throw a network error. */ export declare function stubPermissionNetworkError(client: OryAgentClient): import("vitest").Mock & { batch: import("vitest").Mock; }; /** Stub checkPermission to throw a rate-limit error. */ export declare function stubPermissionRateLimited(client: OryAgentClient): import("vitest").Mock & { batch: import("vitest").Mock; }; /** Stub both checkPermission (server allow) and batchCheckPermission (both allow). */ export declare function stubMcpAllowed(client: OryAgentClient): import("vitest").Mock; /** Stub checkPermission to deny (server-only MCP check). */ export declare function stubMcpServerDenied(client: OryAgentClient): import("vitest").Mock; /** Stub batchCheckPermission: server allowed, tool denied. */ export declare function stubMcpToolDenied(client: OryAgentClient): import("vitest").Mock; /** Stub checkPermission to throw network error (MCP fail-open). */ export declare function stubMcpNetworkError(client: OryAgentClient): import("vitest").Mock;