Wekan
Open source kanban board application built with Meteor
Alternative to: trello
v10.78
2026-08-09Binaries in these bundles
Each bundle carries a Node.js, a FerretDB and the MongoDB Database Tools. Which source has a given CPU varies from release to release - nodejs.org builds some architectures, unofficial-builds others, and the wekan/node-patches build the ones neither of them does - and not every source publishes a checksum. This is what went into this release, and which downloads were checked against a published SHA256.
| Bundle | Binary | From | Version | Checked | SHA256 |
|---|---|---|---|---|---|
| amd64 | FerretDB | wekan/FerretDB | v1.48.0 | verified | 2737687fd29a8a76… |
| amd64 | Node.js | nodejs.org | v24.19.0 | verified | 14b342e71204f811… |
| arm64 | FerretDB | wekan/FerretDB | v1.48.0 | verified | 5ae705dd49515a4e… |
| arm64 | Node.js | nodejs.org | v24.19.0 | verified | 01443c1e1a29e531… |
| armhf | FerretDB | wekan/FerretDB | v1.48.0 | verified | 2232872afa468a83… |
| armhf | Node.js | wekan/node-patches | v24.19.0 | verified | b55350f3071b765a… |
| armv7 | FerretDB | wekan/FerretDB | v1.48.0 | verified | 2232872afa468a83… |
| armv7 | Node.js | wekan/node-patches | v24.19.0 | verified | 8dbe0a9aa8550ad5… |
| i386 | FerretDB | wekan/FerretDB | v1.48.0 | verified | 63d7a9e5e2754cbf… |
| i386 | Node.js | wekan/node-patches | v24.19.0 | verified | 3b0b3bbfe27daf58… |
| mac-arm64 | FerretDB | wekan/FerretDB | v1.48.0 | verified | 9b15f4c10e473cd0… |
| mac-arm64 | Node.js | nodejs.org | v24.19.0 | verified | 3f1cf157479c1480… |
| ppc64le | FerretDB | wekan/FerretDB | v1.48.0 | verified | 0400cd6dfc3d10d9… |
| ppc64le | Node.js | nodejs.org | v24.19.0 | verified | c510c6ce12f07010… |
| riscv64 | FerretDB | wekan/FerretDB | v1.48.0 | verified | d37c35af988670b9… |
| riscv64 | Node.js | unofficial-builds.nodejs.org | v24.19.0 | verified | cd1f14af28121480… |
| s390x | FerretDB | wekan/FerretDB | v1.48.0 | verified | 6c7d61fbb8c79b2e… |
| s390x | Node.js | nodejs.org | v24.19.0 | verified | a4792e65962ffa0a… |
| win64 | FerretDB | wekan/FerretDB | v1.48.0 | verified | ea57e1bcd153b51d… |
| win64 | Node.js | nodejs.org | v24.19.0 | verified | 57f71ab3652e797d… |
A row saying no checksum published is not a failed check - it is a source that publishes nothing to check against. Those are the ones worth fixing at the source.
v10.78 2026-08-09 WeKan ® release
In short: the AppImage workflow. It built both AppImages, started them,
waited for WeKan to answer on port 8080, uploaded them as artifacts - and then
attached nothing to the release, because the job that does the attaching never
checks the repository out and its two gh calls were the only ones in the file
without --repo. Fixed, and the matrix grows from two architectures to
four: i686 and armhf are the other two an AppImage runtime exists for.
The Flatpak workflow had the same one-line bug and a second beside it - it
was attaching the ostree repository along with the bundles - and it stays at two
architectures, because a flatpak needs a published runtime and only x86_64 and
aarch64 have one. Beside that, the Docker images now carry full SLSA
provenance at every one of the four sites that pushes one, and a test pins
that every bundled binary - FerretDB, the MongoDB Database Tools, Node.js -
is still fetched as the NEWEST one everywhere it is fetched, which is what makes
those projects’ security fixes arrive without a commit here - and the table
below is that working: FerretDB v1.48.0 replaces v10.77’s v1.45.0 on every
platform, with no change in this repository, because latest now resolves to
it. That is the release carrying go1.25.11 and x/sys v0.46.0, which answers
the Go advisories a Quay scan reported against the v10.77 image. Node.js stays
v24.19.0, the newest 24.x. The rest of this release is the same theme - what a
build REPORTS versus what it did. The armhf snap failed three times on a
package name that has not existed since Ubuntu 24.04 renamed it, while the
message blamed a transient build-farm reset; three snaps that BUILT were
reported FAILED by the step that saves their logs; and the provenance table
printed every row twice, left amd64 out entirely, and gave six platforms the
version “latest”.
| Platform | Binary | From | Version | SHA256 |
|---|---|---|---|---|
| amd64 | Node.js | nodejs.org | v24.19.0 | 14b342e71204f811bde6153be8e04b62aef63c236fef92b55f9c83154b409647 |
| amd64 | FerretDB | wekan/FerretDB | v1.48.0 | 2737687fd29a8a761cd960e45f300b68cf7b4a87d50c4cc5280bcbd42b6aa163 |
| arm64 | Node.js | nodejs.org | v24.19.0 | 01443c1e1a29e531ccad5a46fefa6df490d2189c49f7955904aecdbb0fe86fdc |
| arm64 | FerretDB | wekan/FerretDB | v1.48.0 | 5ae705dd49515a4ecd4e295c3b9aa4f3b454fad78613ec60fb99316bd7c34e3f |
| loong64 | Node.js | unofficial-builds.nodejs.org | v24.19.0 | c24f224726f2d785bd18a1fd09f5e6d1fecf0269928451a60c5da9eac8e92e68 |
| loong64 | FerretDB | wekan/FerretDB | v1.48.0 | 06ec86263455a7b598d22a87df0e044ea73ab5a3b72e96ad12ebed03c1374ac2 |
| mac-arm64 | Node.js | nodejs.org | v24.19.0 | 3f1cf157479c1480352083105e13faf9d008ede98e7e157746b6df940d197b94 |
| mac-arm64 | FerretDB | wekan/FerretDB | v1.48.0 | 9b15f4c10e473cd0a2c4feb4cb43e18042bd60c7035ec66cab3cfbe13edaabab |
| mac-x64 | Node.js | nodejs.org | v24.19.0 | d35e95230f46f6f0751df497c56622c6735e05d5e1fb1630996a005b9d328fe4 |
| mac-x64 | FerretDB | wekan/FerretDB | v1.48.0 | 4e188246dfa33bccef4cdd86701bc498b037cb3e91f579ff0dccb93aa0ef03ad |
| ppc64le | Node.js | nodejs.org | v24.19.0 | c510c6ce12f07010f771e6edb22a3fe23f4f2e6f40b1ffd4941aed0646a0d8b3 |
| ppc64le | FerretDB | wekan/FerretDB | v1.48.0 | 0400cd6dfc3d10d987a0fe80d75baa86c03c19170770fa2e602c92d558c3cfa6 |
| riscv64 | Node.js | unofficial-builds.nodejs.org | v24.19.0 | cd1f14af2812148002f58b58a5f9af512a50e3b8e8c148e0db44019dcb68edfd |
| riscv64 | FerretDB | wekan/FerretDB | v1.48.0 | d37c35af988670b9ed182b8c5966c06a06362f6c6ace6aebd93ccdfa32c9a26b |
| s390x | Node.js | nodejs.org | v24.19.0 | a4792e65962ffa0af42627aacf1122a60c3c88dbf4e4184f06820d66f9da8ba4 |
| s390x | FerretDB | wekan/FerretDB | v1.48.0 | 6c7d61fbb8c79b2e8733be8f71910f710e8c5cd25208c451bdc513c8313b0340 |
| win64 | Node.js | nodejs.org | v24.19.0 | 57f71ab3652e797d84acddc79c81cc9ff1c6ddb2a1974cdb83f00fee9bff4c73 |
| win64 | FerretDB | wekan/FerretDB | v1.48.0 | ea57e1bcd153b51d2065ab01515b21ec05d8f615444c15603ab8158b8a661dd2 |
This release adds the following new features:
AppImage - which CPUs get one.
Build the other two architectures an AppImage runtime exists for. Thanks to xet7.
x86_64 and aarch64 become four, with i686 and armhf. That is the whole
set: an AppImage BEGINS with a runtime binary the kernel executes, and runtimes
exist for exactly those four. ppc64le, s390x, riscv64 and loong64 have
none, so they cannot have an AppImage however the job is written - they are
served by the bundle zip and the .deb, and the matrix now says so where somebody
would otherwise try.
The two are not equally safe and are not treated as though they were. i686
builds on the x86_64 runner, which runs 32-bit x86 natively: no emulation, no
multiarch, appimagetool-i686 runs as-is. armhf builds on the aarch64
runner, which runs 32-bit ARM only if the kernel has CONFIG_COMPAT and the
32-bit loader is installed - GitHub promises neither - so it is
continue-on-error, the same treatment TSC gives its emulated armhf job. It
cannot decide whether the other three reach the release.
The smoke test needed the distinction too. It starts the AppImage and waits for port 8080, which a 64-bit runner cannot do for a 32-bit build it cannot execute. A check that cannot RUN is not a failed check: when the binary will not execute at all AND it is not this machine’s architecture, it warns, says the AppImage is uploaded unchecked, and moves on. A build that DOES start and then does not answer still fails - that is the bug the step exists for.
Docker images - what an image records about how it was built.
Attach full build provenance at every site that pushes an image. Thanks to xet7.
BuildKit attaches MINIMAL provenance on its own, which is where the
unknown on unknown rows beside each real platform on quay.io come from - that
is the OCI marker for “not a runnable image”, so docker pull never selects
one. Minimal is a build id and a timestamp, which answers nothing anybody asks
of a supply chain. mode=max records what does: which commit, which base
image, which build arguments, which frontend.
The hazard is not getting it wrong once, it is that WeKan pushes images from
FOUR places - docker-publish.yml, two sites in release-all.yml, and
releases/docker-build.sh - and a fifth added later would silently fall back to
the default. So the test finds the call sites by searching the repository
instead of from a list, and fails when a pushing one lacks the flag.
SBOM stays off, deliberately: it enumerates every OS package and npm dependency, so the attestation grows from tens of kilobytes to megabytes per platform. Turning it on is a decision rather than a default to drift into.
The --load build in docker-build.sh must NOT ask for it - the docker
exporter cannot carry an attestation at all - and that is a test of its own, so
the flag is not added there by symmetry one day.
One more thing the test pins, because it was written the wrong way twice while
this was being done: a # comment sitting among a continued command’s
arguments. docker buildx build \ followed by a comment line comments out the
REST OF THE JOINED LINE, so the command becomes a bare docker buildx build
with every platform, tag and flag swallowed. bash -n accepts it - it is valid
syntax, just a different command - and a YAML run: block is a shell script,
which is where it happened the first time.
and fixes the following bugs:
The snap builds - what the Launchpad jobs build, and what they report.
libcurl4 does not exist on armhf, so name the package noble ships. Thanks to xet7.
The armhf snap failed all three attempts in v10.77 while s390x, ppc64el and riscv64 each built on attempt 1. The Launchpad build log says why, one line into the mongodb part:
Stage package not found in part 'mongodb': libcurl4.
Build failed
Ubuntu 24.04’s 64-bit time_t transition renamed the library, and libcurl4 is
not a real package on any architecture in noble - the binary is
libcurl4t64 everywhere. On the 64-bit architectures the renamed package keeps
the old name alive, Provides: libcurl4 (= 8.5.0-2ubuntu10), and the armhf
libcurl4t64 has no Provides line at all, because there the ABI really
changed. That is what makes this class of bug reach exactly one architecture -
which is also what makes it look like flakiness on that architecture.
It had already happened, to libssl3 and libgoogle-perftools4 in v10.71, and
the comment above this list describes it exactly; libcurl4 was the same
transition and was left behind. All fourteen stage-packages were checked against
the noble armhf main+universe indices this time, and it was the only one that
did not resolve.
The workflow’s own guidance made it worse. snapcraft ends a missing
stage-package as a Stopped build with no artifact, which from the outside is
indistinguishable from Launchpad cancelling a build, so the message offered “an
OOM in the Meteor npm install, or a transient build-farm reset - re-run” for a
failure that will never succeed on a re-run. The step now looks for that line
first, names the missing package, says it is not transient, explains the
Provides asymmetry, and gives the one-line archive query that checks a name.
Three good snaps were reported as FAILED by the step that saves their logs. Thanks to xet7.
s390x, ppc64el and riscv64 each printed “Remote build <arch> succeeded on
attempt 1” and downloaded their .snap - and each job then ended FAILED,
because the step that saves the build log could not upload it:
The path for one of the files in artifact is not valid:
/snapcraft-wekan-f82a93c2…_s390x_2026-08-09T11:39:05.txt.
Contains the following character: Colon :
snapcraft names a remote-build log after the recipe and an ISO timestamp, and
upload-artifact refuses a colon because NTFS cannot hold one. The colons
become dashes now, so the timestamp is kept rather than the name thrown away -
and the upload is continue-on-error, because a diagnostic upload must
never be able to fail the build it is diagnosing. The snap is the deliverable,
and the renaming is not the last thing that could ever make a log unuploadable.
The release notes - what the provenance table says each bundle carries.
Every row appeared twice, amd64 appeared not at all, and six platforms said "latest". Thanks to xet7.
Three things wrong at once in the v10.77 table, and every one of them silent - nothing errored, the table was simply not what it claimed to be.
Every row appeared twice. provenance-table.sh globbed
provenance/**/*.tsv provenance/*.tsv, and with globstar a **/ matches
zero or more directories, so the first pattern already covered the second
and every file was read twice. It is one pattern now, and rows are also
deduplicated on the WHOLE line - a retried step records an identical line and
nothing tells the copies apart. Deliberately not sort -u -k1,1 -k2,2: two rows
sharing a bundle and a binary but differing elsewhere are not a duplicate, they
are a real disagreement about which Node.js went into a bundle, and hiding one
at random is worse than showing both.
amd64 was missing - the platform most people download. Its step runs
cd .build before mkdir -p provenance, so the rows went to
.build/provenance while the upload looked at provenance/ from the workspace
root and found nothing. Every other build job records from the workspace root,
which is why only this one was affected. That turned out to be half the story;
the entry below is the other half.
Six platforms said Version latest. amd64, arm64, win64, win32, mac-arm64
and mac-x64 passed the literal string; only the extra-architecture job asked
what latest actually was, with its own inline curl. “Which FerretDB did
v10.77 ship” is the one question that column exists to answer. All seven sites
now call releases/ferretdb-latest-tag.sh, which asks once per job and caches,
authenticates when there is a token so a shared 60/hour limit is not what makes
it fail, checks the answer is shaped like a tag before printing it into a
markdown cell, and prints nothing and exits 0 when it cannot find out - a
release note must never fail a build that produced a good bundle.
The table’s prose also linked wekan/node; the binaries come from
wekan/node-patches, which is what the
rows themselves already linked.
The amd64 provenance scripts were never found, only never complained. Thanks to xet7.
The amd64 build failed with exit 127, after the bundle had been zipped and checksummed:
a95d331b… wekan-10.78-amd64.zip
bash: releases/record-provenance.sh: No such file or directory
bash: releases/ferretdb-latest-tag.sh: No such file or directory
The step runs cd .build first, so nothing relative in it means what it looks
like it means - and that is two bugs, of which only the second had ever been
visible. bash releases/record-provenance.sh resolves against .build/, which
has no releases/, so it had printed “No such file or directory” on every run
since it was written and the || true on the end swallowed it. amd64 had
therefore never recorded any provenance at all, and the only symptom was its
absence from the table - so the missing-directory fix above repaired the half
that showed and left the half that did not.
What made it loud is that the FerretDB tag lookup added alongside it is an
assignment. Under set -e, and every GitHub run: is bash -e,
VAR="$(cmd)" ends the step when the command fails - so a line that had been
quietly doing nothing for months became a hard failure of the whole amd64 build.
Every path in that step is absolute now, and every FERRET_TAG assignment
across all seven sites ends || true: the bundle is the deliverable, and which
version string reaches a markdown cell is not worth failing a good build for.
Only amd64’s step cds - the other six run from the workspace root, which is
exactly what the v10.77 run showed, since all six uploaded provenance and amd64
did not.
The guard added with it is the general form rather than this one line: it walks
back from every provenance call to its step header and requires an absolute path
whenever a cd runs inside that step.
The release upload - what reaches the release page.
Attach the built AppImages to the release again. Thanks to xet7.
Both AppImages built. Both passed the smoke test that starts them and waits for WeKan to answer. Both uploaded as artifacts, and both were downloaded by the attaching job with matching SHA256 digests. Then:
gh release upload 'v10.77' assets/* --clobber
failed to run git: fatal: not a git repository
That job does not check the repository out - it has no reason to, it only
downloads artifacts - so gh had no git remote to infer the repository from.
Every other gh call in the workflow already passed --repo; those two did
not.
Every call passes it now, including the ones in jobs that DO check out: a call
relying on an inferred remote breaks the day somebody removes the checkout, and
the error it gives names neither gh nor the workflow.
Worth recording for whoever reads that failed run, because the log looks far
worse than the bug: ::error:: lines appear in the build jobs for the
bundle-file check and the port check, and in the attaching job for “no
architecture produced an AppImage - every build job failed”. None of them fired.
They carry the escape codes of the ##[group] header - they are the SCRIPT
being echoed, not output - and a few lines below them ls -lh assets shows both
AppImages sitting there at 225M and 227M. One line in the whole run was a real
error.
Flatpak: attach the bundles to the release, and only the bundles. Thanks to xet7.
The same one-line bug as the AppImage workflow above, from the same cause: the
job that attaches the bundles does not check the repository out - it only
downloads artifacts - so gh had no git remote to infer the repository from and
gh release upload failed with “fatal: not a git repository”. Both flatpaks
had built and uploaded as artifacts; nothing reached the release. Every gh
call in that workflow passes --repo now too.
And a second one beside it: assets/* was not the bundles. The artifacts also
carry the ostree repository the flatpak was exported through - config,
objects/, refs/, summaries/, summary, summary.idx - which is build
scaffolding, and attaching it would have put a few hundred directories on the
release beside the two files anyone wants. The upload names the bundles and
their checksums instead.
No architectures could be added here, and the workflow header now says why
rather than leaving it to be rediscovered. A flatpak runs against a RUNTIME, not
the host’s libraries, so an architecture exists only if freedesktop.org
publishes org.freedesktop.Platform for it: x86_64 and aarch64, the i386 and
arm runtimes having been discontinued. That is the difference from the AppImage
work above, which could grow from two architectures to four - an AppImage
carries its own runtime binary, and those exist for i686 and armhf as well.
and has the following developer-facing change:
Bundled binaries - keeping “newest” true everywhere it is claimed.
Pin that every bundled binary is fetched as the newest one. Thanks to xet7.
WeKan ships binaries other projects publish - FerretDB, the MongoDB Database Tools, Node.js - and fetches each from a release URL. There are many such URLs, across workflows, release scripts and compose files, and they must all agree: one that names a fixed version stops receiving that project’s security fixes silently, and nothing about the build fails when it does.
That is not hypothetical. A Quay scan of the v10.77 image reported Go
advisories in the FerretDB binary baked into the bundle - stdlib 1.25.9
wanting 1.25.11, golang.org/x/sys v0.38.0 wanting 0.44.0. The source was
already fixed and v1.48.0 was already published carrying go1.25.11 and
x/sys v0.46.0; the image had simply captured an older latest at build time.
Had any of these URLs been pinned instead, the rebuild would not have fixed it
either.
The URLs are found by searching the repository rather than from a list, so a
build site added later is checked too, and three shapes are accepted:
latest/download/<asset>, the bare latest API endpoint that release-all.yml
asks which version latest resolved to so the provenance table can record it,
and ${VAR} whose default is separately asserted to be latest - that is
FERRETDB_RELEASE in the compose files, which an operator may pin for their own
reasons but which must not freeze everybody who does not.
Node.js is a different mechanism with the same effect, so it is pinned too:
NODE_VERSION is the bare major 24, and releases/resolve-node-source.sh
answers with that CPU’s newest 24.x from whichever of nodejs.org,
unofficial-builds or wekan/node-patches
has one.
What makes latest safe rather than merely convenient is the provenance table
above: rebuilding an old release would embed a different FerretDB than it
shipped with, and the only reason that is a trade rather than a hole is that
every release RECORDS the versions and SHA256s it actually shipped. So that is
asserted here as well - releases/record-provenance.sh exists, and the
CHANGELOG still carries the table it produces.
Thanks to above GitHub users for their contributions and translators for their translations.