feat: partial extraction reporting and --atomic flag (#89)#105
Conversation
5c218f1 to
71467f3
Compare
bug-ops
left a comment
There was a problem hiding this comment.
Failing test: test_per_entry_encrypted_check_catches_missed_by_sampling
The test at crates/exarch-core/src/formats/zip.rs:1544 fails on all platforms because PR #105 introduces PartialExtraction wrapping for mid-extraction errors.
Root cause: With a 400-entry archive and the encrypted entry at index 125, extraction writes 125 plain files before hitting the encrypted entry. The new PartialExtraction variant wraps the error:
PartialExtraction {
source: SecurityViolation { reason: "archive is password-protected..." },
report: ExtractionReport { files_extracted: 125, ... }
}
The test asserts matches!(err, ExtractionError::SecurityViolation { .. }) — which no longer matches because the error is now wrapped.
Fix: Update the assertion to accept both forms:
assert!(
matches!(
&err,
ExtractionError::SecurityViolation { .. }
| ExtractionError::PartialExtraction { source, .. }
if matches!(source.as_ref(), ExtractionError::SecurityViolation { .. })
),
"per-entry check must catch encrypted entry missed by sampling, got: {err:?}"
);Or alternatively, unwrap the inner source before asserting:
let root = match &err {
ExtractionError::PartialExtraction { source, .. } => source.as_ref(),
other => other,
};
assert!(
matches!(root, ExtractionError::SecurityViolation { .. }),
"per-entry check must catch encrypted entry missed by sampling, got: {err:?}"
);This is the only failing test. Everything else on the PR passes.
|
Failing test: The test at Root cause: With a 400-entry archive and the encrypted entry at index 125, extraction writes 125 plain files before hitting the encrypted entry. The new The test asserts Fix: Unwrap the inner source before asserting: let root = match &err {
ExtractionError::PartialExtraction { source, .. } => source.as_ref(),
other => other,
};
assert!(
matches!(root, ExtractionError::SecurityViolation { .. }),
"per-entry check must catch encrypted entry missed by sampling, got: {err:?}"
);This is the only failing test; everything else passes. |
Add ExtractionError::PartialExtraction variant that wraps the original
error together with an ExtractionReport snapshot captured at the point
of failure. All three extractors (TAR, ZIP, 7z) now wrap mid-extraction
errors in this variant when at least one file was written before the
error occurred.
The CLI displays a human-readable warning ("Extraction was stopped.
N items were written to disk before the error.") and the JSON error
output includes a partial_report field.
Add ExtractionOptions struct with an atomic flag, plus
extract_archive_with_options() and extract_archive_full() public API
functions. When --atomic is set the CLI extracts into a temporary
directory inside the same parent as the destination, renames on
success, and relies on TempDir RAII drop for cleanup on failure.
Move tempfile from dev-dependencies to dependencies in exarch-core.
Remove const qualifier from is_security_violation() and
is_recoverable() to allow delegation through Box<ExtractionError>.
Update Python and Node binding error converters with exhaustive
PartialExtraction match arms.
Closes #89
Restore 8 tests that were accidentally removed from zip.rs during
the PartialExtraction implementation: raw_zip_with_custom_entry helper,
crc32_ieee helper, test_unsupported_compression_method_rejected,
test_symlink_target_too_large, test_symlink_target_invalid_utf8,
create_large_archive_with_encrypted_entry helper,
test_password_protected_large_archive_{first,middle,last}_entry,
test_large_archive_no_encryption_passes_constructor, and
test_per_entry_encrypted_check_catches_missed_by_sampling.
Update test_per_entry_encrypted_check_catches_missed_by_sampling to
unwrap one level of PartialExtraction before asserting SecurityViolation:
entries 0..125 extract successfully before the encrypted entry is hit,
so the error is now wrapped in PartialExtraction by design.
3d55e4a to
37143c4
Compare
Summary
ExtractionError::PartialExtraction { source, report }variant that wraps the original error with anExtractionReportsnapshot captured at point of failure. TAR, ZIP, and 7z extractors now wrap mid-extraction errors in this variant when at least one file was written before the error.--atomicCLI flag: extracts to a temporary directory in the same parent as the destination, renames on success, and usesTempDirRAII drop for cleanup on failure.partial_reportfield; human-readable output shows a warning with the count of files written before the error.Changes
ExtractionOptions { atomic: bool }+extract_archive_with_options()/extract_archive_full()public APItempfilefromdev-dependenciestodependenciesinexarch-coreconstfromis_security_violation()andis_recoverable()to allow delegation throughBox<ExtractionError>PartialExtractionmatch armsKnown follow-ups (non-blocking)
PartialExtraction(callback API limitation) — filed separatelyExtractionOptionsis exposed — deferred to binding PR--force + --atomic: existing destination is removed before extraction starts (documented in help text); true post-extraction removal deferredTest plan
cargo +nightly fmt --all -- --checkpassescargo clippy --all-targets --all-features --workspace -- -D warningspasses (0 warnings)cargo nextest run --workspace --all-features --exclude exarch-python --exclude exarch-node --lib --bins— 542 passed, 0 failedcargo deny checkcleanexarch extract --max-file-size 500 two-files.zip /tmp/out/— warning appears with file countexarch extract --atomic archive.tar.gz /tmp/out/— temp dir cleaned on failureCloses #89