@@ -359,6 +359,35 @@ fn collision_and_unsafe_zip_reach_no_mutating_host_or_service_runner() {
|
||||
assert!(unsafe_host.calls.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fresh_install_rejects_invalid_service_xml_before_committing_ownership() {
|
||||
let temp = TestDir::new();
|
||||
let root = temp.path.join("sing-box");
|
||||
let (runtime_path, runtime_proof) = runtime_package(&temp, "1.13.19", PackageSource::Bundled);
|
||||
let (wrapper_path, wrapper_proof) = wrapper_package(&temp);
|
||||
let mut promoted = promoted_snapshot(
|
||||
&root,
|
||||
"1.13.19",
|
||||
"2.12.0",
|
||||
SingBoxNativeServiceState::Stopped,
|
||||
);
|
||||
assert!(!promoted.receipt_valid && !promoted.marker_valid);
|
||||
promoted.service_xml_matches = false;
|
||||
let mut host = FakeHost::new(root.clone(), vec![missing_snapshot(&root), promoted]);
|
||||
|
||||
let error = install_singbox_native_core(
|
||||
&mut host,
|
||||
package_view(&runtime_path, &runtime_proof),
|
||||
package_view(&wrapper_path, &wrapper_proof),
|
||||
)
|
||||
.expect_err("invalid XML must fail before committing ownership");
|
||||
|
||||
assert_eq!(error, SingBoxNativeError::OwnershipMismatch);
|
||||
assert!(host.metadata.is_none());
|
||||
assert_eq!(host.rollback, Some((SingBoxNativeMode::Install, true)));
|
||||
assert!(!host.calls.contains(&CallKind::StartService));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_receipt_and_config_mismatch_run_no_service_mutation() {
|
||||
let temp = TestDir::new();
|
||||
|
||||
@@ -1257,7 +1257,10 @@ impl SingBoxNativeHost for SystemSingBoxNativeHost {
|
||||
let mut receipt_files_match = false;
|
||||
let mut marker_valid = false;
|
||||
let mut marker_files_match = false;
|
||||
let mut service_xml_matches = false;
|
||||
// Freshly promoted files are checked before the receipt/marker is committed.
|
||||
// XML validity must not depend on that later ownership metadata.
|
||||
let service_xml_matches =
|
||||
root_exists && install_root_trusted && verify_service_xml(self.root.path()).is_ok();
|
||||
let mut marker = None;
|
||||
if root_exists && install_root_trusted {
|
||||
if let Ok((verified_receipt, verified_marker, receipt_match, marker_match)) =
|
||||
@@ -1267,7 +1270,6 @@ impl SingBoxNativeHost for SystemSingBoxNativeHost {
|
||||
marker_valid = true;
|
||||
receipt_files_match = receipt_match;
|
||||
marker_files_match = marker_match;
|
||||
service_xml_matches = verify_service_xml(self.root.path()).is_ok();
|
||||
self.last_receipt = Some(verified_receipt);
|
||||
self.last_marker = Some(verified_marker.clone());
|
||||
marker = Some(verified_marker);
|
||||
@@ -1284,7 +1286,7 @@ impl SingBoxNativeHost for SystemSingBoxNativeHost {
|
||||
self.promoted_has_runtime_config,
|
||||
)
|
||||
.is_ok()
|
||||
&& verify_service_xml(self.root.path()).is_ok()
|
||||
&& service_xml_matches
|
||||
} else {
|
||||
receipt_files_match && marker_files_match && service_xml_matches
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user