Skip to content

Commit 19e9b49

Browse files
authored
fix(gates): gate-57 1→0 (retire groupfolder storage, closes #87), gate-16 84→0, CVE-2026-65954 (#100)
* fix(security): bump phpcsstandards/phpcsutils to 1.2.3 for CVE-2026-65954 phpcsstandards/phpcsutils < 1.2.3 carries CVE-2026-65954 (arbitrary code execution, GHSA-r6hr-vr92-vv28, affected >=1.0.0-alpha1,<1.2.3). The advisory was published today, so composer audit turns red on a lock file that has not changed. The Security (composer) job in run 31516037194 passed at 17:25Z only because it ran before the advisory landed. Negative control before the bump, on this tree: composer audit --locked -> Found 1 security vulnerability advisory affecting 1 package phpcsstandards/phpcsutils / CVE-2026-65954 / exit 1 After 'composer update phpcsstandards/phpcsutils --no-install --no-scripts' (1.2.2 => 1.2.3, a lock-only change, 0 installs 0 removals): composer audit --locked -> No security vulnerability advisories found / exit 0 The bump is exercised rather than merely locked: phpcs runs green against the new library on PHP 8.4 -- 0 ERRORS AND 468 WARNINGS IN 211 FILES, exit 0 so no sniff regressed on the upgrade. * refactor: retire the inert groupfolder-storage-backend capability (closes #87, gate-57 1 -> 0) gate-57 (orphaned-write-capability) reported exactly one finding on this repo: lib/Service/DashboardService.php:3189 method=writeDashboardContent rule=orphaned-write-capability class=DashboardService It is a true positive and the real scope is larger than one method. Task 5 of the original change -- the wiring that would have routed dashboard get/create/update/delete through the storage factory -- was ticked in tasks.md but never performed. Everything around it landed, which is why the capability looked complete from every angle except the one that mattered. Measured on this tree, every absence claim taken with a positive control (the same search resolves callers for getUserDashboards and ->findByUuid): DashboardService::writeDashboardContent() 0 callers DashboardService::readDashboardContent() 0 callers DashboardService::deleteDashboardContent() 0 callers DashboardContentStorageFactory::getStorage() 0 (only the three above) DashboardApiController::storageUnavailableResponse() 0 callers DashboardMapper::findAll() 1 -- the migration command So nothing ever populated oc_launchpad_dashboards.content, Dashboard:: jsonSerialize() emitted a content key that was always null, launchpad. content_storage was a no-op setting, and launchpad:storage:migrate-to-groupfolder migrated nothing. Retired rather than completed, per Ruben's decision on #87: finishing it needs an ADR-level ruling on whether the content blob or the WidgetPlacement rows are the source of truth for a dashboard's layout. The spec asserts the blob, the code has used the rows since long before this capability existed, and wiring the blob in as a second source of truth invites divergence. Nobody uses it, so retiring costs nothing and removes that risk permanently. Removed: lib/Service/DashboardContentStorage/ (interface, both backends, three exceptions), DashboardContentStorageFactory, the three DashboardService facade methods and the factory constructor parameter, storageUnavailableResponse(), DashboardMapper::findAll(), both CLI commands and their <command> registrations, the $content/$locale properties with decodeContent() and their jsonSerialize() keys, and the five PHPUnit classes covering the removed tree. Version002009Date20260811000000 drops the content and locale columns. That loses no data: the only writer, DbContentStorage::write(), was reachable only through the factory, which was reachable only through the three orphaned facade methods, so the columns were NULL on every row of every install. The step is idempotent (hasColumn-guarded). Version002001Date20260603000000 and DashboardTableBuilder::addContentStorageColumns() are deliberately KEPT -- a shipped migration is part of the version ledger and deleting it would desynchronise instances that have already run it. Deliberately NOT removed, and tracked as Task 8 on #87: launchpad.content_storage, AdminSettingKey::CONTENT_STORAGE, SetupWizardService::{get,set}ContentStorage / hasGroupfolderApp, AdminController::setWizardStorage and setup-wizard step 2. Those belong to the setup-wizard capability, which WRITES the setting; this capability was the READER. The setting was already inert before this change, so removing the reader does not make it worse, and retiring the wizard step edits a different spec and deserves its own review. The spec is marked withdrawn rather than deleted, which also retires its 16 @e2e exclude markers -- their stated reasons cited DbContentStorageTest.php, a file this change deletes, so they would otherwise have become sixteen exemptions resting on a class that no longer exists. Verification, all on this tree: gate-57 over lib/Service/*.php 1 -> 0 planted true positive (postGate57Probe, a tracked write method with no caller) 0 -> 1, naming exactly the plant plant removed 1 -> 0 PHPUnit 1570 tests, 4032 assertions, 0 failures, 3 pre-existing skips phpcs 0 errors, 468 warnings, 211 files -- identical to the pre-change baseline check_spec_anchors.py over lib/ 0 dangling anchors gate-19 unchanged at 77 (base origin/beta) NOTE for anyone reproducing gate-57: its checker takes a FILE LIST, not a directory. `check_orphaned_write_capability.py .` prints nothing and exits 0 whatever the tree contains, which reads exactly like a clean repo. * chore(openspec): add the missing .openspec.yaml to the retirement change Every other active change dir under openspec/changes/ carries one (schema/created/status); the retirement change was missing it. * docs(spec): annotate the 84 changed frontend methods gate-16 reports (84 -> 0) gate-16 (spec-coverage) reported 84 changed methods without an @SPEC tag against base origin/beta. All 84 were in src/; zero were PHP -- the 273 lib/**/*.php files in the same diff are fully annotated already, established with a positive control (WeatherService.php carries 2 tags, HealthPingController 3) so that "all in one layer" is a measurement rather than a failed lookup. Closed with 84 real @SPEC anchors and exactly 2 reason-bearing exclusions. The anchors point at the specs the methods actually implement -- principally clock-weather-widgets, iframe-embed-widget, live-data-tile-widget, service-health-ping and tile-quick-search. Every one resolves: the canonical check_spec_anchors.py reports 0 dangling anchors across all of src/. That matters because a dangling anchor fails SILENTLY in this gate family, so an unresolvable tag would have made the gate green while asserting nothing. The two exclusions, both verified against the source rather than argued from the scenario text: ClockWidget.vue::pointOnCircle -- pure polar-to-cartesian trigonometry. The body reads neither this.now nor this.content, so it encodes no clock, timezone, format or accessibility behaviour. Verified its only two callers are tickCoords and handCoords, and both carry the REQ-CLOCK-003 tag. useTileClickTracking.js::__resetTileClickTrackingForTest -- test-only harness hook. Verified by grep that its only importer anywhere in the repo is src/composables/__tests__/useTileClickTracking.spec.js; it implements no product behaviour, only clearing cachedEnabled / inflightConfigPromise so each test starts from a cold cache. Both reasons name a concrete artifact (a caller, an importing test file) rather than a state of the world, which is the shape that survives re-checking. This diff is comment-only and provably so: 0 added and 0 removed lines fall outside a docblock. No runtime behaviour can change. Verification: gate-16 (base origin/beta) 84 -> 0 check_spec_anchors.py 0 dangling anchors across src/ tools/check-spec-annotations.php unchanged at 12 pre-existing PHP findings (TileClickMapper, WidgetPlacement, TileClick, ImportLaunchpadRegister, Version002007) -- none introduced here, none in a file this PR touches phpcs 0 errors, 468 warnings, 211 files (baseline) No gate was weakened: no baseline, no allowlist widening, no skipped test. * docs(spec): anchor WeatherWidget::temperatureAriaLabel to REQ-WEATHER-003 Landed a moment after the main annotation commit. gate-16 was already 0 without it, so this adds no gate movement -- but the method builds the accessible label that spells out the temperature unit, which is exactly what REQ-WEATHER-003 ("Locale-aware units and language, WCAG AA") governs, so the tag belongs there. Verified: check_spec_anchors.py reports 0 dangling anchors for the file, and REQ-WEATHER-003 exists at openspec/specs/clock-weather-widgets/spec.md:119. * docs: make the placementItemKey NOTE precise and point it at #101 The note claimed a 'REQ-GRID-010 "Placement key regeneration"' requirement. REQ-GRID-010 is titled **Grid Styling**; the stale scenario merely sits inside it, at spec.md:405. Reworded to say exactly that, to name the line, and to record that getPlacementKey() -- the method the scenario requires -- no longer exists. A wrong diagnosis written into a code comment is worse than no comment: the next reader inherits it as established fact and nobody re-measures it. Filed the substance as #101 rather than leaving it only in a docblock.
1 parent e24334b commit 19e9b49

50 files changed

Lines changed: 836 additions & 3049 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

appinfo/info.xml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,6 @@ Vrij en open source onder de EUPL-1.2-licentie.
157157
<command>OCA\LaunchPad\Command\DemoShowcasesListCommand</command>
158158
<!-- REQ-WIZ-010: setup wizard via `php occ launchpad:setup`. -->
159159
<command>OCA\LaunchPad\Command\SetupCommand</command>
160-
<!-- REQ-GFSB-008: one-time DB→GroupFolder content migration. -->
161-
<command>OCA\LaunchPad\Command\MigrateStorageToGroupFolder</command>
162-
<!-- REQ-GFSB-010: toggle the active storage backend. -->
163-
<command>OCA\LaunchPad\Command\ToggleStorageSetting</command>
164160
</commands>
165161

166162
<navigations>

composer.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/Command/MigrateStorageToGroupFolder.php

Lines changed: 0 additions & 212 deletions
This file was deleted.

0 commit comments

Comments
 (0)