You either die a hero... #710
No reviewers
Labels
No labels
accepted
bug
dependencies
docker
documentation
duplicate
enhancement
github-actions
github_actions
good first issue
gradle
hacktoberfest-accepted
help wanted
invalid
javascript
not-an-issue
npm
question
rejected
wontfix
Working on it
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Griefed/ServerPackCreator!710
Loading…
Reference in a new issue
No description provided.
Delete branch "develop"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A release failed on 2026-10-07 because the Windows app-image job existed twice, in `devbuild.yml` and in `release-build.yml`, with two different invocation shapes -- and only the rehearsed one worked. Everything here follows from that: the immediate breakages, then the structure that let one job drift from its twin, then a runner host that can be asked what went wrong. Verified by a real run: the Windows app-image builds. THE BREAKAGES - the Windows step wrote its output with a UTF-8 BOM. Forgejo parses `$GITHUB_OUTPUT` byte-wise, so the first key silently carried a BOM in its name and the value arrived empty at the consumer. - `-JarPath` then received that empty string and advised a Gradle build instead of failing, turning a broken hand-off into a confusing success. It now refuses an empty path. - the dev build shipped install4j media built at `version=dev` rather than at the build's own version, and died if the install4j installer was already absent. - `devbuild.yml`'s jar job was missing the Gradle setup every other job had. - the nightly published `main` as the dev build. THE STRUCTURE `artifacts-reusable.yml` is one definition of what a build produces: `jars` once, then `appimage`, `winimage` and `media` from those same bytes, fanned into `stage`. The contract is the `release-assets` artifact, so a caller has no collection step of its own to drift. `devbuild.yml` calls it. Not yet `release-build.yml` -- it still has its own `winimage` and `assets` jobs. The file header and claude-docs/WINDOWS-RUNNER.md both say otherwise and are wrong about it; that is the next piece of work, not a finished claim. Underneath, three composite actions remove the repeated job preamble (`setup-build`, version resolution, registry login), `test.yml`, `qodana.yml` and four more jobs take them, and a check fails the build when a workflow step is written twice. Five repeats survive and are documented as unshareable rather than left looking like oversights -- `secrets: inherit` is all-or-nothing on Forgejo, so `on.workflow_call.secrets` cannot narrow what a caller passes. Measured rather than assumed, in throwaway probes that are deleted again here: runs 987 and 988 answered how Forgejo propagates a failing job out of a reusable workflow, and that a workflow absent from the default branch is invisible to the dispatch menu but reachable by REST against an explicit ref. THE RUNNER HOST `misc/windows-runner/` replaces a `dockurr/windows` container with a libvirt domain. During run 1005 the app-image job sat in `git checkout` for 38 minutes with the container's own console unresponsive -- a stall below Windows, which the container offered no way to interrogate and `virsh domstate`, `domjobinfo` and `domblkstat` answer in seconds. `domain.xml` is the whole definition, validated against libvirt's RelaxNG schema, with the Windows 11 requirements that a hand-written file loses: q35 for SMM for Secure Boot, firmware auto-selection rather than a hardcoded OVMF path, an emulated TPM 2.0, suspend disabled because a sleeping runner is an offline runner with no error anywhere, and a NAT-only NIC so nothing outside the host can reach an unauthenticated runner. The guest agent channel makes it answerable when Windows is not. The job's checkout is sparse -- 182 files of 2570, where a full checkout is what hung -- and the runner binary is built in the guest, so the provisioning log names the commit that produced it. There is no published Forgejo runner binary for Windows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>`release-build.yml` kept its own `winimage` and `assets` jobs, so the "one definition" the shared workflow was built to be had two callers' worth of claims and one caller. Three places said otherwise and were wrong about it: the header of `artifacts-reusable.yml`, `claude-docs/WINDOWS-RUNNER.md`, and the commit that merged the branch. They are true now. `fix:` rather than `refactor:`, because behaviour changes on both paths. What a release does differently: - the Windows app-image is inside `release-assets` and therefore inside `checksum.txt`. It could not be before: `assets` wrote the checksums and `winimage` ran after it, so the artifact most worth verifying was the one file the checksum list did not cover. `stage` runs after `winimage`. - `winimage` no longer runs after `assets`, and byte-identity is kept rather than bought: the shared `jars` job builds once and every consumer takes that artifact, so the Windows image and the released jar are the same bytes with the two jobs in parallel instead of in series. - per-artifact `.sha256` files now ship on the release path too; they were dev-only. `updates.xml` and the API reference now ship on the dev path; they were release-only. One collection step, so the two sets cannot differ. - the plugin-jar count is checked on a release (it was dev-only), and the dokka zip is produced unconditionally instead of behind `if [ -d ... ]`, which failed open on every rehearsal and ran for the first time on release day. - `release`, `mirror` and `virustotal` no longer merge `winimage-*` in separately; it is already in `release-assets`. And on both paths: - the `media` job regains `-x :serverpackcreator-api:test -x :serverpackcreator-app:test`. The root build declares `tasks.register<Install4jTask>("media") { dependsOn(tasks.build) }`, so without them it re-runs the whole api and app suite that `jars` just skipped and `test.yml` already ran on the commit. release-build.yml's old `assets` job had the exclusions; `artifacts-reusable.yml` never did, so the dev build has been paying for a second full test run and the conversion would have put one on the release's critical path. `virustotal`'s comment claimed the Windows app-images are excluded by not being downloaded. They were not, and are not: the loop globs `*.jar *.sh *.dmg *.exe` and a `.zip` never matched it. The comment now says what actually excludes them. misc/ci-duplication-check.py went from 5 unexplained repeats to 0. Three disappeared with the duplicate jobs (`setup-install4j`, `Remove install4j script`, the `winimage-*` download), and the two that remain are allowlisted with the argument rather than silenced: both are one producer and three consumers of an artifact, and a step cannot be shared between jobs except through a composite action, whose files arrive only with a checkout -- which `mirror` and `virustotal` do not have and need nothing else from. NOTE, because it is a gap rather than a fix: nothing runs that check. It is in no workflow, which is why it was already red at HEAD and nobody knew. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>`npm update`, with no change to `package.json`. Every direct dependency sat at the exact FLOOR of its own caret range - axios 1.16.0 for `^1.16.0`, quasar 2.19.3 for `^2.19.3`, and so on - so the lockfile had never been refreshed since those ranges were written, and transitive dependencies had been frozen at whatever first resolved. This is the single highest-value commit of the sweep. Measured against npm's bulk advisory endpoint, before and after, over the lockfile's full resolved set: before 29 vulnerable packages, 83 advisories (4 critical, 45 high, 30 moderate, 4 low) after 8 vulnerable packages, 12 advisories (2 critical, 6 high, 3 moderate, 1 low) 71 of 83 advisories closed without editing a single declared range. Direct dependencies that moved, and what they fix: axios 1.16.0 -> 1.20.0 13 advisories (6 high, 7 moderate) quasar 2.19.3 -> 2.35.0 the CRITICAL unescaped-SSR-meta XSS, plus 2 more vue 3.5.35 -> 3.5.43 @vue/server-renderer XSS (needed >= 3.5.42) vue-i18n 11.1.12 -> 11.4.14 vue-router 4.6.3 -> 4.6.4 Plus 21 transitive packages, `brace-expansion` alone accounting for 16 of the closed advisories. What is left is deliberate, and three groups: - @quasar/app-vite 2.6.2 and its two @quasar/* children: `^2.4.0` cannot reach the fix, which needs > 3.2.0. Next commit. - vitest 3.2.7, @vitest/mocker, tinypool, esbuild: `^3.2.6` cannot reach the fix, which needs >= 4.1.11. The commit after that. - braces 3.0.3, reached through @intlify/unplugin-vue-i18n -> fast-glob -> micromatch. THIS ONE HAS NO FIX. The advisory covers <= 3.0.3 and 3.0.3 is the newest version published, so no amount of updating closes it; micromatch 4.0.8 still asks for ^3.0.3. It is build-time glob matching in a devDependency and has to be dismissed on the alert page rather than fixed here. Verified: 15 files / 37 tests, unchanged; `quasar build` succeeds. Noted while here, not fixed: npm reports all three options in `serverpackcreator-web-frontend/.npmrc` as unknown project config (`shamefully-hoist`, `strict-peer-dependencies`, `resolution-mode`). They are pnpm options in an npm project and have never done anything. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>`^2.4.0` cannot reach the fix: the advisories cover <= 3.2.0, so the range has to cross a major. Taking 3.10.2 rather than the 3.3.0 floor costs nothing extra - same major, same migration - and avoids repeating this in a month. Clears 6 of the 7 advisories that were left outside vitest: @quasar/app-vite 3 high + 1 moderate (dev TLS key permissions, SSR/SSG error page env disclosure, unsafe SSR nonce, recursive build cleanup) @quasar/render-ssr-error 1 high transitive, same disclosure @quasar/ssl-certificate 1 high transitive, same key permissions esbuild 1 low pulled forward by vite 8 Running total: 29 packages / 83 advisories at the start of this branch, 4 / 5 now. THE MIGRATION IS WIDER THAN THE BUMP, and all of it is forced: 1. `#q-app/wrappers` is gone. The wrappers moved to the package's own main export, so `defineConfig`, `defineBoot`, `defineRouter` and `defineStore` now come `from '@quasar/app-vite'`. Five files: `quasar.config.js`, both boot modules, the router and the store index. 2. `build.allowOutsideProjectDistDir` is now required. app-vite 3 refuses a dist directory outside the project, and this SPA is deliberately built straight into `serverpackcreator-app/src/main/resources/static` so the Spring app can serve it. The flag sits beside `distDir` with the reason, because the pairing is what makes either readable. 3. THE PATH ALIASES ARE RENAMED. app-vite 2 generated one alias per directory - `src/`, `boot/`, `stores/`, `components/`, `layouts/`, `pages/`, `assets/`. app-vite 3 generates exactly one, `@`, pointing at `src/`. That is not configuration this project chose; it is what `quasar prepare` writes into `.quasar/tsconfig.json`, which the root tsconfig does nothing but extend. 67 specifiers across 31 files, rewritten mechanically and verified by grep leaving no occurrence of the old scheme behind. Three forms needed separate handling, and the last two are why the suite went red in between: - `from`/`import()`/`vi.mock()` specifiers -> `@/...` - Quasar's `~assets/x` in .vue template attributes -> `~@/assets/x` - `url("assets/x")` in src/css/app.scss -> `url("@/assets/x")` The first pass caught only the first form, and the suite dropped from 37 tests to 23 - three files failing to resolve webp and svg imports that live in markup rather than in an import statement. That is the whole reason this branch asserts a test COUNT rather than a green tick. 4. `vitest.config.js` carried its own copy of the per-directory alias map. It is now the single `@` alias, so the test resolver and the app resolver cannot drift apart again. vue-tsc, ESLint and the comments in three test files all referred to the old scheme; the comments are corrected rather than left to rot, and the module's CLAUDE.md gains a short "Path aliases" section, because a newcomer writing an import now has no way to guess the convention from the surrounding code alone. Verified: 15 files / 37 tests, matching the pre-branch baseline exactly; `quasar build` succeeds; `vue-tsc --noEmit` clean; `eslint` clean. This is Dependabot PR #1296 and Renovate PR 705, both unmerged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>`^3.2.6` cannot reach the fix, which needs >= 4.1.11. Latest is 5.0.3, so this crosses two majors at once - taken deliberately, because the alternative is doing the same migration again shortly for the same reason. Clears the last four fixable advisories: tinypool 2 CRITICAL prototype-pollution gadgets to RCE in worker and run() options. vitest 5 drops the dependency outright, so the package is gone rather than bumped. @vitest/mocker 1 moderate path traversal / arbitrary file read vitest 1 moderate the same, through the mocker That takes this branch from 29 vulnerable packages / 83 advisories to 1 / 1. A PASSING TEST RUN IS NOT EVIDENCE FOR THIS PARTICULAR BUMP. A vitest major can change config shape or the default `include` glob so that zero tests run and the command still exits 0, which reads exactly like success. The repo's own rule covers it: a check that cannot run must skip, never pass. So two things were checked instead of one. First, the count. 15 files / 37 tests, byte-identical to the baseline taken before any commit on this branch - not merely "green". `vitest.config.js` keeps its explicit `include` and `setupFiles`, and both are still honoured. Second, that the assertions still bite. Two mutations were planted and the suite re-run: src/utils/format.ts BINARY_UNITS[0] 'B' -> 'WRONG' -> RED, `expected '0 WRONG' to be '0 B'`. The runner is genuinely executing assertions under 5.0.3, not collecting zero of them. DrawerLink.vue color="accent" -> color="MUTATED" -> GREEN, and that is a REAL FINDING, not a vitest problem. `test/components/DrawerLink.test.ts` asserts the icon's name but never its colour, so the component's colour is unguarded. The module's own CLAUDE.md records a bug where this prop was misspelled `colour=` and every drawer icon silently rendered in the default colour; the fix landed, a guard against it recurring did not. Fixed in the next commit, separately, because a test addition is not a dependency bump. Verified: 37/37 matching baseline; `quasar build` succeeds; `vue-tsc --noEmit` clean; `eslint` clean. This is Dependabot PR #1241 and Renovate PR 706, both unmerged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>Ten actions were behind, several by two majors. All of them now run on the node24 runtime, which is the substantive part: the node20-based releases they were pinned to are the ones GitHub is retiring. actions/checkout v6 -> v7 25 lines actions/setup-java v5 -> v6 6 actions/cache v5 -> v6 2 actions/github-script v7 -> v9 4 actions/setup-node v6 -> v7 1 peter-evans/create-pull-request v7 -> v8 1 docker/build-push-action v6 -> v7 5 docker/setup-qemu-action v3 -> v4 2 docker/setup-buildx-action v3 -> v4 2 docker/login-action v3 -> v4 2 DONE ACROSS BOTH TREES, and that is the point. Dependabot's `github-actions` entry is `directory: "/"`, which reaches `.github/workflows` and nothing else - so the 40 `uses:` lines under `.forgejo/` are watched by no bot at all and drift until somebody does this by hand. Which is why they were up to two majors behind while the `.github` copies were merely one. Every bump was checked before it was made, not after: for each action, the inputs this repository actually passes were parsed out of the workflows by indentation, then looked up in that major's own `action.yml`. All present, no removals - so nothing here is a silent behaviour change at the input level. `actions/setup-gradle@v6` and `actions/upload-artifact@v7` were already current and are untouched. Deliberately NOT bumped, each for a reason already recorded in the repo: - `code.forgejo.org/forgejo/upload-artifact@v5` (12 lines) and `download-artifact@v7` (10). The forks lag upstream on purpose; v5 and v7 are the newest majors the forks publish, and upstream's majors abort off github.com with GHESNotSupportedError. - `tiyee/action-ssh@v1.0.1`, `nogsantos/scp-deploy@v1.3.0`, `luangong/setup-install4j@v1`, `jmgilman/actions-generate-checksum@v1` - the four non-bare-major refs, each with a recorded reason. Version TAGS, not SHAs, per .claude/rules/ci-workflows.md - Griefed's explicit call, and this commit is the argument for it: ten actions had drifted a major or two behind, which is exactly the staleness an unrevisited SHA pin guarantees. Checked before committing: every target major is mirrored on data.forgejo.org, so the bare references under `.forgejo/` still resolve there; no stale reference of any bumped action remains anywhere; all 24 workflow files still parse as YAML. CI cannot be run locally, so the runtime proof is the next push. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>Renovate on git.griefed.de has been running against a config written for a version of Renovate that no longer exists, which is why it opened PR 708 against its own configuration. Three things in it were removed or renamed upstream: config:base renamed to config:recommended :enableGradleLite removed, along with the `gradle-lite` object it enabled matchPaths renamed to matchFileNames `gradle-lite` is the one that mattered. It was the whole Gradle half of Renovate's remit here, and it has not been a thing for some time - so Renovate has been managing npm and nothing else. Replaced with `gradle: { enabled: true }`, which is what the migration calls for. Two changes beyond Renovate's own diff: `baseBranches: ["develop"]`. Renovate had none, so it targeted the default branch - main. This project's convention is that PRs target develop and main is the release branch, so every Renovate PR has been aimed at the wrong branch since it was set up. All six currently open ones (703-708) are against main. The `packageRules` entry is dropped rather than migrated. It read `{ extends: "config:base", matchPaths: ["package.json"] }`, which extends an entire preset from inside a single rule and matches `package.json` at the repository root. There is no package.json at the root - the only one is `serverpackcreator-web-frontend/package.json` - so the rule matched nothing and would have been a no-op even if the path had been right. Renovate's migration carried it across mechanically; there is no reason to keep it. The five open dependency PRs are superseded by earlier commits on this branch: 703 (axios 1.20.0) and 704 (quasar 2.32.2) by the lockfile refresh, 705 (@quasar/app-vite v3) and 706 (vitest v4) by the two major bumps, 707 (pin dependencies) by declaring the two hoisted build plugins. They can be closed, or left for Renovate to retire on its next run against develop. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>