fix(file_service): add CSV extension and 50MB size validation to store_upload()#254
Open
dncoder14 wants to merge 1 commit intoc2siorg:mainfrom
Open
fix(file_service): add CSV extension and 50MB size validation to store_upload()#254dncoder14 wants to merge 1 commit intoc2siorg:mainfrom
dncoder14 wants to merge 1 commit intoc2siorg:mainfrom
Conversation
…e_upload()
Problems fixed:
- store_upload() accepted any file extension, not just .csv
- store_upload() placed no cap on file size; huge files could silently
consume all available disk space
Changes to app/services/file_service.py:
- Add MAX_FILE_SIZE constant (50 * 1024 * 1024 bytes)
- Validate file.filename extension (case-insensitive) before any disk
I/O; raise ValueError("Only CSV files are supported. Got: {ext}")
if the extension is not .csv
- Read file content to measure size; raise
ValueError("File size {n}MB exceeds maximum allowed size of 50MB")
if size > MAX_FILE_SIZE
- Seek file pointer back to 0 after the size check so that
shutil.copyfileobj writes the complete file content to disk
New file tests/test_file_service.py (11 tests, 3 classes):
- TestStoreUploadExtension: .csv accepted, .CSV (uppercase) accepted,
.xlsx / .exe / no-extension / .zip all raise ValueError with the
correct message
- TestStoreUploadSize: under limit accepted, exactly at limit accepted,
one byte over raises ValueError with actual MB in message
- TestStoreUploadPointerReset: disk file contains full content after
store_upload(), proving the seek(0) is in the right place
PR ReviewBackend
This comment updates automatically on each push. |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Description
Fixes two silent security and reliability gaps in
store_upload()insideapp/services/file_service.py:.exe,.zip,.xlsx).validate_upload_file()insecurity.pyalready enforces these at the HTTP layer, butstore_upload()operates at the service layer and can be called directly, so it must enforce its own invariants.Changes:
MAX_FILE_SIZE = 50 * 1024 * 1024(50 MB) module-level constant..csvonly) before any disk I/O; raisesValueError("Only CSV files are supported. Got: {ext}").ValueError("File size {n}MB exceeds maximum allowed size of 50MB")if exceeded.file.file.seek(0)after the size check soshutil.copyfileobjwrites the complete file to disk.tests/test_file_service.pywith 11 tests covering all new validations.Fixes #(issue number)
Type of Change
How Has This Been Tested?
All tests run with
pytestagainst Python 3.12 using the project's ownpyproject.tomldependencies. Disk I/O is mocked so tests are fast and hermetic.Test results:
New test classes:
TestStoreUploadExtension(6 tests) —.csvand.CSVaccepted;.xlsx,.exe, no-extension,.zipraiseValueErrorwith the actual extension in the message.TestStoreUploadSize(4 tests) — under limit accepted, exactly at limit accepted, 1 byte over raisesValueErrorwith actual MB in message.TestStoreUploadPointerReset(1 test) — verifies disk file bytes match original content byte-for-byte, provingseek(0)runs before the write.Screenshots (if applicable)
N/A
Checklist