fix: clean up temporary file after table maintenance job execution#245
fix: clean up temporary file after table maintenance job execution#245iemejia wants to merge 3 commits into
Conversation
The table maintenance command created a temporary file with NamedTemporaryFile(delete=False) to pass job configuration, but never removed it after the job completed. The temp file persisted in the system temp directory indefinitely on every invocation. Wrap the job execution in a try/finally block to ensure os.unlink() is called, removing the temp file even if the job fails. CWE-459: Incomplete Cleanup
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds robust cleanup for the temporary job config file used by fab tables opt, and introduces tests to ensure the temp file is removed in both success and failure scenarios.
Changes:
- Ensure the temp config file is always deleted via
try/finallyinexec_command. - Add tests validating temp-file cleanup on success and on error.
- Add a test validating the written temp config contents match expected job configuration.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/fabric_cli/commands/tables/fab_tables_opt.py |
Ensures temp config file is unlinked even when jobs.run_command raises. |
tests/test_core/test_fab_tables_opt.py |
Adds coverage for temp file cleanup and correct config serialization. |
| try: | ||
| jobs.run_command(args) | ||
| finally: | ||
| os.unlink(temp_file.name) |
There was a problem hiding this comment.
Fixed. Wrapped with contextlib.suppress(OSError) (broadened from FileNotFoundError to also cover PermissionError on Windows).
| try: | ||
| fab_tables_opt.exec_command(args) | ||
| except RuntimeError: | ||
| pass |
There was a problem hiding this comment.
Fixed. Replaced with pytest.raises(RuntimeError, match="Job failed") so the test fails if the exception is not thrown.
8709239 to
b5a3394
Compare
| args.configuration = None | ||
| args.input = temp_file.name | ||
| args.params = None | ||
| jobs.run_command(args) | ||
|
|
||
| try: | ||
| jobs.run_command(args) | ||
| finally: | ||
| with contextlib.suppress(FileNotFoundError): | ||
| os.unlink(temp_file.name) |
There was a problem hiding this comment.
Fixed. Moved job execution and cleanup outside the with tempfile.NamedTemporaryFile block so the file handle is closed before os.unlink. Captured the path as temp_path = temp_file.name before exiting the with block.
…suppress OSError Move job execution outside the NamedTemporaryFile with block so the file handle is closed before os.unlink, which is required on Windows. Broaden suppression to OSError (covers PermissionError on Windows too).
Summary
The table maintenance command (
fab tables optimize/fab tables vacuum) created a temporary file viaNamedTemporaryFile(delete=False)to pass job configuration to the job runner, but never removed it after the job completed. The temp file persisted in the system temp directory indefinitely on every invocation.Problem
Each invocation of the table maintenance command left an orphaned file in the system temp directory (
/tmp/on Linux,%TEMP%on Windows). Over time, this accumulated files containing table maintenance job configuration (table names, schema names, maintenance parameters).CWE-459: Incomplete Cleanup
Fix
Wrap the job execution in a
try/finallyblock to ensureos.unlink()is called, removing the temp file even if the job fails with an exception.Tests
3 new tests:
test_exec_command_cleans_up_temp_file— verifies the temp file is removed after successful executiontest_exec_command_cleans_up_temp_file_on_error— verifies the temp file is removed even when the job raises an exceptiontest_exec_command_writes_correct_config_to_temp_file— verifies the config content (table name, schema, parameters) is written correctlyAll existing tests pass (488 total).