Repository navigation
fix(recovery): accept custom-format restore seek positions - #212
Conversation
Prove a successful pg_restore that seeks to TOC and data blocks may leave the caller descriptor mid-archive. Copy every fingerprint field in the older mutation helper so a single-field override remains the only change. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Custom-format pg_restore seeks through the archive, so a usable isolated restore must not fail after commit merely because the shared descriptor is not at end-of-file. Keep metadata-fingerprint verification. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Document the caller-owned trust assertion, libpq allowlist, direct SQL single-transaction boundary, and the operator action when post-restore metadata changes after pg_restore has already committed. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
Stale comment
Review (
63a89c7)Local restore suite: 48 passed.
coverage run --branch --source=pg_llm_batch.postgres_logical_restoreis 100% statement and branch.interrogateon the restore module is 100%. CodeRabbit CLI is not present in this environment.No must-fix on the seek contract. Dropping the EOF consumption check is the correct repair for closed #209. Custom-format
pg_restoreseeks to TOC and data blocks, sooffset == st_sizeis not a valid completeness signal after--single-transactionhas committed. Metadata-fingerprint verification and fail-closed descriptor inspection remain.Operator next actions
- Merge this PR only at exact head
63a89c7b39d5dad87c7186bdbeaae2c2043f1b66after every then-required check is terminal-success on that head.- Rebase or merge protected main
d2f1e32271910a6db98a0757d67194ddadca4566before landing so hosted CI sees the already-merged #205/#206/#207 evidence modules together with this executor.git merge-treeis clean; this is combined-tree hygiene, not a content conflict.- After it lands, continue #204 with a live isolated custom-format restore drill (schema, extension, tenant/RLS, checkpoint, lifecycle). Do not retry into the same service after a metadata-mismatch error.
- Do not treat a stub
pg_restorethat exits 0 without reading as proof of consumption. ADR 0016 accepts that residual because offset is not a reliable consumption signal for seekable custom archives.Residuals (not blocking)
- Import the executor from
pg_llm_batch.postgres_logical_restore. It is not in the package-root__all__.- Tests remain subprocess-mocked. They do not prove live
pg_restore, schema/RLS parity, or WAL/PITR.CHANGELOG.mdcurrently has two adjacent### Addedsections.This slice does not claim CSAP, SOC 2, or a complete recovery program.
Sent by Cursor Automation: Fix Issues
Succeed the #204 isolated-target gap without racing #212. Operators must name a live pg_service and a distinct restore-drill service before pg_restore. DSNs, tenant scope, and same-name reuse fail closed. Allocate ADR 0021 so the record does not collide with #216/#219/#221. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
seonghobae
left a comment
There was a problem hiding this comment.
Reviewed exact head 1f567cff9337476f410759b9c166776fcbfee876 against protected main@d2f1e32271910a6db98a0757d67194ddadca4566. The previous EOF postcondition is correctly absent for seekable custom-format pg_restore; the implementation instead binds success to shell-free absolute pg_restore, --single-transaction, --exit-on-error, explicit trusted-source assertion, bounded/private regular archive checks, allowlisted libpq environment, and post-execution metadata/identity stability. Diagnostics are content-free, and the docstring correctly warns that a post-restore metadata mismatch can occur after the SQL transaction committed and must not be treated as a safe retry signal. The service selector is explicitly not treated as authorization or proof of isolation. No unresolved review thread or current must-fix finding was found. Approval applies only to this unchanged head; exact-head workflows/checks, current ancestry/mergeability, and all then-live release/security gates still must terminal-success before merge.
seonghobae
left a comment
There was a problem hiding this comment.
Reviewed exact head 8a8778eb11aff40a220d54189e92e356d0b339dc against protected main@5267146534a259f85c0985e153f3f6cb1281f58f. The only new commit after the previously reviewed restore head is the merge of that protected main, which contributes the now-shipped bounded reconciliation single-flight module/tests; the logical-restore executor, custom-format seek repair, rollback/security documentation, and focused restore tests are unchanged. The invalid EOF-consumption postcondition remains absent; success remains bound to shell-free absolute pg_restore, --single-transaction, --exit-on-error, explicit trusted-source assertion, bounded/private regular archive checks, allowlisted libpq environment, and post-execution metadata/descriptor identity stability. Current review-thread inventory is empty. No new source-level must-fix was introduced by the protected-main merge. Approval is exact-head only; every live required workflow/check, actual checkout commit, current mergeability/ancestry, and release/security gate must terminal-success before integration.
…228) * test(recovery): require isolated restore-target service names Add the RED contract for #204 isolated-target identity: a live pg_service name and a restore-drill name must be exact distinct libpq service identities. DSNs, tenant scope, subclasses, and same-name reuse must fail closed before pg_restore. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com> * feat(recovery): isolate restore-target libpq service names Succeed the #204 isolated-target gap without racing #212. Operators must name a live pg_service and a distinct restore-drill service before pg_restore. DSNs, tenant scope, and same-name reuse fail closed. Allocate ADR 0021 so the record does not collide with #216/#219/#221. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com> * fix(recovery): allocate collision-free restore-target ADR 0022 #222 already files ADR 0021 for the workflow-registry audit. Keep the isolation seam unchanged and retarget this decision, doctoring, and the documentation contract to 0022 after a fresh open-writer inventory. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com> * fix(recovery): require cluster identity for restore-target isolation Distinct libpq service names are not cluster isolation. Require caller-owned pg_control_system() identifiers so two aliases for the same production cluster fail closed before pg_restore. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com> Co-authored-by: Seongho Bae <me@seonghobae.me>


Why this exists
PR #209 at
afbe449still requires the shared archive descriptor to finish at end-of-file. PostgreSQL custom-formatpg_restoreseeks to the table of contents and data blocks, so a real isolated restore can leave the descriptor mid-archive after--single-transactionhas already committed. That is a buyer-visible recovery failure: SQL is applied, the Python API reports failure, and a retry into the same target is unsafe.This branch keeps the #209 executor and replaces the EOF consumption check with metadata-fingerprint verification. It also records the direct-SQL rollback contract that #209 deferred.
Operator action
source_superusers_trusted=True.afbe449while the EOF check remains.Evidence
2f7f0b0failed witharchive was not consumed completelywhen the child sought to TOC and data and left a mid-archive offset.3627dc3keeps fingerprint verification and drops the EOF requirement.coverage run --branch --source=pg_llm_batch.postgres_logical_restoreis 100% statement and branch. Restore unit plus documentation tests: 54 passed.docs/doctoring/postgres-logical-restore.md,docs/adr/0016-postgres-logical-restore-seek.md, README, ARCHITECTURE, CHANGELOG.This slice still does not prove schema/RLS/PITR parity, CSAP, or SOC 2 readiness. Refs #204. Related #209.