Skip to content

[FC-0118] docs: add ADR for introducing a row-level security layer#38354

Open
Abdul-Muqadim-Arbisoft wants to merge 1 commit intoopenedx:docs/ADRs-axim_api_improvementsfrom
edly-io:docs/ADR-introduce-row-level-security-layer
Open

[FC-0118] docs: add ADR for introducing a row-level security layer#38354
Abdul-Muqadim-Arbisoft wants to merge 1 commit intoopenedx:docs/ADRs-axim_api_improvementsfrom
edly-io:docs/ADR-introduce-row-level-security-layer

Conversation

@Abdul-Muqadim-Arbisoft
Copy link
Copy Markdown
Contributor

Adds ADR proposing a reusable row-level security layer to standardize how Open edX list endpoints handle record visibility, replacing the current ad-hoc pattern of inline has_access checks mixed with endpoint guards and user-driven filtering.
Currently, ~150 has_access call sites and helpers like has_studio_read_access(), has_course_author_access(), and get_course_with_access() are applied inline across views in contentstore, enrollments, discussion, and course blocks APIs, tangling three distinct concerns into single blocks of view logic. This makes access behavior inconsistent across endpoints, difficult to audit, and hard to test in isolation. This ADR documents the decision to separate every list endpoint into three layers, endpoint access via DRF permission classes, record visibility via RLS-scoped querysets in get_queryset(), and user-driven filtering via django-filter, backed by a shared RLSQuerysetMixin and pluggable RLSPolicy interface. The rollout targets high-impact ORM-backed endpoints first (course listing, enrollment, certificates) with in-memory filtering fallback for modulestore-backed endpoints like Course Blocks. This ADR is complementary to the existing bridgekeeper ADR (0003) , it defines the architectural pattern that any permission engine plugs into, rather than prescribing a specific engine.
issue:#38282

Introduce an architectural decision record that standardizes how list

endpoints separate three concerns: endpoint access (DRF permission

classes), record visibility (RLS queryset scoping), and user-driven

filtering (django-filter).

This complements the existing bridgekeeper ADR (0003) by defining the

view-layer pattern that any permission engine plugs into, rather than

prescribing a specific engine.

Includes code examples using CourseOverview, a reusable RLSQuerysetMixin,

and a rollout plan targeting course listing, enrollment, and certificate

endpoints first.
Copy link
Copy Markdown
Contributor

@bradenmacdonald bradenmacdonald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be an update to OEP-66 instead of an ADR?

How does this integrate with Casbin?

When the user requests a single object from a GET endpoint, does this still use a filter that could involve complicated/slow logic to construct, or does it just query the permissions of that one single object? i.e. is getting a single object more like "list all the courses the user is allowed to see and then select one" or is it like "check if the user is allowed to see course X".

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