Skip to content

Release 2026.2.7.2 - #858

Merged
bencap merged 5 commits into
mainfrom
release-2026.2.7.2
Aug 22, 2026
Merged

Release 2026.2.7.2#858
bencap merged 5 commits into
mainfrom
release-2026.2.7.2

Conversation

@bencap

@bencap bencap commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

Features

NA

Bug Fixes

  • Various fixes to data set privacy, permissions, and security across the application

Maintenance

NA

bencap added 5 commits August 21, 2026 16:43
fetch_score_set_by_urn's owner_or_contributor filter led with ScoreSet.private.is_(False), which
only_published already guarantees. The two arguments constrained the same column and the looser
subsumed the stricter, so passing user_data narrowed nothing: the call collapsed to an Action.READ
check on a published score set, which every caller passes. Any authenticated user could record their
own score set as the successor to any published one, and because replaces_id is unique, the first
claim permanently blocked the real owner from superseding their own work.

Drop the public-visibility disjunct so the argument means what its name and the docstring say. The
other three call sites pass None and are unaffected.

Supersession still has no Action of its own, so the authorization remains the shape of the query
rather than a permission handler; the call site now says so. Contributors are admitted alongside
owners, matching the documented rule -- broader than _handle_publish_action, which is owner-only, and
worth settling when Action.SUPERSEDE lands.
…arch

/experiments/search has no auth dependency, and build_search_experiments_query_filter narrows by
owner or contributor rather than by visibility -- the router passes None. Unlike /score-sets/search
it never constrained published, which defaults to None and applies no filter at all, so an empty
request body returned every unpublished experiment in the database, with its title, abstract, method
text and owner ORCID iD.

Force published to true and reject an explicit false, mirroring the score set endpoint. Unpublished
experiments stay reachable through /me/experiments/search, which is unchanged. The UI only ever
called that route, so no client change is required.

Three tests asserted the old behaviour, one of them checking that another user's given name came
back. The replacements assert against one published and one unpublished experiment matching the same
search text, so they fail whether the filter is missing or too aggressive.
…rch results

enrich_experiment_with_num_score_sets is what filters a nested experiment's score_set_urns by
permission, and /score-sets/search ran it only when the request left
includeExperimentScoreSetUrnsAndCount unset or true. Sent false, the ORM experiment reached
SavedExperiment.generate_score_set_urn_list directly, which lists every score set on the experiment,
disclosing the tmp URNs of private ones and their count. SearchView sends false, so this was the
served behaviour of the main search page rather than an opt-in path.

Remove the field rather than defaulting it safe: the response cannot be correct with the filter off,
so it should not be expressible. The view models do not forbid extra fields, so a client still
sending it is unaffected.

The enrichment is now unconditional on that route, which costs it roughly 1.3ms per result, or about
130ms at the 100-result limit SearchView requests. Building ShortScoreSet rather than ScoreSet in the
loop recovers most of that, since the response model narrows to ShortScoreSet anyway; held back as a
separate change.
…tings

/target-genes/names and /target-genes/categories are unauthenticated and aggregate the whole
target_genes table with no join to scoresets, so they disclosed the gene symbols and categories under
assay in unpublished work. Neither route names an entity to assert a permission on, and both sibling
routes in the module already filter.

Join the parent score set and require a published date -- the same predicate the statistics routes
use through _join_model_and_filter_unpublished. Keeping these two on that shape means the RLS work
retires them together rather than one at a time.
@coveralls

coveralls commented Aug 22, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 32538749194

Coverage increased (+0.02%) to 88.962%

Details

  • Coverage increased (+0.02%) from the base build.
  • Patch coverage: 14 of 14 lines across 4 files are fully covered (100%).
  • 5 coverage regressions across 1 file.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

5 previously-covered lines in 1 file lost coverage.

File Lines Losing Coverage Coverage
src/mavedb/lib/utils.py 5 62.5%

Coverage Stats

Coverage Status
Relevant Lines: 15555
Covered Lines: 13838
Line Coverage: 88.96%
Coverage Strength: 0.89 hits per line

💛 - Coveralls

@bencap
bencap merged commit 5609911 into main Aug 22, 2026
14 of 15 checks passed
@bencap
bencap deleted the release-2026.2.7.2 branch August 22, 2026 02:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants