Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ v2_enum_from_core!(
pub enum FileSystemAccessMode from CoreFileSystemAccessMode {
Read,
Write,
None
Deny

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve none alias in v2 filesystem access

When an app-server client built against the previous v2 schema replies to item/permissions/requestApproval (or sends an experimental additional-permissions payload) with an entry whose access is still "none", this v2 enum now rejects the JSON before it can be converted to the core type that still has #[serde(alias = "none")]. Since the prior generated TypeScript exposed "none" as the valid value, mixed-version clients will fail permission approvals involving deny-read entries unless this wrapper enum also accepts the legacy alias on Deny.

Useful? React with 👍 / 👎.

}
);

Expand Down
4 changes: 2 additions & 2 deletions codex-rs/app-server-protocol/src/protocol/v2/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ fn additional_file_system_permissions_preserves_canonical_entries() {
path: CoreFileSystemPath::GlobPattern {
pattern: "**/*.env".to_string(),
},
access: CoreFileSystemAccessMode::None,
access: CoreFileSystemAccessMode::Deny,
},
],
glob_scan_max_depth: NonZeroUsize::new(2),
Expand All @@ -445,7 +445,7 @@ fn additional_file_system_permissions_preserves_canonical_entries() {
path: FileSystemPath::GlobPattern {
pattern: "**/*.env".to_string(),
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
]),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ mod thread_processor_behavior_tests {
path: FileSystemPath::GlobPattern {
pattern: "/tmp/project/**/*.env".to_string(),
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
]),
NetworkSandboxPolicy::Restricted,
Expand Down
24 changes: 17 additions & 7 deletions codex-rs/core/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -817,13 +817,23 @@
"type": "object"
},
"FileSystemAccessMode": {
"description": "Access mode for a filesystem entry.\n\nWhen two equally specific entries target the same path, we compare these by conflict precedence rather than by capability breadth: `none` beats `write`, and `write` beats `read`.",
"enum": [
"read",
"write",
"none"
],
"type": "string"
"description": "Access mode for a filesystem entry.\n\nWhen two equally specific entries target the same path, we compare these by conflict precedence rather than by capability breadth: `deny` beats `write`, and `write` beats `read`.",
"oneOf": [
{
"enum": [
"read",
"write"
],
"type": "string"
},
{
"description": "`none` is a legacy input alias retained temporarily for compatibility.",
"enum": [
"deny"
Comment on lines +831 to +832

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Allow legacy none in the config schema

For users who still have existing config.toml permission profiles with "none", the Rust deserializer accepts them via the new alias, but the generated config.schema.json no longer does, so schema-based validation/editors will mark otherwise supported configs as invalid. If none is intentionally retained as a temporary compatibility input, this enum should include the legacy value (or another schema allowance) alongside canonical deny.

Useful? React with 👍 / 👎.

],
"type": "string"
}
Comment on lines +821 to +835

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This codegen seems a bit unfortunate...

]
},
"FilesystemPermissionToml": {
"anyOf": [
Expand Down
9 changes: 7 additions & 2 deletions codex-rs/core/src/config/config_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,7 @@ default_permissions = "workspace"

[permissions.workspace.filesystem]
":minimal" = "read"
"/tmp/secret.env" = "deny"

[permissions.workspace.filesystem.":workspace_roots"]
"." = "write"
Expand Down Expand Up @@ -777,6 +778,10 @@ allow_upstream_proxy = false
":minimal".to_string(),
FilesystemPermissionToml::Access(FileSystemAccessMode::Read),
),
(
"/tmp/secret.env".to_string(),
FilesystemPermissionToml::Access(FileSystemAccessMode::Deny),
),
(
":workspace_roots".to_string(),
FilesystemPermissionToml::Scoped(BTreeMap::from([
Expand Down Expand Up @@ -1700,7 +1705,7 @@ async fn workspace_root_glob_none_compiles_to_filesystem_pattern_entry() -> std:
":workspace_roots".to_string(),
FilesystemPermissionToml::Scoped(BTreeMap::from([
(".".to_string(), FileSystemAccessMode::Write),
("**/*.env".to_string(), FileSystemAccessMode::None),
("**/*.env".to_string(), FileSystemAccessMode::Deny),
])),
)]),
}),
Expand Down Expand Up @@ -1739,7 +1744,7 @@ async fn workspace_root_glob_none_compiles_to_filesystem_pattern_entry() -> std:
path: FileSystemPath::GlobPattern {
pattern: expected_pattern,
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
})
);
}
Expand Down
4 changes: 2 additions & 2 deletions codex-rs/core/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2026,15 +2026,15 @@ fn apply_managed_filesystem_constraints(
path: codex_protocol::permissions::FileSystemPath::GlobPattern {
pattern: deny_read.as_str().to_string(),
},
access: codex_protocol::permissions::FileSystemAccessMode::None,
access: codex_protocol::permissions::FileSystemAccessMode::Deny,
}
} else {
let Ok(path) = AbsolutePathBuf::try_from(deny_read.as_str()) else {
continue;
};
codex_protocol::permissions::FileSystemSandboxEntry {
path: codex_protocol::permissions::FileSystemPath::Path { path },
access: codex_protocol::permissions::FileSystemAccessMode::None,
access: codex_protocol::permissions::FileSystemAccessMode::Deny,
}
};
if !file_system_sandbox_policy
Expand Down
20 changes: 10 additions & 10 deletions codex-rs/core/src/config/permissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ pub(crate) fn compile_permission_profile(
push_warning(
startup_warnings,
format!(
"Filesystem glob `{pattern}` uses `read` or `write` access, which is not fully supported by this platform's sandboxing. Use an exact path or trailing `/**` subtree rule instead. `none` deny-read globs are supported."
"Filesystem glob `{pattern}` uses `read` or `write` access, which is not fully supported by this platform's sandboxing. Use an exact path or trailing `/**` subtree rule instead. `deny` globs are supported."
),
);
}
Expand Down Expand Up @@ -414,7 +414,7 @@ fn compile_filesystem_permission(
Some(FileSystemSpecialPath::ProjectRoots { .. }) | None => true,
Some(_) => false,
};
if has_glob && *access == FileSystemAccessMode::None && can_compile_as_pattern {
if has_glob && *access == FileSystemAccessMode::Deny && can_compile_as_pattern {
// Scoped glob syntax is a first-class filesystem policy
// pattern entry. Literal scoped paths continue through the
// exact-path parser so existing path semantics stay intact.
Expand Down Expand Up @@ -449,7 +449,7 @@ fn compile_filesystem_access_path(
return compile_filesystem_path(path, startup_warnings);
}

if access == FileSystemAccessMode::None {
if access == FileSystemAccessMode::Deny {
// At this point `path` is an unscoped filesystem table key. Top-level
// glob deny entries still go through the absolute-path parser before
// becoming policy patterns; relative project-root glob syntax is
Expand Down Expand Up @@ -520,10 +520,10 @@ fn compile_scoped_filesystem_pattern(
// Pattern entries currently mean deny-read only. Supporting broader access
// modes here would imply glob-based read/write allow semantics that the
// sandbox policy does not express yet.
if access != FileSystemAccessMode::None {
if access != FileSystemAccessMode::Deny {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("filesystem glob subpath `{subpath}` only supports `none` access"),
format!("filesystem glob subpath `{subpath}` only supports `deny` access"),
));
}
let subpath = parse_relative_subpath(subpath)?;
Expand Down Expand Up @@ -559,7 +559,7 @@ fn compile_read_write_glob_path(path: &str, access: FileSystemAccessMode) -> io:
Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"filesystem glob path `{path}` only supports `none` access; use an exact path or trailing `/**` for `{access}` subtree access"
"filesystem glob path `{path}` only supports `deny` access; use an exact path or trailing `/**` for `{access}` subtree access"
),
))
}
Expand All @@ -569,15 +569,15 @@ fn unsupported_read_write_glob_paths(filesystem: &FilesystemPermissionsToml) ->
for (path, permission) in &filesystem.entries {
match permission {
FilesystemPermissionToml::Access(access) => {
if *access != FileSystemAccessMode::None
if *access != FileSystemAccessMode::Deny
&& contains_glob_chars(remove_trailing_glob_suffix(path))
{
patterns.push(path.clone());
}
}
FilesystemPermissionToml::Scoped(scoped_entries) => {
for (subpath, access) in scoped_entries {
if *access != FileSystemAccessMode::None
if *access != FileSystemAccessMode::Deny
&& contains_glob_chars(remove_trailing_glob_suffix(subpath))
{
patterns.push(format!("{path}/{subpath}"));
Expand All @@ -597,15 +597,15 @@ fn unbounded_unreadable_globstar_paths(filesystem: &FilesystemPermissionsToml) -
let mut patterns = Vec::new();
for (path, permission) in &filesystem.entries {
match permission {
FilesystemPermissionToml::Access(FileSystemAccessMode::None) => {
FilesystemPermissionToml::Access(FileSystemAccessMode::Deny) => {
if path.contains("**") {
patterns.push(path.clone());
}
}
FilesystemPermissionToml::Access(_) => {}
FilesystemPermissionToml::Scoped(scoped_entries) => {
for (subpath, access) in scoped_entries {
if *access == FileSystemAccessMode::None && subpath.contains("**") {
if *access == FileSystemAccessMode::Deny && subpath.contains("**") {
patterns.push(format!("{path}/{subpath}"));
}
}
Expand Down
10 changes: 5 additions & 5 deletions codex-rs/core/src/config/permissions_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ fn read_write_glob_warnings_skip_supported_deny_read_globs_and_trailing_subpaths
(
":workspace_roots".to_string(),
FilesystemPermissionToml::Scoped(BTreeMap::from([
("**/*.env".to_string(), FileSystemAccessMode::None),
("**/*.env".to_string(), FileSystemAccessMode::Deny),
("docs/**".to_string(), FileSystemAccessMode::Read),
("src/**/*.rs".to_string(), FileSystemAccessMode::Write),
])),
Expand All @@ -340,7 +340,7 @@ fn read_write_glob_warnings_skip_supported_deny_read_globs_and_trailing_subpaths
"/tmp/**/*.log".to_string(),
":workspace_roots/src/**/*.rs".to_string()
],
"`none` glob patterns are supported as deny-read rules; only `read`/`write` globs should warn"
"`deny` glob patterns are supported as deny-read rules; only `read`/`write` globs should warn"
);
}

Expand All @@ -351,8 +351,8 @@ fn unreadable_globstar_warning_is_suppressed_when_scan_depth_is_configured() {
entries: BTreeMap::from([(
":workspace_roots".to_string(),
FilesystemPermissionToml::Scoped(BTreeMap::from([
("**/*.env".to_string(), FileSystemAccessMode::None),
("*.pem".to_string(), FileSystemAccessMode::None),
("**/*.env".to_string(), FileSystemAccessMode::Deny),
("*.pem".to_string(), FileSystemAccessMode::Deny),
])),
)]),
};
Expand Down Expand Up @@ -435,7 +435,7 @@ fn read_write_glob_patterns_still_reject_non_subpath_globs() {
assert_eq!(err.kind(), std::io::ErrorKind::InvalidInput);
assert!(
err.to_string()
.contains("filesystem glob path `src/**/*.rs` only supports `none` access"),
.contains("filesystem glob path `src/**/*.rs` only supports `deny` access"),
"{err}"
);
}
6 changes: 3 additions & 3 deletions codex-rs/core/src/exec_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ fn windows_restricted_token_rejects_unreadable_split_carveouts() {
},
codex_protocol::permissions::FileSystemSandboxEntry {
path: codex_protocol::permissions::FileSystemPath::Path { path: blocked },
access: codex_protocol::permissions::FileSystemAccessMode::None,
access: codex_protocol::permissions::FileSystemAccessMode::Deny,
},
]);

Expand Down Expand Up @@ -846,7 +846,7 @@ fn windows_elevated_supports_unreadable_split_carveouts() {
path: codex_utils_absolute_path::AbsolutePathBuf::from_absolute_path(&blocked)
.expect("absolute blocked"),
},
access: codex_protocol::permissions::FileSystemAccessMode::None,
access: codex_protocol::permissions::FileSystemAccessMode::Deny,
},
]);

Expand Down Expand Up @@ -908,7 +908,7 @@ fn windows_elevated_supports_unreadable_globs() {
path: codex_protocol::permissions::FileSystemPath::GlobPattern {
pattern: "**/*.env".to_string(),
},
access: codex_protocol::permissions::FileSystemAccessMode::None,
access: codex_protocol::permissions::FileSystemAccessMode::Deny,
},
]);

Expand Down
2 changes: 1 addition & 1 deletion codex-rs/core/src/safety_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ fn explicit_unreadable_paths_prevent_auto_approval_for_external_sandbox() {
path: FileSystemPath::Path {
path: blocked_absolute,
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
]);

Expand Down
4 changes: 2 additions & 2 deletions codex-rs/core/src/session/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3522,7 +3522,7 @@ async fn session_configuration_apply_permission_profile_preserves_existing_deny_
path: FileSystemPath::GlobPattern {
pattern: "**/*.env".to_string(),
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
};
let mut existing_file_system_policy =
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
Expand Down Expand Up @@ -7171,7 +7171,7 @@ fn file_system_policy_with_unreadable_glob(turn_context: &TurnContext) -> FileSy
path: FileSystemPath::GlobPattern {
pattern: format!("{cwd_display}/**/*.env"),
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
});
policy
}
Expand Down
2 changes: 1 addition & 1 deletion codex-rs/core/src/tools/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ mod tests {
path: FileSystemPath::GlobPattern {
pattern: "**/*.env".to_string(),
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
],
glob_scan_max_depth: None,
Expand Down
Loading
Loading