Skip to content

feat(rbac): a $memberOf match admits by the caller's membership records - #4741

Merged
rubenvdlinde merged 6 commits into
developmentfrom
feature/member-of-match
Oct 21, 2026
Merged

rubenvdlinde merged 6 commits into
developmentfrom
feature/member-of-match

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Part 2 of 3 for spec #4739. Stacked on the resolver PR (contains its commits); merge that first.

ConditionMatcher::resolveDynamicValue() hands an operator object holding $memberOf to the resolver. Both SQL list paths (QueryBuilder and raw SQL) and the PHP verdict resolve through it, so list, count, single read, property rules and deny rules read one set. No resolver injected: unresolvable, deny. Two token comparisons became in_array() to stay under PHPMD's class complexity limit.

Tests: ConditionMatcherMemberOfTest (single-object verdict) and MagicRbacMemberOfListTest, which runs the real list WHERE conditions against an SQLite table of three administrations: another administration's rows are excluded, COUNT(*) is exact, LIMIT/OFFSET pages add up, a bookkeeper without memberships gets 0, nine verdicts plus a list read the membership rows once, and the QueryBuilder path emits in(t.administration_id, [adm-1, adm-2]). Both fail without the wiring.

Gates on the last branch (feature/member-of-docs, 8a964bd), one composer check:strict run: lint, check:migration-version, phpcs, phpmd, psalm, phpstan all green. PHPUnit: 26,768 tests, 15 errors, all inherited (AuditTrail*/DraftRemovalAuditRow tests need OC\DB\Schema\Table, absent without a Nextcloud core; none touch this change).

AI disclosure: written with Claude Code (claude-opus-5-5).

🤖 Generated with Claude Code

…er request

Reads the caller's rows of a membership schema without RBAC, filters them by
static where conditions and an optional validity window, and returns the
values of the named property. A malformed operand is unresolvable; a failed
read is the empty set. Both deny.

Assisted-by: ClaudeCode:claude-opus-5-5
… it cannot resolve

Assisted-by: ClaudeCode:claude-opus-5-5
Keeps the operator logic in the resolver so ConditionMatcher only delegates,
and splits the operand checks to stay under the class complexity limit.

Assisted-by: ClaudeCode:claude-opus-5-5
…t and pages

The list test runs the WHERE conditions a list builds, over the real
MagicRbacHandler, ConditionMatcher and MemberOfResolver, against an SQLite
table of three administrations: another administration's rows are excluded,
COUNT(*) is exact and the LIMIT/OFFSET pages add up to the list.

Assisted-by: ClaudeCode:claude-opus-5-5
ConditionMatcher::resolveDynamicValue() hands an operator object holding
$memberOf to MemberOfResolver, which returns it with $in over the caller's
set. Both SQL list paths and the PHP verdict resolve through here, so they
read the same set. Without a resolver the property is unresolvable and denies.

Two token comparisons become in_array() to keep the class under the PHPMD
complexity limit.

Assisted-by: ClaudeCode:claude-opus-5-5
@rubenvdlinde
rubenvdlinde merged commit afe6bbe into development Oct 21, 2026
38 of 40 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ 5ae37e4

Check PHP Vue Security License Tests
lint ✅
phpcs ✅
phpmd ✅
psalm ✅
phpstan ✅
phpmetrics ✅
eslint ✅
stylelint ✅
build ✅
check-specs ✅
test-l10n ✅
test-l10n-parity ✅
format ✅
check-schema-l10n ✅
composer ✅ ✅ 173/173
npm ✅ ✅ 648/648
app:check-code ⏭️
info.xml ✅
REUSE ✅
lockfile sync ✅
PHPUnit ❌
Newman ❌
Playwright ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it locally with npx playwright test, or from the Actions tab on a branch with no open pull request into development.
Hydra gates ❌

Quality workflow — 2026-10-21 12:13 UTC

Download the full PDF report from the workflow artifacts.

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.

1 participant