The compose buffer was passed through verbatim, so whatever the author last
pressed ended up in the payload — usually a trailing newline. That is not
content, but it becomes content the moment it is signed, and nothing
downstream can remove it without invalidating the signature.
smolboid refuses any post whose text carries a line break, because a published
record is one line of a feed, so every post sent from carrier was rejected
with "contains TAB, LF, CR or U+2028". Trimming has to happen here, before the
seal, rather than at the receiver: stripping is not invertible, so a receiver
that trimmed could no longer rebuild the bytes the author signed.
Reusing the linux job's binary (previous commit) doesn't work: it's
dynamically linked against ~100 libraries at absolute /nix/store
paths, including its own ELF interpreter, none of which exist inside
the Flatpak sandbox - confirmed locally via a real install+run
(execvp: No such file or directory). Reverted to building from source
inside flatpak-builder's sandbox via the rust-stable SDK extension,
same as the existing local `devbox run package` already does.
Also fixes two things needed for that in-sandbox build to work under
the forgejo-runner service (not an interactive session):
- appstreamcli (used by flatpak-builder to compose AppStream metadata)
wasn't on PATH - added as a devbox package (linux-only, like
gtk4/libadwaita) rather than a NixOS system package, keeping it
scoped to the project.
- rofiles-fuse's mount/unmount cycle fails under the service context
even though /dev/fuse itself is world-writable; --disable-rofiles-fuse
is flatpak-builder's own documented workaround for this.
Verified locally: full build, appstreamcli compose, bundle install,
and the installed binary actually executing inside the sandbox.
rofiles-fuse's mount/unmount cycle fails under the forgejo-runner
systemd service ("Permission denied" / "Operation not permitted" on
fusermount3) even though /dev/fuse itself is world-writable - services
don't get the same mount-namespace treatment an interactive session
does. --disable-rofiles-fuse is flatpak-builder's own documented
workaround for exactly this class of environment (containers/CI).
Missing --user (present on the existing package script, omitted here
by mistake) made flatpak-builder try to install missing deps
system-wide, which this unprivileged CI user can't authorize via
polkit: "Flatpak system operation GetRevokefsFd not allowed for user".
apfel is a laptop that's frequently asleep/offline; gating the release
on it (needs: [macos, linux, flatpak]) meant the whole release stalled
whenever it wasn't reachable. macos now appends its own asset directly
via the Forgejo API once it finishes, polling for the release that
linux+flatpak already created/overrode, instead of going through
actions/forgejo-release (which can only blind-create, not append to an
existing release).
Builds carrier-x86_64.flatpak from the linux job's already-built binary
rather than recompiling inside flatpak-builder's sandbox (which can't
see the shared cargo cache anyway, making an in-sandbox build pure
duplicate work). com.randogoth.carrier.release.json is a separate
manifest from the main one, which stays as-is for local
`devbox run package` dev-from-source builds.
actions/upload-artifact@v4 and download-artifact@v4 use GitHub's newer
Artifacts-v2 protocol, which Forgejo's server explicitly refuses
("not currently supported on GHES"). Forgejo maintains its own forks
(forgejo/upload-artifact@v5, forgejo/download-artifact@v7) with that
check disabled. Also drops archive: false, an input that fork doesn't
expose - the earlier binary rename already keeps filenames distinct
through the default zip/extract round-trip.
Builds macos-arm64 and linux-x86_64 release binaries in parallel and
uploads them as build artifacts; a single release job gated on both
then downloads and publishes them to one Forgejo release. Splitting it
this way avoids a real race in actions/forgejo-release itself: its
script always does a blind create-then-upload for the tag with no
merge path, so two parallel callers against the same tag either
hard-fail or stomp each other's uploaded assets.
Renamed macos.yml to ci.yml with two jobs (macos, linux) under one
push/PR/dispatch trigger, so both run from the same commit instead of
needing separate files. Cache keys are now OS-prefixed (cargo-macos-/
cargo-linux-): target/ artifacts are platform-specific and would
otherwise collide under a shared key.
Linux now gets gtk4/libadwaita declared as nix devbox packages (scoped
to linux platforms, with the dev output requested explicitly - nixpkgs
splits runtime libs from headers/pkgconfig, and devbox only installs
the default output unless told otherwise). macOS keeps using Homebrew's
build exactly as before (nixpkgs' GTK build is much rockier there).
PKG_CONFIG_PATH moved out of the static env block (which can't be
platform-conditional) into init_hook, which can branch on uname.
Verified building clean with 0 warnings on both this machine (Linux)
and apfel (macOS).
On Apple Silicon Macs, many GTK-related nixpkgs packages are marked as
unsupported on aarch64-darwin. Instead of using nixpkgs for the GUI stack,
use Homebrew which provides pre-built bottles for gtk4, libadwaita, and
all their dependencies (glib, pango, cairo, gdk-pixbuf, graphene, etc.).
The devbox config now provides only the Rust toolchain (rustc, cargo,
pkg-config, rustfmt) and sets environment variables to locate the
Homebrew-installed libraries:
- PKG_CONFIG_PATH: /opt/homebrew/lib/pkgconfig
- PKG_CONFIG_PATH_arm64_apple_darwin: /opt/homebrew/lib/pkgconfig
- PATH: Includes /opt/homebrew/bin and /opt/homebrew/sbin
This allows building the project with: devbox run build
All 16 tests pass with: devbox run check
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>