Skip to content

Release: merge development into beta#70

Merged
rubenvdlinde merged 2 commits intobetafrom
development
Apr 30, 2026
Merged

Release: merge development into beta#70
rubenvdlinde merged 2 commits intobetafrom
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.

rubenvdlinde and others added 2 commits April 30, 2026 23:07
…#39)

Walkthrough of all 9 archived OpenSpec features uncovered three critical
runtime bugs in features marked "implemented". This commit restores them
and clears the supporting quality stack.

Critical fixes
--------------
- ConditionalRule.createdAt: switch ?DateTime to ?string ('c' format) to
  match sibling entities. Doctrine DBAL cannot bind a DateTime without
  an explicit addType registration; INSERT now succeeds. Same change in
  AdminSetting.updatedAt.
- AdminTemplateService + TemplateService: drop the ramsey/uuid require
  and inline the random_bytes(16) UUID generator already used by
  DashboardFactory. The ramsey class was never autoloaded at runtime
  (Application.php does not require vendor/autoload.php), so admin
  template creation and template-based dashboard provisioning both
  threw 500.
- DashboardService: stop hardcoding PERMISSION_FULL when auto-creating
  user dashboards. Read defaultPermissionLevel and defaultGridColumns
  from AdminSettingMapper and pass them to DashboardFactory.

Quality
-------
- NamedParametersSniff: skip Entity-magic accessors (set*/get*/is*) on
  classes extending OCP\AppFramework\Db\Entity. Entity::__call uses
  args[0], so named arguments break those calls. Eliminates 4 false
  positives.
- DashboardService: add the missing WidgetPlacement import (PHPMD).
- PageController: replace \OC::server->get(IManager::class) with proper
  DI (Psalm).
- UserAttributeResolver: drop the non-existent IUser::getLanguage() call
  and read 'core/lang' from IConfig instead (Psalm).

Frontend warnings
-----------------
- TileEditor + WidgetStyleEditor: NcSelect was passing 'Icon' as the
  vue-select label key (option.Icon does not exist). Use input-label
  for the visible label and label="label" for the option key.
- AdminSettings: replace HTML <label> + bare NcSelect with input-label
  prop, satisfying NcSelect's accessibility requirement.
- DashboardSwitcher / WidgetPicker / WidgetWrapper / TileEditor /
  WidgetStyleEditor: add aria-label or input-label to icon-only NcButton
  / unlabeled NcTextField / inline color-pick NcButton instances.

Tests: 106 / 106 passing (293 assertions). composer phpcs / phpmd /
psalm clean. End-to-end API verified for conditional rules, admin
templates, prometheus metrics.
* fix(security): Stop leaking exception messages to API clients (ADR-005)

`ResponseHelper::error()` was returning `\$exception->getMessage()` in
the response body, which surfaces internal error detail (stack traces,
DB errors, file paths) to any authenticated caller that triggered a
thrown exception. ADR-005 Rule 5 forbids this: "No stack traces in API
responses; generic messages."

