fix(fetchart): prevent deletion of configured fallback cover art#6283
Conversation
|
Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry. |
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The direct
candidate.path != self.fallbackcomparison may be fragile if paths differ in representation (e.g., symlinks, relative vs absolute, case differences on case-insensitive filesystems); consider normalizing and/or usingos.path.samefile(guarded for existence) to robustly detect the configured fallback file.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The direct `candidate.path != self.fallback` comparison may be fragile if paths differ in representation (e.g., symlinks, relative vs absolute, case differences on case-insensitive filesystems); consider normalizing and/or using `os.path.samefile` (guarded for existence) to robustly detect the configured fallback file.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
7959f50 to
af547e4
Compare
925da4b to
4ed7686
Compare
|
Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry. |
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The
os.path.samefile(candidate.path, self.fallback)call will raise if either path doesn’t exist (e.g., missing or deleted fallback), so it would be safer to guard this with an existence check or wrap it in atry/except (OSError, FileNotFoundError)and default toFalseon error. - The new
removal_enabledexpression is getting fairly complex; consider extracting the fallback-protection logic into a small helper (e.g.,_is_prunable_source(candidate.path)) to make the intent clearer and easier to reason about.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `os.path.samefile(candidate.path, self.fallback)` call will raise if either path doesn’t exist (e.g., missing or deleted fallback), so it would be safer to guard this with an existence check or wrap it in a `try`/`except (OSError, FileNotFoundError)` and default to `False` on error.
- The new `removal_enabled` expression is getting fairly complex; consider extracting the fallback-protection logic into a small helper (e.g., `_is_prunable_source(candidate.path)`) to make the intent clearer and easier to reason about.
## Individual Comments
### Comment 1
<location> `beetsplug/fetchart.py:1492-1497` </location>
<code_context>
if task in self.art_candidates:
candidate = self.art_candidates.pop(task)
- removal_enabled = self._is_source_file_removal_enabled()
+ removal_enabled = (
+ self._is_source_file_removal_enabled()
+ and candidate.path
+ and (
+ not self.fallback
+ or not os.path.samefile(candidate.path, self.fallback)
+ )
+ )
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard `os.path.samefile` against missing or non-existent paths to avoid unexpected exceptions.
`os.path.samefile` may raise `FileNotFoundError`/`OSError` if `candidate.path` or `self.fallback` doesn’t exist, turning a previously skipped removal into an import-time crash. Please either wrap `samefile` in a helper that catches these exceptions and returns `False`, or guard it with an `os.path.exists` check on both paths before calling it.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #6283 +/- ##
=======================================
Coverage 69.33% 69.33%
=======================================
Files 141 141
Lines 18788 18793 +5
Branches 3061 3061
=======================================
+ Hits 13026 13031 +5
Misses 5117 5117
Partials 645 645
🚀 New features to boost your workflow:
|
bd9ff47 to
40c8480
Compare
|
Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry. |
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `beetsplug/fetchart.py:1454` </location>
<code_context>
+ and self.fallback
+ and os.path.exists(candidate.path)
+ and os.path.exists(self.fallback)
+ and os.path.samefile(candidate.path, self.fallback)
+ )
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard `os.path.samefile` call against a possible race between `exists` and `samefile`.
`os.path.exists` doesn’t fully protect against a race where `candidate.path` or `self.fallback` is removed or becomes unavailable between the `exists` calls and `samefile`, which can raise `FileNotFoundError` or `OSError`. Please wrap `os.path.samefile` in a `try/except (OSError, FileNotFoundError)` and return `False` on failure to make this resilient to concurrent file changes or external cleanup.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
30ee0da to
a689d9c
Compare
a689d9c to
75c44e8
Compare
|
@snejus Any chance to get this into the next patch release? |
75c44e8 to
8f56d33
Compare
8f56d33 to
99b0226
Compare
snejus
left a comment
There was a problem hiding this comment.
Apologies, only noticed your PR now. Just one question here
|
Note you will want to resolve the conflict in the changelog and move your note under the Unreleased section. |
99b0226 to
974d917
Compare
When `import.delete` or `import.move` is enabled, the `assign_art` method calls `task.prune(candidate.path)` unconditionally. This incorrectly deletes the configured `fetchart.fallback` file. Add explicit check to skip pruning when the candidate path matches the configured fallback.
|
Done and ready to be merged :-) |
Description
When
import.deleteorimport.moveis enabled, theassign_artmethod callstask.prune(candidate.path)unconditionally. This incorrectly deletes the configuredfetchart.fallbackfile. Add explicit check to skip pruning when the candidate path matches the configured fallback.To Do
docs/to describe it.) - not required because it's a fixup for 9ddddf4docs/changelog.rstto the bottom of one of the lists near the top of the document.)