Skip to content

Commit 934e620

Browse files
committed
chore: upgrade to codex 0.131 alpha
1 parent 693ea96 commit 934e620

5 files changed

Lines changed: 375 additions & 12 deletions

File tree

UPSTREAM_VERSION

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
rust-v0.130.0
2-
# commit: 58573da43ab697e8b79f152c53df4b42230395a8
3-
# synced: 2026-05-13T20:03:53Z
1+
rust-v0.131.0-alpha.22
2+
# commit: 9b8cf56cdefb09f54564ccc295fd42f6647f558f
3+
# synced: 2026-05-16T19:45:09Z

crates/zerobox/tests/sandbox/misc.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,57 @@ fn allow_read_and_write_combined() {
7575
assert_eq!(content.trim(), "input");
7676
}
7777

78+
#[cfg(target_os = "linux")]
79+
#[test]
80+
fn default_profile_starts_with_empty_credential_files_in_writable_home() {
81+
let tmp = temp_dir();
82+
let home = tmp.path().join("home");
83+
std::fs::create_dir_all(&home).expect("create home");
84+
for name in [".azure", ".gcloud", ".kube", ".git-credentials"] {
85+
std::fs::File::create(home.join(name)).expect("create empty credential file");
86+
}
87+
88+
let out = Command::new(zerobox_exec())
89+
.current_dir(&home)
90+
.env("HOME", &home)
91+
.env("ZEROBOX_HOME", tmp.path().join("zerobox-home"))
92+
.args(["--allow-write=.", "--allow-write=/tmp", "--", "ls"])
93+
.output()
94+
.expect("failed to spawn zerobox");
95+
96+
assert!(
97+
out.status.success(),
98+
"default profile should mask empty credential files without breaking startup, stderr: {}",
99+
stderr(&out)
100+
);
101+
}
102+
103+
#[cfg(target_os = "linux")]
104+
#[test]
105+
fn default_profile_starts_with_tmp_home_and_missing_nested_keyring_path() {
106+
let tmp = temp_dir();
107+
let home = tmp.path().join("home");
108+
std::fs::create_dir_all(&home).expect("create home");
109+
110+
let out = Command::new(zerobox_exec())
111+
.current_dir(&home)
112+
.env("HOME", &home)
113+
.env("ZEROBOX_HOME", tmp.path().join("zerobox-home"))
114+
.args(["--allow-write=.", "--allow-write=/tmp", "--", "ls"])
115+
.output()
116+
.expect("failed to spawn zerobox");
117+
118+
assert!(
119+
out.status.success(),
120+
"default profile should mask ~/.local/share/keyrings without replacing ~/.local, stderr: {}",
121+
stderr(&out)
122+
);
123+
assert!(
124+
!home.join(".local").exists(),
125+
"synthetic missing parents should be cleaned up after bwrap exits"
126+
);
127+
}
128+
78129
#[test]
79130
fn allow_read_and_net_combined() {
80131
let (code, ok) = curl_status(

scripts/sync.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,12 @@ if [ -f "$NODE_PROXY_PATCH" ]; then
277277
patch -p0 < "$NODE_PROXY_PATCH"
278278
fi
279279

280+
PROXY_ZOMBIE_PATCH="$SCRIPT_DIR/upstream-proxy-zombie-cleanup.patch"
281+
if [ -f "$PROXY_ZOMBIE_PATCH" ]; then
282+
echo " proxy-zombie-cleanup"
283+
patch -p0 < "$PROXY_ZOMBIE_PATCH"
284+
fi
285+
280286
BWRAP_FIXES_PATCH="$SCRIPT_DIR/upstream-bwrap-fixes.patch"
281287
if [ -f "$BWRAP_FIXES_PATCH" ]; then
282288
echo " bwrap-fixes"

scripts/upstream-bwrap-fixes.patch

Lines changed: 256 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,38 @@
11
--- upstream/linux-sandbox/src/bwrap.rs
22
+++ upstream/linux-sandbox/src/bwrap.rs
3-
@@ -474,6 +474,20 @@
3+
@@ -485,6 +485,20 @@
4+
.filter(|path| path.exists()),
45
);
56
}
6-
7+
+
78
+ // Skip subpaths covered by another entry. `--ro-bind` is
89
+ // recursive, so the extra bind is redundant, and a subpath
910
+ // symlink like /etc/os-release can resolve into a path whose
1011
+ // prefix is not yet bound, making bwrap fail with ENOENT.
1112
+ let readable_roots: BTreeSet<PathBuf> = readable_roots
1213
+ .iter()
1314
+ .filter(|path| {
14-
+ !readable_roots.iter().any(|parent| {
15-
+ parent.as_path() != path.as_path() && path.starts_with(parent)
16-
+ })
15+
+ !readable_roots
16+
+ .iter()
17+
+ .any(|parent| parent.as_path() != path.as_path() && path.starts_with(parent))
1718
+ })
1819
+ .cloned()
1920
+ .collect();
20-
+
21+
2122
// A restricted policy can still explicitly request `/`, which is
2223
// the broad read baseline. Explicit unreadable carveouts are
23-
// re-applied later.
24-
@@ -1072,10 +1086,11 @@
24+
@@ -1071,7 +1085,7 @@
25+
if let Some(first_missing_component) = find_first_non_existent_component(subpath)
26+
&& is_within_allowed_write_paths(&first_missing_component, allowed_write_paths)
27+
{
28+
- append_missing_read_only_subpath_args(bwrap_args, &first_missing_component)?;
29+
+ append_missing_read_only_subpath_args(bwrap_args, subpath, &first_missing_component)?;
30+
}
31+
return Ok(());
32+
}
33+
@@ -1085,10 +1099,11 @@
2534
}
26-
35+
2736
fn append_empty_file_bind_data_args(bwrap_args: &mut BwrapArgs, path: &Path) -> Result<()> {
2837
- if bwrap_args.preserved_files.is_empty() {
2938
- bwrap_args.preserved_files.push(File::open("/dev/null")?);
@@ -37,3 +46,241 @@
3746
bwrap_args.args.push("--ro-bind-data".to_string());
3847
bwrap_args.args.push(null_fd);
3948
bwrap_args.args.push(path_to_string(path));
49+
@@ -1104,8 +1119,12 @@
50+
bwrap_args.args.push(path_to_string(path));
51+
}
52+
53+
-fn append_missing_read_only_subpath_args(bwrap_args: &mut BwrapArgs, path: &Path) -> Result<()> {
54+
- if path.file_name().is_some_and(is_protected_metadata_name) {
55+
+fn append_missing_read_only_subpath_args(
56+
+ bwrap_args: &mut BwrapArgs,
57+
+ path: &Path,
58+
+ first_missing_component: &Path,
59+
+) -> Result<()> {
60+
+ if path == first_missing_component && path.file_name().is_some_and(is_protected_metadata_name) {
61+
append_empty_directory_args(bwrap_args, path);
62+
bwrap_args
63+
.synthetic_mount_targets
64+
@@ -1113,6 +1132,7 @@
65+
return Ok(());
66+
}
67+
68+
+ append_missing_mount_parent_dir_args(bwrap_args, path, first_missing_component);
69+
append_missing_empty_file_bind_data_args(bwrap_args, path)
70+
}
71+
72+
@@ -1175,12 +1195,64 @@
73+
if let Some(first_missing_component) = find_first_non_existent_component(unreadable_root)
74+
&& is_within_allowed_write_paths(&first_missing_component, allowed_write_paths)
75+
{
76+
- append_missing_empty_file_bind_data_args(bwrap_args, &first_missing_component)?;
77+
+ append_missing_unreadable_root_args(
78+
+ bwrap_args,
79+
+ unreadable_root,
80+
+ &first_missing_component,
81+
+ )?;
82+
}
83+
return Ok(());
84+
}
85+
86+
append_existing_unreadable_path_args(bwrap_args, unreadable_root, allowed_write_paths)
87+
+}
88+
+
89+
+fn append_missing_unreadable_root_args(
90+
+ bwrap_args: &mut BwrapArgs,
91+
+ unreadable_root: &Path,
92+
+ first_missing_component: &Path,
93+
+) -> Result<()> {
94+
+ append_missing_mount_parent_dir_args(bwrap_args, unreadable_root, first_missing_component);
95+
+ append_missing_empty_file_bind_data_args(bwrap_args, unreadable_root)
96+
+}
97+
+
98+
+fn append_missing_mount_parent_dir_args(
99+
+ bwrap_args: &mut BwrapArgs,
100+
+ mount_target: &Path,
101+
+ first_missing_component: &Path,
102+
+) {
103+
+ let Some(parent) = mount_target.parent() else {
104+
+ return;
105+
+ };
106+
+ if !parent.starts_with(first_missing_component) {
107+
+ return;
108+
+ }
109+
+
110+
+ let mut dir = first_missing_component.to_path_buf();
111+
+ append_missing_mount_parent_dir(bwrap_args, &dir);
112+
+
113+
+ let Ok(relative_parent) = parent.strip_prefix(first_missing_component) else {
114+
+ return;
115+
+ };
116+
+ for component in relative_parent.components() {
117+
+ use std::path::Component;
118+
+ match component {
119+
+ Component::Normal(part) => {
120+
+ dir.push(part);
121+
+ append_missing_mount_parent_dir(bwrap_args, &dir);
122+
+ }
123+
+ Component::CurDir => {}
124+
+ Component::ParentDir | Component::RootDir | Component::Prefix(_) => return,
125+
+ }
126+
+ }
127+
+}
128+
+
129+
+fn append_missing_mount_parent_dir(bwrap_args: &mut BwrapArgs, path: &Path) {
130+
+ bwrap_args.args.push("--dir".to_string());
131+
+ bwrap_args.args.push(path_to_string(path));
132+
+ bwrap_args
133+
+ .synthetic_mount_targets
134+
+ .push(SyntheticMountTarget::missing_empty_directory(path));
135+
}
136+
137+
fn append_existing_unreadable_path_args(
138+
@@ -1749,6 +1821,78 @@
139+
}
140+
141+
#[test]
142+
+ fn missing_nested_read_only_subpath_masks_leaf_not_first_missing_ancestor() {
143+
+ let temp_dir = TempDir::new().expect("temp dir");
144+
+ let home = temp_dir.path().join("home");
145+
+ let first_missing = home.join(".local");
146+
+ let missing_parent = first_missing.join("share");
147+
+ let blocked = missing_parent.join("keyrings");
148+
+ std::fs::create_dir_all(&home).expect("create home");
149+
+
150+
+ let home_root = AbsolutePathBuf::from_absolute_path(&home).expect("absolute home");
151+
+ let blocked_root = AbsolutePathBuf::from_absolute_path(&blocked).expect("absolute blocked");
152+
+ let policy = FileSystemSandboxPolicy::restricted(vec![
153+
+ FileSystemSandboxEntry {
154+
+ path: FileSystemPath::Path { path: home_root },
155+
+ access: FileSystemAccessMode::Write,
156+
+ },
157+
+ FileSystemSandboxEntry {
158+
+ path: FileSystemPath::Path { path: blocked_root },
159+
+ access: FileSystemAccessMode::Read,
160+
+ },
161+
+ ]);
162+
+
163+
+ let args =
164+
+ create_filesystem_args(&policy, temp_dir.path(), NO_UNREADABLE_GLOB_SCAN_MAX_DEPTH)
165+
+ .expect("filesystem args");
166+
+
167+
+ assert_dir_created(&args.args, &first_missing);
168+
+ assert_dir_created(&args.args, &missing_parent);
169+
+ assert_empty_file_bound_without_perms(&args.args, &blocked);
170+
+ assert_no_empty_file_bind(&args.args, &first_missing);
171+
+ let synthetic_targets = synthetic_mount_target_paths(&args);
172+
+ assert!(synthetic_targets.contains(&first_missing));
173+
+ assert!(synthetic_targets.contains(&missing_parent));
174+
+ assert!(synthetic_targets.contains(&blocked));
175+
+ }
176+
+
177+
+ #[test]
178+
+ fn missing_nested_unreadable_root_masks_leaf_not_first_missing_ancestor() {
179+
+ let temp_dir = TempDir::new().expect("temp dir");
180+
+ let home = temp_dir.path().join("home");
181+
+ let first_missing = home.join(".local");
182+
+ let missing_parent = first_missing.join("share");
183+
+ let blocked = missing_parent.join("keyrings");
184+
+ std::fs::create_dir_all(&home).expect("create home");
185+
+
186+
+ let home_root = AbsolutePathBuf::from_absolute_path(&home).expect("absolute home");
187+
+ let blocked_root = AbsolutePathBuf::from_absolute_path(&blocked).expect("absolute blocked");
188+
+ let policy = FileSystemSandboxPolicy::restricted(vec![
189+
+ FileSystemSandboxEntry {
190+
+ path: FileSystemPath::Path { path: home_root },
191+
+ access: FileSystemAccessMode::Write,
192+
+ },
193+
+ FileSystemSandboxEntry {
194+
+ path: FileSystemPath::Path { path: blocked_root },
195+
+ access: FileSystemAccessMode::None,
196+
+ },
197+
+ ]);
198+
+
199+
+ let args =
200+
+ create_filesystem_args(&policy, temp_dir.path(), NO_UNREADABLE_GLOB_SCAN_MAX_DEPTH)
201+
+ .expect("filesystem args");
202+
+
203+
+ assert_dir_created(&args.args, &first_missing);
204+
+ assert_dir_created(&args.args, &missing_parent);
205+
+ assert_empty_file_bound_without_perms(&args.args, &blocked);
206+
+ assert_no_empty_file_bind(&args.args, &first_missing);
207+
+ let synthetic_targets = synthetic_mount_target_paths(&args);
208+
+ assert!(synthetic_targets.contains(&first_missing));
209+
+ assert!(synthetic_targets.contains(&missing_parent));
210+
+ assert!(synthetic_targets.contains(&blocked));
211+
+ }
212+
+
213+
+ #[test]
214+
fn transient_empty_preserved_file_uses_empty_file_bind_data() {
215+
let temp_dir = TempDir::new().expect("temp dir");
216+
let workspace = temp_dir.path().join("workspace");
217+
@@ -1796,6 +1940,40 @@
218+
}
219+
220+
#[test]
221+
+ fn multiple_existing_empty_file_masks_use_distinct_preserved_fds() {
222+
+ let temp_dir = TempDir::new().expect("temp dir");
223+
+ let azure = temp_dir.path().join(".azure");
224+
+ let gcloud = temp_dir.path().join(".gcloud");
225+
+ File::create(&azure).expect("create empty azure file");
226+
+ File::create(&gcloud).expect("create empty gcloud file");
227+
+
228+
+ let azure_root = AbsolutePathBuf::from_absolute_path(&azure).expect("absolute azure");
229+
+ let gcloud_root = AbsolutePathBuf::from_absolute_path(&gcloud).expect("absolute gcloud");
230+
+ let policy = FileSystemSandboxPolicy::restricted(vec![
231+
+ FileSystemSandboxEntry {
232+
+ path: FileSystemPath::Path { path: azure_root },
233+
+ access: FileSystemAccessMode::None,
234+
+ },
235+
+ FileSystemSandboxEntry {
236+
+ path: FileSystemPath::Path { path: gcloud_root },
237+
+ access: FileSystemAccessMode::None,
238+
+ },
239+
+ ]);
240+
+
241+
+ let args =
242+
+ create_filesystem_args(&policy, temp_dir.path(), NO_UNREADABLE_GLOB_SCAN_MAX_DEPTH)
243+
+ .expect("filesystem args");
244+
+
245+
+ assert_file_masked(&args.args, &azure);
246+
+ assert_file_masked(&args.args, &gcloud);
247+
+ assert_eq!(
248+
+ args.preserved_files.len(),
249+
+ 2,
250+
+ "each ro-bind-data mount needs its own fd"
251+
+ );
252+
+ }
253+
+
254+
+ #[test]
255+
fn missing_child_git_under_parent_repo_uses_protected_create_target() {
256+
let temp_dir = TempDir::new().expect("temp dir");
257+
let repo = temp_dir.path().join("repo");
258+
@@ -2687,9 +2865,28 @@
259+
&& window[4] == path
260+
}),
261+
"missing path bind should not set explicit file perms for {path}: {args:#?}"
262+
+ );
263+
+ }
264+
+
265+
+ fn assert_no_empty_file_bind(args: &[String], path: &Path) {
266+
+ let path = path_to_string(path);
267+
+ assert!(
268+
+ !args
269+
+ .windows(3)
270+
+ .any(|window| { window[0] == "--ro-bind-data" && window[2] == path }),
271+
+ "did not expect empty file bind for {path}: {args:#?}"
272+
);
273+
}
274+
275+
+ fn assert_dir_created(args: &[String], path: &Path) {
276+
+ let path = path_to_string(path);
277+
+ assert!(
278+
+ args.windows(2)
279+
+ .any(|window| window == ["--dir", path.as_str()]),
280+
+ "expected synthetic directory creation for {path}: {args:#?}"
281+
+ );
282+
+ }
283+
+
284+
fn assert_empty_directory_mounted_read_only(args: &[String], path: &Path) {
285+
let path = path_to_string(path);
286+
assert!(

0 commit comments

Comments
 (0)