Repository navigation
Migration workflow: add research types to CERN_SCIENTIFIC_COMMUNITY #542
Description
Activity
8 remaining items
Context
Analyze what it would need to override on CDS the permission so that each record submission or inclusion request can be read only from the community that was the receiver of the request even though the record could belong to multiple ones i.e one community cannot see the requests of another one if a record belongs to both.
Claude plan to be heavily reviewed
Plan: Restrict Community Request Visibility to Receiver Community
Problem
When a record belongs to multiple communities, curators of all those communities
can read each other's community inclusion/submission requests for that record.Root cause trace
RequestPermissionPolicy.can_readincludesTopic()for submitted/accepted/etc. requests.Topic.needs()callsrequest.type.entity_needs(entity)whenresolve_topic_needs = True.- Both
CommunityInclusionandCommunitySubmissionhaveresolve_topic_needs = True. entity_needs()callsentity.get_needs(ctx=needs_context)on the record entity.- The record entity resolver evaluates
can_previewfromCDSRDMRecordPermissionPolicy:can_preview → can_curate → can_manage → RecordCommunitiesAction("curate") RecordCommunitiesAction("curate")emitsCommunityRoleNeed(community_id, role)for
every community the record already belongs to — not just the receiver community.
The
Receiver()generator incan_readalready grants the correct target community access.
The receiver is not the problem. The leak isRecordCommunitiesAction("curate")firing for
unrelated communities viaTopic().Note:
community_rolesinneeds_contextis only consumed by community entity resolvers
(subcommunity requests), not by the record entity resolver — so it's irrelevant here.
What we want
Who Should see request? Record owner ✅ yes Explicit collaborators (AccessGrant, SecretLinks) ✅ yes Target community curators (the receiver) ✅ yes Committee referees (CommitteeRefereeVersionGrant) ✅ yes Curators of OTHER communities the record is in ❌ no
Solution: narrow
record_permissionused for topic resolutionKeep
resolve_topic_needs = True(we still want explicit collaborators to have access).
Add a custom permission actioncan_preview_requeststhat is identical tocan_preview
but withoutRecordCommunitiesAction("curate").
Step 1 — Add
can_preview_requeststoCDSRDMRecordPermissionPolicyFile:
site/cds_rdm/permissions.pyAdd to imports:
from invenio_rdm_records.services.generators import ( AccessGrant, RecordOwners, RequestReviewers, SecretLinks, SubmissionReviewer, )
Add to
CDSRDMRecordPermissionPolicy:# Like can_preview but without RecordCommunitiesAction("curate"). # Used as the topic-resolution permission for community inclusion/submission # requests so that explicit record collaborators can see the request, # but curators of unrelated communities cannot. can_preview_requests = [ RecordOwners(), AccessGrant("manage"), AccessGrant("edit"), SecretLinks("edit"), AccessGrant("preview"), SecretLinks("preview"), SubmissionReviewer(), # current review's receiver community (safe: returns [] for inclusion requests) RequestReviewers(), # assigned request reviewers (gated on REQUESTS_REVIEWERS_ENABLED) UserManager, SystemProcess(), CommitteeRefereeVersionGrant(), # CDS-specific: committee referees ]
Step 2 — CDS request-type subclasses
File:
site/cds_rdm/requests/community_requests.py(new file)from invenio_rdm_records.checks import requests as checks_requests class CDSCommunityInclusion(checks_requests.CommunityInclusion): """CommunityInclusion with narrowed topic-resolution permission. Prevents curators of unrelated communities from reading inclusion requests for records they happen to share a community with. """ needs_context = { "community_roles": ["owner", "manager", "curator"], # for community topics (unused here) "record_permission": "preview_requests", # replaces "preview" } class CDSCommunitySubmission(checks_requests.CommunitySubmission): """CommunitySubmission with narrowed topic-resolution permission.""" needs_context = { "community_roles": ["owner", "manager", "curator"], "record_permission": "preview_requests", }
Export from
site/cds_rdm/requests/__init__.pyif needed.
Step 3 — Wire up in
invenio.cfgReplace the existing two lines:
# Before: RDM_COMMUNITY_SUBMISSION_REQUEST_CLS = checks_requests.CommunitySubmission RDM_COMMUNITY_INCLUSION_REQUEST_CLS = checks_requests.CommunityInclusion # After: from cds_rdm.requests.community_requests import ( CDSCommunityInclusion, CDSCommunitySubmission, ) RDM_COMMUNITY_SUBMISSION_REQUEST_CLS = CDSCommunitySubmission RDM_COMMUNITY_INCLUSION_REQUEST_CLS = CDSCommunityInclusion
Files changed
File Change site/cds_rdm/permissions.pyAdd can_preview_requeststoCDSRDMRecordPermissionPolicysite/cds_rdm/requests/community_requests.pyNew file: two subclasses invenio.cfgSwap config vars to CDS subclasses No changes needed to
CDSRequestsPermissionPolicy,can_read, orguest_token.
Why
SubmissionReviewer()is safe incan_preview_requestsSubmissionReviewer.needs()readsrecord.parent.review— the active review request on the record:- For inclusion requests: the record is published,
reviewisNone→ returns[]. - For submission requests:
reviewpoints to the submission request whose receiver is
the target community — the same community already covered byReceiver().
So it adds no unintended access.
When migrating public (only public) research records (meaning resource type preprint, article etc - please align on the full list of resource types) we need to include them automatically in CERN_SCIENTIFIC_COMMUNITY (in config) - CERN Research community to ensure the curation rights are given to SIS team.
Implement this as part of global workflow (for all collections, this should be based on resource type)