You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix: enforce size limit on individual files in build_bundle() - #3911
Hi @mnriem — I've addressed Copilot's feedback: builds now write to a temporary sibling file first, and the final artifact path is only replaced atomically after every member passes validation. This prevents a partial/corrupt archive from being left at the output path if a file exceeds the size limit. The temp file is cleaned up on any failure. Added est_oversized_file_does_not_corrupt_output and est_temp_file_cleaned_up_on_failure to verify the atomic behavior. All 19 tests pass. Ready for re-review when you get a chance.
Reject files exceeding MAX_ZIP_MEMBER_BYTES (10 MiB) before archiving, bounding the actual read to prevent a TOCTOU bypass of the size check. Build into a temporary sibling file and atomically replace the final artifact only after every member passes validation, so a rejected member never leaves a partial/corrupt archive at the output path; the staging file is cleaned up on any failure.
…lection
mkstemp() creates the staging file 0600 and os.replace() preserves that mode, so every rebuilt artifact became owner-only; chmod the staging file before replacing (preserving an existing artifact's mode on rebuild, otherwise 0644). Also exclude leftover mkstemp staging files (<id>-<version>-<random>.tmp) from _collect_files so a killed build's partial archive is never re-packaged when out_dir is the bundle source tree.
The member loop's size check runs after BundleManifest.from_file() has
already read bundle.yml in full, so an oversized manifest still reached
the YAML parser. load_yaml() now takes an optional max_bytes and reads
through a bounded byte read, BundleManifest.from_file() forwards it, and
build_bundle() passes MAX_ZIP_MEMBER_BYTES for the manifest.
Regression coverage: an oversized bundle.yml must be rejected at the
manifest read, identified by the manifest's full path in the message.
Before this change that test failed with the member-loop message
("Bundle file bundle.yml exceeds ...") only after the unbounded parse had
already run.
Assisted-by: opencode (model: mimo-v2.6-flash-free, autonomous)
Addresses 3 Copilot findings:
1. Honor umask for fresh artifacts: use 0666 & ~umask instead of
unconditional 0644 so restrictive umasks (077) produce private
0600 files while normal umasks yield 0644.
2. Restrict staging-file filtering to the bundle root: staging files
are created in the output directory, not arbitrary asset dirs.
A nested asset like assets/demo-bundle-1.2.0-backup.tmp is now
correctly packaged.
3. Add bounded-read regression test: simulates a TOCTOU race where
an asset grows past MAX_ZIP_MEMBER_BYTES between fstat and read.
Verifies rejection, previous artifact preservation, and temp
file cleanup.
Tests added:
- test_fresh_artifact_honors_restrictive_umask
- test_nested_staging_like_asset_is_packaged
- test_read_is_bounded_when_asset_grows_after_fstat
Assisted-by: GitHub Copilot (autonomous)
Hi @mnriem — I've addressed all 3 Copilot findings:
1. Honor umask for fresh artifacts (Medium)
Changed os.chmod(tmp_path, 0o644) to os.chmod(tmp_path, 0o666 & ~umask) so restrictive umasks (077) produce private 0600 files while normal umasks (022) yield the expected 0644. Added \ est_fresh_artifact_honors_restrictive_umask.
2. Restrict staging-file filtering to bundle root (Medium)
Changed the staging filter to only apply when
oot_path == bundle_dir, so legitimate nested assets like \�ssets/demo-bundle-1.2.0-backup.tmp\ are correctly packaged. Added \ est_nested_staging_like_asset_is_packaged.
3. Add coverage for bounded reads after asset growth (Low)
Added \ est_read_is_bounded_when_asset_grows_after_fstat\ that simulates a TOCTOU race — an asset grows past MAX_ZIP_MEMBER_BYTES between fstat and read. Verifies rejection, previous artifact preservation, and temp file cleanup.
All 24 tests pass. Ready for re-review when you get a chance.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
triage-can-waitVerdict: valid and in-scope but deprioritized; held behind the evidence gate
3 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
build_bundle()calledread_bytes()without any size guard. A single large asset file could exhaust memory.Fix
Enforce
MAX_ZIP_MEMBER_BYTES(10 MiB) limit before reading each file.Testing