Skip to content

2.40.0: the Linux updater installs the right package, and every device links attachments the same way - #699

Open
adibhanna wants to merge 2 commits into
mainfrom
v2.40.0
Open

2.40.0: the Linux updater installs the right package, and every device links attachments the same way#699
adibhanna wants to merge 2 commits into
mainfrom
v2.40.0

Conversation

@adibhanna

@adibhanna adibhanna commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Opens the 2.40.0 cycle. Two fixes so far.


1. The Linux updater installs the package you actually run

Report (Kelv, Discord, CachyOS): "Install and Relaunch" asked for a root password and then ran dpkg -i, a Debian command that does not exist on Arch, so the updater never worked and every update had to be installed from a terminal by hand.

Cause, which is in the build. electron-builder stamps a package-type file into the install, and electron-updater reads it to decide which release asset to download and which installer to run. All five Linux targets are cut from one staging directory, they build concurrently (platformPackager.js:105-126; isAsyncSupported defaults true in core.js:49), and only the deb and rpm targets write that file (FpmTarget.js:117, supportsAutoUpdate at :234). A package ships whichever value a neighbour left behind.

Verified against the published 2.39.0 downloads:

asset stamp consequence
.pacman deb downloads the .deb and runs dpkg, the reported bug
.deb deb correct
.rpm rpm correct
.tar.gz none falls back to the AppImage updater, which self-disables

Fix. One file with several racing writers cannot be made reliable at build time, so the app stops trusting the stamp's contents and takes the format from /etc/os-release (ID, then ID_LIKE, which carries derivatives like CachyOS without enumerating them). The stamp is consulted for presence only, so an AppImage and an AUR or tarball install keep behaving exactly as they do today. A build-time hook was written first and dropped on purpose: with the targets racing over one file it is only usually right, and "usually" is what shipped this bug. As a backstop, an update whose format contradicts the system never reaches pkexec.

Arch users on 2.39.0 or earlier carry the wrong stamp already, so 2.40.0 needs one last manual sudo pacman -U; after that it installs itself.


2. Every device links an attached file the same way

Attaching or dropping a file wrote a different link depending on where you did it. Paste, and an existing asset dragged from the sidebar, embedded a vault-relative wikilink; a drop wrote a note-relative markdown link ![pic](<../assets/pic.png>); the self-hosted server produced that same note-relative form for the web client; and the mobile apps had a third answer. Same file, same folder, three different links.

The note-relative form was also wrong, not merely different: nothing rewrites relative asset paths when a note moves, so ../assets/pic.png broke the moment the note changed depth.

One rule now, everywhere: the file lands in assets/ and is linked by vault-relative path, an image as ![[assets/pic.png]] and anything else as [name](<assets/report.pdf>).

route before now
Desktop paste wikilink unchanged
Desktop drag existing asset wikilink unchanged
Desktop drop / attach ![alt](<../assets/x>) wikilink
Web paste wikilink unchanged
Web drop (via server) note-relative link wikilink
Go server import note-relative link wikilink
Mobile paste, both vault kinds wikilink unchanged
Mobile attach, local vault vault root + ../ link wikilink

Existing notes are unaffected: resolveAssetVaultRelativePath tries note-relative, then vault-root, then a unique basename, so both the old and the new form keep resolving on both rendering surfaces.

The mobile half ships separately, in ZenNotes/zennotesandroid#41 and ZenNotes/zennotesios#15, which also fix corrupted attachment uploads to a self-hosted server.


Verification

  • npm run typecheck clean; 1513 + 1825 + 651 tests pass
  • cd apps/server && go vet ./... && go test ./... clean, with a new test pinning the image form at three note depths
  • npm run pack, then the packaged macOS app launched over CDP with an isolated vault and config: page target in 3s, renderer mounted, clean log
  • Not exercisable here: no Linux machine on this host, so the pacman install has not been run end to end

Note for the reviewer

