Skip to content

Packaging: one fix removes half of this list, and the rest is Linux #562

Description

@PathGao

@alecdotdev @LargeModGames

Markpad ships eleven artifacts across six channels, and the packaging issues open against them are not eleven separate problems. This is what they reduce to, what has already been fixed without needing anyone's decision, and the three things that are genuinely yours to decide.

Long evidence is folded into the <details> blocks. The top level is the part worth reading.


The whole problem in one table

Every channel has to answer three questions:

channel installs can update itself trusted by the OS
Windows *-setup.exe #334 #466
Windows portable .exe
Chocolatey
macOS .dmg #209 #505 #557
Linux AppImage ⚠️ #182 #498
Linux .deb
Linux .rpm
Linux snap 💀 dead since June

The third column is one cause, not four. Every ❌ there is the same missing thing — a code-signing identity. It accounts for five open issues and needs zero lines of code.

Once that column is green, everything left is Linux. The only exception in the list is #84 (custom install path on Windows), an ordinary feature request rather than part of this.

How many people are behind each row

GitHub publishes per-asset download counts. v2.7.2, three days after release:

Windows  x64 installer     540  ┐
         x64 portable      245  │  818 = 91%
         arm64 installer    17  │
         arm64 portable     16  ┘
macOS    universal.dmg      37  =  4%
Linux    AppImage           26  ┐
         .deb               15  │   44 =  5%
         .rpm                3  ┘

Chocolatey's feed reports 6–22 installs per version. The Snap Store publishes nothing — that is structural, and the snap section below explains why. The ratio holds across v2.7.0 and v2.7.1 too, so it is not an artefact of a three-day window.

These are downloads, not users, and they say nothing about who is already installed and updating in place. But the shape is stark enough to order the work:


1. Signing — @alecdotdev

One action, five issues, no code, and 91% of downloads on the Windows half. It is the highest-value item here by a wide margin and the only one nobody can implement without you.

Windows may be free. SignPath Foundation gives OSS projects free OV code signing through a managed pipeline. Their conditions: OSI-approved licence with no commercial dual-licensing, no proprietary components, actively maintained, already released in the form to be signed. Markpad appears to meet every line. Approval takes days to weeks.

The judgement call is not technical: artifacts would be signed on a third-party managed platform. That is the same class of question raised in #500 about what sits next to TAURI_SIGNING_PRIVATE_KEY.

macOS is $99/year and has history. In #209 you said you would look into the Apple Developer Program; I said not to take the cost on purely for cross-platform development, and that my own lapsed membership might be an option later. It is still needed, so that offer stands — but who the releasing identity is belongs to you, and I do not want to decide it by implementing it.

Why signing and not a workflow fix — the mechanism
macOS      ad-hoc signature, no Developer ID, not notarized
           → macOS cannot bind a persistent TCC grant to this identity
           → #209, #505, #557: the folder-permission prompt returns forever
           → Gatekeeper refuses first launch; the dialog offers only
             Cancel and Move to Trash

Windows    no Authenticode signature
           → SmartScreen "unrecognized app"
           → #334 "the windows installer has a trojan virus"
           → #466 VirusTotal heuristic on the portable exe

tauri.conf.json still carries "signingIdentity": null and "entitlements": null, and there is no notarization step. Neither symptom is reachable from application code or from CI.

The paid Windows alternative is Azure Trusted Signing at $9.99/month, but it is limited to verified US/CA/EU/UK businesses and self-employed individuals — identity validation is the gate rather than the price.

Until either lands, the release notes' "sign it yourself in Keychain Access" workaround (thanks @nashv, #209) is the ceiling, and it has to be redone after every update.

What I need: yes/no on applying to SignPath for Windows, and separately whether macOS signing is something you want to own, want me to explore with my own Developer ID, or want left documented as a known limitation.


2. Linux should have one channel that can update itself — @LargeModGames

Four Linux artifacts today: one is dead, two cannot update, one is structurally fragile. Adding more — AUR, Flatpak, winget — is the wrong instinct, because the channel count is the complexity. The target is one line that can update itself, plus the others being honest about what they are:

keep one          AppImage  or  Flatpak       ← pick one, not both
say the truth     .deb / .rpm: installs, does not auto-update
retire            snap

Keep it proportional while reading this: Linux is 5% of downloads, and within it the split is AppImage 26, .deb 15, .rpm 3 per release. The AppImage is already the channel most Linux users pick.

AppImage or Flatpak is the real question. AppImage self-updates but carries libraries that must come from the host, which is what #182 and #498 both were — fixed twice by hand, and CI can never catch the next one, because the runner's Mesa is the one the libraries were copied from. #498 had to be found by a user on Arch. Flatpak takes the graphics stack and WebKitGTK from the runtime, so that class of bug does not arise.

The honest summary of Flatpak, with the costs measured below: it would be a better-behaved AppImage, not a categorically safer package. The sandbox has to be opened up anyway for a file editor, and the in-app updater has to be patched out. That is still worth having — a better-behaved AppImage is exactly what #498 asked for — but it should not be sold as more.

Flatpak: what it costs, measured against a Tauri app already on Flathub

Read off flathub/in.cinny.Cinny — Cinny Desktop is Tauri v2 with both npm and cargo dependencies, the same shape as Markpad, and live on Flathub today — plus the Flathub requirements.

One-time

item size in Cinny's repo notes
manifest 3.0 KB runtime org.gnome.Platform 50, finish-args, build commands
appdata.xml 4.7 KB mandatory AppStream metainfo, must pass validation. Markpad has none
.desktop 0.4 KB must be named after the app ID
Flathub PR fork, new-pr branch, review rounds, then push access to our own flathub/<id> repo

The app ID has to be decided first. Flathub requires reverse-DNS on a domain we control, or a code-hosting prefix with at least four components. com.alecdotdev.markpad does not qualify unless alecdotdev.com is ours. Either dev.sftwr.Markpad (matches the existing website) or io.github.sftwrdotdev.Markpad (needs no domain). It becomes the desktop-file name, the metainfo ID and the Flathub URL, so it is worth picking once, deliberately.

Per release, and it is automatable. Flathub builds with no network access, so every npm and cargo dependency is vendored into the manifest: cargo-sources.json 331 KB, node-sources.json 1.27 MB, regenerated on every upstream release. Cinny automates it — a weekly cron in the Flathub repo runs flatpak-external-data-checker, re-runs the two generators, and opens a PR; automerge-flathubbot-prs: false keeps a human in the loop. Steady state is reviewing one bot PR per release, plus non-release maintenance: Cinny's log shows a GNOME 48→50 bump and three libvips bumps in three months.

Three costs specific to Markpad, which are what make the answer non-obvious:

  1. The in-app updater has to be disabled in the Flatpak build. /app is read-only in the sandbox. Cinny carries 0001-disable-tauri-updater.patch for exactly this. Flatpak would join .deb/.rpm/snap in "updates come from the channel".
  2. The sandbox is largely surrendered anyway. Cinny's manifest is candid: "Tauri does not yet support the Freedesktop.org File Transfer portal, so this is needed to support the drag and drop files"--filesystem=home; and Tauri writes <a download> targets straight into XDG_DOWNLOAD_DIR instead of using the File Chooser portal. Markpad opens arbitrary paths for a living and would need at least the same.
  3. Cinny ships x11-only--socket=wayland commented out, reason recorded: "Wayland has title bar color related issues."
The snap: dead since June, and that is worse than not having one

api.snapcraft.io for markpad: stable / amd64 / revision 15 / version 2.6.11 / released 2026-06-03. Six versions behind. The build has failed every time since:

Environment validation failed for part 'markpad': 'rustup' not found and part
'markpad' does not depend on a part named 'rust-deps' that would satisfy the
dependency.

That line is from the successful 2.7.2 run — continue-on-error turned it into a green check. #561 fixed the build and removed the swallowing.

Nobody reported it, and that is not evidence nobody is affected — it is what the failure looks like from outside:

no snap at all   →  user downloads .deb / AppImage, knows updates are manual
a dead snap      →  snapd checks daily and tells them they are current.
                    They do not have #463, #498, #544, #548, #546 — and they
                    have no reason to suspect it.

