@@ -1282,7 +1282,7 @@ impl SingBoxNativeHost for SystemSingBoxNativeHost {
|
|||||||
&& verify_runtime_root_shape(
|
&& verify_runtime_root_shape(
|
||||||
self.root.path(),
|
self.root.path(),
|
||||||
files,
|
files,
|
||||||
false,
|
receipt_valid && marker_valid,
|
||||||
self.promoted_has_runtime_config,
|
self.promoted_has_runtime_config,
|
||||||
)
|
)
|
||||||
.is_ok()
|
.is_ok()
|
||||||
@@ -1854,6 +1854,81 @@ impl SystemSingBoxNativeHost {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore = "requires elevated Windows and PROXYWARDEN_TEST_APP_ROOT; no service mutations"]
|
||||||
|
fn promoted_inventory_survives_metadata_commit_on_windows() {
|
||||||
|
let parent = PathBuf::from(
|
||||||
|
std::env::var_os("PROXYWARDEN_TEST_APP_ROOT").expect("trusted test parent"),
|
||||||
|
);
|
||||||
|
safe_fs::verify_path_under_trusted_program_files(&parent)
|
||||||
|
.expect("trusted Program Files parent");
|
||||||
|
let app = parent.join(format!(".singbox-inventory-test-{}", uuid::Uuid::new_v4()));
|
||||||
|
let components = app.join("components");
|
||||||
|
let root = CanonicalComponentRoot::from_current_exe_for_tests(
|
||||||
|
&app.join("ProxyWarden.exe"),
|
||||||
|
ManagedComponent::SingBox,
|
||||||
|
)
|
||||||
|
.expect("isolated root");
|
||||||
|
for path in [&app, &components, root.path()] {
|
||||||
|
safe_fs::create_directory_admin_owned_user_read_only(path)
|
||||||
|
.expect("sealed test directory");
|
||||||
|
}
|
||||||
|
let files = vec![
|
||||||
|
staged(SINGBOX_LICENSE_FILE, b"license"),
|
||||||
|
staged(WINSW_WRAPPER_FILE, b"wrapper"),
|
||||||
|
staged(WINSW_SERVICE_XML_FILE, singbox_service_xml().as_bytes()),
|
||||||
|
staged(SINGBOX_CRONET_FILE, b"cronet"),
|
||||||
|
staged(SINGBOX_RUNTIME_FILE, b"runtime"),
|
||||||
|
];
|
||||||
|
let runtime = PrivilegedPackageProof {
|
||||||
|
component_id: ComponentId::SingBox,
|
||||||
|
version: "1.13.19".to_owned(),
|
||||||
|
asset_name: "sing-box-1.13.19-windows-amd64.zip".to_owned(),
|
||||||
|
sha256: "a".repeat(64),
|
||||||
|
size: 100,
|
||||||
|
source: PackageSource::Bundled,
|
||||||
|
independent_proof: None,
|
||||||
|
};
|
||||||
|
let wrapper = SingBoxMarkerPackage {
|
||||||
|
version: "2.12.0".to_owned(),
|
||||||
|
asset_name: "WinSW.NET461.exe".to_owned(),
|
||||||
|
sha256: "b".repeat(64),
|
||||||
|
size: 100,
|
||||||
|
source: PackageSource::Bundled,
|
||||||
|
};
|
||||||
|
let metadata =
|
||||||
|
build_metadata(&runtime, wrapper, installed_file_inventory(&files)).expect("metadata");
|
||||||
|
write_staged_files(root.path(), &files).expect("sealed runtime files");
|
||||||
|
let mut host = SystemSingBoxNativeHost::new(root);
|
||||||
|
host.promoted_files = Some(installed_file_inventory(&files));
|
||||||
|
host.promoted_runtime_version = Some("1.13.19".to_owned());
|
||||||
|
host.promoted_wrapper_version = Some("2.12.0".to_owned());
|
||||||
|
let before = host.inspect();
|
||||||
|
let committed = host.commit_metadata(SingBoxNativeMode::Install, &metadata);
|
||||||
|
let after = host.inspect();
|
||||||
|
// Exact receipt-owned cleanup only; this test never creates or controls a service.
|
||||||
|
host.rollback(SingBoxNativeMode::Install, false)
|
||||||
|
.expect("remove isolated runtime");
|
||||||
|
fs::remove_dir(&components).expect("empty components directory");
|
||||||
|
fs::remove_dir(&app).expect("empty test directory");
|
||||||
|
let before = before.expect("pre-commit inventory");
|
||||||
|
assert!(before.service_xml_matches && before.promoted_files_match);
|
||||||
|
assert!(!before.receipt_valid && !before.marker_valid);
|
||||||
|
committed.expect("metadata commit");
|
||||||
|
let after = after.expect("post-commit inventory");
|
||||||
|
assert!(
|
||||||
|
after.receipt_valid
|
||||||
|
&& after.receipt_files_match
|
||||||
|
&& after.marker_valid
|
||||||
|
&& after.marker_files_match
|
||||||
|
);
|
||||||
|
assert!(after.service_xml_matches);
|
||||||
|
assert!(
|
||||||
|
after.promoted_files_match,
|
||||||
|
"committed metadata must not invalidate promoted files"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn staged(name: &str, bytes: &[u8]) -> SingBoxStagedFile {
|
fn staged(name: &str, bytes: &[u8]) -> SingBoxStagedFile {
|
||||||
SingBoxStagedFile {
|
SingBoxStagedFile {
|
||||||
relative_path: name.to_owned(),
|
relative_path: name.to_owned(),
|
||||||
|
|||||||
Reference in New Issue
Block a user