Skip to content

Release: merge development into beta - #90

Open
github-actions[bot] wants to merge 142 commits into
betafrom
development
Open

Release: merge development into beta#90
github-actions[bot] wants to merge 142 commits into
betafrom
development

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Automated PR to sync development changes to beta for beta release.

Merging this PR will trigger the beta release workflow.

Reminder: Add a major, minor, or patch label to this PR to control the version bump. Default is patch.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/larpingapp
Commit e341203
Branch 90/merge
Event pull_request
Generated 2026-03-19 18:55 UTC
Workflow Run https://github.com/ConductionNL/larpingapp/actions/runs/23311646375

Summary

Group Result
PHP Quality PASS
Vue Quality PASS
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs PASS
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint PASS

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (94 total)

Metric Count
Approved (allowlist) 94
Approved (override) 0
Denied 0

npm dependencies (248 total)

Metric Count
Approved (allowlist) 247
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/larpingapp
Commit 473e6d9
Branch 90/merge
Event pull_request
Generated 2026-03-19 18:58 UTC
Workflow Run https://github.com/ConductionNL/larpingapp/actions/runs/23311789570

Summary

Group Result
PHP Quality PASS
Vue Quality PASS
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs PASS
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint PASS

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (94 total)

Metric Count
Approved (allowlist) 94
Approved (override) 0
Denied 0

npm dependencies (248 total)

Metric Count
Approved (allowlist) 247
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/larpingapp
Commit e047e5b
Branch 90/merge
Event pull_request
Generated 2026-03-19 19:05 UTC
Workflow Run https://github.com/ConductionNL/larpingapp/actions/runs/23312031182

Summary

Group Result
PHP Quality PASS
Vue Quality PASS
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs PASS
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint PASS

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (94 total)

Metric Count
Approved (allowlist) 94
Approved (override) 0
Denied 0

npm dependencies (248 total)

Metric Count
Approved (allowlist) 247
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/larpingapp
Commit f41b40e
Branch 90/merge
Event pull_request
Generated 2026-03-19 19:09 UTC
Workflow Run https://github.com/ConductionNL/larpingapp/actions/runs/23312246198

Summary

Group Result
PHP Quality PASS
Vue Quality PASS
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs PASS
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint PASS

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (94 total)

Metric Count
Approved (allowlist) 94
Approved (override) 0
Denied 0

npm dependencies (248 total)

Metric Count
Approved (allowlist) 247
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/larpingapp
Commit 0644c0a
Branch 90/merge
Event pull_request
Generated 2026-03-19 19:12 UTC
Workflow Run https://github.com/ConductionNL/larpingapp/actions/runs/23312369818

Summary

Group Result
PHP Quality PASS
Vue Quality PASS
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs PASS
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint PASS

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (94 total)

Metric Count
Approved (allowlist) 94
Approved (override) 0
Denied 0

npm dependencies (248 total)

Metric Count
Approved (allowlist) 247
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/larpingapp
Commit 68e5a77
Branch 90/merge
Event pull_request
Generated 2026-03-19 21:37 UTC
Workflow Run https://github.com/ConductionNL/larpingapp/actions/runs/23318051893

Summary

Group Result
PHP Quality PASS
Vue Quality PASS
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs PASS
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint PASS
stylelint PASS

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (94 total)

Metric Count
Approved (allowlist) 94
Approved (override) 0
Denied 0

npm dependencies (248 total)

Metric Count
Approved (allowlist) 247
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/larpingapp
Commit 2aef093
Branch 90/merge
Event pull_request
Generated 2026-03-23 21:38 UTC
Workflow Run https://github.com/ConductionNL/larpingapp/actions/runs/23461376504

Summary

Group Result
PHP Quality PASS
Vue Quality FAIL
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP

PHP Quality

Tool Result
lint PASS
phpcs PASS
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint FAIL
stylelint PASS

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (94 total)

Metric Count
Approved (allowlist) 94
Approved (override) 0
Denied 0

npm dependencies (248 total)

Metric Count
Approved (allowlist) 247
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented Apr 9, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/larpingapp
Commit 3fded4f
Branch 90/merge
Event pull_request
Generated 2026-04-09 09:47 UTC
Workflow Run https://github.com/ConductionNL/larpingapp/actions/runs/24183657526

Summary

Group Result
PHP Quality PASS
Vue Quality FAIL
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP
Playwright SKIP

PHP Quality

Tool Result
lint PASS
phpcs PASS
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint FAIL
stylelint PASS

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (94 total)

Metric Count
Approved (allowlist) 94
Approved (override) 0
Denied 0

npm dependencies (248 total)

Metric Count
Approved (allowlist) 247
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.

E2E Tests (Playwright)

Playwright E2E tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented Apr 9, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report

Repository ConductionNL/larpingapp
Commit f2c3b5d
Branch 90/merge
Event pull_request
Generated 2026-04-09 10:24 UTC
Workflow Run https://github.com/ConductionNL/larpingapp/actions/runs/24184200585

Summary

Group Result
PHP Quality PASS
Vue Quality FAIL
Security PASS
License PASS
PHPUnit SKIP
Newman SKIP
Playwright SKIP

PHP Quality

Tool Result
lint PASS
phpcs PASS
phpmd PASS
psalm PASS
phpstan PASS
phpmetrics PASS

Vue Quality

Tool Result
eslint FAIL
stylelint PASS

Security

Ecosystem Result
composer PASS
npm PASS

License Compliance

Ecosystem Result
composer PASS
npm PASS

