Commit graph

11 commits

Author SHA1 Message Date
Trevon
d398556ee5
fix(tests): replace frozen expectations and harden release gates (#323)
* test(search,daemon,storage): assert behaviour instead of frozen literals

Several suites encoded exact internal values that legitimate tuning and
ranking changes are allowed to move: SCIENTIFIC-era profile weights and
rrfK values, corpus-statistic figures, and hardcoded timeout/cancellation
numbers. They failed on every platform after those changes landed, so the
real behaviour regressions they should catch were hidden behind noise.

Replace the frozen literals with contract assertions: weights are finite,
non-negative and normalize, state selection still holds, capability-gated
sources stay zeroed, and hybrid results keep matching canonical hash/path
sets. Deadlines are not widened and the daemon paths they cover are
unchanged.

Also add independent corpus and adapter oracles, deterministic collector
cancellation and late-result gates, and synchronize ServiceManager
shutdown observation, so the tests fail for the behaviour they name.

The portability allowlist keeps its two reviewed raw test-env reads; only
their line numbers moved.

Signed-off-by: trvon <git@trevon.dev>

* ci(tests): summarise Meson failures without flooding the log

A failing test run printed the whole Meson suite output, so the actual
failing test names and their assertion messages were buried and the
uploaded logs were dominated by passing-test chatter.

Add a bounded reporter that extracts the failing test names plus their
surrounding diagnostics, keeps an overall cap on emitted lines, and is
unit-tested against representative Meson output. Wire it into the Tests
workflow so failures stay readable.

Signed-off-by: trvon <git@trevon.dev>

* build(deb): validate candidate identity, mapping and upgrade ordering

The Debian packaging scripts took filenames and versions on trust, so a
misnamed candidate or a wrong package ordering could pass validation while
the real install path was never exercised.

Fail closed on candidate identity, version and architecture, verify the
package-to-source mapping, seed the legacy-only layout, wait on the actual
services, and assert install/upgrade/remove ordering for both Debian and
RPM in an offline container. Cases that cannot be proven on a host are
reported as skipped rather than silently passing.

Signed-off-by: trvon <git@trevon.dev>

---------

Signed-off-by: trvon <git@trevon.dev>
2026-10-19 19:16:57 -06:00
trvon
c4f0ce4338
ci(packaging): probe the bundled ONNX Runtime with a separate user
Switching the main test user's embedding backend to onnxruntime (no
model installed) and back left state behind that the later phases then
tripped over. Probe the runtime with a third user whose own config
enables plugin autoload with the auto backend (config_version = 3 so
the daemon does not migrate it to the simeon default), and keep the main
user on yams init's configuration throughout.

Signed-off-by: trvon <me@trevon.dev>
2026-10-02 10:12:02 -06:00
trvon
c1483e4478
ci(packaging): make the user-unit checks match real sessions
First runs of the user-unit validation on all four lanes found harness
gaps, fixed here:

- Arch's `su -` does not run pam_systemd, so the login shell had no
  XDG_RUNTIME_DIR and the CLI looked for /tmp/yams-daemon-<uid>.sock;
  the checks now provide the runtime dir a real login session gets and
  report whether su set it.
- Ubuntu 24.04's systemctl --user needs the user D-Bus bus: the
  Debian/Ubuntu lane image gains dbus-user-session (standard on real
  installs) and the checks pass the bus address when present.
- CLI commands fall back to an in-process daemon instead of spawning
  one, so the lifecycle check uses `yams daemon start` (which starts the
  unit) rather than expecting an ordinary command to start it.
- `yams init`'s default embedder is the built-in simeon backend, which
  skips the onnx model provider by design. The onnx phase now checks
  that init's config autoloads plugins, then switches [embeddings]
  backend to onnxruntime to prove the bundled runtime loads (from the
  user journal), and restores init's config so the later phases run the
  user's real configuration.

docs/install.md no longer claims ordinary CLI commands start the unit:
`yams daemon start` and on-demand starters do.

Signed-off-by: trvon <me@trevon.dev>
2026-10-02 09:18:38 -06:00
trvon
e0b0b575e2
ci(packaging): validate the systemd user unit in every lane
The package validation now exercises the per-user service:

- service: the user unit and user preset are installed, the unit is
  enabled for all users (systemctl --global), no system unit remains,
  and the unit does not hide the user's home or /tmp.