Fix closes the leak immediately by returning a generic
\`"Operation failed"\` message to the client regardless of the
underlying exception.

The helper now accepts two optional parameters for callers that want
to preserve visibility + customise the client message:

- \`?LoggerInterface \$logger\` — when provided, the real exception is
  recorded at ERROR level with full context (`['exception' => \$exception]`)
  before the response is returned.
- \`string \$message='Operation failed'\` — generic client-facing text.

Signature stays backwards-compatible: all 20 existing
\`ResponseHelper::error(exception: \$e)\` call sites across
DashboardApiController, TileApiController, WidgetApiController,
RuleApiController, AdminController continue to work unchanged, and
they now return generic text instead of leaking.

Follow-up (not in this commit): thread \`\$this->logger\` through the
6 controllers that currently don't inject a LoggerInterface so the
server log regains exception visibility. Tracked in docs/adr-audit.md.

* fix(licence): Remove contradictory AGPL SPDX block from 72 PHP files (ADR-014)

Every PHP file in lib/ and tests/Unit/ carried TWO licence declarations
that disagreed: the PHPDoc `@license EUPL-1.2` (correct, Conduction
standard) plus a separate SPDX block declaring
`SPDX-License-Identifier: AGPL-3.0-or-later` with
`SPDX-FileCopyrightText: 2024 MyDash Contributors`. Any REUSE-based
compliance tooling would reject this — two licences on one file is
ambiguous.

Removed the SPDX block from all 72 files. The PHPDoc `@license
EUPL-1.2` + `@copyright 2024 Conduction b.v.` tags are now the single
source of truth. REUSE compliance will be restored by the REUSE.toml
addition in the next commit — path-based annotations map **/*.php to
EUPL-1.2 + Conduction copyright.

Verified: `grep -rl "SPDX-License-Identifier: AGPL" lib/ tests/` returns
zero. Same for `SPDX-FileCopyrightText: 2024 MyDash Contributors`.

The PHPDoc blocks now terminate cleanly after `@link` / `@license`,
no trailing orphan SPDX tags.

* refactor(frontend): @nextcloud/vue → @conduction/nextcloud-vue (ADR-004)

ADR-004 requires Conduction apps to route all Nextcloud Vue components
through the @conduction/nextcloud-vue wrapper instead of importing from
@nextcloud/vue directly. Nine Vue files had direct imports:

- src/components/WidgetWrapper.vue       (NcButton)
- src/components/TileEditor.vue          (NcModal, NcButton, NcTextField, NcSelect, NcColorPicker)
- src/components/WidgetPicker.vue        (NcButton, NcTextField, NcEmptyContent)
- src/views/Views.vue                    (NcButton, NcEmptyContent)
- src/components/TileCard.vue            (NcButton)
- src/components/DashboardSwitcher.vue   (NcSelect)
- src/components/WidgetRenderer.vue      (NcDashboardWidget, NcEmptyContent, NcLoadingIcon)
- src/components/WidgetStyleEditor.vue   (NcModal, NcButton, NcTextField, NcSelect, NcColorPicker, NcCheckboxRadioSwitch)
- src/components/admin/AdminSettings.vue (NcButton, NcSelect, NcSelectTags, NcTextField, NcCheckboxRadioSwitch, NcEmptyContent, NcModal)

All 9 now import from @conduction/nextcloud-vue. The package was already
in package.json dependencies, so no dep bump needed.

Verified: `grep -rn "from '@nextcloud/vue'" src/` returns zero matches.

* chore: Add REUSE.toml + bump Nextcloud max-version to 34

**REUSE.toml**: closes the REUSE-compliance hole from the previous
commit. The SPDX block was removed from 72 PHP files; this declaration
restores machine-readable licence + copyright data via path-based
annotations:

- `**/*.php` → EUPL-1.2 + "2024 Conduction B.V." (matches every PHP
  file's PHPDoc @license/@copyright tags — reuse lint accepts the
  PHPDoc form when the REUSE.toml declares it explicitly)
- Vue / JS / TS / CSS / SCSS / shell → EUPL-1.2 + Conduction
- Config / data / markdown / JSON / YAML / XML / TOML / img / l10n /
  lockfiles → CC0-1.0 (standard Nextcloud-app treatment)

Template-matching shape — same structure as nextcloud-app-template's
REUSE.toml, year bumped to 2024 (MyDash inception) instead of 2026,
and `**/*.toml` added to the CC0 block so REUSE.toml itself is
covered.

**info.xml**: Nextcloud max-version 33 → 34. Template supports 34; no
reason MyDash shouldn't.

Skipped the Makefile dev-link symlink helper from the template — the
template needs it because the repo is cloned as
`nextcloud-app-template` but the <id> is `app-template`. MyDash's
<id> is `mydash` and the repo is cloned as `mydash`, so the symlink
trick is a no-op here.

* docs: Add architecture, ADR index, ADR compliance audit

Three new markdown docs wire into the Docusaurus site (autogenerated
sidebar picks them up automatically):

- `docs/architecture.md` — component map (Controller/Service/Mapper
  layers with concrete class counts), request flow for dashboard
  update, auth posture, DI posture, capability table mapping to
  openspec/specs/, and an explicit "does NOT do" list covering the
  ADRs that are legitimately N/A for MyDash.
- `docs/adr/README.md` — names the canonical ADR location
  (ConductionNL/hydra/openspec/architecture/) and explains why app
  repos no longer carry stale copies (decidesk #71 false-positive
  drift lesson). Quick index of the 23 ADRs.
- `docs/adr-audit.md` — per-ADR compliance matrix for MyDash as of
  2026-04-24. 25 compliant / 4 partial / 2 gaps / 14 N/A. Each row
  carries a status + evidence + link to fix when applicable.

Captures the verified findings from the two-agent audit run at the
start of this PR:

- 0 service-locator escapes in lib/ (fixed in commit 5712903)
- `ResponseHelper::error` no longer leaks (commit 9be1255)
- 72 PHP files have clean EUPL-1.2 headers (commit ab9fc70)
- 9 @nextcloud/vue imports swapped (commit 222cf3f)
- REUSE.toml + max-version bump (commit b5ca3a4)

The two remaining `❌` gaps — @SPEC annotation pass + Newman
collection — are flagged for OpenSpec changes + Hydra pickup in the
next commit.

Corrects the earlier audit's false-alarm IDOR claim (agent 2 stopped
at controller null-check, didn't trace through to the service-layer
ownership verification). ADR-005 per-object auth is actually PASS
once you follow DashboardApiController::update → PermissionService →
DashboardService's ownership guard.

* spec: Two OpenSpec changes for the remaining ADR gaps

Converts the two ❌ items from docs/adr-audit.md into formal OpenSpec
changes so Hydra's pipeline can pick them up once this PR merges.

**spec-annotation-pass-2026-04-24/** — Close the ADR-003 `@spec` tag
gap. Runs `/opsx-annotate mydash` against the 66 methods already
classified by `openspec/coverage-report.md` (61 Bucket 1 + 5 Bucket
2b from the legacy-widget-bridge retrofit). Design.md resolves the
3 NEEDS-REVIEW flags from the coverage scan:

- `DashboardResolver::getEffectivePermissionLevel` vs
  `PermissionService::getEffectivePermissionLevel` — both tag with
  `@spec permissions/spec.md#requirement-effective-permission-level`;
  PermissionService is the authoritative impl, DashboardResolver is
  a thin delegator.
