feat: packages, services and updates
CI / test (3.10) (push) Successful in 26s
CI / test (3.11) (push) Successful in 24s
CI / test (3.12) (push) Successful in 26s
CI / test (3.10) (pull_request) Successful in 25s
CI / test (3.11) (pull_request) Successful in 24s
CI / test (3.12) (pull_request) Successful in 25s

The write side NetOrk/netork#799 needs, on both drivers.

- Packages: get_packages (FreeBSD `pkg query` with the repository as
  source, nothing on a classic system without pkg; OpenBSD `pkg_info`),
  install_package / uninstall_package as root (`pkg install`/`pkg
  delete`, `pkg_add -I`/`pkg_delete`), names checked before anything is
  sent, a failure raised with what the tool printed.
- Updates: get_available_updates. FreeBSD `pkg upgrade -n`, with
  `security` from VuXML (`pkg audit`: True for a listed package, False for
  any other, None when the audit could not run); OpenBSD `pkg_add -u -n
  -v` (no security verdict). Base-system patches are one `base-system`
  entry, as decided in #799: OpenBSD's `syspatch -c`, and on a classic
  FreeBSD what `freebsd-update` has fetched; on pkgbase the base system is
  packages from FreeBSD-base.
- Services: get_services lists the enabled ones (FreeBSD `service ...
  status` as root, as root-only pidfiles hide daemons otherwise, without
  root when sudo refuses; OpenBSD `rcctl check`), manage_service runs
  start/stop/restart/enable/disable as root and returns success and
  output.

Fixtures recorded on the FreeBSD 15.1 and OpenBSD 7.9 VMs with genuinely
outdated packages (FreeBSD pointed at the latest branch, an OpenBSD
package taken back to its release build). Checked live on both, including
a service restart and installing and removing a package.
This commit is contained in:
2026-10-08 09:59:04 +02:00
parent 045f809602
commit e8468a292a
24 changed files with 1703 additions and 3 deletions
+86
View File
@@ -269,3 +269,89 @@ class TestListeningSockets:
def test_a_socket_held_by_two_processes_is_listed_once(self):
text = "www nginx 901 6 tcp4 *:80 *:*\nwww nginx 900 6 tcp4 *:80 *:*\n"
assert [(s["pid"]) for s in parse.sockstat(text)] == [901]
class TestPackages:
def test_freebsd_pkg_query_names_the_repository(self):
packages = parse.pkg_query(fixture("freebsd-vm", "pkg_query_n_v_R_sb_c.txt"))
acct = next(p for p in packages if p["name"] == "FreeBSD-acct")
assert acct == {
"name": "FreeBSD-acct",
"version": "15.1p4",
"installed": True,
"description": "System resource accounting",
"size": 118976,
"source": "FreeBSD-base",
}
assert any(p["source"] == "FreeBSD-ports" for p in packages)
@pytest.mark.parametrize(
("full", "name", "version"),
[
("pcre2-10.44", "pcre2", "10.44"),
("bash-completion-2.17.0", "bash-completion", "2.17.0"),
("py3-tzdata-2026.3", "py3-tzdata", "2026.3"),
("argon2-20190702p0", "argon2", "20190702p0"),
("gettext-runtime-1.0", "gettext-runtime", "1.0"),
],
)
def test_openbsd_package_names(self, full, name, version):
assert parse.split_package(full) == (name, version)
def test_openbsd_pkg_info(self):
packages = parse.pkg_info(fixture("openbsd-vm", "pkg_info_full.txt"))
assert packages[1] == {
"name": "bash",
"version": "5.3.9",
"installed": True,
"description": "GNU Bourne Again Shell",
"size": 0,
"source": "pkg_add",
}
assert any(p["name"] == "bash-completion" for p in packages)
class TestUpdates:
def test_freebsd_pkg_upgrade_dry_run(self):
updates = parse.pkg_upgrades(fixture("freebsd-vm", "sudo_pkg_upgrade_n_latest.txt"))
assert len(updates) == 10
assert updates[0] == {
"name": "expat",
"current_version": "2.8.2",
"new_version": "2.8.5",
"origin": "FreeBSD-ports",
}
def test_freebsd_pkg_audit_names_the_vulnerable_packages(self):
text = fixture("freebsd-vm", "sudo_pkg_audit_Fq.txt").replace("rc=1\n", "")
assert parse.pkg_audit(text) == {"python312", "expat"}
def test_openbsd_update_candidates_that_change(self):
updates = parse.pkg_add_candidates(fixture("openbsd-vm", "sudo_pkg_add_u_n_v.txt"))
assert updates == [
{"name": "pcre2", "current_version": "10.44", "new_version": "10.48"},
{"name": "py3-tzdata", "current_version": "2026.3", "new_version": "2026.4"},
]
def test_openbsd_syspatch(self):
patches = parse.syspatch(fixture("openbsd-vm", "syspatch_c.txt"))
assert len(patches) == 34
assert patches[0] == "001_xserver"
class TestServices:
def test_freebsd_status_as_root(self):
services = {
s["name"]: s
for s in parse.service_status(fixture("freebsd-vm", "sudo_service_status_loop.txt"))
}
assert services["sshd"] == {"name": "sshd", "running": True, "enabled": True, "pid": 1282}
assert services["qemu-guest-agent"]["running"] is False
assert services["hostid"]["running"] is False # a one-shot script without a status
def test_openbsd_rcctl_check(self):
services = {
s["name"]: s for s in parse.rcctl_check(fixture("openbsd-vm", "rcctl_check_loop.txt"))
}
assert services["sshd"] == {"name": "sshd", "running": True, "enabled": True, "pid": 0}
assert services["check_quotas"]["running"] is False