- user: a normal user with lingering gets a user manager; the unit is
  enabled and active without a manual start and `systemd-analyze --user
  verify` is clean; the socket is in $XDG_RUNTIME_DIR and owned by the
  user; through a login shell with no YAMS_* variables the CLI reports
  status, adds from $HOME and /tmp, searches, stores in
  ~/.local/share/yams and logs to ~/.local/state/yams, and the only
  daemon is the unit's MainPID; `yams daemon stop`, CLI auto-start and
  `yams daemon restart` go through systemd; `yams daemon install --user`
  enables the packaged unit without writing an override; a second user
  cannot reach the first one's daemon.
- onnx: after `yams init` the restarted user daemon logs "Using bundled
  ONNX Runtime" and `yams plugin health` lists the onnx plugin.
- persist: with lingering the user's daemon is back after a reboot with
  the data intact.
- upgrade from 0.20.3: the old system unit is stopped, removed and
  leaves no enablement links, /var/lib/yams is left alone, the user unit
  is enabled for all users and the user's daemon and CLI work.
- remove: running user daemons are stopped, global enablement is gone,
  no daemon process is left, user corpora survive (deb: also purge).
- minimal: bare base images still install with declared dependencies
  only; the account checks are gone with the yams account.

The Fedora lane image replaces the systemd-user PAM stack, which cannot
run in a container (unix_chkpwd, pam_selinux, pam_loginuid), with a
minimal one that still runs pam_systemd, so user@.service starts.

Signed-off-by: trvon <me@trevon.dev>
2026-10-02 08:30:55 -06:00
trvon
ca1710fdcc
fix(packaging): give the system daemon an /etc configuration file
The packaged service had no configuration file it would read: with
HOME=/var/lib/yams it looked for /var/lib/yams/.config/yams/config.toml,
which nothing creates. Plugins load only with [daemon]
auto_load_plugins = true, so the onnx and glint plugins and the bundled
ONNX Runtime shipped in the packages were never used by the service
("No plugins loaded"), and an administrator had no obvious place to turn
them on.

The unit now sets YAMS_CONFIG=/etc/yams/config.toml (the package ships
no file; ProtectSystem=strict leaves /etc readable). With
auto_load_plugins = true there, the sandboxed daemon loads all three
plugins and logs "Using bundled ONNX Runtime 1.23.0 from
/usr/lib/yams/onnxruntime/libonnxruntime.so.1 (no system copy found)",
ready=true. docs/install.md describes the file and how to check which
runtime was loaded; the validation's onnx phase writes it, restarts the
unit and checks the bundled runtime and plugin health.

Signed-off-by: trvon <me@trevon.dev>
2026-10-02 00:57:34 -06:00
trvon
2cd2ff68e3
ci(packaging): validate on bare base images and check the bundled ONNX Runtime
The lane images boot systemd and carry the tools the checks use, so
systemd-sysusers always existed and the deb postinst's broken `adduser`
fallback was never exercised.

Each lane now also installs the package in the raw distro image
(debian:trixie-slim, ubuntu:24.04, fedora:42, the Arch base) with no
systemd running and nothing preinstalled, so only declared dependencies
are present. It checks that the install finishes (deb: dpkg status
"install ok installed", not half-configured), that the yams account and
group exist, and that `yams add` + `yams search` work without the
service.

A new onnx phase checks, on the systemd lane, that the package ships the
private runtime in <libdir>/yams/onnxruntime and the onnx plugin, that
the system daemon logs "Using bundled ONNX Runtime", and that
`yams plugin health` lists the onnx plugin.

Signed-off-by: trvon <me@trevon.dev>
2026-10-02 00:01:55 -06:00
trvon
6e25a8b90f
ci(packaging): allow the bundled ONNX Runtime in package validation
Packages now carry the private fallback ONNX Runtime in
/usr/lib/yams/onnxruntime/ (libonnxruntime.so -> .so.1 -> .so.1.x.y and
libonnxruntime_providers_shared.so). Without an allowlist entry the
layout check rejects them as unreviewed paths. The pattern admits only
those library names under that directory.

