summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHermes Agent <hermes@localhost>2026-08-12 03:08:50 +0000
committerHermes Agent <hermes@localhost>2026-08-12 03:08:50 +0000
commitca6572f7c96fd14733b42ad6dcd361bc136093ed (patch)
tree85a4f091cc32ed52e6de01a111817f61664559b9
parenta60cf70253fb1e22dfcc480385c0499272b75477 (diff)
Validate direct systemd wants service facts
-rw-r--r--src/manifest.rs22
-rw-r--r--tests/compare.rs24
2 files changed, 43 insertions, 3 deletions
diff --git a/src/manifest.rs b/src/manifest.rs
index 5b7ae77..ed326e1 100644
--- a/src/manifest.rs
+++ b/src/manifest.rs
@@ -279,9 +279,25 @@ fn portable_path(path: &Path) -> Result<String> {
}
fn is_enabled_service(path: &str) -> bool {
- path.starts_with("etc/systemd/system/")
- && path.contains(".target.wants/")
- && path.ends_with(".service")
+ let mut components = path.split('/');
+ matches!(
+ (
+ components.next(),
+ components.next(),
+ components.next(),
+ components.next(),
+ components.next(),
+ components.next(),
+ ),
+ (
+ Some("etc"),
+ Some("systemd"),
+ Some("system"),
+ Some(wants),
+ Some(service),
+ None,
+ ) if wants.ends_with(".target.wants") && service.ends_with(".service")
+ )
}
fn is_internal_metadata_path(path: &str) -> bool {
diff --git a/tests/compare.rs b/tests/compare.rs
index 63e4a4f..2dfd46d 100644
--- a/tests/compare.rs
+++ b/tests/compare.rs
@@ -371,3 +371,27 @@ fn archive_collection_coalesces_a_service_enabled_by_multiple_targets() {
assert_eq!(manifest.services, vec![ServiceRecord::new("controller.service", true)]);
}
+
+#[test]
+fn archive_collection_only_treats_direct_target_wants_symlinks_as_enabled_services() {
+ let fixture = tempdir().expect("temporary directory");
+ let artifact = fixture.path().join("malformed-service-state.tar");
+ let file = fs::File::create(&artifact).expect("create archive");
+ let mut archive = tar::Builder::new(file);
+ let mut header = tar::Header::new_gnu();
+ header.set_entry_type(tar::EntryType::Symlink);
+ header.set_size(0);
+ header.set_cksum();
+ archive
+ .append_link(
+ &mut header,
+ "etc/systemd/system/multi-user.target.wants/nested/controller.service",
+ "/usr/lib/systemd/system/controller.service",
+ )
+ .expect("append nested symlink");
+ archive.finish().expect("finish archive");
+
+ let manifest = ArtifactManifest::collect_archive(&artifact).expect("collect archive facts");
+
+ assert!(manifest.services.is_empty());
+}