Use permission profiles for protected-model startup downgrades (#59933)

## What changed

Check the effective permission profile directly when applying startup restrictions for models that require automatic review, instead of converting it to a legacy sandbox policy.

Preserve the downgrade to `workspace-write` for profiles with full disk write access and enabled network access, excluding external enforcement and writable paths that cannot be converted to local paths. Share writable-path conversion with the legacy sandbox adapter.

## Testing

Add startup regression coverage for profiles that are downgraded, preserved, or rejected, including read-only carveouts and writable paths that cannot be converted locally. Verify restored permissions, automatic review selection, and workspace settings.

GitOrigin-RevId: 256c949f23d84dfba185a45a01b638ff5f1df52e
This commit is contained in:
ioanbudea-OAI
2026-11-06 16:00:54 +00:00
committed by copyberry
parent 814347ecd2
commit c1c07853fe
3 changed files with 202 additions and 8 deletions
+15 -3
View File
@@ -226,6 +226,19 @@ impl FileSystemSandboxEntry {
pub fn skips_missing_path(&self) -> bool {
self.missing_path_behavior == Some(FileSystemSandboxEntryMissingPathBehavior::Skip)
}
/// Projects an explicit writable path for the legacy native-path sandbox adapter.
/// Special paths and glob patterns are handled separately by that adapter.
pub fn legacy_writable_path(&self) -> io::Result<Option<AbsolutePathBuf>> {
match &self.path {
FileSystemPath::Path { path } if self.access.can_write() => {
path.to_abs_path().map(Some)
}
FileSystemPath::Path { .. }
| FileSystemPath::Special { .. }
| FileSystemPath::GlobPattern { .. } => Ok(None),
}
}
}
#[derive(
@@ -1880,9 +1893,8 @@ impl FileSystemSandboxPolicy {
for entry in &self.entries {
match &entry.path {
FileSystemPath::GlobPattern { .. } => {}
FileSystemPath::Path { path } => {
if entry.access.can_write() {
let path = path.to_abs_path()?;
FileSystemPath::Path { .. } => {
if let Some(path) = entry.legacy_writable_path()? {
if cwd_absolute.as_ref().is_some_and(|cwd| cwd == &path) {
workspace_root_writable = true;
} else {