Signed-off-by: trvon <me@trevon.dev>
2026-10-01 22:42:44 -06:00
trvon
4563f92d55
ci(packaging): allow private libraries under lib/yams in package validation
The install-surface cleanup moved libyams_onnx_resource from /usr/lib to
/usr/lib/yams, matching scripts/ci/install_surface_policy.json. The
package validation allowlist only accepted libyams_* directly in the
library directory and would have failed every lane; accept both, and
nested paths under /usr/share/doc/yams like the policy does.

Signed-off-by: trvon <me@trevon.dev>
2026-10-01 21:16:29 -06:00
trvon
7ef6cc9366
ci(packaging): make the per-user service and reboot checks host-robust
x86_64 runs on a loaded host showed three harness problems:

- The Debian/Ubuntu and Fedora lane images lacked pam_systemd, so
  user@.service could not start and `yams daemon install --user` looked
  broken. Install libpam-systemd / systemd-pam. Where a host still
  cannot start a user manager in a container, the check reports INFO
  instead of failing, since that says nothing about yams.
- `systemctl --user -M user@` needs machined; query the user manager as
  that user instead. The "CLI uses its unit" check now also requires that
  the only daemon running for the user is the unit's MainPID, so a
  CLI-spawned second daemon no longer passes.
- A container reboot can sit in 'starting' past 60 s under load; wait up
  to three minutes and print pending jobs if it still does not boot.

Signed-off-by: trvon <me@trevon.dev>
2026-10-01 21:11:34 -06:00
trvon
25114dadc7
ci(packaging): harden package validation from its first real runs
Running the gate against v0.20.3 and branch packages on Debian, Ubuntu,
Fedora and Arch showed harness gaps, fixed here:

- The driver ran only under bash 4+ (mapfile, empty arrays under set -u);
  it now works with macOS's bash 3.2 so it runs on Docker Desktop too.
- Paths dropped by the image's dpkg path-exclude (docs) or rpm nodocs
  no longer fail the permission check, and rpm's /usr/lib/.build-id links
  and the package doc/license directories are on the allowlist.
- The upgrade check pins the system socket, so it measures whether the
  corpus survived rather than whether an older CLI can discover it.
- Debian keeps enablement links until purge, so for deb the dangling-link
  check runs after purge.
- New per-user service check: `yams daemon install --user` beside the
  system unit starts a working user unit, and that user's CLI uses it.

The unit comment and install guide now describe the socket as group
read/write with no access for others (the daemon sets owner rwx, group
rw), rather than a literal 0660.

Signed-off-by: trvon <me@trevon.dev>
2026-10-01 21:11:27 -06:00
trvon
53f0061d31
ci(release): gate packages on a real systemd install, CLI and upgrade run
The old package-validate.sh only checked that the unit came up and that
`yams daemon status` answered with YAMS_DAEMON_SOCKET set by hand, so it
passed while nobody's CLI ever reached the system daemon, the socket was
world-writable and `yams add ~/file` failed.

package-validate.sh stays the single entry point (same --only/--deb/
--rpm/--arch flags the workflow uses) and now drives
package-validate-checks.sh inside Debian, Ubuntu, Fedora and Arch
containers booted with systemd as PID 1 (private cgroup namespace; the
host's cgroups are not shared). Per lane it checks: install with no
manual steps; the installed file list against a runtime allowlist with
no headers, static libs, pkg-config or CMake files; no world-writable,
setuid or non-root files; resolvable DT_NEEDED and $ORIGIN-or-/usr/lib
RPATH/RUNPATH; unit enabled and active as the yams account; socket group
yams and closed to others; `systemd-analyze verify` and a
`systemd-analyze security` exposure budget; root, a yams-group member
and a non-member using the CLI with no YAMS_* variables (add from $HOME
and /tmp, search, shared corpus, no private fallback store, clear
directory error, non-member denied, `daemon stop` deferring to systemd);
state after a container reboot; removal and deb purge. With
--upgrade-from-<fmt> it installs an older package, stores a document,
upgrades and checks the restart and the document. Every check reports
PASS/FAIL, a summary table follows, and any FAIL fails the run.

release.yml's existing validation steps (the gate before artifacts are
uploaded for publishing) pass the latest published release's packages as
the upgrade source. The unreferenced packaging/systemd/Dockerfile is
removed; the lane images take a BASE_IMAGE argument and add binutils
and util-linux for the checks.

Signed-off-by: trvon <me@trevon.dev>
2026-10-01 21:11:15 -06:00