Files
punktfunk/clients/linux/build.rs
T
a87fbebc0a feat(client/linux): the client says whether it is current, and can update itself
`punktfunk-client --check-update` fetches the same Ed25519-signed per-channel
manifest the host trusts, works out how this client was installed, and reports
what — if anything — can be done about a newer build. `--apply-update` does the
part it owns. `--version` prints the CI-stamped build string, which is both what
the comparison needs and what a packaging gate can run the binary for.

The engine lives here rather than in the Decky plugin for two reasons: verifying
a signature needs crypto that Decky's embedded Python does not have, and the
plugin is not the only surface that wants the answer. Every UI becomes a caller,
exactly as it already is for --pair, --library and --list-hosts.

What is possible depends on the install, and the module refuses to pretend
otherwise. A flatpak is a per-user install its launcher can update. A .deb/.rpm/
pacman client goes through the packaged root helper — a fixed, parameterless
systemd oneshot polkit authorises for members of the punktfunk-update group, so
the request carries nothing an attacker could influence and the payload comes
from the distro's own signed repositories. A sysext, a nix profile or a source
build gets the command and nothing else: the signed sysext feed carries the HOST
image, so a client sysext has no feed to update from, and a button that can only
fail is worse than one honest line.

A failed check reports the failure. "Could not tell" rendering as "up to date"
is the one answer that must never happen.

The box's capabilities are probed once into a `Caps` struct so the routing rules
are a pure function of (install kind, caps) — all seven of them are tested
without a box, including that the kill switch beats every kind and that pacman
needs its own root-owned full-sysupgrade opt-in on top of the group.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 09:41:26 +02:00

30 lines
1.6 KiB
Rust

//! Compile the shell's embedded assets (`data/` — the host-card OS-mark symbolic icons)
//! into a gresource bundle, registered at startup via `gio::resources_register_include!`,
//! and stamp the build version the update check compares against.
fn main() {
// Build provenance, identical to the host's (crates/punktfunk-host/build.rs): the packaging
// jobs set PUNKTFUNK_BUILD_VERSION to the full package version (`0.23.0~ci10250.gab12cd34`
// on deb, `0.23.0-0.ci10250.g…` on rpm, …), a plain `cargo build` falls back to the crate
// version. This is what `--version` prints and what `--check-update` compares against the
// signed manifest — and the canary suffix is load-bearing there, because canary channels
// compare CI run numbers rather than patch fields (pf_update_check::version).
let version = std::env::var("PUNKTFUNK_BUILD_VERSION")
.ok()
.filter(|v| !v.trim().is_empty())
.unwrap_or_else(|| std::env::var("CARGO_PKG_VERSION").unwrap_or_else(|_| "unknown".into()));
println!("cargo:rustc-env=PUNKTFUNK_VERSION={version}");
println!("cargo:rerun-if-env-changed=PUNKTFUNK_BUILD_VERSION");
// Host cfg gate mirrors this crate's `#[cfg(target_os = "linux")]` modules: on any other
// host the crate compiles to an empty stub and `glib-compile-resources` may not exist.
#[cfg(target_os = "linux")]
if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("linux") {
glib_build_tools::compile_resources(
&["data"],
"data/resources.gresource.xml",
"punktfunk-client.gresource",
);
}
}