composer dependencies (94 total)

Metric Count
Approved (allowlist) 94
Approved (override) 0
Denied 0

npm dependencies (248 total)

Metric Count
Approved (allowlist) 247
Approved (override) 1
Denied 0

PHPUnit Tests

PHPUnit tests were not enabled for this run.

Integration Tests (Newman)

Newman integration tests were not enabled for this run.

E2E Tests (Playwright)

Playwright E2E tests were not enabled for this run.


Generated automatically by the Quality workflow.

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ b546553

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm ✅ 248/248
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-03 15:17 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ c1a4891

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-03 17:46 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ d8ed25b

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-03 18:04 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ 4088ad6

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-07 20:52 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ 12b7df9

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-07 21:24 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ c5aa97a

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-12 21:23 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ 446d4ca

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-12 21:55 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ 7a3fde5

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-12 22:33 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ 2cc636a

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-12 22:41 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ ee6d310

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm ✅ 375/375
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-05-12 23:27 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ f419a22

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm ✅ 375/375
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/10 statements)


Quality workflow — 2026-05-13 04:40 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ df3f275

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm ✅ 376/376
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/10 statements)


Quality workflow — 2026-05-13 04:47 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ 77ae22a

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm ✅ 376/376
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/10 statements)


Quality workflow — 2026-05-13 05:46 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ 9715dd5

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm ✅ 376/376
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/10 statements)


Quality workflow — 2026-05-13 07:50 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ d3fa104

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm ✅ 376/376
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/10 statements)


Quality workflow — 2026-05-13 09:13 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ 3ff1dbf

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm ✅ 376/376
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/10 statements)


Quality workflow — 2026-05-18 18:19 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ 25e72bc

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm ✅ 376/376
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/10 statements)


Quality workflow — 2026-05-18 18:56 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ effa7eb

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm ✅ 376/376
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/10 statements)


Quality workflow — 2026-05-18 19:15 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ fac6d7f

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm ✅ 376/376
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/10 statements)


Quality workflow — 2026-05-18 20:46 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ f1e6e24

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm ✅ 376/376
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/10 statements)


Quality workflow — 2026-05-18 21:00 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/larpingapp @ 339eb74

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 94/94
npm ✅ 376/376
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/10 statements)


Quality workflow — 2026-05-18 21:17 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde and others added 4 commits August 4, 2026 07:30
Pin the exact version (no caret). The 3.0.0 major removes CnFlowCanvas,
CnEditFlowsModal and CnFlowCanvasModal; this app imports none of them.
Peer set is unchanged from 2.1.0-vue3.16, so no new peers are declared.

Verified from the lockfile: @conduction/nextcloud-vue 3.0.0-vue3.4 exact,
vue3-apexcharts 1.8.0 (below the proprietary 1.9.0 line).
Built with USE_LOCAL_LIB=false; built js/ carries CnFlowEditModal and
CnAppNav and none of the three removed symbols.

