mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Make deny canonical for filesystem permission entries (#23493)
## Why Filesystem permission profiles used `none` for deny-read entries, which is less direct than the action the entry actually represents. This change makes `deny` the canonical filesystem permission spelling while preserving compatibility for older configs that still send `none`. ## What changed - rename `FileSystemAccessMode::None` to `Deny` - serialize and generate schemas with `deny` as the canonical value - retain `none` only as a legacy input alias for temporary config compatibility - update filesystem glob diagnostics and regression coverage to use the canonical spelling - refresh config and app-server schema fixtures to match the new wire shape ## Validation - `cargo test -p codex-protocol` - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-core config_toml_deserializes_permission_profiles --lib` - `cargo test -p codex-core read_write_glob_patterns_still_reject_non_subpath_globs --lib` Earlier in the session, a broad `cargo test -p codex-core` run reached unrelated pre-existing failures in timing/snapshot/git-info tests under this environment; the targeted surfaces touched by this PR passed cleanly.
This commit is contained in:
committed by
GitHub
Unverified
parent
05b8ce4354
commit
3c76081876
+1
-1
@@ -277,7 +277,7 @@
|
||||
"enum": [
|
||||
"read",
|
||||
"write",
|
||||
"none"
|
||||
"deny"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@
|
||||
"enum": [
|
||||
"read",
|
||||
"write",
|
||||
"none"
|
||||
"deny"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@
|
||||
"enum": [
|
||||
"read",
|
||||
"write",
|
||||
"none"
|
||||
"deny"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1085,7 +1085,7 @@
|
||||
"enum": [
|
||||
"read",
|
||||
"write",
|
||||
"none"
|
||||
"deny"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
+1
-1
@@ -631,7 +631,7 @@
|
||||
"enum": [
|
||||
"read",
|
||||
"write",
|
||||
"none"
|
||||
"deny"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
+1
-1
@@ -8524,7 +8524,7 @@
|
||||
"enum": [
|
||||
"read",
|
||||
"write",
|
||||
"none"
|
||||
"deny"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
+1
-1
@@ -4913,7 +4913,7 @@
|
||||
"enum": [
|
||||
"read",
|
||||
"write",
|
||||
"none"
|
||||
"deny"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
Generated
+1
-1
@@ -69,7 +69,7 @@
|
||||
"enum": [
|
||||
"read",
|
||||
"write",
|
||||
"none"
|
||||
"deny"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
Generated
+1
-1
@@ -62,7 +62,7 @@
|
||||
"enum": [
|
||||
"read",
|
||||
"write",
|
||||
"none"
|
||||
"deny"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type FileSystemAccessMode = "read" | "write" | "none";
|
||||
export type FileSystemAccessMode = "read" | "write" | "deny";
|
||||
|
||||
@@ -178,7 +178,7 @@ v2_enum_from_core!(
|
||||
pub enum FileSystemAccessMode from CoreFileSystemAccessMode {
|
||||
Read,
|
||||
Write,
|
||||
None
|
||||
Deny
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -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),
|
||||
@@ -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,
|
||||
},
|
||||
]),
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -836,13 +836,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"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"FilesystemPermissionToml": {
|
||||
"anyOf": [
|
||||
|
||||
@@ -740,6 +740,7 @@ default_permissions = "workspace"
|
||||
|
||||
[permissions.workspace.filesystem]
|
||||
":minimal" = "read"
|
||||
"/tmp/secret.env" = "deny"
|
||||
|
||||
[permissions.workspace.filesystem.":workspace_roots"]
|
||||
"." = "write"
|
||||
@@ -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([
|
||||
@@ -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),
|
||||
])),
|
||||
)]),
|
||||
}),
|
||||
@@ -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,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2031,7 +2031,7 @@ 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 {
|
||||
@@ -2039,7 +2039,7 @@ fn apply_managed_filesystem_constraints(
|
||||
};
|
||||
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
|
||||
|
||||
@@ -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."
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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)?;
|
||||
@@ -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"
|
||||
),
|
||||
))
|
||||
}
|
||||
@@ -569,7 +569,7 @@ 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());
|
||||
@@ -577,7 +577,7 @@ fn unsupported_read_write_glob_paths(filesystem: &FilesystemPermissionsToml) ->
|
||||
}
|
||||
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}"));
|
||||
@@ -597,7 +597,7 @@ 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());
|
||||
}
|
||||
@@ -605,7 +605,7 @@ fn unbounded_unreadable_globstar_paths(filesystem: &FilesystemPermissionsToml) -
|
||||
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}"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
])),
|
||||
@@ -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"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
])),
|
||||
)]),
|
||||
};
|
||||
@@ -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}"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
@@ -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(
|
||||
@@ -7137,7 +7137,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
|
||||
}
|
||||
|
||||
@@ -441,7 +441,7 @@ mod tests {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/*.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
],
|
||||
glob_scan_max_depth: None,
|
||||
|
||||
@@ -2106,7 +2106,7 @@ async fn spawn_agent_reapplies_runtime_sandbox_after_role_config() {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
});
|
||||
let expected_network_sandbox_policy = NetworkSandboxPolicy::from(&expected_sandbox);
|
||||
let expected_permission_profile = PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
|
||||
@@ -281,7 +281,7 @@ fn shell_request_escalation_execution_is_explicit() {
|
||||
path: FileSystemPath::Path {
|
||||
path: AbsolutePathBuf::from_absolute_path("/tmp/secret").unwrap(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
let network_sandbox_policy = NetworkSandboxPolicy::Restricted;
|
||||
|
||||
@@ -143,7 +143,7 @@ fn deny_read_blocks_explicit_escalation_but_preserves_policy_bypass() {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/*.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}]);
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -148,7 +148,7 @@ fn workspace_write_with_unreadable_path(unreadable_path: AbsolutePathBuf) -> Per
|
||||
path: FileSystemPath::Path {
|
||||
path: unreadable_path,
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
|
||||
@@ -380,7 +380,7 @@ async fn shell_command_enforces_glob_deny_read_policy() -> Result<()> {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: format!("{}/**/*.env", config.cwd.as_path().display()),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
});
|
||||
config
|
||||
.permissions
|
||||
|
||||
@@ -2774,7 +2774,7 @@ async fn unified_exec_enforces_glob_deny_read_policy() -> Result<()> {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: format!("{}/**/*.env", config.cwd.as_path().display()),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
});
|
||||
config
|
||||
.permissions
|
||||
|
||||
@@ -527,7 +527,7 @@ async fn view_image_tool_applies_local_sandbox_read_denies() -> anyhow::Result<(
|
||||
path: FileSystemPath::Path {
|
||||
path: denied_path.clone(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
});
|
||||
let permission_profile = PermissionProfile::from_runtime_permissions(
|
||||
&file_system_sandbox_policy,
|
||||
|
||||
@@ -91,13 +91,13 @@ async fn windows_restricted_token_rejects_exact_and_glob_deny_read_policy() -> a
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/*.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path {
|
||||
path: future_secret,
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
let permission_profile = PermissionProfile::from_runtime_permissions(
|
||||
@@ -173,11 +173,11 @@ async fn windows_elevated_enforces_exact_and_glob_deny_read_policy() -> anyhow::
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/*.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: exact_secret },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
let permission_profile = PermissionProfile::from_runtime_permissions(
|
||||
|
||||
@@ -1347,7 +1347,7 @@ mod tests {
|
||||
fn unreadable_glob_entry(pattern: String) -> FileSystemSandboxEntry {
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::GlobPattern { pattern },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1547,7 +1547,7 @@ mod tests {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: link_blocked },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -1672,7 +1672,7 @@ mod tests {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: link_private },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -1989,7 +1989,7 @@ mod tests {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::project_roots(Some(".secrets".into())),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -2172,7 +2172,7 @@ mod tests {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: blocked },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -2299,7 +2299,7 @@ mod tests {
|
||||
path: FileSystemPath::Path {
|
||||
path: blocked.clone(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path {
|
||||
@@ -2368,7 +2368,7 @@ mod tests {
|
||||
path: FileSystemPath::Path {
|
||||
path: blocked.clone(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path {
|
||||
@@ -2447,7 +2447,7 @@ mod tests {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: blocked },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: allowed },
|
||||
@@ -2498,7 +2498,7 @@ mod tests {
|
||||
path: FileSystemPath::Path {
|
||||
path: blocked.clone(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -2542,7 +2542,7 @@ mod tests {
|
||||
path: FileSystemPath::Path {
|
||||
path: blocked_file.clone(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
@@ -805,7 +805,7 @@ async fn sandbox_blocks_explicit_split_policy_carveouts_under_bwrap() {
|
||||
path: FileSystemPath::Path {
|
||||
path: AbsolutePathBuf::try_from(blocked.as_path()).expect("absolute blocked dir"),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
let permission_profile = PermissionProfile::from_runtime_permissions(
|
||||
@@ -873,7 +873,7 @@ async fn sandbox_reenables_writable_subpaths_under_unreadable_parents() {
|
||||
path: FileSystemPath::Path {
|
||||
path: AbsolutePathBuf::try_from(blocked.as_path()).expect("absolute blocked dir"),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path {
|
||||
@@ -931,7 +931,7 @@ async fn sandbox_blocks_root_read_carveouts_under_bwrap() {
|
||||
path: FileSystemPath::Path {
|
||||
path: AbsolutePathBuf::try_from(blocked.as_path()).expect("absolute blocked dir"),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
let permission_profile = PermissionProfile::from_runtime_permissions(
|
||||
|
||||
@@ -126,7 +126,7 @@ impl FileSystemPermissions {
|
||||
match entry.access {
|
||||
FileSystemAccessMode::Read => read.push(path.clone()),
|
||||
FileSystemAccessMode::Write => write.push(path.clone()),
|
||||
FileSystemAccessMode::None => return None,
|
||||
FileSystemAccessMode::Deny => return None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1788,7 +1788,7 @@ mod tests {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/*.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}]);
|
||||
file_system_sandbox_policy.glob_scan_max_depth = Some(2);
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ impl NetworkSandboxPolicy {
|
||||
/// Access mode for a filesystem entry.
|
||||
///
|
||||
/// When two equally specific entries target the same path, we compare these by
|
||||
/// conflict precedence rather than by capability breadth: `none` beats
|
||||
/// conflict precedence rather than by capability breadth: `deny` beats
|
||||
/// `write`, and `write` beats `read`.
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -117,12 +117,14 @@ impl NetworkSandboxPolicy {
|
||||
pub enum FileSystemAccessMode {
|
||||
Read,
|
||||
Write,
|
||||
None,
|
||||
/// `none` is a legacy input alias retained temporarily for compatibility.
|
||||
#[serde(alias = "none")]
|
||||
Deny,
|
||||
}
|
||||
|
||||
impl FileSystemAccessMode {
|
||||
pub fn can_read(self) -> bool {
|
||||
!matches!(self, FileSystemAccessMode::None)
|
||||
!matches!(self, FileSystemAccessMode::Deny)
|
||||
}
|
||||
|
||||
pub fn can_write(self) -> bool {
|
||||
@@ -341,7 +343,7 @@ pub enum FileSystemPath {
|
||||
path: AbsolutePathBuf,
|
||||
},
|
||||
/// A git-style glob pattern. Pattern entries currently support
|
||||
/// FileSystemAccessMode::None only.
|
||||
/// FileSystemAccessMode::Deny only.
|
||||
GlobPattern {
|
||||
pattern: String,
|
||||
},
|
||||
@@ -412,7 +414,7 @@ impl FileSystemSandboxPolicy {
|
||||
&& self
|
||||
.entries
|
||||
.iter()
|
||||
.any(|entry| entry.access == FileSystemAccessMode::None)
|
||||
.any(|entry| entry.access == FileSystemAccessMode::Deny)
|
||||
}
|
||||
|
||||
pub fn from_legacy_sandbox_policy_preserving_deny_entries(
|
||||
@@ -429,7 +431,7 @@ impl FileSystemSandboxPolicy {
|
||||
for deny_entry in existing
|
||||
.entries
|
||||
.iter()
|
||||
.filter(|entry| entry.access == FileSystemAccessMode::None)
|
||||
.filter(|entry| entry.access == FileSystemAccessMode::Deny)
|
||||
{
|
||||
if !rebuilt.entries.iter().any(|entry| entry == deny_entry) {
|
||||
rebuilt.entries.push(deny_entry.clone());
|
||||
@@ -445,7 +447,7 @@ impl FileSystemSandboxPolicy {
|
||||
let has_deny_read_entries = existing
|
||||
.entries
|
||||
.iter()
|
||||
.any(|entry| entry.access == FileSystemAccessMode::None);
|
||||
.any(|entry| entry.access == FileSystemAccessMode::Deny);
|
||||
if matches!(self.kind, FileSystemSandboxKind::Unrestricted) && has_deny_read_entries {
|
||||
*self = Self::restricted(vec![FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
@@ -466,7 +468,7 @@ impl FileSystemSandboxPolicy {
|
||||
for deny_entry in existing
|
||||
.entries
|
||||
.iter()
|
||||
.filter(|entry| entry.access == FileSystemAccessMode::None)
|
||||
.filter(|entry| entry.access == FileSystemAccessMode::Deny)
|
||||
{
|
||||
if !self.entries.iter().any(|entry| entry == deny_entry) {
|
||||
self.entries.push(deny_entry.clone());
|
||||
@@ -492,7 +494,7 @@ impl FileSystemSandboxPolicy {
|
||||
FileSystemPath::Path { .. } => !self.has_same_target_write_override(entry),
|
||||
FileSystemPath::GlobPattern { .. } => true,
|
||||
FileSystemPath::Special { value } => match value {
|
||||
FileSystemSpecialPath::Root => entry.access == FileSystemAccessMode::None,
|
||||
FileSystemSpecialPath::Root => entry.access == FileSystemAccessMode::Deny,
|
||||
FileSystemSpecialPath::Minimal | FileSystemSpecialPath::Unknown { .. } => {
|
||||
false
|
||||
}
|
||||
@@ -654,7 +656,7 @@ impl FileSystemSandboxPolicy {
|
||||
}
|
||||
|
||||
let Some(path) = resolve_candidate_path(path, cwd) else {
|
||||
return FileSystemAccessMode::None;
|
||||
return FileSystemAccessMode::Deny;
|
||||
};
|
||||
|
||||
self.resolved_entries_with_cwd(cwd)
|
||||
@@ -662,7 +664,7 @@ impl FileSystemSandboxPolicy {
|
||||
.filter(|entry| path.as_path().starts_with(entry.path.as_path()))
|
||||
.max_by_key(resolved_entry_precedence)
|
||||
.map(|entry| entry.access)
|
||||
.unwrap_or(FileSystemAccessMode::None)
|
||||
.unwrap_or(FileSystemAccessMode::Deny)
|
||||
}
|
||||
|
||||
pub fn can_read_path_with_cwd(&self, path: &Path, cwd: &Path) -> bool {
|
||||
@@ -1062,7 +1064,7 @@ impl FileSystemSandboxPolicy {
|
||||
dedup_absolute_paths(
|
||||
self.resolved_entries_with_cwd(cwd)
|
||||
.iter()
|
||||
.filter(|entry| entry.access == FileSystemAccessMode::None)
|
||||
.filter(|entry| entry.access == FileSystemAccessMode::Deny)
|
||||
.filter(|entry| !self.can_read_path_with_cwd(entry.path.as_path(), cwd))
|
||||
// Restricted policies already deny reads outside explicit allow roots,
|
||||
// so materializing the filesystem root here would erase narrower
|
||||
@@ -1083,7 +1085,7 @@ impl FileSystemSandboxPolicy {
|
||||
let mut patterns = self
|
||||
.entries
|
||||
.iter()
|
||||
.filter(|entry| entry.access == FileSystemAccessMode::None)
|
||||
.filter(|entry| entry.access == FileSystemAccessMode::Deny)
|
||||
.filter_map(|entry| match &entry.path {
|
||||
FileSystemPath::GlobPattern { pattern } => {
|
||||
Some(AbsolutePathBuf::resolve_path_against_base(pattern, cwd))
|
||||
@@ -1142,7 +1144,7 @@ impl FileSystemSandboxPolicy {
|
||||
}
|
||||
FileSystemPath::Special { value } => match value {
|
||||
FileSystemSpecialPath::Root => match entry.access {
|
||||
FileSystemAccessMode::None => {}
|
||||
FileSystemAccessMode::Deny => {}
|
||||
FileSystemAccessMode::Read => {}
|
||||
FileSystemAccessMode::Write => {
|
||||
unbridgeable_root_write = true;
|
||||
@@ -2191,7 +2193,7 @@ mod tests {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: link_blocked },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -2253,7 +2255,7 @@ mod tests {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: link_blocked },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -2354,7 +2356,7 @@ mod tests {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: link_private },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -2401,7 +2403,7 @@ mod tests {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: link_private },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -2443,7 +2445,7 @@ mod tests {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: alias },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -2503,7 +2505,7 @@ mod tests {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: link_blocked },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -2549,7 +2551,7 @@ mod tests {
|
||||
path: FileSystemPath::Path {
|
||||
path: docs_private.clone(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path {
|
||||
@@ -2569,7 +2571,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
policy.resolve_access_with_cwd(docs_private.as_path(), cwd.path()),
|
||||
FileSystemAccessMode::None
|
||||
FileSystemAccessMode::Deny
|
||||
);
|
||||
assert_eq!(
|
||||
policy.resolve_access_with_cwd(docs_private_public.as_path(), cwd.path()),
|
||||
@@ -2710,7 +2712,7 @@ mod tests {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::Root,
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: docs.clone() },
|
||||
@@ -2746,14 +2748,14 @@ mod tests {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::Root,
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
assert!(!policy.has_full_disk_write_access());
|
||||
assert_eq!(
|
||||
policy.resolve_access_with_cwd(root.as_path(), cwd.path()),
|
||||
FileSystemAccessMode::None
|
||||
FileSystemAccessMode::Deny
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2877,7 +2879,7 @@ mod tests {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: project_roots_glob_pattern(Path::new("**/*.env")),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -2920,7 +2922,7 @@ mod tests {
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
@@ -2931,7 +2933,7 @@ mod tests {
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
])
|
||||
);
|
||||
@@ -2944,7 +2946,7 @@ mod tests {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: project_roots_glob_pattern(Path::new("**/*.env")),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}]);
|
||||
|
||||
let actual = policy.materialize_project_roots_with_cwd(cwd.path());
|
||||
@@ -2957,7 +2959,7 @@ mod tests {
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}])
|
||||
);
|
||||
}
|
||||
@@ -3006,7 +3008,7 @@ mod tests {
|
||||
#[test]
|
||||
fn file_system_access_mode_orders_by_conflict_precedence() {
|
||||
assert!(FileSystemAccessMode::Write > FileSystemAccessMode::Read);
|
||||
assert!(FileSystemAccessMode::None > FileSystemAccessMode::Write);
|
||||
assert!(FileSystemAccessMode::Deny > FileSystemAccessMode::Write);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -3016,7 +3018,7 @@ mod tests {
|
||||
path: FileSystemPath::Path {
|
||||
path: denied.clone(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}]);
|
||||
|
||||
let rebuilt = FileSystemSandboxPolicy::from_legacy_sandbox_policy_preserving_deny_entries(
|
||||
@@ -3031,7 +3033,7 @@ mod tests {
|
||||
== FileSystemPath::Path {
|
||||
path: denied.clone(),
|
||||
}
|
||||
&& entry.access == FileSystemAccessMode::None
|
||||
&& entry.access == FileSystemAccessMode::Deny
|
||||
}),
|
||||
"expected explicit deny entry to be preserved"
|
||||
);
|
||||
@@ -3064,14 +3066,14 @@ mod tests {
|
||||
path: FileSystemPath::Path {
|
||||
path: AbsolutePathBuf::try_from(path).expect("absolute deny path"),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}])
|
||||
}
|
||||
|
||||
fn unreadable_glob_entry(pattern: String) -> FileSystemSandboxEntry {
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::GlobPattern { pattern },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4211,7 +4211,7 @@ mod tests {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: blocked },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -4268,7 +4268,7 @@ mod tests {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: secret },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -5163,7 +5163,7 @@ mod tests {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "/tmp/private/**/*.txt".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
])),
|
||||
model: "gpt-5".to_string(),
|
||||
@@ -5191,7 +5191,7 @@ mod tests {
|
||||
"type": "glob_pattern",
|
||||
"pattern": "/tmp/private/**/*.txt"
|
||||
},
|
||||
"access": "none"
|
||||
"access": "deny"
|
||||
}]
|
||||
})
|
||||
);
|
||||
|
||||
@@ -183,7 +183,7 @@ fn transform_additional_permissions_preserves_denied_entries() {
|
||||
path: FileSystemPath::Path {
|
||||
path: denied_path.clone(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
let permissions = PermissionProfile::from_runtime_permissions(
|
||||
@@ -228,7 +228,7 @@ fn transform_additional_permissions_preserves_denied_entries() {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: denied_path },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: allowed_path },
|
||||
|
||||
@@ -28,7 +28,7 @@ pub fn normalize_additional_permissions(
|
||||
let glob_scan_max_depth = file_system.glob_scan_max_depth;
|
||||
for entry in file_system.entries {
|
||||
if matches!(&entry.path, FileSystemPath::GlobPattern { .. })
|
||||
&& entry.access != FileSystemAccessMode::None
|
||||
&& entry.access != FileSystemAccessMode::Deny
|
||||
{
|
||||
return Err(
|
||||
"glob file system permissions only support deny-read entries".to_string(),
|
||||
@@ -221,7 +221,7 @@ fn effective_glob_scan_depth(
|
||||
entries
|
||||
.iter()
|
||||
.any(|entry| {
|
||||
entry.access == FileSystemAccessMode::None
|
||||
entry.access == FileSystemAccessMode::Deny
|
||||
&& matches!(&entry.path, FileSystemPath::GlobPattern { .. })
|
||||
})
|
||||
.then_some(match depth {
|
||||
@@ -273,7 +273,7 @@ fn retain_constraining_deny_entries(
|
||||
let mut retained_entries = Vec::new();
|
||||
for entry in source_entries
|
||||
.iter()
|
||||
.filter(|entry| entry.access == FileSystemAccessMode::None)
|
||||
.filter(|entry| entry.access == FileSystemAccessMode::Deny)
|
||||
{
|
||||
if !deny_entry_constrains_accepted_grant(entry, accepted_entries, cwd) {
|
||||
continue;
|
||||
@@ -340,7 +340,7 @@ fn access_covers(requested: FileSystemAccessMode, granted: FileSystemAccessMode)
|
||||
match granted {
|
||||
FileSystemAccessMode::Read => requested.can_read(),
|
||||
FileSystemAccessMode::Write => requested.can_write(),
|
||||
FileSystemAccessMode::None => false,
|
||||
FileSystemAccessMode::Deny => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ fn root_write_policy_with_carveouts_still_uses_platform_sandbox() {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: blocked },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -187,7 +187,7 @@ fn normalize_additional_permissions_preserves_deny_globs() {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/*.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}],
|
||||
glob_scan_max_depth: std::num::NonZeroUsize::new(2),
|
||||
}),
|
||||
@@ -203,7 +203,7 @@ fn normalize_additional_permissions_preserves_deny_globs() {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/*.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}],
|
||||
glob_scan_max_depth: std::num::NonZeroUsize::new(2),
|
||||
}),
|
||||
@@ -427,7 +427,7 @@ fn intersect_permission_profiles_materializes_cwd_deny_entries() {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::project_roots(/*subpath*/ None),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
],
|
||||
glob_scan_max_depth: None,
|
||||
@@ -448,7 +448,7 @@ fn intersect_permission_profiles_materializes_cwd_deny_entries() {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: request_cwd },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
],
|
||||
glob_scan_max_depth: None,
|
||||
@@ -480,7 +480,7 @@ fn intersect_permission_profiles_drops_deny_entries_without_filesystem_grants()
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: secret },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
],
|
||||
glob_scan_max_depth: None,
|
||||
@@ -520,7 +520,7 @@ fn intersect_permission_profiles_rejects_concrete_grants_matched_by_requested_de
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/*.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
],
|
||||
glob_scan_max_depth: std::num::NonZeroUsize::new(2),
|
||||
@@ -558,7 +558,7 @@ fn intersect_permission_profiles_materializes_relative_deny_globs_for_reuse() {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/*.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
};
|
||||
let permissions = PermissionProfile {
|
||||
file_system: Some(FileSystemPermissions {
|
||||
@@ -586,7 +586,7 @@ fn intersect_permission_profiles_materializes_relative_deny_globs_for_reuse() {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: request_cwd.join("**/*.env").to_string_lossy().into_owned(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
],
|
||||
glob_scan_max_depth: std::num::NonZeroUsize::new(2),
|
||||
@@ -657,7 +657,7 @@ fn intersect_permission_profiles_uses_granted_bounded_glob_scan_depth() {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/*.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
};
|
||||
let requested = PermissionProfile {
|
||||
file_system: Some(FileSystemPermissions {
|
||||
@@ -689,7 +689,7 @@ fn intersect_permission_profiles_uses_granted_bounded_glob_scan_depth() {
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
],
|
||||
glob_scan_max_depth: std::num::NonZeroUsize::new(4),
|
||||
@@ -712,7 +712,7 @@ fn intersect_permission_profiles_uses_granted_unbounded_glob_scan_depth() {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/*.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
};
|
||||
let requested = PermissionProfile {
|
||||
file_system: Some(FileSystemPermissions {
|
||||
@@ -744,7 +744,7 @@ fn intersect_permission_profiles_uses_granted_unbounded_glob_scan_depth() {
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
],
|
||||
glob_scan_max_depth: None,
|
||||
@@ -775,7 +775,7 @@ fn merge_file_system_policy_with_additional_permissions_preserves_unreadable_roo
|
||||
path: FileSystemPath::Path {
|
||||
path: denied_path.clone(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]),
|
||||
&FileSystemPermissions::from_read_write_roots(
|
||||
@@ -787,7 +787,7 @@ fn merge_file_system_policy_with_additional_permissions_preserves_unreadable_roo
|
||||
assert_eq!(
|
||||
merged_policy.entries.contains(&FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: denied_path },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}),
|
||||
true
|
||||
);
|
||||
@@ -806,7 +806,7 @@ fn merge_file_system_policy_with_additional_permissions_carries_bounded_glob_sca
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/*.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
};
|
||||
let merged_policy = merge_file_system_policy_with_additional_permissions(
|
||||
&FileSystemSandboxPolicy::restricted(vec![FileSystemSandboxEntry {
|
||||
@@ -853,7 +853,7 @@ fn effective_file_system_sandbox_policy_returns_base_policy_without_additional_p
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: denied_path },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -883,7 +883,7 @@ fn effective_file_system_sandbox_policy_merges_additional_write_roots() {
|
||||
path: FileSystemPath::Path {
|
||||
path: denied_path.clone(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
let additional_permissions = PermissionProfile {
|
||||
@@ -900,7 +900,7 @@ fn effective_file_system_sandbox_policy_merges_additional_write_roots() {
|
||||
assert_eq!(
|
||||
effective_policy.entries.contains(&FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: denied_path },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}),
|
||||
true
|
||||
);
|
||||
|
||||
@@ -195,7 +195,7 @@ fn explicit_unreadable_paths_are_excluded_from_full_disk_read_and_write_access()
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: unreadable },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -267,7 +267,7 @@ fn explicit_unreadable_paths_are_excluded_from_readable_roots() {
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path: unreadable },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -372,7 +372,7 @@ fn unreadable_glob_policy_includes_canonicalized_static_prefix() {
|
||||
let mut policy = FileSystemSandboxPolicy::default();
|
||||
policy.entries.push(FileSystemSandboxEntry {
|
||||
path: FileSystemPath::GlobPattern { pattern },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
});
|
||||
|
||||
let seatbelt_policy = build_seatbelt_unreadable_glob_policy(&policy, temp_dir.path());
|
||||
|
||||
@@ -294,7 +294,7 @@ mod tests {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
],
|
||||
glob_scan_max_depth: None,
|
||||
|
||||
@@ -960,7 +960,7 @@ pub(crate) fn format_additional_permissions_rule(
|
||||
.entries
|
||||
.iter()
|
||||
.flatten()
|
||||
.filter(|entry| entry.access == FileSystemAccessMode::None),
|
||||
.filter(|entry| entry.access == FileSystemAccessMode::Deny),
|
||||
);
|
||||
if !denied_reads.is_empty() {
|
||||
parts.push(format!("deny read {denied_reads}"));
|
||||
@@ -1820,7 +1820,7 @@ mod tests {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/*.env".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]),
|
||||
glob_scan_max_depth: None,
|
||||
|
||||
@@ -112,7 +112,7 @@ async fn submission_includes_configured_active_permission_profile() {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "/home/user/project/secrets/**".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
],
|
||||
glob_scan_max_depth: None,
|
||||
|
||||
@@ -245,7 +245,7 @@ async fn session_configured_syncs_widget_config_permissions_and_cwd() {
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: "**/.secret".to_string(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
],
|
||||
glob_scan_max_depth: None,
|
||||
|
||||
@@ -43,7 +43,7 @@ pub fn resolve_windows_deny_read_paths(
|
||||
path: FileSystemPath::GlobPattern {
|
||||
pattern: pattern.clone(),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
@@ -205,7 +205,7 @@ mod tests {
|
||||
fn unreadable_glob_entry(pattern: String) -> FileSystemSandboxEntry {
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::GlobPattern { pattern },
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ mod tests {
|
||||
path: FileSystemPath::Path {
|
||||
path: AbsolutePathBuf::from_absolute_path(path).expect("absolute path"),
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
access: FileSystemAccessMode::Deny,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user