import type { BackupConfig } from "./config.js"; import type { Manifest } from "./manifest.js"; import { type SnapshotStore } from "./snapshot-store.js"; import { type OrphanedForeignKey } from "./orphaned-foreign-keys.js"; import { type GrantRestore } from "./grants.js"; import { type AuthDrillReport, type AuthDumpForDrill } from "./auth-drill.js"; /** * 无放回随机抽样:部分 Fisher-Yates,只洗出前 n 位(O(n) 次交换,不必全 shuffle)。 * 此前恒取 manifest 顺序的前 CAP 个 → 超过 CAP 的项目里排序靠后的文件永远不被校验; * 随机抽样让每次演练覆盖不同子集,损坏的文件长期必然被抽中。 * 随机源用 Math.random 足够:演练是一次性进程,无可复现性要求——校验失败的文件名 * 会原样列进报告,定位问题不依赖重放同一批样本。 */ export declare function sampleStorageFiles(files: T[], n: number): T[]; /** @internal 托管 worker 专用钩子;事件不携带客户数据或凭据,不属于稳定 CLI 契约。 */ export type DrillPhase = "download" | "storage" | "sandbox" | "restore" | "verify" | "auth" | "cleanup"; export interface DrillSupervision { /** 仅 runDrill 使用:supervisor 独占的空临时目录,由 supervisor 清理。 */ workdir: string; /** 每次尝试唯一;即使 docker run 被中断,supervisor 也能按名字清理。 */ resourceName: string; /** 非 cleanup、非 auth 阶段抛错 = 主动中止并清理;上报失败应由调用方自行吞掉,回调须自带超时(托管 worker 另有进程级执行上限)。 * cleanup 阶段同步/异步错误均忽略,最多等待 5 秒,绝不阻止 teardown。auth 阶段抛错只跳过 Auth 附加检查。 */ observe: (event: { phase: DrillPhase; dumpBytes?: number; }) => Promise; /** * 2.10.0 起:supervisor 叫停 Auth 附加检查(比如磁盘吃紧)。这一节记 not_checked,演练结论不变—— * 结论在 Auth 这一节之前就定了。"auth" 阶段的 observe 被拒绝同样只跳过这一节,不中止演练 */ authStop?: AbortSignal; } export interface DrillCheck { name: string; pass: boolean; detail: string; } export interface DrillReport { snapshot: string; pass: boolean; checks: DrillCheck[]; restoreSeconds: number; restoredTableCount: number; restoredRowTotal: number; /** --keep 且演练失败时:被保留的沙箱(供排查/脚本消费);其余情况不存在 */ keptSandbox?: { containerId: string; connString: string; }; /** 源库自带孤儿行的外键:演练和真实恢复都把它们建成 NOT VALID,不算失败。没有时不出现 */ orphanedForeignKeys?: OrphanedForeignKey[]; /** * 2.10.0 起,快照带 Auth 用户时的附加校验(见 auth-drill.ts)。**不参与 pass 的判定**; * 快照不带 Auth 时不出现 */ auth?: AuthDrillReport; } export interface SandboxTuning { settings: string[]; /** docker --shm-size 的值;并行建索引走动态共享内存,要跟 maintenance_work_mem 一起长 */ shmSize: string; /** pg_restore --jobs;1 = 单连接 */ restoreJobs: number; } export declare function sandboxTuning(totalMemBytes: number, cpus?: number): SandboxTuning; export declare function sandboxDataVolumeTarget(major: number): string; /** post-data 第二遍恢复的结果:用户对象失败 vs Supabase 托管对象的沙箱预期跳过。 */ interface PostDataResult { supabaseSkipped: number; failures: string[]; /** 已同时计入 failures */ orphanedForeignKeys?: OrphanedForeignKey[]; /** 授权重建结果;失败时不存在,原因在 failures 里 */ grants?: GrantRestore; } /** 兼容层:历史签名保留,分类逻辑的单一权威在统一引擎(restore-engine.ts)。 */ export declare function classifyPostDataErrors(stderr: string): PostDataResult; /** 兼容层:见 restore-engine.ts finalizePass(非零退出且零错误块 = 通用失败)。 */ export declare function postDataResult(code: number | null, stderr: string): PostDataResult; /** 导出:真实恢复(restore.ts)复用同一套表级验证——两条路径对同一快照必须同一结论。 */ export declare function verifyRestored(connString: string, manifest: Manifest, /** 恢复用的那份 dump:恢复出空表时回查它,见第 3 项检查 */ dumpPath?: string): Promise<{ checks: DrillCheck[]; tableCount: number; rowTotal: number; }>; export declare const APP_CHECK_TIMEOUT_MS: number; /** * 语义层钩子:结构检查全绿后、销毁沙箱前,把沙箱连接串经 BACKUPDRILL_SANDBOX_URL * 交给用户命令执行,校验数据/业务不变量(判据只存在于应用侧,引擎不解释命令输出, * 只裁决退出码:0 = pass)。注意这不是 RLS 行为测试:连接身份是沙箱超级用户 * (绕过 RLS),且引用 Supabase 托管角色的策略在恢复时已被归类跳过。 * 子进程输出定向到 stderr:stdout 是 CLI 的机器可读 JSON 通道,不能被污染。 * 红线:托管 worker 绝不能把用户输入传到这里(任意代码执行);此钩子只属于 * 用户在自己机器上运行的 CLI(见 PRD §1.4 演练后应用自检钩子)。 */ export declare function runAppCheck(command: string, connString: string, timeoutMs?: number): Promise; /** * 演练核心:把一份本地 dump 恢复进临时 Postgres 并对照 manifest 校验,然后销毁容器。 * 与 S3 解耦,便于离线测试。`preChecks` 用于把下载阶段的校验(如归档校验和)带进报告。 */ export declare function drillDump(dumpPath: string, manifest: Manifest, snapshot: string, preChecks?: DrillCheck[], opts?: { appCheckCommand?: string; keepSandboxOnFailure?: boolean; supervision?: DrillSupervision; /** 快照带 Auth 用户时 runDrill 在后台下载的 auth.dump(和正式演练同时进行) */ authDump?: Promise; /** Auth 那一节超时放弃时,叫停还没下完的 auth.dump */ stopAuthDownload?: () => void; }): Promise; /** 演练一份快照:从桶里下载→drillDump(含 Storage 校验)→报告。 */ export declare function runDrill(config: BackupConfig, opts?: { snapshot?: string; verifyAllFiles?: boolean; /** CLI 专用。红线:托管 worker 绝不能传入(在 worker 上执行用户命令 = RCE)。 */ appCheckCommand?: string; keepSandboxOnFailure?: boolean; supervision?: DrillSupervision; /** 快照从哪读;省略 = config.storage 指的 S3 兼容桶 */ store?: SnapshotStore; /** * 快照带 Auth 用户时做不做附加的 Auth 校验(不影响结论,见 auth-drill.ts)。默认:没有 supervision 时做 * (CLI);有 supervision(托管 worker)时不做——auth.dump 不在它按 dumpBytes 算的磁盘预算里, * 等 worker 把两份都算进预算再显式打开 */ authCheck?: boolean; }): Promise; export {};