From 95c2055e013e3ce2bfad5a03bee6a9c68536b216 Mon Sep 17 00:00:00 2001 From: Jaap de Haan <261428+jdehaan@users.noreply.github.com> Date: Sat, 16 May 2026 13:54:44 +0200 Subject: [PATCH] fix(snap): do not flag snapd as a snap/apt duplicate snapd is intentionally present as both a Debian package and a snap. The APT package bootstraps the host; once running, the snapd snap re-executes the snapd binary and handles its own updates via the normal snap mechanism. Reporting this as a duplicate is a false positive. --- crates/hah-checks/src/snap.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/crates/hah-checks/src/snap.rs b/crates/hah-checks/src/snap.rs index b515c6e..e5fdf40 100644 --- a/crates/hah-checks/src/snap.rs +++ b/crates/hah-checks/src/snap.rs @@ -123,6 +123,12 @@ impl Check for SnapAptDuplicateCheck { let mut result = CheckResult::default(); for name in snaps.intersection(&apt) { + // snapd is intentionally present in both: the Debian package + // bootstraps the host, then the snapd snap takes over for + // self-updates. Reporting it as a duplicate is a false positive. + if name == "snapd" { + continue; + } if ctx.config.allowlist.packages.contains(name) { continue; } @@ -340,6 +346,25 @@ mod tests { ); } + #[test] + fn snapd_present_in_both_apt_and_snap_is_not_reported() { + // snapd Debian package is the bootstrap; the snap updates itself. + // Having both is expected and must not produce a finding. + let mock = MockRunner::new(); + mock.on( + "snap", + b"Name Version Rev Tracking Publisher Notes\n\ + snapd 2.63 21 latest/stable canonical -\n", + true, + ); + mock.on("dpkg-query", b"snapd\n", true); + let result = SnapAptDuplicateCheck.run(&ctx(Arc::new(mock))); + assert!( + result.findings.is_empty(), + "snapd must not be reported as a snap/apt duplicate" + ); + } + #[test] fn snap_apt_duplicate_dpkg_error_returns_result_with_error() { let mock = MockRunner::new();