UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

54 lines • 2.83 kB
import type { SqlParserLike } from './parser.js'; /** Configuration for {@link TenantScopeRewriter}. */ export interface TenantScopeConfig { /** The column that carries the tenant key on every scoped table (e.g. `base_id`, `org_id`). */ tenantColumn: string; /** Tables that must be constrained to the caller's tenant when referenced. */ scopedTables: string[]; } /** * Rewrites a SELECT so every reference to a scoped table is constrained to a * single tenant: `<tenantColumn> = '<tenantRef>'` is AND-ed into the WHERE for * each scoped table in the FROM. An existing predicate for a different tenant * is rejected (no cross-tenant reads). `tenantRef === undefined` is the * privileged path and passes the SQL through unchanged. * * CRITICAL: only a strictly `=== undefined` tenantRef is privileged. A `null` * or empty-string tenantRef is NOT privileged — it flows into the rewrite and * injects a predicate that matches nothing (fail-closed), so a missing tenant * can never accidentally read every tenant's rows. * * Scoped mode rejects CTEs, UNION/INTERSECT/EXCEPT, and subqueries in FROM: * those make it impossible to statically guarantee every tenant-bearing source * is constrained, so we fail closed and ask the caller to rephrase. * * The `node-sql-parser` `Parser` is injected (see {@link loadSqlParser}) so this file never imports the * optional peer at module load. */ export declare class TenantScopeRewriter { private readonly parser; private readonly tenantColumn; private readonly scopedTables; constructor(config: TenantScopeConfig, parser: SqlParserLike); /** Rewrite `sql` to constrain scoped tables to `tenantRef`. Strictly-`undefined` → pass through. */ rewrite(sql: string, tenantRef: string | undefined): string; /** * Every tenant-column `=` predicate anywhere in the tree (recurses into both `AND` and `OR`). * Used ONLY for the mismatch check: a query naming a foreign tenant anywhere must be rejected, * even where that predicate cannot be relied on to actually constrain the result set. */ private collectAllTenantPredicates; /** * Tenant-column `=` predicates on the top-level `AND` spine only. Descent stops at `OR` (and at * any operator other than `AND`/`=`, e.g. `NOT`, which the parser represents as a `unary_expr` * and so is never a `binary_expr` here) because only a conjunctively-combined predicate is * guaranteed to hold for every row the query can return. Used for coverage: a table alias is * "already scoped" only when one of these covers it. */ private collectConjunctiveTenantPredicates; private extractTenantPredicate; private buildTenantEquality; private andCondition; private forceParens; } //# sourceMappingURL=tenant-scope.d.ts.map