ci: restore CI — reusable-workflow refs pointed at a non-existent org for two months - #74
Merged
Merged
Conversation
…nt Conduction org All 8 reusable-workflow calls referenced `Conduction/.github`. That GitHub org does not exist (the 2026-06-01 rename went the wrong way; `GET /orgs/Conduction` is a 404). Actions cannot resolve the ref, so every run produced ZERO jobs and failed instantly. No ESLint, PHPCS, PHPMD, PHPStan, Psalm, licence scan, security scan, SBOM or PHPUnit has run on this repo since. The tell: in `gh run list --json name`, an unresolved run's `name` is the raw path (`.github/workflows/code-quality.yml`) rather than the workflow's declared `name:` (`Code Quality`). Also fixes a 9th dead reference a `uses:`-only grep misses: the `additional-apps` input cloned `https://github.com/Conduction/openregister.git`, which would have 404'd inside the PHPUnit / Newman / Playwright legs even after the `uses:` fix. `.forgejo/workflows/` is deliberately untouched — on Codeberg the org really is `Conduction`, so those refs are correct.
Contributor
Quality Report — ConductionNL/openbuild @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ❌ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ❌ | ||||
| stylelint | ❌ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ❌ | ❌ | |||
| PHPUnit | ⏭️ | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ |
Quality workflow — 2026-08-01 07:55 UTC
Download the full PDF report from the workflow artifacts.
Every npm-based quality job (ESLint, Stylelint, License (npm), Security (npm)) died before running a single check: npm error `npm ci` can only install packages when your package.json and npm error package-lock.json ... are in sync. npm error Missing: pinia@4.0.2 from lock file npm error Missing: vite@8.2.0 from lock file ... + the whole esbuild/rolldown/lightningcss platform-binary fan-out Cause: `@nextcloud/vue` carries a nested `vue-router@5.2.0` whose `peerDependenciesMeta`-optional peers are `pinia: ^3.0.4 || ^4.0.2` and `vite: ^7.3.0 || ^8.0.0`. Those versions have since been published, so npm's ideal tree now includes them while the committed lockfile predates them. The lockfile was simply never regenerated — nobody noticed, because the workflow that would have caught it produced zero jobs. Regenerated with the npm major this repo pins (`engines.npm: ^10.0.0`) on Node 20. npm@11 must NOT be used here: it reports this lockfile as "up to date" and produces one that npm@10 `ci` then rejects. The diff is additive and does not touch the app's own dependency graph: - 0 packages removed - 0 nested version changes - 1 version change: @napi-rs/wasm-runtime 1.1.6 -> 1.2.2 (a wasm shim) - ~60 additions, all platform binaries pulled in by the optional peers above Vue, pinia (top-level 2.3.1), @nextcloud/vue and @conduction/nextcloud-vue are all unchanged, so the produced bundle — and the e2e runs verified against it — are unaffected. Fixed by resyncing rather than by `--legacy-peer-deps` or an `overrides` block: suppressing the resolution would leave the lockfile lying about the tree that `npm ci` actually builds.
Contributor
Quality Report — ConductionNL/openbuild @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ❌ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ❌ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ❌ 1/566 denied | |||
| PHPUnit | ⏭️ | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ |
❌ Denied npm licenses
| Package | Version | License |
|---|---|---|
| vue3-apexcharts | 1.10.0 | Custom: https://apexcharts.com/media/vue-apexcharts.png |
Quality workflow — 2026-08-01 08:01 UTC
Download the full PDF report from the workflow artifacts.
With the workflow refs and lockfile fixed, all 23 jobs actually run. This
clears what they found.
Stylelint (40 errors, was blocked behind `npm ci`)
`rule-empty-line-before` across ThemePickerDialog, WorkflowAttachmentDialog
and app.css. Applied the repo's own `stylelint-fix`.
PHPCS (14 errors)
Alignment, control-structure spacing and long-condition closing comments.
Applied the repo's own `phpcbf`, then hand-fixed the two it cannot:
an uncapitalised inline comment and a missing docblock on
`AppRepoParser::parseCompanionSchemas()`.
PHPStan — and the reason nobody saw these
`composer phpstan`, `psalm` and `phpmd` all ended in
`|| echo '<tool> not installed, skipping...'`, so they exited 0 no matter
what. The CI job for PHPStan reported SUCCESS on the previous run while the
log contained `[ERROR] Found 2 errors` and two `##[error]` annotations — a
gate that runs, finds real problems, and reports green. Dropped the
swallowing `|| echo` from phpstan and psalm. Both are now genuinely clean:
- AutomationCompilerService::apply() had a stray early `return $provenance;`
that orphaned the block below it. The dead half is where the load-bearing
"DO NOT tidy this back into `'ruleSetSlug' => $ruleSetSlug`" comment lives
— precisely the warning a future reader needed, stranded in unreachable
code. Behaviour was unaffected (both halves were identical); removed the
duplicate and kept the documented one.
- SetupController::runAction() applied `?? 0` to `$result['updated']`, which
the seeder's return shape guarantees is always a non-null int.
Psalm (2 errors)
`GenericHealthController` / `GenericMetricsController` are bound as string
class names in lazy closures and resolved at request time. psalm.xml already
carries a documented per-class allow-list for exactly these dynamically
loaded OpenRegister classes; these two were simply missing from it. Added
them there rather than suppressing at the call site.
Features Check
`docs/features.json` predated `openspec/features.overlay.json`, which the
extractor treats as the authoritative curated list. Regenerated.
NOT fixed — stated plainly rather than hidden
`composer phpmd` keeps its `|| echo` fallback. Removing it exposes 15
violations that the committed `phpmd.baseline.xml` does not cover
(TooManyMethods, ExcessiveClassComplexity, 3x CyclomaticComplexity,
ExcessiveMethodLength, ElseExpression, ...). Those need real refactoring of
GitHubAppSyncService / TemplateSeedService / IconService and should not ride
along in a CI-restoration PR. I did NOT regenerate the baseline to bury them.
The fallback message now says so out loud instead of claiming PHPMD is
"not installed". This is the top follow-up.
Contributor
Quality Report — ConductionNL/openbuild @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ❌ 1/566 denied | |||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ |
❌ Denied npm licenses
| Package | Version | License |
|---|---|---|
| vue3-apexcharts | 1.10.0 | Custom: https://apexcharts.com/media/vue-apexcharts.png |
Coverage: 89.4% (17/19 statements)
Quality workflow — 2026-08-01 08:43 UTC
Download the full PDF report from the workflow artifacts.
…prietary vue3-apexcharts
The revived licence gate caught a real exposure: `vue3-apexcharts` was MIT up
to and including 1.8.0, and at 1.9.0 (2025-10-13) moved to a proprietary
dual-license — free only under $2M USD annual revenue, forbidding
"sublicensing under different terms" (which is what redistributing inside an
EUPL-1.2 app is) and requiring a paid OEM licence for "No-code dashboards",
"Embedded BI tools" and "White-labeled apps or SDKs".
Not the same as the `apexcharts` entry in .license-overrides.json: that one is
a genuine license-checker misread of an MIT package, and the core
apexcharts@4.7.0 is still MIT. Only the Vue 3 wrapper changed licence. The
identical `Custom: <image-url>` symptom made them look alike.
The dependency is transitive through @conduction/nextcloud-vue, and the fix
already existed upstream:
2.1.0-vue3.7 -> vue3-apexcharts ~1.10.0 (proprietary)
2.1.0-vue3.13 -> vue3-apexcharts ~1.8.0 (MIT)
This repo declared `^2.1.0-vue3.7`. A caret does not move an already-resolved
prerelease in a lockfile, so the pin held us on the proprietary line even
though a fixed release had shipped. Now pinned EXACTLY, without a caret — a
caret floats prereleases, and that is how this drifted in the first place.
Verified from the lockfile rather than the manifest:
- node_modules/vue3-apexcharts: 1.10.0 -> 1.8.0
- exactly one copy in the tree; zero 1.9.0+ entries at any nesting depth
- installed package.json now declares `"license": "MIT"` (was
`"see LICENSE in LICENSE"`), which is what license-checker reads
No override was added. .license-overrides.json is unchanged and contains no
vue3-apexcharts entry — the gate passes because the dependency changed.
Lockfile churn is exactly two entries: the nc-vue bump and the apexcharts
downgrade. 0 additions, 0 removals, 0 nested version changes.
Contributor
Quality Report — ConductionNL/openbuild @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 659/659 | |||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ |
Coverage: 89.4% (17/19 statements)
Quality workflow — 2026-08-01 08:55 UTC
Download the full PDF report from the workflow artifacts.
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.
Restore CI: reusable-workflow refs pointed at a non-existent org for two months
The defect
All 8 reusable-workflow calls pointed at
Conduction/.github. That GitHub org does not exist —GET /orgs/Conductionreturns 404. The 2026-06-01 rename went the wrong way. Actions cannot resolve the ref, so every run produced ZERO jobs and failed instantly.Nothing has been linted, statically analysed, licence-scanned, security-scanned or unit-tested on this repo in two months.
The tell, before and after
In
gh run list --json name, an unresolved run'snameis the raw path; a resolved one shows the workflow's declaredname:.name.github/workflows/code-quality.ymlCode QualityVerified by API on the runs listed below, not inferred.
Also fixed
A 9th dead reference a
uses:-only grep misses. (openbuild only) Theadditional-appsinput clonedhttps://github.com/Conduction/openregister.git, which would still have 404'd inside the PHPUnit / Newman / Playwright legs after theuses:fix.Two workflows pinned a branch that does not exist. (launchpad only)
issue-triage.ymlandopenspec-sync.ymlused@feature/openspec-project-sync; that ref is absent fromConductionNL/.githubtoo, so an org-only fix would have left them broken. Both now use@main..forgejo/workflows/is deliberately untouched. On Codeberg the org really isConduction, so those refs are correct. Only the GitHub Actions ones were wrong.sync-to-beta.ymlDead purely from the org ref — now live. Unlike petstore, this repo has both
developmentandbeta, so the trigger branch and the target branch both exist. Expect it to start openingdevelopment -> betarelease PRs on the next push todevelopment. That is the intended behaviour; flagging it because it has not happened for two months.Lockfile: every npm job died before running a check
ESLint, Stylelint, License (npm) and Security (npm) all failed at
npm ci, not on findings:@nextcloud/vuecarries a nestedvue-router@5.2.0whose optional peers arepinia: ^3.0.4 || ^4.0.2andvite: ^7.3.0 || ^8.0.0. Those versions have since been published, so npm's ideal tree now includes them while the committed lockfile predates them.Regenerated with the npm major this repo pins (⚠️ npm@11 must not be used here — it reports this lockfile as "up to date" and writes one that npm@10
engines.npm: ^10.0.0).cirejects.The diff is additive and does not touch the app's own graph: 0 removed, 0 nested version changes, 1 version change (
@napi-rs/wasm-runtime1.1.6 → 1.2.2, a wasm shim), ~60 additions that are all platform binaries pulled in by those optional peers. Vue, pinia (top-level 2.3.1),@nextcloud/vueand@conduction/nextcloud-vueare unchanged, so the bundle — and the e2e runs verified against it — are unaffected.Fixed by resyncing rather than
--legacy-peer-depsor anoverridesblock: suppressing the resolution would leave the lockfile lying about the treenpm ciactually builds.✅ Licence exposure resolved:
vue3-apexchartsback on the MIT lineThe revived licence gate caught a real problem, and it is the most valuable thing this PR surfaced.
vue3-apexchartswas MIT up to and including 1.8.0. At 1.9.0 (2025-10-13) it moved to a proprietary dual-license:It is not the same as the
apexchartsentry already in the overrides file. That one is a genuine license-checker misread of an MIT package. The coreapexcharts@4.7.0is still MIT — only the Vue 3 wrapper changed licence. The identicalCustom: <image-url>symptom made it look like the same benign misreport. It is not.How it was fixed
It arrives transitively through
@conduction/nextcloud-vue, and the fix already existed upstream:vue3-apexcharts2.1.0-vue3.7~1.10.02.1.0-vue3.13~1.8.0This repo declared
^2.1.0-vue3.7. A caret does not move an already-resolved prerelease in a lockfile, so the pin held it on the proprietary line even though a fixed release had shipped.Bumped to
2.1.0-vue3.13, pinned exactly with no caret — a caret floats prereleases, and that is precisely how this drifted.Verified from the lockfile, not the manifest
@conduction/nextcloud-vue2.1.0-vue3.72.1.0-vue3.13node_modules/vue3-apexcharts1.9.0+copy anywhere in the treepackage.json.licensesee LICENSE in LICENSEMITChecked every lockfile entry whose path ends in
vue3-apexcharts, not just the top-level one — there is exactly one copy, at 1.8.0, with no nested survivors.No override was added.
.license-overrides.jsonis byte-for-byte unchanged and contains novue3-apexchartsentry. The gate goes green because the dependency changed.Lockfile churn for the bump is exactly two lines per repo —
@conduction/nextcloud-vueandvue3-apexcharts. 0 additions, 0 removals, 0 nested version changes.Fallout fixed (openbuild)
🔴 A second dead gate: three tools could never fail
composer phpstan,psalmandphpmdall ended in|| echo '<tool> not installed, skipping...', so they exited 0 regardless of findings. On the previous run the PHPStan job reported SUCCESS while its log contained[ERROR] Found 2 errorsplus two##[error]annotations. Even once the org ref was fixed, those three gates would have stayed decorative.Dropped the swallowing
|| echofrom phpstan and psalm, and made both genuinely clean. What they had been hiding:AutomationCompilerService::apply()had a stray earlyreturn $provenance;that orphaned the block below. The unreachable half is where the load-bearing "DO NOT tidy this back into'ruleSetSlug' => $ruleSetSlug" comment lives — precisely the warning a future reader needed, sitting in code that can never run. Behaviour was unaffected (both halves were identical); removed the duplicate, kept the documented one.SetupController::runAction()applied?? 0to$result['updated'], which the seeder's return shape guarantees is a non-null int.UndefinedClasserrors wereGenericHealthController/GenericMetricsController.psalm.xmlalready carries a documented per-class allow-list for exactly these dynamically-loaded OpenRegister classes; these two were just missing from it. Added there rather than suppressed at the call site.Not fixed, stated plainly
composer phpmdkeeps its|| echo. Removing it exposes 15 violations the committedphpmd.baseline.xmldoes not cover (TooManyMethods, ExcessiveClassComplexity, 3× CyclomaticComplexity, ExcessiveMethodLength, ElseExpression, …) inGitHubAppSyncService/TemplateSeedService/IconService. Those need real refactoring and should not ride along in a CI-restoration PR. I did not regenerate the baseline to bury them. The fallback message now says so out loud instead of claiming PHPMD is "not installed". Top follow-up.Final CI state
28 jobs, 0 failures. Fully green.
Local verification on this box: ESLint clean, Stylelint clean,
webpackcompiles (3 warnings, all pre-existing bundle-size advisories, 0 errors) against nc-vue vue3.13.npm run test(vitest) cannot run on this WSL box —@rollup/rollup-linux-x64-gnuneedsGLIBC_2.32and the host has 2.31. Not caused by anything here: that package is pinned at4.62.3identically onorigin/development, on the pre-bump commit, and on HEAD. It is also not a CI gate —frontend-checksis unset, soFrontend Checkis skipped.