Skip to content

ci: restore CI — reusable-workflow refs pointed at a non-existent org for two months - #74

Merged
rubenvdlinde merged 4 commits into
developmentfrom
ci/restore-shared-workflow-refs
Aug 1, 2026
Merged

ci: restore CI — reusable-workflow refs pointed at a non-existent org for two months#74
rubenvdlinde merged 4 commits into
developmentfrom
ci/restore-shared-workflow-refs

Conversation

@rubenvdlinde

@rubenvdlinde rubenvdlinde commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

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/Conduction returns 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's name is the raw path; a resolved one shows the workflow's declared name:.

run name jobs
before .github/workflows/code-quality.yml 0
after Code Quality 23

Verified by API on the runs listed below, not inferred.

Also fixed

A 9th dead reference a uses:-only grep misses. (openbuild only) The additional-apps input cloned https://github.com/Conduction/openregister.git, which would still have 404'd inside the PHPUnit / Newman / Playwright legs after the uses: fix.

Two workflows pinned a branch that does not exist. (launchpad only) issue-triage.yml and openspec-sync.yml used @feature/openspec-project-sync; that ref is absent from ConductionNL/.github too, so an org-only fix would have left them broken. Both now use @main.

.forgejo/workflows/ is deliberately untouched. On Codeberg the org really is Conduction, so those refs are correct. Only the GitHub Actions ones were wrong.

sync-to-beta.yml

Dead purely from the org ref — now live. Unlike petstore, this repo has both development and beta, so the trigger branch and the target branch both exist. Expect it to start opening development -> beta release PRs on the next push to development. 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:

npm error Missing: pinia@4.0.2 from lock file
npm error Missing: vite@8.2.0 from lock file

@nextcloud/vue carries a nested vue-router@5.2.0 whose 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.

Regenerated with the npm major this repo pins (engines.npm: ^10.0.0). ⚠️ npm@11 must not be used here — it reports this lockfile as "up to date" and writes one that npm@10 ci rejects.

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-runtime 1.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/vue and @conduction/nextcloud-vue are unchanged, so the bundle — and the e2e runs verified against it — are unaffected.

Fixed by resyncing rather than --legacy-peer-deps or an overrides block: suppressing the resolution would leave the lockfile lying about the tree npm ci actually builds.


✅ Licence exposure resolved: vue3-apexcharts back on the MIT line

The revived licence gate caught a real problem, and it is the most valuable thing this PR surfaced.

vue3-apexcharts was MIT up to and including 1.8.0. At 1.9.0 (2025-10-13) it moved to a proprietary dual-license:

  • Free only for orgs with < $2M USD annual revenue.
  • "Sublicensing under different terms" — which is what redistributing inside an EUPL-1.2 app is.
  • "Redistribution in toolkits, SDKs, or platforms".
  • A paid OEM/Redistribution licence is required for "No-code dashboards", "Embedded BI tools", "White-labeled apps or SDKs" — a list that describes LaunchPad and OpenBuild almost word for word.

It is not the same as the apexcharts entry already in the overrides file. That one is a genuine license-checker misread of an MIT package. The core apexcharts@4.7.0 is still MIT — only the Vue 3 wrapper changed licence. The identical Custom: <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:

nc-vue pins vue3-apexcharts
2.1.0-vue3.7 ~1.10.0 proprietary
2.1.0-vue3.13 ~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 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

before after
@conduction/nextcloud-vue 2.1.0-vue3.7 2.1.0-vue3.13
node_modules/vue3-apexcharts 1.10.0 1.8.0
any 1.9.0+ copy anywhere in the tree 0
installed on disk package.json.license see LICENSE in LICENSE MIT

Checked 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.json is byte-for-byte unchanged and contains no vue3-apexcharts entry. The gate goes green because the dependency changed.

Lockfile churn for the bump is exactly two lines per repo — @conduction/nextcloud-vue and vue3-apexcharts. 0 additions, 0 removals, 0 nested version changes.

Fallout fixed (openbuild)

Gate Before After
Stylelint 40 errors 0
PHPCS 14 errors 0
PHPStan 2 errors (reported green!) 0
Psalm 2 errors (reported green!) 0
ESLint clean clean
Features Check stale regenerated

🔴 A second dead gate: three tools could never fail

composer phpstan, psalm and phpmd all 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 errors plus two ##[error] annotations. Even once the org ref was fixed, those three gates would have stayed decorative.

Dropped the swallowing || echo from phpstan and psalm, and made both genuinely clean. What they had been hiding:

  • Dead code with the warning stranded inside it. AutomationCompilerService::apply() had a stray early return $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 ?? 0 to $result['updated'], which the seeder's return shape guarantees is a non-null int.
  • Psalm's 2 UndefinedClass errors were GenericHealthController / GenericMetricsController. psalm.xml already 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 phpmd keeps its || echo. Removing it exposes 15 violations the committed phpmd.baseline.xml does not cover (TooManyMethods, ExcessiveClassComplexity, 3× CyclomaticComplexity, ExcessiveMethodLength, ElseExpression, …) in GitHubAppSyncService / 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, webpack compiles (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-gnu needs GLIBC_2.32 and the host has 2.31. Not caused by anything here: that package is pinned at 4.62.3 identically on origin/development, on the pre-bump commit, and on HEAD. It is also not a CI gate — frontend-checks is unset, so Frontend Check is skipped.

…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.
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openbuild @ e080c99

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.
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openbuild @ b711f6d

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.
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openbuild @ 3fdc5e6

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.
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openbuild @ f884a28

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.

@rubenvdlinde
rubenvdlinde merged commit b35ce35 into development Aug 1, 2026
30 checks passed
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