- `MyDashAdmin::getForm` + `MyDashAdminSection::getID` — treat as
  plumbing (Nextcloud admin-UI boilerplate, no domain behaviour),
  skip `@spec` annotation with an explanatory docblock note.

**newman-integration-suite-2026-04-24/** — Close the ADR-008 Newman
gap. Adds `tests/integration/mydash.postman_collection.json` covering
all 17 OCS endpoints across 6 folders (Health+Metrics, Dashboards,
Tiles, Widgets, Rules, Admin). Fixture setup/teardown pattern avoids
test pollution; admin-vs-member auth branch tests verify
authorization posture. `.github/workflows/code-quality.yml` already
has `enable-newman: true` — the collection is all that's missing.

Each change has proposal.md + design.md + tasks.md + specs/README.md
explaining that they're annotation-only / test-only (no Requirement
deltas needed). Format mirrors the archived retrofits in
openspec/changes/archive/.

GitHub issues + Hydra dispatch handled in a follow-up — spec files
land on development first so Hydra can locate them.

* chore: update SBOM

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
@rubenvdlinde rubenvdlinde merged commit 822f41d into beta Apr 30, 2026
30 of 37 checks passed
@github-actions
Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/mydash @ 6bace01

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

Quality workflow — 2026-04-30 21:24 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde added a commit that referenced this pull request May 1, 2026
Lockfile-only update via `npm audit fix` (no --force, no
package.json changes, no major bumps). Resolves every high-severity
npm vulnerability flagged on the development branch:

- fast-xml-parser CVE chain (incl. Dependabot alerts #52, #70):
  4.5.4 → 4.5.6 (entity-expansion bypass + comment/CDATA injection)
- lodash prototype pollution
- node-forge prototype pollution
- path-to-regexp ReDoS
- picomatch ReDoS

As a side effect npm chose @conduction/nextcloud-vue 0.1.0-beta.15
(was beta.3), picking up the 12 intervening upstream releases
including all the recent CnAppNav/CnAppRoot work. The Nc* re-export
issue blocking eslint is unaffected — that lands when nextcloud-vue
PR #102 ships and a new beta is published.

Remaining: 12 moderate + 32 low. All require major-version bumps
(@nextcloud/webpack-vue-config v7, vue-loader v17, @vue/test-utils v2
which is Vue-3-only and would break the app, etc.) — out of scope
for an audit-fix sweep, deserve dedicated PRs with build/test
verification.

Verified locally:
- `npm run build` succeeds (35 webpack warnings, same baseline as dev)
- `npm run lint` no new errors (the 32 Nc* `import/named` errors are
  pre-existing, fixed by nextcloud-vue PR #102)
- `npm audit` reports 0 high-severity vulnerabilities (was 6)
rubenvdlinde added a commit that referenced this pull request May 1, 2026
#81)

Lockfile-only update via `npm audit fix` (no --force, no
package.json changes, no major bumps). Resolves every high-severity
npm vulnerability flagged on the development branch:

- fast-xml-parser CVE chain (incl. Dependabot alerts #52, #70):
  4.5.4 → 4.5.6 (entity-expansion bypass + comment/CDATA injection)
- lodash prototype pollution
- node-forge prototype pollution
- path-to-regexp ReDoS
- picomatch ReDoS

As a side effect npm chose @conduction/nextcloud-vue 0.1.0-beta.15
(was beta.3), picking up the 12 intervening upstream releases
including all the recent CnAppNav/CnAppRoot work. The Nc* re-export
issue blocking eslint is unaffected — that lands when nextcloud-vue
PR #102 ships and a new beta is published.

Remaining: 12 moderate + 32 low. All require major-version bumps
(@nextcloud/webpack-vue-config v7, vue-loader v17, @vue/test-utils v2
which is Vue-3-only and would break the app, etc.) — out of scope
for an audit-fix sweep, deserve dedicated PRs with build/test
verification.

Verified locally:
- `npm run build` succeeds (35 webpack warnings, same baseline as dev)
- `npm run lint` no new errors (the 32 Nc* `import/named` errors are
  pre-existing, fixed by nextcloud-vue PR #102)
- `npm audit` reports 0 high-severity vulnerabilities (was 6)
rubenvdlinde added a commit that referenced this pull request May 3, 2026
#81)

Lockfile-only update via `npm audit fix` (no --force, no
package.json changes, no major bumps). Resolves every high-severity
npm vulnerability flagged on the development branch:

- fast-xml-parser CVE chain (incl. Dependabot alerts #52, #70):
  4.5.4 → 4.5.6 (entity-expansion bypass + comment/CDATA injection)
- lodash prototype pollution
- node-forge prototype pollution
- path-to-regexp ReDoS
- picomatch ReDoS

As a side effect npm chose @conduction/nextcloud-vue 0.1.0-beta.15
(was beta.3), picking up the 12 intervening upstream releases
including all the recent CnAppNav/CnAppRoot work. The Nc* re-export
issue blocking eslint is unaffected — that lands when nextcloud-vue
PR #102 ships and a new beta is published.

Remaining: 12 moderate + 32 low. All require major-version bumps
(@nextcloud/webpack-vue-config v7, vue-loader v17, @vue/test-utils v2
which is Vue-3-only and would break the app, etc.) — out of scope
for an audit-fix sweep, deserve dedicated PRs with build/test
verification.

Verified locally:
- `npm run build` succeeds (35 webpack warnings, same baseline as dev)
- `npm run lint` no new errors (the 32 Nc* `import/named` errors are
  pre-existing, fixed by nextcloud-vue PR #102)
- `npm audit` reports 0 high-severity vulnerabilities (was 6)
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