Repository navigation
fix(access): the members of a case's assigned group read it, up to vertrouwelijk (REVIEW: access, personal data) - #5136
Open
rubenvdlinde wants to merge 4 commits into
Open
rubenvdlinde wants to merge 4 commits into
rubenvdlinde wants to merge 4 commits into
Conversation
Ruben decided that the members of a case's assigned group may read that case, and only read it. OpenRegister keys the case matrix on assignedGroup and asks dossiq for rows; each group of the signed-in user now becomes one read row for the cases assigned to that group. The active organisation still scopes which cases a reader reaches. The rows dossiq hands OpenRegister now name dossiq as the app answering. OpenRegister keeps only rows from the app that owns the provider id, so every case type rights row was being dropped. Assisted-by: ClaudeCode:claude-opus-5-5
A case marked confidentieel, geheim or zeer geheim, or with a missing or unknown level, needs its behandelaar or explicit rights (Ruben, 3 Nov). Assisted-by: ClaudeCode:claude-opus-5-5
rubenvdlinde
requested review from
WilcoLouwerse,
bbrands02 and
rjzondervan
as code owners
November 3, 2026 06:50
Contributor
Quality Report — ConductionNL/dossiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ❌ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue3-compile | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ❌ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-debt-ratchet | ❌ | ||||
| check-types-e2e | ✅ | ||||
| composer | ✅ | ✅ 109/109 | |||
| npm | ✅ | ✅ 657/657 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| lockfile sync | ✅ | ||||
| PHPUnit | ✅ 10436/10436 · 14 skipped | ||||
| 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-11-03 07:28 UTC
Download the full PDF report from the workflow artifacts.
…hat the assigned group reads, and the harness carries the team rules - A rights row that names delete grants the rest of its row: deleting a case stays with administrators (REQ-ACC-10). - REQ-ACC-10 now states Ruben's decision of 3 November: the assigned group reads its cases, read only, up to vertrouwelijk, in the case's own organisation, and the rights matrix is honoured. - The access harness now loads the case schema with the handling team rules the projector writes, which switch off OpenRegister's organisation filter for a caller they qualify. Its cross-organisation assertions fail until OpenRegister keeps that filter. Assisted-by: ClaudeCode:claude-opus-5-5
Assisted-by: ClaudeCode:claude-opus-5-5
Contributor
Quality Report — ConductionNL/dossiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ❌ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue3-compile | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ❌ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-debt-ratchet | ❌ | ||||
| check-types-e2e | ✅ | ||||
| composer | ✅ | ✅ 109/109 | |||
| npm | ✅ | ✅ 657/657 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| lockfile sync | ✅ | ||||
| PHPUnit | ❌ 10456/10457 · 16 skipped | ||||
| 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-11-03 08:45 UTC
Download the full PDF report from the workflow artifacts.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this does
Ruben decided (3 November) that the members of a case's assigned group may read that case. It is read only: no edit, no move, no status change. It applies only within the case's own active organisation, and only up to and including the confidentiality level
vertrouwelijk.How it is expressed
The case schema's
authorization.matrixis keyed onassignedGroup, withrowsFrom: dossiq.case-type-rights. OpenRegister asks dossiq for rows throughMatrixRowsRequestedEvent, andCaseTypeRightsRowsListeneranswers.The new
AssignedGroupReadRowsadds one row per group of the signed-in user:{"group": "<G>", "values": ["<G>"], "where": {"confidentiality": {"$in": ["openbaar", "beperkt_openbaar", "intern", "zaakvertrouwelijk", "vertrouwelijk"]}}, "actions": ["read"]}A member of G reads the cases assigned to G. The levels come from
CaseTypeRightsMatrixRows::LEVELS, the ZGW ordering already in dossiq.authenticated,publicoradmin(MatrixRowsFromApps::RESERVED_GROUPS).CaseRightsRowSources), so its constructor stays at four parameters.Finding: on development, case-type rights grant nothing
CaseTypeRightsRowsListenercalledaddRows()without anappId. OpenRegister keeps only the rows answered by the app that owns the provider id (dossiq), so every case-type rights row was dropped on development.The effect was that the case-type rights matrix granted nothing at all. That fails closed, but no access was granted through rights rows anywhere. The real-OpenRegister harness
CaseTypeRightsEnforcedAccessTestfails on development because of this; it is green with this PR.The listener now passes
appId: Application::APP_IDfor both kinds of row. This change is a widening of access compared with what development does today, back to what case-type rights were meant to grant. Review it with that in mind.Why REVIEW
It widens read access to cases, which is personal data, and it restores the case-type rights matrix.
Evidence
Real OpenRegister harness.
CaseTypeRightsEnforcedAccessTestruns OpenRegister's own PermissionHandler (single object) and MagicSearchHandler/MagicRbacHandler (SQL list), over the shipped case schema. All 11 tests are green. Before the change, the new cases fail and the existing ones fail too, because of the appId bug.The new cases cover:
update,delete,create,readFiles,addFilesordeleteFiles. A move is an update, so that is refused too.vertrouwelijkis readable.confidentieel, no level, and an unknown level are not.Existing expectations that change:
anna(team-vergunningen) now also reads c-5, through her team. She still does not read c-4, which isgeheim.dirk(team-toezicht) also reads c-3 and c-7.Caveats:
Other checks:
AssignedGroupReadRowsTestcovers the row shape, reserved and blank groups, and no signed-in user.values: ['$self']instead of[G]survives the harness, because it is equivalent for reads, and is killed by the unit test.Rework after RW78
_organisation(MagicRbacHandler::hasConditionalRulesBypassingMultitenancy). The projected handling team rules are such rules, so for a team member the assigned-group rows also read across organisations, on the list and on a single read._organisationcondition on the rows themselves is not possible today. OpenRegister refuses a matrix row whosewherenames a non-property (matrix.where-unknown-field) and drops the row whole. The case schema has no organisation property to name instead.deleteis out of the case edit verbs, so a rights row that names it grants the rest of its row and not case deletion (REQ-ACC-10, "delete stays with administrators"). No shipped row names it; this makes the rule hold in code, not by luck. A new test checks that a row naming delete gives update and no delete.Assisted-by: ClaudeCode:claude-opus-5-5. This PR was prepared with AI assistance; a person reviews it before merge.