Skip to main content

Module clp

Module clp 

Source
Expand description

Class-level permission enforcement.

CLP evaluation is two stages, not one. Stage one, validate_permission, is a gate that throws. Stage two, apply_pointer_permissions, is a filter that narrows the query. Passing the gate is not authorization to read anything: {find: {requiresAuthentication: true, pointerFields: ['owner']}} passes the gate for any logged-in user and is still restricted to that user’s own rows by stage two. Conflating them, or treating stage two as optional extra narrowing, is a data-exposure bug rather than a missing feature.

Two more shapes here are load bearing:

  • CLP is default-open. An absent operation entry means unrestricted. That lives in parse_rust_core::clp, where op() returns Option<&OpPerm> and OpPerm has no Default. test_permissions is the only place that reads the rule, and both stages call it.
  • Deny-all cannot be spelled None. PointerPermOutcome has three variants and is #[must_use], because upstream signals deny-all by returning undefined from a function that otherwise returns a query (DatabaseController.js:1770-1772), and an Option<Query> reproduces that hazard exactly: None reads as “nothing to add”.

Every denial in this module is one of upstream’s createSanitizedError call sites, so each one goes through ParseError::permission_denied and the client sees Permission denied at the default. The detailed strings are still exact, because they are what the wire carries when enableSanitizedErrorResponse is off, and they are what the log carries either way.

Master and maintenance never reach any of this. Every upstream call site is guarded by isMaster ? Promise.resolve() : ... (DatabaseController.js:575-578, :849-852, :935-938, :1471-1474), and here the guard is the caller matching on crate::AclScope::Unrestricted.

Structs§

PermissionOptions
Options that change what a permission check decides, and what it says when it denies.
ProtectedFieldPlan
The fields to strip from a result, plus the rules that can only be evaluated against a row.

Enums§

PointerPermOutcome
Stage two’s three outcomes. #[must_use], and every caller matches all three.
WriteAction
Which write a permission check belongs to.

Functions§

adds_field
canAddField (DatabaseController.js:970-998): does this write introduce a field the schema does not have?
apply_pointer_permissions
Stage two: the query filter. addPointerPermissions (DatabaseController.js:1731-1819).
deny_protected_fields
denyProtectedFields (RestQuery.js:928-984).
filter_sensitive_data
filterSensitiveData (DatabaseController.js:192-303), applied to one row in upstream’s order.
plan_protected_fields
addProtectedFields (DatabaseController.js:1821-1925).
test_permissions
testPermissions (SchemaController.js:1365-1382).
validate_permission
Stage one: the gate. validatePermission (SchemaController.js:1385-1459).