Skip to content

fix(permissions): stop wildcards from granting negative permissions#13

Draft
hbrombeer wants to merge 1 commit into
mainfrom
fix/negative-permissions-not-granted-by-wildcards
Draft

fix(permissions): stop wildcards from granting negative permissions#13
hbrombeer wants to merge 1 commit into
mainfrom
fix/negative-permissions-not-granted-by-wildcards

Conversation

@hbrombeer

Copy link
Copy Markdown
Member

The bug

/msg answered "Du bist gemutet." for every admin, and their global chat was dropped silently.

Ground truth from the dev cluster:

role admin        -> ALLOW  *  (GLOBAL)
catalog           -> grounds.chat.muted   (plugin-chat)
PermissionPattern -> pattern == "*" -> true

grounds.chat.muted is an inverted permission: holding it takes chat away. ALLOW * means "give this player everything" — and the matcher dutifully handed them the mute too. Every admin was muted by their own admin role.

It is not specific to chat. Any negative permission anyone adds to the catalog gets handed to every wildcard holder on the next snapshot.

The fix

A manifest entry can declare negative: true. A negative permission is then only ever matched by an exact grant — never by * or foo.*. Muting still works, it just has to be done by name.

The decision is made here, not in service-permissions: the service only serves snapshots of patterns, and nothing server-side calls PolicyEngine.hasPermission in production. Every real check runs in this plugin, in the JVM that loaded the manifests — which makes those manifests the complete authority on what is negative.

Follow-up (not in this PR)

  • service-permissions carries a second copy of the same matcher (PolicyEngine/PermissionPattern). It has no production caller today, but it would reintroduce this bug the day it gets one.
  • The catalog table has no negative column, so the Portal permission panel cannot warn that ticking grounds.chat.muted mutes somebody.

Verified

  • New regression tests: * and grounds.chat.* no longer grant grounds.chat.muted while still granting grounds.chat.staff; an exact grant still mutes; DENY still beats an exact grant.
  • ./gradlew build green.

Needs plugin-chat to mark the key negative (separate PR) before it changes anything at runtime.

A permission whose meaning is inverted — holding it takes something away —
was matched by `*` like any other. The admin role holds `ALLOW *`, so every
admin also held `grounds.chat.muted` and was silently muted: /msg answered
"Du bist gemutet." and their global chat was dropped without a word.

A manifest entry can now declare `negative: true`. Negative permissions are
only ever matched by an exact grant, never by `*` or `foo.*`, so a wildcard
keeps meaning "give this player everything" instead of also meaning "mute
them". Muting still works — by name.

The loaded plugins' own manifests are the authority: only they can be asked
about a permission in this JVM, so the checker is built from the collected
manifests before it answers its first question.
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