Co-authored-by: Ruben van der Linde <juan.claude@conduction.nl>
…ed config sharing (#250)

RESCUED FROM CODEBERG. This landed on codeberg.org/Conduction/larpingapp as
4f9f4123 (PR #70, 2026-07-26) and never reached GitHub. Codeberg is being
retired, so it would have been destroyed with the remote.

Part of the 2026-07-26 federated-config-sharing wave, six repos of which
were merged only on Codeberg: decidesk, docudesk, larpingapp, opencatalogi,
softwarecatalog and (already present here) hermiq.

Only the hunk is ported, not the file. GitHub's copy of this register is
NEWER than Codeberg's in other respects — Codeberg still carries
`"icon": "Earth"` for setting where GitHub has `"Globe"` — so taking the
Codeberg file wholesale would have silently reverted unrelated work.

Verified equivalent to the Codeberg blob after the port:

  gh version 1.2.0 | cb version 1.2.0
  gh configuration {'x-openregister-shareable': True} | cb configuration {'x-openregister-shareable': True}
  MATCH
Codeberg is retired; ConductionNL is GitHub-only. GitHub Actions never
executes .forgejo/**, so these workflows contributed zero status checks.

Deleted 3 of 5: pre-merge-check-strict.yaml (covered by
.github/workflows/code-quality.yml) and app-tests-live.yml + tests-live.yml.

KEPT app-tests.yml + tests.yml -- tests.yml carries the only definition of
the l10n extraction gate and the coverage ratchets (no .github/workflows/
l10n.yml here, enable-coverage-guard unset).

Also repointed the .forgejo reference in tests/e2e/visual/README.md.
Enables `quality / E2E Tests (Playwright)`, which reported `skipped` on every run before this — a conclusion indistinguishable from a pass in every summary the pipeline prints.

Measured green: **171 passed / 0 failed / 1 skipped in 8.5 min** (run 30895160734, job 91946606594), 10m53s job wall against a 45 min cap.

Proven able to go red: a negative control on a throwaway branch truncated every `js/*.js` to 0 bytes and ran the suite unchanged — 118 of the 122 specs that reached a verdict failed (#251, job 91930520433). The four survivors were investigated: two are legitimate backend HTTP probes, two were genuinely dead and are fixed here.

Real defects fixed, not hidden:
- `character.ocName` is a required `format: uuid` relation to a `player`; three fixtures passed a display name and got HTTP 400. One of them failed silently and left seventeen character-detail specs asserting against `#/characters/seed-missing`.
- Sidebar nav groups defaulted closed, so none of the eight entity entries existed in the DOM on the dashboard, contradicting `dashboard/spec.md#sidebar-shows-all-entity-views`. Fixed with `"open": true` in the manifest.
- The first-visit walkthrough's full-viewport dim layer intercepted clicks and cost a spec a 60 s timeout; `ci-seed.sh` now marks it seen and verifies the write read back.
- Four assertions that only held while a defect was present (or asserted nothing at all) now assert the thing their scenario names.
- 23 parked `test.fixme` specs un-parked after measuring that they pass.

Filed rather than fixed: #252 (event-data widget renders "Data" instead of its manifest title), #255 (computed character stats are not surfaced anywhere in the UI — the one remaining skip).

Merged with --admin into `development`; the human gate sits between development and beta.
Comment thread .github/workflows/code-quality.yml Fixed
rubenvdlinde and others added 4 commits August 4, 2026 14:12
…quired context never reported (#256)

The org rulesets "Main Branch Protection" and "Beta Branch Protection"
require the status context `branch-protection / check-branch`. GitHub
composes a reusable-workflow context as `<caller-job-id> / <called-job-name>`,
and this caller job was named `protect` — so the check that actually got
emitted was `protect / check-branch` and the required one never appeared.

Every PR to main or beta therefore sat permanently pending on a check that
could not arrive, and only `--admin` could merge. Same defect petstore had
(petstore#20).

larpingapp has both `beta` and `development`, so the branch topology the
shared check-branch job requires (development -> beta, beta|hotfix/* -> main)
is satisfied and making the gate report does not newly block anything.
chore(deps): @conduction/nextcloud-vue 3.0.0-vue3.6
…pping (#261)

A skipped job and a passing job are indistinguishable in the Quality
Report. Every gate turned on here reported 'skipped' in every run.

Each newly-enabled leg was measured against this tree BEFORE being
enabled; the results are in the PR description. Legs that were measured
failing are enabled anyway - the defects are pre-existing, and the only
thing that changed is that CI can now see them.

Journeydoc Capture and enable-axe are deliberately NOT enabled.
Comment thread .github/workflows/code-quality.yml Fixed
rubenvdlinde and others added 10 commits August 5, 2026 15:18
…o its own ruleset (#263)

phpmd.xml declared the rule with a NESTED
    <exclude-pattern>*Migration*</exclude-pattern>
which is INERT. PHPMD 2.15 reads exclude-patterns in
RuleSetFactory::getIgnorePattern(), which walks $xml->children() - only
elements DIRECTLY under <ruleset>. A nested one parses without error and does
nothing, so lib/Migration was always scanned by the rule the pattern was meant
to spare, and both migrations needed an
@SuppressWarnings(PHPMD.UnusedFormalParameter) tag to stay quiet. This file was
inherited byte-identically from nextcloud-app-template
(ConductionNL/.github#155, this repo #262).

Promoting the pattern to the top level of phpmd.xml is not the fix: PDepend
applies a top-level exclude-pattern at file-collection time, so it drops the
file from EVERY rule in the ruleset. Measured on openregister, that shape is
silently swallowing 11 real non-UnusedFormalParameter findings in lib/Migration.

UnusedFormalParameter now lives alone in phpmd-unusedparams.xml with a
TOP-LEVEL */Migration/* exclude-pattern, and the composer script runs both
rulesets as separate legs keeping the worst exit code, so neither leg can
short-circuit the other. The 2 now-redundant suppressions are deleted.

Why lib/Migration is exempt from this one rule: OCP\Migration\IMigrationStep
mandates changeSchema(IOutput $output, Closure $schemaClosure, array $options),
so a step that uses none of the three parameters still cannot drop them.

MEASURED - PHPMD 2.15.0 / PHP 8.4.22, both legs, worst exit code:

  suppression-free true count   23 -> 17
  retired                       6 UnusedFormalParameter, all in lib/Migration
  newly appearing               0
  lib/Migration non-UFP         0 before, 0 after (nothing was swallowed)

  shipped reported count        0 -> 0, exit 0 on both legs

Positive-controlled with probe classes in lib/Migration and lib/Probe: the
Migration probe's UnusedFormalParameter is dropped while its ElseExpression is
still reported by leg 1, and the lib/Probe probe reports from leg 2 - so the
exclusion is real and scoped to the one rule, and leg 2 is not a dead gate
even though it reports nothing on today's tree.

No phpmd.baseline.xml exists in this repo; none was added or removed.
No @SuppressWarnings was added. The 4 UnusedFormalParameter suppressions
outside lib/Migration and the other 19 suppressions in lib/ are untouched.

phpunit -c phpunit-unit.xml: 153 tests / 541 assertions before and after.

Refs #262
…#264)

* refactor(phpmd): burn the true finding count from 17 to 1 and the suppressions from 25 to 1

TRUE PHPMD findings — measured with EVERY @SuppressWarnings stripped on a
throwaway copy, PHPMD 2.15.0 / PHP 8.4.22 inside nextcloud:latest — go
**17 → 1**. Shipped findings stay at 0. There is no phpmd.baseline.xml in this
repo and there must not be: PHPMD AUTO-DISCOVERS that filename, so a baseline
stays active even after the `baseline` CLI flag is removed.

phpmd.xml, phpmd-unusedparams.xml, phpcs.xml and every phpunit config are
BYTE-UNCHANGED. No threshold was raised, no rule removed, no baseline added.

The one surviving finding
-------------------------
`Application::boot(IBootContext $context)` — UnusedFormalParameter. The
signature is mandated by OCP\AppFramework\Bootstrap\IBootstrap and the body is
legitimately empty: register/schema initialisation moved to the
`InitializeRegister` repair step. The parameter can be neither dropped nor used.
This is the floor.

Clean differential as a positive control: TRUE = 1 finding / exit 2, SHIPPED =
0 findings / exit 0. The single surviving suppression demonstrably suppresses
exactly one real finding, and the harness discriminates in both directions —
so "0 shipped" is a measurement, not an artefact of a rule that never fired.

Suppressions adjudicated: 25 → 1
--------------------------------
* DEAD, deleted — 8. Six `ShortVariable` tags (EventsController ×3,
  CharactersController ×2, RegisterObjectFetcher ×1) sat on methods whose only
  short variable is `$id`, which phpmd.xml's ShortVariable `exceptions`
  allowlist already covers — they suppressed nothing. One
  `UnusedFormalParameter` on `Application::register()`, which uses `$context`.
  One `NPathComplexity` on the listener's `handle()`, which never fired.
* FIXABLE, fixed and deleted — 16.
* JUSTIFIED, kept — 1 (`Application::boot()`). All 25 originally carried a bare
  tag with NO reason text; the survivor now carries a written one.

What the fixes actually were
----------------------------
* EventsController (7 findings: CouplingBetweenObjects, ExcessiveClassComplexity,
  3× CyclomaticComplexity, 2× NPathComplexity) — extracted `EventRosterService`,
  which now owns the participation, attendance and run-sheet-context rules. The
  controller is a thin HTTP/auth boundary again. Also collapsed the
  authenticate-then-authorize pair into `resolveGameMaster()` returning
  `[uid, refusal]`, and removed a duplicate of `resolvePlayerName` that had been
  inlined into the cast builder.
* SkillRequirementService (4) — extracted `SkillRequirementChecker` (the four
  requirement kinds, with `requiredConditions`/`requiredEffects` collapsed into
  one shared membership check) and `IdListNormaliser`, used by both. `validate()`
  went from ~117 lines to orchestration.
* CharacterService (1) — extracted `EffectApplier`, a stateless collaborator
  holding effect resolution, non-cumulative dedup and signed-modifier logic.
  Pure move; the arithmetic is unchanged.
* CharacterRequirementListener (2) — extracted `extractEntities()` (early-return,
  so the `else` disappears rather than relocating) and `collectVeto()`. MEASURED,
  not assumed: removing an `else` is not complexity-neutral, so both the
  ElseExpression and the CyclomaticComplexity were re-measured and both cleared.
* BooleanArgumentFlag ×2 — the rule fires on the parameter's DEFAULT VALUE, not
  the call site, which was confirmed before changing anything. Split into
  intention-revealing `loadSettings()` / `reloadSettings()` over a private
  `importRegister(bool $force)` with NO default. Three call sites and the test
  updated.

Tests
-----
153 tests / 541 assertions, OK — before and after, identically conditioned, and
re-run after every refactor round. Where a constructor gained a dependency the
tests construct the REAL collaborator over the existing mock (e.g.
`new EventRosterService($this->objectFetcher)`), so every assertion still
exercises the same behaviour end to end. No assertion was weakened; the two
`loadSettings` delegation tests gained an `expects($this->never())` on the
sibling method.

Also verified inside nextcloud:latest with `composer install` run IN this
worktree: phpcs 0 errors, PHPStan "[OK] No errors", `php -l` clean across lib/
and tests/. All four new services are pure-autowired; the app registers no
services explicitly, so no DI wiring was needed.

Not done, and why
-----------------
* `SkillRequirementService::resolveXpAbility()` is public with no caller. Left
  alone: it is documented as a shared resolution rule with
  `event-xp-award-workflow` and carries a @SPEC tag. Deleting a documented
  public API is not a debt burn-down.
* Psalm dies before analysis in a bare container on
  `Cannot resolve stubfile path vendor/nextcloud/ocp/OCP.bak/...`. Pre-existing
  and unrelated — psalm.xml is untouched here and that directory does not exist
  in a fresh clone. psalm.xml was deliberately NOT edited to make it pass;
  PHPStan covers the same ground and is clean.
* `tests/integration/EffectChainIntegrationTest.php` is run by NEITHER
  phpunit.xml nor phpunit-unit.xml — both include only tests/unit. Its
  constructor call and import were updated so it stays consistent and lints,
  but flagging it: that file is currently dead weight in CI and deserves its
  own look.

* fix(licence): align the touched files' @license headers with the declared EUPL-1.2

gate-28 (license-triangle) went red on this PR, and it was MY change that
surfaced it: the gate is diff-scoped, so a file's stale header only gets
compared against composer.json once the file is edited. 11 of the files this PR
touches declared AGPL-3.0-or-later while every authoritative declaration in the
repo says EUPL-1.2 — composer.json `"license": "EUPL-1.2"`,
appinfo/info.xml `<licence>EUPL-1.2</licence>`, and the LICENSE file itself
("EUROPEAN UNION PUBLIC LICENCE v. 1.2"). 19 files under lib/ already said
EUPL-1.2; the AGPL headers are stale copy-paste from the upstream Nextcloud app
skeleton.

This is not a licence change: it makes the file headers agree with the licence
the project already grants under. Both docblock positions (file and class) were
corrected in the files this PR touches.

Also reverts lib/Controller/CharactersController.php to its development state.

WHY, in full, because reverting deliberate work needs a reason:
the only change there was deleting two DEAD
`@SuppressWarnings(PHPMD.ShortVariable)` tags (dead because the sole short
variable is `$id`, which phpmd.xml's ShortVariable `exceptions` list already
allows). But editing the file at all pulled it into the diff scope of gate-49
(controller-exception-translation), which then reported `downloadPdf()` and
`requirementReport()`: both call `RegisterObjectFetcher::getObject()` and catch
only a broad `\Exception`, with no tracked-exception catch and no `@throws`.

That is a real pre-existing debt, and the honest fix was tried: split the catch
into `DoesNotExistException` (client error, 404, silent) and `\Exception`
(server-side — an unconfigured register — same 404 so nothing leaks, but
logged). It works and gate-49 goes green. It also costs a PHPMD finding: the
`use OCP\AppFramework\Db\DoesNotExistException;` import takes
CharactersController's CouplingBetweenObjects from 12 to 13, one over the
threshold, taking SHIPPED findings from 0 to 1. MEASURED, not assumed. An FQCN
in the catch instead of an import is not a way out either — phpmd.xml enables
MissingImport.

The coupling headroom is gone because `downloadPdf()` re-implements, inline via
ContainerInterface + IAppManager, exactly what `Service\DocuDeskPdfRenderer`
already does (`isDocuDeskAvailable`, `normaliseTemplateId`, `getTemplate`,
`render`) and which `EventsController` already consumes. Consolidating onto it
would drop two dependencies, delete the duplication AND leave room for the
exception import — but it rewrites ~60 lines and the mocks in
CharactersControllerTest, which is its own change, not a rider on a PHPMD
burn-down. Rather than ship a net PHPMD regression to satisfy a different gate,
this PR leaves the file alone and the debt is written up in the PR description.

Net effect: TRUE findings stay at 1 and SHIPPED at 0 (the two reverted
suppressions were dead, so removing them never moved either number), gate-49
returns to its development state, and gate-28 is satisfied for every file this
PR does touch.
…on/* to */lib/Migration/* (#266)

`*/Migration/*` is a path-SEGMENT pattern, not a directory anchor. PDepend
compiles an exclude-pattern into an UNANCHORED regex — Input\ExcludePathFilter
preg_quote()s the pattern and then turns `\*` into `.*` — so it matches ANY path
containing a `/Migration/` segment: `lib/Service/Migration/`,
`lib/Command/Migration/`, any future `lib/*/Migration/`. Those are ordinary
classes with no interface-mandated signature, and a genuine unused parameter in
one of them would never be reported while the run still looked clean.

PROBE MATRIX, PHPMD 2.15.0 / PHP 8.4.22, three probe classes on a throwaway copy:

  probe                                   */Migration/*   */lib/Migration/*
  lib/Migration/…            UFP          not reported    not reported  (intended)
  lib/Migration/…            Else (leg 1) reported        reported      (leg 1 unaffected)
  lib/Service/…              UFP          reported        reported
  lib/Service/Migration/…    UFP          NOT REPORTED    reported      (the leak)

The IMigrationStep exclusion still does exactly its job — a step that cannot drop
changeSchema/preSchemaChange/postSchemaChange's three mandated parameters is
still spared — and leg 1 still analyses lib/Migration for every other rule.

Real numbers: UNCHANGED. A grep for `/Migration/` directories outside
lib/Migration/ found none in this repo, so nothing was actually being swallowed.
The trap goes regardless.

One process note worth recording: the first draft of this comment contained a
literal `<-` inside the <description>, which made the ruleset UNPARSEABLE. PHPMD
then exited 1 and reported NOTHING — and "no findings printed" is exactly what a
clean run looks like to a grep. It was caught only by reading the exit code
directly. The XML is validated as part of the check now.
…failing CI (#269)

v1.0.1 is `f4d9756` (2026-08-03) and predates three gate fixes, so every
Hydra Gates run this repo has ever made executed a script in which 16
gates reported PASS when their helper never ran (ConductionNL/.github#147),
gate-33 had no axe report to read and never said so (#148), and gates 6
and 7 reported PASS on an empty scope (#149). The tick was identical
either way, which is why nothing in this repo's history shows it.

That pin is now also RED, and the mechanism is worth writing down.
quality.yml is referenced `@main` while this package is PINNED, so the
two can desync. #164 flipped `hydra-gates-require-full-coverage` to
default true in the shared workflow, and that flag requires a gate to
DECLARE itself not-applicable. v1.0.1 contains ZERO `_skip` calls; v1.3.0
has 36. v1.0.1 has no vocabulary to declare, so every absent prerequisite
became "DID NOT RUN" and failed the job — for gates the repo has no
subject matter for.

Measured on this branch, diff-scoped against origin/development exactly
as CI scopes it, in a private mount namespace with a private tmpfs (the
runner's ~50 /tmp/hydra-gate-*.log paths are shared state and two
concurrent runs corrupt each other's counts, .github#158 item 6):

  v1.0.1  exit 98  FAIL — "GATES THAT DID NOT RUN: 24 33"
  v1.3.0  exit 0   PASS — those gates named NOT APPLICABLE, with reasons

Independently confirmed end-to-end: doriath#160 changed this one line and
nothing else, and its Hydra Gates job went failure -> success.

v1.3.0 is `f7eaf2a` = .github@main at the time it was cut.

Refs ConductionNL/.github#159
The repo already declares EUPL-1.2 in composer.json, package.json,
appinfo/info.xml and LICENSE, but 34 source files still carried AGPL-3.0
headers in three different shapes:

  - `@license AGPL-3.0-or-later ...`
  - `@license https://www.gnu.org/licenses/agpl-3.0.html GNU AGPL v3 or later`
  - `SPDX-License-Identifier: AGPL-3.0-or-later`

All are now the canonical shape already used by lib/AppInfo/Application.php:

  * @license   EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
  SPDX-License-Identifier: EUPL-1.2

The SPDX identifier is first so hydra gate-28 (license-triangle) parses it.
Five files under lib/ were failing that gate; it now passes.

Only `@license` / `SPDX-License-Identifier` lines were touched — every
`@copyright` / `SPDX-FileCopyrightText` holder and year is unchanged.
Header-only change: phpunit 153 tests / 541 assertions OK before and after.
…r, closing gate-49 (#267)

* refactor(characters): consolidate downloadPdf onto DocuDeskPdfRenderer, closing gate-49

CharactersController failed hydra gate-49 (controller-exception-translation)
on both downloadPdf() and requirementReport(): each calls
RegisterObjectFetcher::getObject() but caught only \Exception, so an
OpenRegister DoesNotExistException was never translated explicitly.

The obvious fix -- importing DoesNotExistException -- is a net regression on
its own. Measured on PHP 8.4.22 / PHPMD 2.15.0:

  import alone:  CouplingBetweenObjects 12 -> 13, shipped findings 0 -> 1

DocuDeskPdfRenderer already existed and its docblock already claimed both the
character-sheet and the event run-sheet export as callers -- but downloadPdf()
never actually used it and re-implemented the whole pipeline inline. Routing
downloadPdf() through the renderer (as EventsController::downloadRunsheet
already does) drops IAppManager, ContainerInterface and LoggerInterface from
the controller, which buys back the budget the exception import needs.

  before:  CBO 12, shipped PHPMD findings 0, gate-49 FAIL (2 methods)
  after:   CBO 11, shipped PHPMD findings 0, gate-49 PASS

No behaviour change. The existing downloadPdf tests were kept driving a REAL
DocuDeskPdfRenderer built from the same IAppManager/Container/Logger mocks the
controller used to hold, so they still exercise the identical end-to-end
pipeline and act as a behaviour-preservation check rather than an assertion
about the new internal shape.

Tests: 153/541 -> 173/577, all passing. Adds the first tests for
DocuDeskPdfRenderer, which had none despite already serving EventsController,
and pins the details this refactor could have silently changed: the template
body, render context and page options handed to DocuDesk, the derived
download filename, and template-id lower-casing.

Fail-proof (mutation testing, each reverted):
  isDocuDeskAvailable -> true            kills 3 tests (incl. controller 424)
  normaliseTemplateId -> passthrough     kills 8 tests (incl. controller 400)
  render error -> '' instead of null     kills 2 tests (incl. controller 500)

No suppressions, baselines, thresholds or waivers were added or changed.

* fix(license): align @license with composer.json EUPL-1.2 on the files this change touches

gate-28 (license-triangle) is diff-scoped, so editing CharactersController
pulled a pre-existing header drift into scope: the file declared AGPL-3.0
while composer.json declares EUPL-1.2. Fixed properly rather than waived, on
the two files this change touches plus the new test.

DashboardController, DeepLinkRegistrationListener and LarpingAppAdmin carry
the same pre-existing drift but are outside this diff and are already covered
by chore/eupl-license-normalisation-2026-08-05; left alone to avoid conflicting
with that branch.
…kflow needs

The Hydra Gates job fails with a message that says outright it is not about this
repository:

  hydra-gates-ref <old> does not contain: scripts/lib/check_spec_anchors.py
  scripts/lib/check_form_labels.py scripts/lib/check_license_triangle.py

The reusable workflow floats on @main and calls those scripts BY PATH inside the
PINNED package, so a pin older than the scripts cannot run the gates that
implement them. A pinned ref is a silent expiry date on every upstream change,
and the failure reports on the pin while saying nothing about the code.

v1.5.0 is the first tag containing all of them, verified by reading each path at
that tag rather than assuming the newest tag has everything.

Swept across the fleet: 11 of 13 repos were pinned below v1.5.0 and every one of
them was failing this way.
…#272)

.coverage-baseline was read as a floor by the phpunit guard and as an exact
target by the push-side staleness check. Together they demand equality with a
checked-in constant, which against a moving base branch is not satisfiable:
closing "stale" means committing the value the tree will measure after the PR
lands. Measured on openregister — committed 58.93, development advanced
16030->16038 tests, merge result measured 58.88, guard reported a 0.05% drop.

coverage-guard.php gains --against=<clover.xml>, naming a report measured at
the merge base. When present it is the only floor; the committed constant is
reported but not enforced. Both numbers then come from one driver in one job,
so the xdebug/pcov statement-counting difference cancels rather than being
baked in, and the merge base cannot go stale.

Ratios are compared as exact integer cross-products, not rounded percentages:
at two decimals a one-statement regression read as "unchanged" and exited 0.
An empty or zero-statement report is now a hard error rather than 0%, which as
the merge-base side would set the floor to zero and pass every drop.

Verified on real CI clover artifacts: a genuine 1.44% drop fails, an unchanged
tree passes, and adding untested code fails while adding tested code passes.
* chore(ci): move hydra-gates-ref v1.3.0 -> v1.4.0

A pinned `hydra-gates-ref` is a silent expiry date on every upstream fix:
this repo cannot receive a gate-package change until this line moves.

v1.4.0 is the latest tag and the first one that carries
`hydra-gates/scripts/axe-run.cjs` (verified absent at v1.3.0), so it is
also the first that has ConductionNL/.github#168 axe DOM scoping and
ConductionNL/.github#165 gate-46 fix.

`enable-axe` is deliberately NOT enabled in this commit. Ordering matters:
the ref lands first, enabling axe is a separate decision.

* chore(ci): stop pinning hydra-gates — track the package at @main

Removes the `hydra-gates-ref` input from the `quality.yml` caller. The
shared workflow already defaults it to `main`, and this repo consumes
`quality.yml` itself at `@main`, so dropping the override makes both
sides move together: a gate-package fix lands here without a commit here.

A pin is a silent expiry date on every upstream fix, and we have paid for
that twice already:

  - .github#159 — 22 repos sat on v1.0.1, which predated the gate fixes.
    16 gates were dead fleet-wide and every single one reported PASS. A
    gate that never runs emits a tick identical to one that did, so
    nothing in any repo's history showed it.

  - .github#173 — the shared side flipped a default at @main while the
    package stayed pinned per caller. Old runners lacked the coverage
    accounting the new default assumed, so they went red on gates they
    had no subject matter for.

Removing the pin closes both shapes at once. Rolling back is a revert on
ConductionNL/.github main, which reaches the whole fleet in one commit;
holding this one repo still is still possible by setting the input
explicitly, with a reason.

`enable-hydra-gates: true` is unchanged. `enable-axe` remains unset.
The comment block that justified the pin is replaced with a short note
saying why there is no pin.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Comment thread .github/workflows/code-quality.yml Outdated
Comment on lines +32 to +36
uses: ConductionNL/.github/.github/workflows/release-beta.yml@main
with:
app-name: larpingapp
channel: dev
secrets: inherit
…ommand injection) (#278)

quality / Security (composer) is red on every PR here as of today:

    Advisory ID: PKSA-rdkp-vv9z-mjkg
    CVE: CVE-2026-67434  —  OS Command injection
    Affected versions: <3.13.6|>=4.0.0,<4.0.2
    Reported at: 2026-08-05T23:53:11+00:00

The advisory was published YESTERDAY and roave/security-advisories installs
as dev-latest each run, so the same lockfile was clean on 2026-08-05 and is
vulnerable on 2026-08-06 with no commit in between. The last green run is
evidence of when it ran, not that the lockfile is safe.

composer.json's existing constraint already permits the fixed version, so
this is a lockfile move only: 1 update, 0 installs, 0 removals. Verified the
diff touches exactly two lines, both the version string, and no other file.

Part of a fleet sweep — 13 of 16 repos checked were on the affected 3.13.5.
#279)

OS command injection in PHP_CodeSniffer, GHSA-hmqg-cxww-wqhq, reported
2026-08-05. Affected: <3.13.6 | >=4.0.0,<4.0.2. This repo was on 3.13.5.

All 16 repos checked across the fleet are on 3.13.5 and equally affected. The
advisory is live in the audit DB, so this repo's Security (composer) gate is
failing until this lands.

Verified
- composer audit --locked: 'No security vulnerability advisories found' (was 1).
- vendor/bin/phpcs --version -> 3.13.6.
- composer phpcs: rc=0.
- Positive control: a deliberately non-conforming file under lib/ made phpcs
  exit 2 with 13 findings, so the green above is a real pass and not a checker
  that no-ops. Probe removed; only composer.lock is modified.
…es (#280)

axe-core sat in `dependencies`, declaring an accessibility *testing*
library as an application runtime dependency.

Measured: nothing under src/ imports axe-core, and the built production
bundle does not contain it — 0 hits for `axe-core`, `axe.run` and axe's
own signature strings (`aria-allowed-attr`, `color-contrast`), while those
strings are present in the installed axe-core (positive control).

What put it in every app manifest is @conduction/nextcloud-vue, which
declares axe-core as an OPTIONAL peerDependency. nc-vue does use it, but
only in `src/testing/a11y.js` — a testing helper that is never imported
from `src/index.js`, so it never reaches an app bundle. nc-vue's own file
header states axe-core "is a devDependency" and that consumers wanting the
a11y assertion "add `axe-core` to their OWN devDependencies". This change
follows that instruction.

Not a bundle-size fix; the bundle is byte-identical. It stops a test
dependency being declared as production surface (SBOM, `npm ci --omit=dev`,
advisory triage). An optional peer is satisfied by a devDependency, so
nothing breaks.

Verified: npm ci + production build both exit 0.
)

min-version is enforced at install time, so a 32 floor makes occ app:enable
refuse on stable31, which this repo's own CI runs. The e2e seed then fails
with "is not installed or enabled".

The reason the floor was raised no longer holds: openregister#2372 removed
every eager reference to its ContextChat provider, so the class is only
loaded behind interface_exists() guards and never read on an older server.
openregister#2380 restored its own 28 floor on that evidence.
…eed a player for character.ocName (#281)

* fix(pdf): validate the template id before probing for DocuDesk, and seed a player for character.ocName

Newman on `development` (run 31110917018, job 92648343763):
1 collection · 27 requests · 43 assertions · 33 passed · 10 FAILED.

Two root causes account for all ten.

## 1. The collection sent a free-text `ocName` (8 failures — fixture wrong)

The character schema declares `ocName` as
`{ "$ref": "player", "format": "uuid", "x-allow-create": true }` — it is the
PLAYER RELATION, not an out-of-character display name. The collection sent
`"ocName": "NEWMAN character"`.

Measured live against the dev instance, status code printed:

    POST .../objects/larpingapp/character  {"ocName":"NEWMAN character"}
    -> HTTP 400 "Property 'ocName' should match format 'uuid' but
       'NEWMAN character' does not."

The app is CORRECT; the fixture was not. `x-allow-create` is not an
OpenRegister annotation at all (`grep -rn x-allow-create` over openregister
returns nothing), so it is a silently-ignored hint and does not permit a bare
name on write.

Every other object create in the collection (item, skill, condition, effect,
event, player) passed, because none of them carries a relation property. The
failing create left `charId` undefined, which cascaded into the 404s on read /
update / delete and put the literal `null` into the PDF URLs.

Fix: a `0. Setup` folder seeds a player and captures `setupPlayerId` BEFORE
section 1, and the character create/update bodies reference it. Section 2's
own player create is untouched, so domain-object coverage is unchanged; a
matching teardown removes the seeded player.

### The negative test was passing for the wrong reason

`Create character ERROR: missing required ocName (400, not 500)` asserted only
`within(400, 499)`. While `ocName` was malformed the endpoint answered 400 to
EVERY request, so that test would have passed even if the endpoint did nothing
at all. It is now pinned to the missing-required branch by name — the body must
mention `required` and `ocName`, and must NOT be the uuid-format rejection,
which is also a 400. Measured, the two branches are distinguishable:

    {"description": "..."}  -> 400 "The required properties (name, ocName) are missing."
    {"ocName": "not-a-uuid"} -> 400 "Property 'ocName' should match format 'uuid'"

This is a strengthening, not a relaxation.

## 2. The DocuDesk probe ran before input validation (1 failure — app bug)

`downloadPdf ERROR: invalid (non-UUID) template -> 400 not 500` got 424.

`CharactersController::downloadPdf()` and `EventsController::downloadRunsheet()`
both checked `isDocuDeskAvailable()` BEFORE `normaliseTemplateId()`. CI does not
install DocuDesk alongside LarpingApp, so the availability probe answered 424 to
every request and the documented 400 contract was unreachable — a crafted
template value was never rejected on its own merits.

Input validation is a property of the REQUEST and must not depend on which
optional apps are installed. `normaliseTemplateId()` is a pure regex with no
DocuDesk dependency, so the two guards are now in the correct order in both
controllers.

### Failure proof

No existing test covered the combination that matters — DocuDesk ABSENT and a
non-UUID template. Every case fixed one guard while leaving the other in its
passing state, so BOTH orders satisfied all of them, which is why the bug
survived. The two tests added here cover exactly that combination. Measured:

    ARM A (original order):  2 failures — "Failed asserting that 424 is identical to 400"
    ARM B (this change):     OK (27 tests, 62 assertions)
    full suite:              OK (175 tests, 581 assertions)

Three existing tests passed a non-UUID template while asserting 424; they now
pass a well-formed UUID so the 424 branch is genuinely reached rather than
being short-circuited by the 400.

## Not fixed here — needs a product decision

`Create character AUTHZ: anonymous write returns 401` still fails. Measured:

    POST (no auth) .../objects/larpingapp/character
    -> HTTP 403 {"error":"User 'Anonymous' does not have permission to
       'create' objects in schema 'Character'"}

LarpingApp's own `/api/settings` correctly answers 401 to an anonymous caller.
This 403 comes from OpenRegister's RBAC layer, not from LarpingApp, so the
assertion is left honest and failing rather than repointed at 403. Whether an
anonymous caller should get 401 (not authenticated) or 403 (operation
forbidden) — and whether naming the schema to an anonymous caller is an
acceptable disclosure — is an OpenRegister decision.

No test was skipped, disabled, relaxed or deleted.

* fix(auth): downloadPdf declared NoAdminRequired while its body required admin (gate-9)

Touching downloadPdf() pulled it into gate-9's ADR-020 diff scope and exposed a
pre-existing contradiction: the method carried `#[NoAdminRequired]` /
`@NoAdminRequired` while its body requires an administrator — the `isAdmin()`
guard added by #205 to close the character-PDF IDOR. Anyone reading the
attribute would conclude any logged-in user may call it.

    lib/Controller/CharactersController.php:131 method=downloadPdf
    rule=no-admin-required-annotation-with-admin-body

The attribute is removed, so Nextcloud's middleware rejects a non-admin before
the controller runs. The in-body guard stays as defence in depth for direct
invocation. Anonymous callers are unaffected: SecurityMiddleware raises
NotLoggedIn (401) before the admin check, so the collection's
`downloadPdf AUTHZ: anonymous -> 401` still holds.

Why this was not caught before: my first local gate run reported gate-9 PASS.
That local checkout of ConductionNL/.github predated
`1558036 fix(gate-9): the admin rule matched no real isAdmin() call`, so the
gate I ran had never matched anything — a dead gate reads exactly like a
passing one. Re-running the version CI actually uses (hydra-gates @ main)
reproduced the FAIL locally, which is also the failure proof:

    with    #[NoAdminRequired]: [gate-9] semantic-auth: FAIL — 1 mismatch
    without #[NoAdminRequired]: [gate-9] semantic-auth: PASS
    gate-5 route-auth: PASS, gate-7 no-admin-idor: PASS
    unit suite: OK (175 tests, 581 assertions)

Per-player self-access remains a follow-up needing a `player` ownership field
on the character schema; when that lands the attribute returns alongside a real
ownership check.
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.

3 participants