Repository navigation
feat(backup): restore a staged backup into a fresh root, verified against its manifest (#731) - #983
Conversation
…ed (#731, slice 4) A staging tree could be taken (slice 3) but nothing read it back: its manifest was returned to the caller and written nowhere, and no code copied the tree into a root or compared it with its digests. snapshot_backup now writes the manifest at the top of the staging tree (cortex-backup-manifest.json, 0600, never over a file). restore_backup reads it and refuses the backup before any write when the manifest is absent, of another format, version or resource table, or of a managed PostgreSQL install; when the tree does not carry exactly the manifest's files (core/backup_verify names each absent, extra or changed one, and the scan still refuses a link); or when the SQLite store fails integrity_check, read on the file opened immutable so nothing is written beside the backup. The target must not exist. The files are copied owner-only into <target>.partial, that copy is scanned and compared with the manifest again, and only then renamed to the target: a failed restore leaves no target. Tests run on the real handlers: a memory written to a live SqliteMemoryStore is read from the store of the restored root. Mutation gate run locally per changed module with the CI test selection: 0 survivors. Not verified here: Windows, pyright, the full suite (torch cannot be installed in this container). The managed cluster is still refused on both sides. Refs #731 Co-Authored-By: Claude Fable 5.2 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYrKg46KKYpvLPXcW4M Signed-off-by: Claude <[email protected]>
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Claude finished @cdeust's task in 2m 45s —— View job Review of PR #983 (review 1 of 3)
Result: I found no Blockers. The review comment lists 3 Notes, none of which needs action before merge:
I didn't run the tests or the linters; this review comes from reading the code. Verdict: approve |
Review 1 of 3: PR #983 (restore a staged backup, #731 slice 4)I found no Blockers. Five reviewers looked at this PR (code quality, performance, test coverage, documentation accuracy, security), and I traced their findings in the code myself. Checked and found safe
Notes, no action before merge
View job run |
…r refused (#731, slice 4) fix(backup): one audited write site in backup_stage (check unit, run 42990175181) write_new_file opened its own os.open/os.fdopen pair, a second storage primitive the ADR-1110 redaction-gate audit counts once. Both writers now go through _new_private_file, so the audited count stays exact. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYrVXPdxGjW7GSfGfmC
|
ci-autopilot — tentative 1 Diagnostic : le check Commit poussé : 58f0621 ( Vérifié localement : le test de gate échoue sur d975f92 (1 failed) et passe sur 58f0621 ; Generated by Claude Code |
|
Claude finished @cdeust's task in 2m 3s —— View job Review 2 of 3: PR #983
Result: I found no Blockers. The refactor keeps the flags (
I didn't run the tests or the linters, because pytest needs approval in this job. This review comes from reading the code. Verdict: approve |
Review 2 of 3: PR #983 (restore a staged backup, #731 slice 4)Earlier Blockers: none. Review 1 approved d975f92 with Notes only. Scope: only the fixup commit pushed after it, 58f0621 ( What the commit does:
This brings the ADR-1110 gate's counts for this module back to the audited 1/1/1 ( I found no Blockers. Notes, no action before merge
I didn't run the tests or the linters: pytest needs approval in this job. This review comes from reading the code. View job run |
Refs #731 (slice 4; the issue stays open, see "Still open").
What
Until now nothing read a staging tree back, and the manifest was returned to the caller but written nowhere.
snapshot_backupwritescortex-backup-manifest.jsonat the top of the staging tree (0600, never over an existing file).restore_backup(archive, target)inmcp_server/handlers/backup_restore.py.mcp_server/core/backup_verify.py;integrity_check, read with the file openedimmutable, so nothing is written beside the backup.<target>.partial, that copy is compared with the manifest again, and only then renamed to the target. A failed restore leaves.partialand no target.Proof
A memory inserted in a live
SqliteMemoryStoreis read back byget_memoryfrom the restored root (tests_py/handlers/test_backup_restore.py). Refusal cases and the target handling are intest_backup_restore_target.py,tests_py/core/test_backup_verify.pyandtests_py/infrastructure/test_backup_stage.py.Checks
ruff checkandruff format --checkon the changed files: clean.scripts/check_craftsmanship.py: OK.scripts/check_doc_claims.py: OK.backup_verify.py47/47,backup_restore.py110/110,backup_snapshot.py90/90,backup_stage.py78/78,sqlite_snapshot.py62/62 killed. No equivalent registered.Not verified
.partialto the target is untested there.mutation_check.shwith mutmut 3.8.1, not from the CI's diff-scoped run.Still open on #731
Generated by Claude Code