Compose selected State Anchor paths over prepared roots

This commit is contained in:
ms2k 2026-07-17 03:58:27 +09:00
commit 4dd2b150d2

View file

@ -33,6 +33,7 @@ impl Fixture {
fs::create_dir(&configuration_directory).unwrap();
fs::create_dir(&workspace).unwrap();
fs::create_dir(&runtime).unwrap();
fs::create_dir(tree.path().join("prepared-root")).unwrap();
let configuration_path = configuration_directory.join("lazaret.toml");
fs::write(
&configuration_path,
@ -149,6 +150,7 @@ env = {{ UNSELECTED_SECRET = "env:UNSELECTED_HOST_SECRET" }}
expected_network_namespace: current_network_namespace(),
root_process,
terminal: Some(self.terminal()),
prepared_root: self.tree.path().join("prepared-root"),
}
}
@ -163,7 +165,9 @@ env = {{ UNSELECTED_SECRET = "env:UNSELECTED_HOST_SECRET" }}
for directory in [
format!("bundles/{container}"),
"runsc".to_owned(),
"state-anchor/merged".to_owned(),
format!("runsc-overlay/{container}"),
"state-anchor/merged/root".to_owned(),
"state-anchor/runtime-files".to_owned(),
format!("sandbox-control/{container}/credentials"),
format!("sandbox-control/{container}/mailbox/requests"),
format!("sandbox-control/{container}/mailbox/results"),
@ -171,6 +175,13 @@ env = {{ UNSELECTED_SECRET = "env:UNSELECTED_HOST_SECRET" }}
] {
fs::create_dir_all(runtime.join(directory)).unwrap();
}
for name in ["resolv.conf", "hosts", "hostname"] {
fs::write(
runtime.join("state-anchor/runtime-files").join(name),
b"fixture",
)
.unwrap();
}
fs::write(
runtime.join(format!("bundles/{container}/config.json")),
bundle.specification_json(),
@ -291,13 +302,13 @@ fn deterministic_snapshot_has_only_private_namespaces_and_fixed_runtime_shape()
assert_eq!(
specification["linux"]["uidMappings"],
serde_json::json!([{
"hostID": rustix::process::getuid().as_raw(), "containerID": 0, "size": 1
"hostID": 0, "containerID": 0, "size": 1
}])
);
assert_eq!(
specification["linux"]["gidMappings"],
serde_json::json!([{
"hostID": rustix::process::getgid().as_raw(), "containerID": 0, "size": 1
"hostID": 0, "containerID": 0, "size": 1
}])
);
@ -323,6 +334,10 @@ fn deterministic_snapshot_has_only_private_namespaces_and_fixed_runtime_shape()
"-rootless".to_owned(),
"-network=host".to_owned(),
"-ignore-cgroups".to_owned(),
format!(
"-overlay2=root:dir={runtime_domain}/runsc-overlay/{}",
"11".repeat(32)
),
"run".to_owned(),
format!(
"-bundle={}/bundles/{}",
@ -340,6 +355,15 @@ fn deterministic_snapshot_has_only_private_namespaces_and_fixed_runtime_shape()
"11".repeat(32),
]
);
assert_eq!(
specification["root"]["path"],
fixture
.tree
.path()
.join("prepared-root")
.display()
.to_string()
);
assert!(!first.command().arguments().iter().any(|argument| {
matches!(
argument.to_str(),
@ -370,7 +394,7 @@ fn product_init_role_has_exact_terminal_neutral_rootless_bundle_shape() {
assert_eq!(
specification["linux"]["uidMappings"],
serde_json::json!([{
"hostID": rustix::process::getuid().as_raw(), "containerID": 0, "size": 1
"hostID": 0, "containerID": 0, "size": 1
}])
);
assert_eq!(
@ -408,6 +432,7 @@ fn selected_environment_volume_modes_and_host_terminal_are_preserved() {
let mounts = mounts(&specification);
assert!(options(mounts[WORKSPACE_DESTINATION]).contains("rw"));
assert!(options(mounts["/root"]).contains("rw"));
assert!(options(mounts["/root/read-only"]).contains("ro"));
assert!(options(mounts["/root/read-write"]).contains("rw"));
let terminfo = &mounts["/run/lazaret/terminfo/x/xterm-lazaret"];
@ -434,6 +459,17 @@ fn selected_environment_volume_modes_and_host_terminal_are_preserved() {
assert!(options(mounts[MAILBOX_RESULTS_DESTINATION]).contains("ro"));
assert!(options(mounts[ESCALATION_CLIENT_DESTINATION]).contains("ro"));
assert!(!options(mounts[ESCALATION_CLIENT_DESTINATION]).contains("noexec"));
for name in ["resolv.conf", "hosts", "hostname"] {
let destination = format!("/etc/{name}");
let mount = &mounts[destination.as_str()];
assert!(options(mount).contains("ro"));
assert!(
mount["source"]
.as_str()
.unwrap()
.ends_with(&format!("state-anchor/runtime-files/{name}"))
);
}
}
#[test]
@ -542,6 +578,7 @@ fn hostile_terminal_names_sources_and_changed_entries_fail_closed() {
expected_network_namespace: current_network_namespace(),
root_process: root_process([]),
terminal: Some(terminal),
prepared_root: fixture.tree.path().join("prepared-root"),
})
.unwrap_err();
assert_eq!(error.kind(), SandboxBuildErrorKind::ChangedAuthority);
@ -578,6 +615,7 @@ fn invalid_processes_and_wrong_network_identity_fail_closed() {
},
root_process: root_process([]),
terminal: Some(fixture.terminal()),
prepared_root: fixture.tree.path().join("prepared-root"),
})
.unwrap_err();
assert_eq!(
@ -633,15 +671,8 @@ fn final_handoff_refuses_replaced_workspace_and_runtime_sources() {
let handoff = bundle
.capture_handoff_authority(&fixture.configuration)
.unwrap();
let runtime = host_path(
fixture
.configuration
.runtime_domain_root()
.canonical_label()
.as_bytes(),
);
let rootfs = runtime.join("state-anchor/merged");
fs::rename(&rootfs, runtime.join("state-anchor/selected")).unwrap();
let rootfs = fixture.tree.path().join("prepared-root");
fs::rename(&rootfs, fixture.tree.path().join("prepared-root-selected")).unwrap();
fs::create_dir(&rootfs).unwrap();
fs::write(rootfs.join("replacement-marker"), b"unchanged").unwrap();
let error = handoff.revalidate().unwrap_err();