Auto-update is the only thing a snap buys over the .deb, and that is exactly what broke.

Cost, measured. On 2026-06-03, the last run where it built, the snap step took 16m31s of a 26m18s Linux job. Since it broke, the same job is 12m57s. snapcraft.yaml runs a full npm ci + cargo build --release inside LXD and reuses nothing from the Build Linux step above it — same binary, compiled twice.

Reach. snapd ships by default essentially only on Ubuntu; Fedora, Arch and openSUSE need it installed by hand, and Mint blocks it. Fit. The home interface does not cover hidden paths under $HOME, and removable-media is absent and would not auto-connect. We spent this cycle on macOS permission prompts; the snap builds a similar wall on Linux by design.

The Snap Store publishes no install counts, and that is structural rather than an oversight: .snap, snapd and the Snap Store are one vendor's stack and the store server is not open source, so there is no second place to look and no public API. Weekly active devices and installs-by-distro are in the snapcraft dashboard's Metrics tab, visible only to whoever holds SNAPCRAFT_STORE_CREDENTIALS. (Both other channels answered on the first try: GitHub exposes per-asset download counts, Chocolatey exposes them in its OData feed.)

For scale when reading that number: all four Linux channels together account for 44 GitHub downloads per release.

dashboard shows do this
three figures or more keep it. #561 already fixed the build; then add removable-media and stop recompiling
two figures or fewer retire it — but not by deleting the workflow. Existing installs would sit on 2.6.11 forever. It needs one last upload whose description points at the .deb/AppImage, and the sudo snap install markpad line removed from README and the release template

The tombstone is the only part of "drop it" that is real work, and the part that is easy to forget.

What I need: from @LargeModGames, AppImage or Flatpak, and whether you would want to hold a Flathub repo — "nobody wants to own it" is a fine answer, and better said now than after a Flathub PR is open. From @alecdotdev, roughly what the snapcraft dashboard says.


3. One more question, and two things that need nobody's permission — @alecdotdev

Would you want the release action itself reduced to one command? Today, cutting a release is: edit version in package.json, edit it again in src-tauri/Cargo.toml, commit, tag, push, then open Actions and dispatch the workflow. Six steps, two of which are the same fact written twice — scripts/releaseWorkflow.test.ts guards them against drifting, a test that exists because the drift is easy.

npm run release 2.7.3 would collapse five of the six. Two preferences I would want from you before writing it, because they are yours rather than facts:

  1. Should pushing a tag trigger the release build, or should dispatching stay manual? A tag trigger is fewer steps; a manual dispatch means an accidental tag push cannot start a release. I lean toward the tag trigger, since the actual gate is still clicking Publish on the draft — but you are the one who would be surprised by it.
  2. Should it touch the changelog? 2.7.3 release notes — what changed since 2.7.2 #556 suggests release notes are their own work. I would default to stopping at the version bump.

This is the only item here that pays off on every future release rather than once.

Not questions, just not done yet:


Already fixed, no decisions involved

#561 Chocolatey and the Snap Store are published from release: published, not from inside the build matrix. markpad-app 2.7.2 had been pushed at 15:37 UTC on 2026-08-07 by a run that then failed and produced no release. Both continue-on-errors removed; the snap build fixed (rust-deps)
#566 The workflow_dispatch recovery path stopped reporting a Chocolatey failure that meant nothing; README and RELEASING.md stopped telling .deb/.rpm users they get updates
#570#573 .deb, .rpm and snap installs were offered an update and then failed to install it — __TAURI_BUNDLE_TYPE is not patched into the Linux binary, so every Linux package took the AppImage install path. Now they are told where updates actually come from
#572, #574 CI: cargo caching, bounded to one set written on master, after the first attempt was measured saving two seconds

Summary

  1. Signing@alecdotdev. Five issues, two platforms, no code, 91% of downloads. Do this first even if nothing else happens.
  2. One Linux channel that updates itself@LargeModGames on AppImage-or-Flatpak; @alecdotdev on the snap number. 5% of downloads: keep it proportional.
  3. The release script@alecdotdev, two preferences above.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    awaiting decisionNeeds a product-direction call from the maintainer before work can startdependenciesPull requests that update a dependency file

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions