fix(flow): resolve sender path and inflight staging - #1773
Conversation
When running sender with dry_run enabled, Flow.send skipped changing to local_dir, causing relative path checks against local_file to fail when the working directory differed from local_dir. Furthermore, inflight modes allowed directory mutations during fileOp events, performed renames on partitioned block transfers, mishandled short final inplace blocks, permitted path traversal, and failed to restore the caller working directory. Resolve local_path with realpath and enforce containment under baseDir. Defer inflight staging and rename checks to payload transfers. Support absolute and subfolder staging paths while disabling accelerated transfers for absolute paths. Ensure block transfers bypass temporary rename, prioritize inplace block offsets over inflight=None, accept short final blocks, validate write byte counts, and restore working directory. Fixes: MetPX#1772 Refs: #138
3d95cd9 to
84f3f23
Compare
|
I gave this PR a thorough review. Two early concerns did not hold up on verification ( My sign-off: mergeable with two small conditions, both one-line comments. At One explicit drop: do not restore the blanket Riskiest remaining item: |
When running sender with dry_run enabled, Flow.send skipped changing directory to local_dir. Relative path existence checks against local_file failed when the daemon working directory differed from local_dir, preventing test executions from completing successfully. Furthermore, staging directories were prepared during fileOp events, partitioned block transfers triggered invalid renames of non-existent temporary paths, short final blocks were rejected during inplace transfers, and non-string inflight values caused unhandled exceptions.
Fixes: #1772
Refs: robjarawan#138
What this adds
Flow.send resolves local_path using os.path.realpath and verifies that os.path.commonpath([base_dir, local_path]) == base_dir. Any attempted path traversal outside base_dir logs an error and returns -1.
Flow.send preserves the original process working directory file descriptor prior to directory modification and restores it in a finally: block across live and dry run modes.
Inflight options enforce string validation. Directory staging paths starting with / or ending in / take precedence over file suffixes. Absolute staging paths disable accelerated transfer and are rejected on object storage backends. Staging directory creation and rename capability checks are deferred to the payload transfer section so fileOp events (remove, rename, directory, link) bypass staging operations.
Partitioned block transfers bypass staging and temporary rename steps. Inplace block transfers extract offsets and lengths from msg['blocks'] manifests, take precedence over inflight is None, and use msg['size'] as the expected written length for short final blocks. In sarracenia/transfer/sftp.py, file truncation during partial block writes is removed so out-of-order block assembly succeeds.
Written byte counts returned by transfer backends are validated against expected_length before executing renames or writing success report codes.
Blast radius and rollback
This change modifies transfer staging, directory switching, and write validation logic in sarracenia/flow/init.py and sarracenia/transfer/sftp.py.
Destructive operations:
If transfer validation fails, files remain in temporary staging paths without replacing existing target files. Rollback is accomplished by reverting the commit on the branch. Reviewers should focus on the staging directory preparation placement in sarracenia/flow/init.py lines 2735-2755 and block transfer precedence in lines 2820-2850.
How to verify
Execute the flow test suite:
Verify formatting and line length:
Evidence
Platform results