import type { Client } from "pg"; export declare const API_ROLES: readonly ["anon", "authenticated", "service_role"]; export type GrantRole = "PUBLIC" | (typeof API_ROLES)[number]; export declare const GRANT_ROLES: readonly GrantRole[]; export type GrantedObjectKind = "schema" | "table" | "sequence" | "routine" | "column"; export declare const GRANTED_OBJECT_KINDS: readonly GrantedObjectKind[]; export declare const GRANT_PRIVILEGES: readonly ["SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER", "MAINTAIN", "USAGE", "EXECUTE", "CREATE"]; /** * 一个对象上 PUBLIC 和三个 API 角色的授权。表、视图、序列、函数一律记下(没有授权也记, * privileges 为空 = 源库没给这几个角色任何权限);列只记有列级授权的;schema 一律记。 */ export interface GrantedObject { kind: GrantedObjectKind; schema: string; /** table / sequence / routine 的名字;column 是它所在的表;schema 没有 */ name?: string; column?: string; /** routine:pg_get_function_identity_arguments,聚合是输入参数类型(search_path 为空时取,类型都带 schema) */ args?: string; privileges: Partial>; } export interface GrantRestore { /** recorded = 照快照记录;legacy-defaults = 旧快照,按 Supabase 以前的默认授权补 public */ mode: "recorded" | "legacy-defaults"; /** 处理过的对象数 */ objects: number; } /** * 一次读取里的一个对象,带上它在这个库里的身份(oid;列是表的 oid 加 attnum)。 * 只在备份端比较转储前后两次读取时用,不进 manifest:换个库 oid 就不一样了。 */ export interface IdentifiedGrants { identity: string; object: GrantedObject; } /** 备份端:读源库里这几个 schema 下每个对象给 PUBLIC 和 API 角色的授权。 */ export declare function captureGrants(client: Client, schemas: string[]): Promise; /** 同 captureGrants,另带每个对象的身份,供 grantsHeldThroughout 比较前后两次读取。 */ export declare function captureIdentifiedGrants(client: Client, schemas: string[]): Promise; /** * 备份端:转储前后各读一次授权,只记两次都有的。 * * 为什么要读两次:授权读不进 pg_dump 的快照(共用快照会拉长 TRUNCATE 的竞态窗口,函数体也不按 * 快照读),只读一次,转储期间的授权变动总有一个方向会出错。转储后读:先抹掉私有表里的数据、 * 再开放给 anon,转储里是抹之前的数据,记下的却是"开放",恢复出来 anon 就能读到原始数据。 * 转储前读:先收回授权、再写进敏感数据,同样会开放出去。两次都有的权限,转储开始前和结束后都 * 开着,拿它配转储里的数据不会比源库开得更多;只有中途收回、写进数据、抹掉、再开放这种来回漏得过去。 * 比的是同一个对象,不只是同名:两次读之间删掉重建的表(oid 变了)、删掉重加的列(attnum 变了), * 转储里是新对象的数据,旧对象的授权不能算到它头上,按转储期间新建处理(交叉审查 2026-10-31)。 * 代价:转储期间新开放的权限要等下一次备份才记上,在那之前恢复,应用对这些对象会报 42501。 * 转储期间新建的对象(转储前没有)记成没有授权;转储期间删掉的不记,恢复端同样按没有授权处理。 */ export declare function grantsHeldThroughout(before: IdentifiedGrants[], after: IdentifiedGrants[]): GrantedObject[]; /** * 把一组对象的授权写成 SQL:schema、表、序列、函数先清掉这几个角色的全部权限再照记录授, * 列级授权放在最后(清表权限会连带清掉列权限)。schema 也要清:源库可能靠不给 USAGE 把整个 * schema 关起来,目标上的 public 却是 Supabase 默认开放的。 * roles:目标上实际存在的角色(PUBLIC 恒在);maintain:目标是否认 MAINTAIN; * revoke: false = 只出授权语句(RECOVERY.md 的清权限按目标目录来,见 recoveryGrantsSql)。 */ export declare function grantStatements(objects: GrantedObject[], opts: { roles: readonly GrantRole[]; maintain: boolean; revoke?: boolean; }): string[]; /** * 恢复端:在恢复出来的对象上照记录重建授权,一个事务内完成,提交前回读目录核对。 * 目标上的对象以目标目录为准:记录里有、目标上没有的(沙箱跳过的托管对象)略过; * 目标上有、记录里没有的(备份转储完之后才建的)按"没有授权"处理,只清不授。 * recorded 为 undefined = 旧快照:public 里的表、序列、函数在目标已有授权之上补齐 Supabase 以前的默认授权。 */ export declare function restoreGrants(client: Client, opts: { schemas: string[]; recorded: GrantedObject[] | undefined; }): Promise; /** * 补授权失败时的退路(只用于真实目标):把恢复出来的表、序列、函数上这几个角色的权限全部收走。 * 应用会 42501,但源库关着的东西不会因为目标的默认授权而开着。schema 不动,免得连带目标上别的东西。 */ export declare function revokeApiAccess(client: Client, schemas: string[]): Promise; /** 演练和恢复报告里的一行。旧快照那句按场合说:恢复是已经开放了要收回,演练是提醒真恢复时会这样。 */ export declare function grantsCheck(outcome: GrantRestore, context: "drill" | "restore"): { name: string; pass: boolean; detail: string; }; /** * RECOVERY.md 手工恢复那一步的 SQL(CLI 的 S3 版和 worker 的 Drive 版共用),做法和 restoreGrants 一样: * 按恢复后的目录,先确认执行的角色是这些对象的属主(不是属主时 GRANT/REVOKE 只告警、不生效或只生效一半), * 再把各 schema 下每个 schema、表、序列、函数上 PUBLIC 和三个角色的权限全部收走(扩展自带的对象不碰)、 * 回读确认收干净,最后逐条授回记录里的。授不上的(对象、列或参数类型不在这次恢复里)跳过并告警、不中断: * 授权只会加权限,跳过一条最多让应用少一点访问,不会把该关的打开。前面几步出错就整段回滚、报错。 * 2.9.0/2.9.1 的授权是在转储完之后读的:两次读之间删掉的对象在转储里、不在记录里,只按记录逐个收权就会漏掉它, * 它会带着默认的 PUBLIC 执行权恢复出来(交叉审查 2026-10-31);反过来,之间新加的对象(列)在记录里、 * 不在转储里,直接授权会报错,在 Supabase 的 SQL 编辑器里整段回滚。所以整段放进一个 DO 块。 * 旧快照没有记录,给 Supabase 以前的默认授权。 * MAINTAIN 只会出现在 PG17+ 源库的记录里,而恢复目标的版本不低于源库,所以照写。 * * 2.9.0 收的是授权数组(旧快照传 undefined),照旧接受:记录里每个备份的 schema 都有一条 schema 条目, * 范围从它取。 */ export declare function recoveryGrantsSql(database: { schemas: string[]; grants?: GrantedObject[]; } | GrantedObject[] | undefined): string;