Not stable yet. WolOS is in active development and the current ISO is a test build: try it in a virtual machine or on a spare disk, not on a computer you depend on.

WolOS
Manual contents

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 through lib 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 + optional wopkg_error, panics stopped at the boundary, callbacks with user_data on the calling thread. Requests and results are JSON documents (archicture/modules/wopkg.md); new fields are only added. libwopkg.so.1, symbols versioned by abi/wopkg.map (WOPKG_1.0), tests/abi.rs fails 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 order wolos > 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 Range into <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; .wol by wol_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, marked unsigned; recipes by an Ed25519-signed recipe index and pinned SHA-256 sources; AUR is marked unreviewed.
  • 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 call package.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) needs packages-unreviewed, which is a separate grant; wold copies the file into root-only staging before pacman -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 lockfile fetch step, build and install steps). Built in the offline sandbox, cached by the recipe's hash, installed into ~/.local. Official recipes live in wopkg/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 /etc files a build needs (no shadow, no keys). Sources are fetched with network (makepkg --verifysource, which also checks upstream PGP signatures when validpgpkeys is given); build() and package() run with no network, and a build that needs one fails with a sentence saying so. .SRCINFO is 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: SKIP on a downloaded (non-VCS) source is refused unless the person types yes; 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 .install scriptlets that run as the administrator.
  • Updates: wopkg aur update shows the diff of PKGBUILD and *.install since the installed commit; a changed maintainer or a new scriptlet needs the word yes. wopkg update never builds AUR packages and -y never answers an AUR question.
  • Built package: bsdtar -tv before pacman sees it: setuid/setgid, device files and files outside /usr, /etc, /opt, /var are refused; hooks and units are flagged; the .INSTALL script is shown and needs yes. One hook, AurHook.check(dir, artifact, trace), hands the package folder, the built file and a system-call trace (strace in the sandbox) to the wopkg-aurlaws analyser 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 .wol go through clamscan as a separate optional process (GPL, never linked); the xguard engine replaces it when it lands. Signed repository packages are not scanned. A hit stops the install with one sentence and needs a typed yes to 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-unreviewed grant 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 search 7-9 ms vs pacman -Ss 206-207 ms (firefox, "python numpy", gcc; mean of 30); info firefox 7.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 --check 0.51-0.56 s (index refresh, release plan, pacman -Qu) vs pacman -Sy + -Qu 0.69-0.71 s, three runs each.
  • 60 packages (57 MB), cold cache, three rounds: wopkg parallel fetch 1.6 s; pacman -Sw 14.3 s with ParallelDownloads=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), and install and update of 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.