fix: make _merge_toml_fragment and _remove_toml_entries use atomic writes - #3972
Open
Quratulain-bilal wants to merge 1 commit into
Open
fix: make _merge_toml_fragment and _remove_toml_entries use atomic writes#3972Quratulain-bilal wants to merge 1 commit into
Quratulain-bilal wants to merge 1 commit into
Conversation
…ites Both functions used write_text() which truncates before writing. A crash or power loss mid-write leaves a partial TOML file. Now uses tempfile.mkstemp + os.replace for atomic writes.
Contributor
There was a problem hiding this comment.
Pull request overview
Updates TOML event configuration writes to use temporary files and atomic replacement.
Changes:
- Adds
tempfilesupport. - Converts TOML merge/removal rewrites to
mkstempandos.replace. - Cleans up staged files on failure.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/events.py |
Adds atomic TOML rewrite paths. |
Review details
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Suppressed comments (2)
src/specify_cli/events.py:1775
- This teardown path also replaces an existing TOML file with
mkstemp's0600mode. Removing Spec Kit entries from a group-readable or group-writable config therefore changes access for unrelated user content. Preserve the destination's existing mode beforeos.replace, as the workflow registry writer does insrc/specify_cli/workflows/catalog.py:162-188.
fd, tmp = tempfile.mkstemp(
dir=str(dst.parent), prefix=f".{dst.name}.", suffix=".tmp"
)
src/specify_cli/events.py:1779
- The removal rewrite has the same durability gap:
os.replaceis namespace-atomic, but the staged bytes and rename are not made durable before returning. Because this PR explicitly claims protection from power loss, sync the staged file before replacement and the parent directory afterward via the same platform-aware helper.
with os.fdopen(fd, "w", encoding="utf-8") as f:
f.write(cleaned)
os.replace(tmp, dst)
- Files reviewed: 1/1 changed files
- Comments generated: 3
- Review effort level: Balanced
Comment on lines
+1734
to
+1735
| try: | ||
| with os.fdopen(fd, "w", encoding="utf-8") as f: |
Comment on lines
+1735
to
+1737
| with os.fdopen(fd, "w", encoding="utf-8") as f: | ||
| f.write(existing.rstrip() + "\n\n" + fragment + "\n") | ||
| os.replace(tmp, dst) |
Comment on lines
+1731
to
+1737
| fd, tmp = tempfile.mkstemp( | ||
| dir=str(dst.parent), prefix=f".{dst.name}.", suffix=".tmp" | ||
| ) | ||
| try: | ||
| with os.fdopen(fd, "w", encoding="utf-8") as f: | ||
| f.write(existing.rstrip() + "\n\n" + fragment + "\n") | ||
| os.replace(tmp, dst) |
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.
Problem
Both _merge_toml_fragment and _remove_toml_entries used write_text() which truncates the file before writing. A crash or power loss mid-write leaves a partial TOML file.
Fix
Now uses empfile.mkstemp + os.replace for atomic writes, matching the pattern used elsewhere in the codebase.