Repository navigation
refactor(tenant): route project scope through models.ProjectScopeFilter - #25
Merged
Merged
Conversation
The module carried two project predicates that disagreed. `projectScope` was a strict equality on `projectId`; `DefaultCompatibleProjectScope`, twenty lines below it, was an independent re-implementation of the shared rule that also matches unstamped documents when the selected project is the organisation's default. The strict one is the one `ScopeWithProject` wired in, and it is the trap: a caller who resolves the hidden default project and reaches for the obvious combined helper silently excludes every document written before the project field existed. There is no error to notice — a predicate that stops matching returns zero documents. `models.ProjectScopeFilter` (v1.7.19) is now the single definition, and it is the one the ingest writer's stamping is paired with, so reader and writer can no longer drift apart across module boundaries. Delete the strict variant, point `ScopeWithProject` at the shared predicate, and reduce `DefaultCompatibleProjectScope` to a deprecated adapter that only exists to take the organisation as an ObjectID. Two consequences worth stating: the tolerance stays conditional on the default project, because relaxing it unconditionally reads identically today and becomes a cross-project leak the day a second project exists; and a non-hex organisation id now drops the project axis entirely rather than narrowing strictly, leaving the read bounded by ownership alone. Bumps models v1.7.16 -> v1.7.20. No caller in any module referenced either predicate, so nothing downstream changes shape today.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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
This change routes project scoping through
models.ProjectScopeFilterso the project-selection rules are defined in exactly one place and shared consistently between readers and writers.The main motivation is to prevent subtle tenant data visibility regressions during the project rollout. A strict equality check on the default project silently excludes historical documents that were created before
projectIdexisted, causing valid organisation data to disappear from queries without producing any error. By delegating to the shared filter logic, reads now correctly tolerate unstamped documents only for the organisation’s default project, while still enforcing strict isolation for all other projects.This also improves long-term safety and maintainability by removing duplicated scoping logic from the database layer. The ingest path and query path now depend on the same predicate semantics, reducing the risk of drift, inconsistent access rules, or future cross-project leakage bugs.
The accompanying test updates strengthen coverage around: