Skip to content

feat(example-sets): a fragment may put parties on its objects - #4766

Merged
rubenvdlinde merged 4 commits into
developmentfrom
feat/example-set-parties
Oct 22, 2026
Merged

rubenvdlinde merged 4 commits into
developmentfrom
feat/example-set-parties

Conversation

@rubenvdlinde

@rubenvdlinde rubenvdlinde commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

What

A new example-set part, parties. Each row gives one party a role on one of the set's objects: {objectUuid, partyUuid, role, validFrom?, validUntil?, note?, primary?}.

  • It is linked through a new trusted path, PartyRoleService::importParty, which records the fragment's app as the linker.
  • The link is recorded, proved on a later install and unlinked on remove.
  • The check refuses an unknown field, a row without an object, party or role, and a date that is not a date.

PartyLinkWriter::write takes an optional linkedBy, used only when nobody is signed in. The signed-in user always wins. The API path (addParty) never passes it, so a request cannot name its own linker.

Why

dossiq's DqZaakBetrokkenen board draws the parties on a Woo case: a representative with a mandate until 31 December, a reporter without an account with an indicator, and a primary requester. Party links live in the party model, not in a register, and the only write path needed a signed-in user, which occ does not have.

Confidentiality needed no new field. The party model already carries secrecy as an indicator with the effect refuse-publication; see the openspec change.

Verified

  • New tests: ExampleSetPartiesTest (a link written, kept, unlinked; a refused party dropped; 6 refusal cases) and PartyLinkWriterTest (named linker, signed-in user wins, 401 when neither is there).
  • PartyRoleServiceTest covers importParty against addParty.
  • The ExampleSet and Party suites pass: 210 tests.
  • phpmd (both rule sets) is clean on lib/Service/ExampleSet and lib/Service/Party. phpstan is clean, and phpcs is clean on the changed files.
  • composer check:strict (local, on the commit before b35f701):
    • phpcs found one line over 150 characters in ExampleSetEngineKinds, wrapped in b35f701.
    • lint, phpmd, psalm and phpstan are clean.
    • test:all fails only on the inherited AuditTrail* and DraftRemoval sqlite errors (they need a Nextcloud root) and on RecentLensLookupCallSitesTest, as on development.

Who can name the linker

linkedBy only matters when nobody is signed in, and only one path passes it. I checked every caller on this branch:

  • PartyLinkWriter::write has exactly one caller: PartyRoleService::linkParty. PartyLinkWriter is injected nowhere else (grep -rn "PartyLinkWriter" lib).
  • linkParty is private. It is reached from:
    • addParty, which always passes linkedBy: null;
    • importParty.
  • addParty is the API path. It is called by PartyController::addParty (lib/Controller/PartyController.php:124) and by PartyRoleService::replacePrimaryParty. Neither can pass a linker, and a linkedBy key in the request payload is not read.
  • importParty has one caller: ExampleSetParties::write (lib/Service/ExampleSet/ExampleSetParties.php:132). That runs only from occ openregister:example-set:install.
  • The writer takes $this->session->getUser()?->getUID() first, so even on the trusted path a signed-in user is recorded rather than the named one.

Tests that prove it:

  • PartyRoleServiceTest::testImportNamesTheLinkerAndAddDoesNot sends 'linkedBy' => 'spoofed' in an addParty payload and asserts the writer received null.
  • PartyLinkWriterTest::testTheSignedInUserWins checks a signed-in user beats the named linker.
  • PartyLinkWriterTest::testNoLinkerIsRefused checks a 401 when neither is there.

Merge order

This one is independent. dossiq feat/woo-role-types-and-party-schemas and the portaliq party data that follows need it.

AI-assisted: written with Claude Code (claude-opus-5-5) and reviewed before submission.

…y its confidentiality

Assisted-by: ClaudeCode:claude-opus-5-5
…dy has

Assisted-by: ClaudeCode:claude-opus-5-5
Party links live in the party model, not in a register, and the only write
path needed a signed-in user, which occ does not have. A fragment's
parties rows are now checked, linked through PartyRoleService::importParty
with the fragment's app as the linker, proved and unlinked on remove.
The API path still records only the signed-in user.

Assisted-by: ClaudeCode:claude-opus-5-5
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ 0039973

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-22 06:20 UTC

Download the full PDF report from the workflow artifacts.

Assisted-by: ClaudeCode:claude-opus-5-5
@rubenvdlinde
rubenvdlinde merged commit 66d3f79 into development Oct 22, 2026
35 of 39 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ 9a805c0

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-22 14:38 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