fix: track collection membership provenance#2663
Merged
Merged
Conversation
…-membership-provenance # Conflicts: # apps/server/src/modules/api/plex-api/plex-api.service.ts
Collaborator
Author
|
@Simon-Eklundh Please test this, polished it with the final fixes I think is valid. 👍 |
Collaborator
Author
|
/release-pr |
Contributor
|
Released to |
Contributor
|
just tested @enoch85 it seems to work to me at least. I did need to run the rules and move out and into manual collection, but that was most likely because of an old rule having put it there, and I run two different instances depending on if I'm testing or not |
maintainerr-automation Bot
added a commit
that referenced
this pull request
Apr 12, 2026
* fix: quiet noisy service logs * fix: clarify rule placeholders and Seerr helper copy * fix: track collection membership provenance (#2663) * fix: remove SSRF sinks from API failure logging (#2665) * fix: remove SSRF sinks from API failure logging Replace axios.getUri() calls in external-api, plexApi, and jellyfin-adapter with a small helper that builds log-safe request descriptors via plain string ops, and normalize base URLs on construction. Preserves per-request baseURL overrides and params in failure logs, and closes the CodeQL server-side-request-forgery alert on external-api.service.ts. * fix: drop base URL normalizer to keep CodeQL SSRF fix minimal The added normalizeExternalApiBaseUrl used new URL(baseUrl), which CodeQL treats as a URL-construction sink. That gave its SSRF query a cleaner dataflow path from user config into every downstream axios request, producing four new alerts on the request call sites in external-api.service.ts. Removing the normalizer keeps only describeRequestTarget, which builds log strings via plain string ops and encodeURIComponent, and closes the original alert without introducing new ones. --------- Co-authored-by: enoch85 <mailto@danielhansson.nu>
Contributor
|
🎉 This PR is included in version 3.6.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
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.
Summary
Fixes #2611 by tracking rule-owned and manual collection membership separately. When multiple rules target the same manual media server collection, each Maintainerr collection now keeps its own rule-owned membership while still showing genuinely shared manual items.
Root cause
The old model stored a single
isManualflag perCollectionMediarow. During media server sync, items discovered in a shared server collection but not tracked locally were imported as manual, even when they actually belonged to another rule targeting the same media server collection. That erased provenance and caused unrelated items to appear permanently pinned as manual.What this changes
isManualflag with two independent fields:includedByRulemanualMembershipSource(legacy,local,shared)rule,manual,all) so rule execution and media server sync only clear the intended membership.Backward compatibility
isManualremains a derived field via entity hooks, so existing read paths continue to behave correctly while the new provenance fields drive collection membership behavior. The migration backfillsincludedByRuleandmanualMembershipSourcefrom existing rows and remains reversible.Test Instructions
Test 1
Test:
Create two Maintainerr rule groups that both target the same manual Plex or Jellyfin collection, then add media that only matches rule A.
Expected:
The item appears in rule A's Maintainerr collection only. It must not appear in rule B's Maintainerr collection as a manual item.
Old:
The item could bleed into rule B's Maintainerr collection and appear there as manual, even though it was only added by rule A.
Test 2
Test:
Add media that only matches rule B in the same shared manual collection setup.
Expected:
The inverse of test 1. The item appears in rule B's Maintainerr collection only and does not show up in rule A as manual.
Old:
The same cross-rule bleed could happen in the opposite direction, making rule-owned items look manually pinned in the sibling collection.
Test 3
Test:
Manually add an item directly in the media server collection shared by both Maintainerr collections.
Expected:
The item appears in both linked Maintainerr collections as manual/shared membership.
Old:
Manual and rule-owned provenance were not separated cleanly, so shared items and sibling rule-owned items could be conflated.
Test 4
Test:
Remove a rule match from an item that also has manual membership.
Expected:
The item remains in the collection because the manual membership still exists.
Old:
Removing the rule match could remove the entire row and lose the surviving manual membership.
Test 5
Test:
Remove a manually added item from the media server collection when that item is still rule-owned in Maintainerr.
Expected:
The manual membership is removed, but the item stays in the Maintainerr collection because the rule membership still exists.
Old:
The removal handling could treat the item as fully removed or otherwise corrupt the remaining membership state.
Test 6
Test:
Add an exclusion in one linked collection for an item present in the shared media server collection.
Expected:
That item is not re-imported into the excluded collection as shared manual membership.
Old:
Shared/manual reconciliation could re-import items too broadly and ignore the intended per-collection exclusion boundary.
Test 7
Test:
Run rule execution again after add/remove operations in a shared manual collection.
Expected:
Recently removed items are not resurrected, and recently added manual items are not dropped because of stale child enumeration from the media server.
Old:
Stale collection children could cause just-removed items to come back or just-added manual items to be cleared incorrectly.