apps/desktop/src/main/updater.ts has further uncommitted refinements in my working tree that are not in this branch (an isOfficialLinuxSystemPackage path check for the /opt/ZenNotes layout, which closes the case where the racing stamp leaks into the tar.gz that AUR repackages). They look right but are not mine, so I left them out. Separately, electron-builder has been bumped to 26.0.1 locally, which prior notes record as blocked by an upstream OOM during packaging; that is also excluded from this branch.

On Arch, "Install and Relaunch" asked for a root password and then ran
`dpkg -i`, a Debian command that does not exist there, so the in-app
updater never worked and every update had to be fetched and installed
from a terminal by hand. Reported on Discord by Kelv, on CachyOS.

The cause is in the build, not the app. electron-builder stamps a
`package-type` file into the install, and electron-updater reads it to
decide which release asset to download and which installer to run. All
five Linux targets are cut from ONE staging directory, they build
concurrently (isAsyncSupported defaults to true), and only the deb and
rpm targets write that file, so a package ships whichever value a
neighbour happened to leave behind. Confirmed against the published
2.39.0 downloads: the .pacman carried `deb`, while the .deb and .rpm
were correct. One file and several racing writers cannot be fixed at
build time, so this stops trusting the stamp's contents.

The format now comes from the running system: /etc/os-release ID, then
ID_LIKE, which is what carries the derivatives (CachyOS declares
ID_LIKE=arch) we would otherwise have to enumerate one by one. The stamp
is still consulted, but only for whether it exists, because that is the
one true thing it says: only a ZenNotes system package carries it. An
AppImage and an AUR or tarball install have none and are deliberately
left exactly as they were, updating in userspace and through their own
package manager respectively. An unrecognized distro changes nothing.

A build-time fix was written first and dropped on purpose: a hook can
stamp each package as it is built, but with the targets racing over one
file it is only usually right, and "usually" is what shipped this bug.

As a backstop, an update whose format contradicts the system no longer
reaches pkexec. Instead of a root prompt for a command the machine does
not have, ZenNotes names the package it needs and links the download.

Arch users on 2.39.0 or earlier carry the wrong stamp in the copy they
already have, so this one still needs a manual install; from here it
installs itself.

Not exercisable on the release host (no Linux machine): the decision and
the guard are unit-tested, and the packaged macOS build was launch
checked over CDP, but the pacman install has not been run end to end.

Claude-Session: https://claude.ai/code/session_01AYTRixg5TJmxn2j6FCqfUD
/** The updater matching what this machine actually runs, rather than the one
* electron-updater chose from the stamp when the module was loaded. */
function linuxUpdater(): AppUpdater {
let format: LinuxPackageFormat = 'unknown'
Attaching or dropping a file wrote a different link depending on which
surface you did it from. Paste, and an existing asset dragged in from the
sidebar, embedded a vault-relative wikilink; a drop wrote a markdown link
with a path relative to the note, `![pic](<../assets/pic.png>)`, and the
self-hosted server produced that same note-relative form for the web
client. The mobile apps had a third answer again. Same file, same folder,
three different links.

The note-relative form was also wrong, not merely different: nothing
rewrites relative asset paths when a note moves, so `../assets/pic.png`
broke the moment the note changed depth.

So there is now one rule, everywhere: the file lands in `assets/` and is
linked by VAULT-relative path, an image as `![[assets/pic.png]]` and
anything else as `[name](<assets/report.pdf>)`. That is what paste and
the sidebar drag already wrote, so this moves the odd routes onto the
form the app already used most.

Existing notes are unaffected: resolveAssetVaultRelativePath tries
note-relative, then vault-root, then a unique basename, so both the old
and the new form keep resolving on both rendering surfaces.

`ImportAsset` no longer reads notePath, since where the note lives can no
longer change what is written; it stays in the signature because the
handler and clients still send it. The matching mobile fixes ship in the
zennotesandroid and zennotesios repos.

Claude-Session: https://claude.ai/code/session_01AYTRixg5TJmxn2j6FCqfUD
@adibhanna adibhanna changed the title Fix(updater): a Linux update installs the package you actually run 2.40.0: the Linux updater installs the right package, and every device links attachments the same way Aug 29, 2026
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.

2 participants