Decisions
0021: wopkg
One package tool for every source, with a stable library behind it.
Status: accepted. Builds on 0011 (.wol), 0016 (pacman base), 0019 (mirrors), 0020 (libwol rules).
Context
apps reach a WolOS machine from pacman repos ([wolos], [wolos-cachy], Arch), Flathub, AppImages, the AUR and .wol files. Each has its own tool, search, update command and trust model, and AppImages have no updater at all. Changing the system needs root on a sealed system (layers, pending slot), but the person should not need sudo to install an app.
Decision
- Split:
libwopkg(Rust,crates/wopkg) holds what must be fast and safe: the search index, the downloader, signature and hash checks, AppImage delta updates, the transaction journal (atomic swap, rollback) and the bridge to wold.wopkg(Crystal,wopkg/) is the CLI and the orchestration: Flatpak and AUR drivers, recipes, the build sandbox. Crystal binds the library throughlib LibWopkg; the App Store (Rust) links the rlib. - ABI: ADR 0020's rules with prefix
wopkg_: opaque handles,_create/_release, UTF-8 with lengths,wopkg_status+ optionalwopkg_error, panics stopped at the boundary, callbacks withuser_dataon the calling thread. Requests and results are JSON documents (archicture/modules/wopkg.md); new fields are only added.libwopkg.so.1, symbols versioned byabi/wopkg.map(WOPKG_1.0),tests/abi.rsfails on any removed or changed symbol or declaration. - Index: one segment file per source (
~/.cache/wopkg/index/<source>.seg), memory-mapped, rebuilt only when its input's size, mtime or ETag changed. Search is a substring scan over a lowercase haystack, ranked (exact name, prefix, word, summary; then source orderwolos>wolos-cachy> Arch >.wol> Flathub > AppImage > recipes > AUR) and grouped into one result per app listing every source that has it. No SQLite: the index is a cache rebuilt from the sources, so it needs no schema, migrations or locking. - Downloads: HTTPS only (loopback HTTP only when a test sets it), parallel, resumed with
Rangeinto<dest>.part, checked against the expected size and SHA-256 before the rename. - Trust per source, never weaker than the source's own tool: pacman packages by pacman's keyring (pacman installs them); Flatpak remotes must have
gpg-verify=true;.wolbywol_core::package::verify(Ed25519, ADR 0011); AppImages by the embedded signature against the key pinned at first install, otherwise by the zsync SHA-1 fetched over TLS, markedunsigned; recipes by an Ed25519-signed recipe index and pinned SHA-256 sources; AUR is markedunreviewed. - Privilege: wopkg runs as the person. User installs (Flatpak
--user, AppImages in~/Applications, recipes in~/.local) need nothing. A system change is one wold portal callpackage.change(verb, names) checked against the consent grant for the verb (packages-install,packages-remove,packages-update; Settings > Privacy & Security). wold runs it through the sealed-system pacman (controller::pkg: live layer, pending slot for kernel/initramfs/init). A locally built package (AUR, recipe) needspackages-unreviewed, which is a separate grant; wold copies the file into root-only staging beforepacman -U. - AUR: the PKGBUILD and its diff against the last reviewed copy are shown before a build; sources are fetched in a bubblewrap sandbox with network,
build()/package()run in a second one without network, never as root. - Recipes:
recipe.toml(name, version, sources with SHA-256, optional lockfilefetchstep,buildandinstallsteps). Built in the offline sandbox, cached by the recipe's hash, installed into~/.local. Official recipes live inwopkg/recipes/and are published with a signed index. - History: every change is a journal line (
~/.local/state/wopkg/history.jsonl); AppImages keep the previous file, Flatpak the previous commit, the system its restore slot.
Consequences
.wol payloads are pacman packages (ADR 0011), so a .wol install is a system change through wold, not a user install. Grants name the executable, so packages-install for /usr/bin/wopkg covers every script that runs wopkg (ADR 0020). Crystal is a build dependency of wopkg only.
AUR hardening (every PKGBUILD and .install is hostile until read; wopkg/src/wopkg/aur_guard.cr, scan.cr, aur_hook.cr). No scanner catches everything: these checks raise flags in plain words and wopkg never says "safe".
- Sandbox: AUR steps use the strict bubblewrap profile: a throwaway user namespace where the build is uid 65534 (never root, never you),
--cap-drop ALL, no home, no session bus, no ssh agent, and only the few/etcfiles a build needs (no shadow, no keys). Sources are fetched with network (makepkg --verifysource, which also checks upstream PGP signatures whenvalidpgpkeysis given);build()andpackage()run with no network, and a build that needs one fails with a sentence saying so..SRCINFOis regenerated inside the sandbox; the one the AUR serves is not used. - Pins: the reviewed commit is recorded (
aur-provenance/<pkg>.json) and the checkout must still be exactly that commit, unedited, before the fetch and before the build. Checkouts with symbolic links are refused. Package metadata (maintainer, first submitted, votes) comes from the AUR RPC over TLS, never from the search dump. - Checksums:
SKIPon a downloaded (non-VCS) source is refused unless the person typesyes; md5/sha1-only sums, plain http and signing keys with no signature file are flagged. - Signals shown before the question: first-seen or young package, orphan, few votes, maintainer change (needs
yes), a source host unrelated to the project's page, link shorteners, paste sites, numeric addresses,curl | sh, base64, eval, writes outside$pkgdir,sudo, home folder access, systemd units, setuid, and.installscriptlets that run as the administrator. - Updates:
wopkg aur updateshows the diff ofPKGBUILDand*.installsince the installed commit; a changed maintainer or a new scriptlet needs the wordyes.wopkg updatenever builds AUR packages and-ynever answers an AUR question. - Built package:
bsdtar -tvbefore pacman sees it: setuid/setgid, device files and files outside/usr,/etc,/opt,/varare refused; hooks and units are flagged; the.INSTALLscript is shown and needsyes. One hook,AurHook.check(dir, artifact, trace), hands the package folder, the built file and a system-call trace (strace in the sandbox) to thewopkg-aurlawsanalyser and returns pass, flag or block with evidence; without it the result is "not checked", never "pass". Provenance (commit, source checksums, maintainer, build date, files) is written next to history. - Malware scan: AUR sources and built packages, AppImages, recipes and third-party
.wolgo throughclamscanas a separate optional process (GPL, never linked); thexguardengine replaces it when it lands. Signed repository packages are not scanned. A hit stops the install with one sentence and needs a typedyesto override; a missing or old (more than 7 days) signature database says so and is never reported as clean. Cost: about 7 s per scan to load signatures. - Consent: installing still goes through wold's
packages-unreviewedgrant and the same password as other admin actions. The App Store has AUR off by default.
Measured on a box nobody else used (c7i.4xlarge, 16 vCPU, Arch core/extra/multilib plus a 123k-package AUR dump and the AppImage/Flathub indexes; warm cache; Frankfurt mirror):
wopkg search7-9 ms vspacman -Ss206-207 ms (firefox, "python numpy", gcc; mean of 30);info firefox7.7 ms vs 199.6 ms.- Index: 142,075 records from 6 sources in 1.7 s cold, about 0.31 s when nothing changed.
wopkg update --check0.51-0.56 s (index refresh, release plan,pacman -Qu) vspacman -Sy+-Qu0.69-0.71 s, three runs each.- 60 packages (57 MB), cold cache, three rounds:
wopkgparallel fetch 1.6 s;pacman -Sw14.3 s withParallelDownloads=1, 5.1-5.5 s with 5 (the default), 2.8-2.9 s with 16. pacman's time includes its signature checks; the fetch checks size and SHA-256 only, so the pacman install that follows still verifies signatures. Not measured: paru (its install was refused by the sandbox policy), andinstallandupdateof apps end to end (system installs need wold on a sealed image; AppImage and Flatpak installs are covered by tests, not benchmarks).
Reference synced from wonderlandos/wolos docs/adr/0021-wopkg.md.