Expose browser and computer-use requirements through app-server (#40000)

## What changed

- Expand `configRequirements/read` with the Browser/Computer Use umbrella
  policy and the complete browser-use policy, including origin-specific access,
  download, upload, auto-review, and approval controls.
- Return computer-use persistent approval, default app access, macOS bundle ID
  rules, and Windows AUMID and executable rules.
- Export the corresponding v2 protocol types and generated JSON and TypeScript
  schemas.

## Testing

- Extend the config requirements RPC test to cover the new browser and
  platform-specific computer-use fields.

GitOrigin-RevId: d1be93388701b06312a26853d640401b63b4d535
This commit is contained in:
rafael-oai
2026-08-21 19:56:52 +00:00
committed by copyberry
parent 9cdc66904f
commit 0f1a30b5c2
21 changed files with 1099 additions and 16 deletions
@@ -6666,6 +6666,13 @@
"AgentPath": {
"type": "string"
},
"AllowDenyRequirement": {
"enum": [
"allow",
"deny"
],
"type": "string"
},
"AnalyticsConfig": {
"additionalProperties": true,
"properties": {
@@ -7555,13 +7562,122 @@
},
"type": "object"
},
"BrowserUseAccessApprovalLifetime": {
"enum": [
"turn",
"thread"
],
"type": "string"
},
"BrowserUseOriginPolicy": {
"properties": {
"access": {
"anyOf": [
{
"$ref": "#/definitions/v2/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"accessApprovalLifetime": {
"anyOf": [
{
"$ref": "#/definitions/v2/BrowserUseAccessApprovalLifetime"
},
{
"type": "null"
}
]
},
"autoReview": {
"anyOf": [
{
"$ref": "#/definitions/v2/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"downloads": {
"anyOf": [
{
"$ref": "#/definitions/v2/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"fullCdpAccess": {
"anyOf": [
{
"$ref": "#/definitions/v2/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"persistentApproval": {
"type": [
"boolean",
"null"
]
},
"uploads": {
"anyOf": [
{
"$ref": "#/definitions/v2/AllowDenyRequirement"
},
{
"type": "null"
}
]
}
},
"type": "object"
},
"BrowserUseRequirements": {
"properties": {
"allowGlobalPersistentApproval": {
"type": [
"boolean",
"null"
]
},
"allowHistoryAccess": {
"type": [
"boolean",
"null"
]
},
"defaultOriginPolicy": {
"anyOf": [
{
"$ref": "#/definitions/v2/BrowserUseOriginPolicy"
},
{
"type": "null"
}
]
},
"disableAutoReview": {
"type": [
"boolean",
"null"
]
},
"origins": {
"additionalProperties": {
"$ref": "#/definitions/v2/BrowserUseOriginPolicy"
},
"type": [
"object",
"null"
]
}
},
"type": "object"
@@ -8365,6 +8481,20 @@
],
"type": "object"
},
"ComputerUseMacosRequirements": {
"properties": {
"bundleIds": {
"additionalProperties": {
"$ref": "#/definitions/v2/AllowDenyRequirement"
},
"type": [
"object",
"null"
]
}
},
"type": "object"
},
"ComputerUseRequirements": {
"properties": {
"allowLockedComputerUse": {
@@ -8372,6 +8502,90 @@
"boolean",
"null"
]
},
"allowPersistentApproval": {
"type": [
"boolean",
"null"
]
},
"defaultAppAccess": {
"anyOf": [
{
"$ref": "#/definitions/v2/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"macos": {
"anyOf": [
{
"$ref": "#/definitions/v2/ComputerUseMacosRequirements"
},
{
"type": "null"
}
]
},
"windows": {
"anyOf": [
{
"$ref": "#/definitions/v2/ComputerUseWindowsRequirements"
},
{
"type": "null"
}
]
}
},
"type": "object"
},
"ComputerUseWindowsExeRequirement": {
"properties": {
"access": {
"$ref": "#/definitions/v2/AllowDenyRequirement"
},
"binaryName": {
"type": [
"string",
"null"
]
},
"productName": {
"type": "string"
},
"publisherName": {
"type": "string"
}
},
"required": [
"access",
"productName",
"publisherName"
],
"type": "object"
},
"ComputerUseWindowsRequirements": {
"properties": {
"aumids": {
"additionalProperties": {
"$ref": "#/definitions/v2/AllowDenyRequirement"
},
"type": [
"object",
"null"
]
},
"exes": {
"items": {
"$ref": "#/definitions/v2/ComputerUseWindowsExeRequirement"
},
"type": [
"array",
"null"
]
}
},
"type": "object"
@@ -8940,6 +9154,12 @@
"null"
]
},
"allowBrowserAndComputerUse": {
"type": [
"boolean",
"null"
]
},
"allowLoginShell": {
"type": [
"boolean",
@@ -391,6 +391,13 @@
"AgentPath": {
"type": "string"
},
"AllowDenyRequirement": {
"enum": [
"allow",
"deny"
],
"type": "string"
},
"AnalyticsConfig": {
"additionalProperties": true,
"properties": {
@@ -1280,13 +1287,122 @@
},
"type": "object"
},
"BrowserUseAccessApprovalLifetime": {
"enum": [
"turn",
"thread"
],
"type": "string"
},
"BrowserUseOriginPolicy": {
"properties": {
"access": {
"anyOf": [
{
"$ref": "#/definitions/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"accessApprovalLifetime": {
"anyOf": [
{
"$ref": "#/definitions/BrowserUseAccessApprovalLifetime"
},
{
"type": "null"
}
]
},
"autoReview": {
"anyOf": [
{
"$ref": "#/definitions/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"downloads": {
"anyOf": [
{
"$ref": "#/definitions/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"fullCdpAccess": {
"anyOf": [
{
"$ref": "#/definitions/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"persistentApproval": {
"type": [
"boolean",
"null"
]
},
"uploads": {
"anyOf": [
{
"$ref": "#/definitions/AllowDenyRequirement"
},
{
"type": "null"
}
]
}
},
"type": "object"
},
"BrowserUseRequirements": {
"properties": {
"allowGlobalPersistentApproval": {
"type": [
"boolean",
"null"
]
},
"allowHistoryAccess": {
"type": [
"boolean",
"null"
]
},
"defaultOriginPolicy": {
"anyOf": [
{
"$ref": "#/definitions/BrowserUseOriginPolicy"
},
{
"type": "null"
}
]
},
"disableAutoReview": {
"type": [
"boolean",
"null"
]
},
"origins": {
"additionalProperties": {
"$ref": "#/definitions/BrowserUseOriginPolicy"
},
"type": [
"object",
"null"
]
}
},
"type": "object"
@@ -4403,6 +4519,20 @@
],
"type": "object"
},
"ComputerUseMacosRequirements": {
"properties": {
"bundleIds": {
"additionalProperties": {
"$ref": "#/definitions/AllowDenyRequirement"
},
"type": [
"object",
"null"
]
}
},
"type": "object"
},
"ComputerUseRequirements": {
"properties": {
"allowLockedComputerUse": {
@@ -4410,6 +4540,90 @@
"boolean",
"null"
]
},
"allowPersistentApproval": {
"type": [
"boolean",
"null"
]
},
"defaultAppAccess": {
"anyOf": [
{
"$ref": "#/definitions/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"macos": {
"anyOf": [
{
"$ref": "#/definitions/ComputerUseMacosRequirements"
},
{
"type": "null"
}
]
},
"windows": {
"anyOf": [
{
"$ref": "#/definitions/ComputerUseWindowsRequirements"
},
{
"type": "null"
}
]
}
},
"type": "object"
},
"ComputerUseWindowsExeRequirement": {
"properties": {
"access": {
"$ref": "#/definitions/AllowDenyRequirement"
},
"binaryName": {
"type": [
"string",
"null"
]
},
"productName": {
"type": "string"
},
"publisherName": {
"type": "string"
}
},
"required": [
"access",
"productName",
"publisherName"
],
"type": "object"
},
"ComputerUseWindowsRequirements": {
"properties": {
"aumids": {
"additionalProperties": {
"$ref": "#/definitions/AllowDenyRequirement"
},
"type": [
"object",
"null"
]
},
"exes": {
"items": {
"$ref": "#/definitions/ComputerUseWindowsExeRequirement"
},
"type": [
"array",
"null"
]
}
},
"type": "object"
@@ -4978,6 +5192,12 @@
"null"
]
},
"allowBrowserAndComputerUse": {
"type": [
"boolean",
"null"
]
},
"allowLoginShell": {
"type": [
"boolean",
@@ -1,6 +1,13 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"AllowDenyRequirement": {
"enum": [
"allow",
"deny"
],
"type": "string"
},
"ApprovalsReviewer": {
"description": "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `auto_review` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request. The legacy value `guardian_subagent` is accepted for compatibility.",
"enum": [
@@ -82,13 +89,122 @@
},
"type": "object"
},
"BrowserUseAccessApprovalLifetime": {
"enum": [
"turn",
"thread"
],
"type": "string"
},
"BrowserUseOriginPolicy": {
"properties": {
"access": {
"anyOf": [
{
"$ref": "#/definitions/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"accessApprovalLifetime": {
"anyOf": [
{
"$ref": "#/definitions/BrowserUseAccessApprovalLifetime"
},
{
"type": "null"
}
]
},
"autoReview": {
"anyOf": [
{
"$ref": "#/definitions/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"downloads": {
"anyOf": [
{
"$ref": "#/definitions/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"fullCdpAccess": {
"anyOf": [
{
"$ref": "#/definitions/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"persistentApproval": {
"type": [
"boolean",
"null"
]
},
"uploads": {
"anyOf": [
{
"$ref": "#/definitions/AllowDenyRequirement"
},
{
"type": "null"
}
]
}
},
"type": "object"
},
"BrowserUseRequirements": {
"properties": {
"allowGlobalPersistentApproval": {
"type": [
"boolean",
"null"
]
},
"allowHistoryAccess": {
"type": [
"boolean",
"null"
]
},
"defaultOriginPolicy": {
"anyOf": [
{
"$ref": "#/definitions/BrowserUseOriginPolicy"
},
{
"type": "null"
}
]
},
"disableAutoReview": {
"type": [
"boolean",
"null"
]
},
"origins": {
"additionalProperties": {
"$ref": "#/definitions/BrowserUseOriginPolicy"
},
"type": [
"object",
"null"
]
}
},
"type": "object"
@@ -102,6 +218,20 @@
],
"type": "string"
},
"ComputerUseMacosRequirements": {
"properties": {
"bundleIds": {
"additionalProperties": {
"$ref": "#/definitions/AllowDenyRequirement"
},
"type": [
"object",
"null"
]
}
},
"type": "object"
},
"ComputerUseRequirements": {
"properties": {
"allowLockedComputerUse": {
@@ -109,6 +239,90 @@
"boolean",
"null"
]
},
"allowPersistentApproval": {
"type": [
"boolean",
"null"
]
},
"defaultAppAccess": {
"anyOf": [
{
"$ref": "#/definitions/AllowDenyRequirement"
},
{
"type": "null"
}
]
},
"macos": {
"anyOf": [
{
"$ref": "#/definitions/ComputerUseMacosRequirements"
},
{
"type": "null"
}
]
},
"windows": {
"anyOf": [
{
"$ref": "#/definitions/ComputerUseWindowsRequirements"
},
{
"type": "null"
}
]
}
},
"type": "object"
},
"ComputerUseWindowsExeRequirement": {
"properties": {
"access": {
"$ref": "#/definitions/AllowDenyRequirement"
},
"binaryName": {
"type": [
"string",
"null"
]
},
"productName": {
"type": "string"
},
"publisherName": {
"type": "string"
}
},
"required": [
"access",
"productName",
"publisherName"
],
"type": "object"
},
"ComputerUseWindowsRequirements": {
"properties": {
"aumids": {
"additionalProperties": {
"$ref": "#/definitions/AllowDenyRequirement"
},
"type": [
"object",
"null"
]
},
"exes": {
"items": {
"$ref": "#/definitions/ComputerUseWindowsExeRequirement"
},
"type": [
"array",
"null"
]
}
},
"type": "object"
@@ -127,6 +341,12 @@
"null"
]
},
"allowBrowserAndComputerUse": {
"type": [
"boolean",
"null"
]
},
"allowLoginShell": {
"type": [
"boolean",
@@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type AllowDenyRequirement = "allow" | "deny";
@@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type BrowserUseAccessApprovalLifetime = "turn" | "thread";
@@ -0,0 +1,7 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { AllowDenyRequirement } from "./AllowDenyRequirement";
import type { BrowserUseAccessApprovalLifetime } from "./BrowserUseAccessApprovalLifetime";
export type BrowserUseOriginPolicy = { access: AllowDenyRequirement | null, downloads: AllowDenyRequirement | null, uploads: AllowDenyRequirement | null, fullCdpAccess: AllowDenyRequirement | null, autoReview: AllowDenyRequirement | null, persistentApproval: boolean | null, accessApprovalLifetime: BrowserUseAccessApprovalLifetime | null, };
@@ -1,5 +1,6 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { BrowserUseOriginPolicy } from "./BrowserUseOriginPolicy";
export type BrowserUseRequirements = { disableAutoReview: boolean | null, };
export type BrowserUseRequirements = { allowHistoryAccess: boolean | null, disableAutoReview: boolean | null, allowGlobalPersistentApproval: boolean | null, defaultOriginPolicy: BrowserUseOriginPolicy | null, origins: { [key in string]?: BrowserUseOriginPolicy } | null, };
@@ -0,0 +1,6 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { AllowDenyRequirement } from "./AllowDenyRequirement";
export type ComputerUseMacosRequirements = { bundleIds: { [key in string]?: AllowDenyRequirement } | null, };
@@ -1,5 +1,8 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { AllowDenyRequirement } from "./AllowDenyRequirement";
import type { ComputerUseMacosRequirements } from "./ComputerUseMacosRequirements";
import type { ComputerUseWindowsRequirements } from "./ComputerUseWindowsRequirements";
export type ComputerUseRequirements = { allowLockedComputerUse: boolean | null, };
export type ComputerUseRequirements = { allowLockedComputerUse: boolean | null, allowPersistentApproval: boolean | null, defaultAppAccess: AllowDenyRequirement | null, macos: ComputerUseMacosRequirements | null, windows: ComputerUseWindowsRequirements | null, };
@@ -0,0 +1,6 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { AllowDenyRequirement } from "./AllowDenyRequirement";
export type ComputerUseWindowsExeRequirement = { publisherName: string, productName: string, binaryName: string | null, access: AllowDenyRequirement, };
@@ -0,0 +1,7 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { AllowDenyRequirement } from "./AllowDenyRequirement";
import type { ComputerUseWindowsExeRequirement } from "./ComputerUseWindowsExeRequirement";
export type ComputerUseWindowsRequirements = { aumids: { [key in string]?: AllowDenyRequirement } | null, exes: Array<ComputerUseWindowsExeRequirement> | null, };
@@ -15,4 +15,4 @@ import type { ResidencyRequirement } from "./ResidencyRequirement";
import type { SandboxMode } from "./SandboxMode";
import type { WindowsSandboxSetupMode } from "./WindowsSandboxSetupMode";
export type ConfigRequirements = {cliAuthCredentialsStore: CliAuthCredentialsStoreMode | null, chatgptBaseUrl: string | null, additionalDeveloperInstructions: string | null, allowedApprovalPolicies: Array<AskForApproval> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWindowsSandboxImplementations: Array<WindowsSandboxSetupMode> | null, allowedPermissionProfiles: { [key in string]?: boolean } | null, defaultPermissions: string | null, allowedWebSearchModes: Array<WebSearchMode> | null, allowManagedHooksOnly: boolean | null, allowAppshots: boolean | null, allowRemoteControl: boolean | null, computerUse: ComputerUseRequirements | null, browserUse: BrowserUseRequirements | null, inAppBrowser: InAppBrowserRequirements | null, featureRequirements: { [key in string]?: boolean } | null, enforceResidency: ResidencyRequirement | null, autoReview: AutoReviewRequirements | null, models: ModelsRequirements | null, sqliteHome: PathUri | null, logDir: PathUri | null, modelCatalogJson: PathUri | null, checkForUpdateOnStartup: boolean | null, allowLoginShell: boolean | null, feedback: FeedbackRequirements | null, windowsSandboxPrivateDesktop: boolean | null};
export type ConfigRequirements = {cliAuthCredentialsStore: CliAuthCredentialsStoreMode | null, chatgptBaseUrl: string | null, additionalDeveloperInstructions: string | null, allowedApprovalPolicies: Array<AskForApproval> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWindowsSandboxImplementations: Array<WindowsSandboxSetupMode> | null, allowedPermissionProfiles: { [key in string]?: boolean } | null, defaultPermissions: string | null, allowedWebSearchModes: Array<WebSearchMode> | null, allowManagedHooksOnly: boolean | null, allowBrowserAndComputerUse: boolean | null, allowAppshots: boolean | null, allowRemoteControl: boolean | null, computerUse: ComputerUseRequirements | null, browserUse: BrowserUseRequirements | null, inAppBrowser: InAppBrowserRequirements | null, featureRequirements: { [key in string]?: boolean } | null, enforceResidency: ResidencyRequirement | null, autoReview: AutoReviewRequirements | null, models: ModelsRequirements | null, sqliteHome: PathUri | null, logDir: PathUri | null, modelCatalogJson: PathUri | null, checkForUpdateOnStartup: boolean | null, allowLoginShell: boolean | null, feedback: FeedbackRequirements | null, windowsSandboxPrivateDesktop: boolean | null};
@@ -16,6 +16,7 @@ export type { AdditionalNetworkPermissions } from "./AdditionalNetworkPermission
export type { AdditionalPermissionProfile } from "./AdditionalPermissionProfile";
export type { AgentMessageDelivery } from "./AgentMessageDelivery";
export type { AgentMessageDeltaNotification } from "./AgentMessageDeltaNotification";
export type { AllowDenyRequirement } from "./AllowDenyRequirement";
export type { AnalyticsConfig } from "./AnalyticsConfig";
export type { AppBranding } from "./AppBranding";
export type { AppInfo } from "./AppInfo";
@@ -43,6 +44,8 @@ export type { AttestationGenerateParams } from "./AttestationGenerateParams";
export type { AttestationGenerateResponse } from "./AttestationGenerateResponse";
export type { AutoReviewDecisionSource } from "./AutoReviewDecisionSource";
export type { AutoReviewRequirements } from "./AutoReviewRequirements";
export type { BrowserUseAccessApprovalLifetime } from "./BrowserUseAccessApprovalLifetime";
export type { BrowserUseOriginPolicy } from "./BrowserUseOriginPolicy";
export type { BrowserUseRequirements } from "./BrowserUseRequirements";
export type { ByteRange } from "./ByteRange";
export type { CancelLoginAccountParams } from "./CancelLoginAccountParams";
@@ -78,7 +81,10 @@ export type { CommandExecutionRequestApprovalResponse } from "./CommandExecution
export type { CommandExecutionSource } from "./CommandExecutionSource";
export type { CommandExecutionStatus } from "./CommandExecutionStatus";
export type { CommandMigration } from "./CommandMigration";
export type { ComputerUseMacosRequirements } from "./ComputerUseMacosRequirements";
export type { ComputerUseRequirements } from "./ComputerUseRequirements";
export type { ComputerUseWindowsExeRequirement } from "./ComputerUseWindowsExeRequirement";
export type { ComputerUseWindowsRequirements } from "./ComputerUseWindowsRequirements";
export type { Config } from "./Config";
export type { ConfigBatchWriteParams } from "./ConfigBatchWriteParams";
export type { ConfigEdit } from "./ConfigEdit";
@@ -396,6 +396,7 @@ pub struct ConfigRequirements {
pub default_permissions: Option<String>,
pub allowed_web_search_modes: Option<Vec<WebSearchMode>>,
pub allow_managed_hooks_only: Option<bool>,
pub allow_browser_and_computer_use: Option<bool>,
pub allow_appshots: Option<bool>,
pub allow_remote_control: Option<bool>,
pub computer_use: Option<ComputerUseRequirements>,
@@ -467,13 +468,75 @@ pub struct FeedbackRequirements {
#[ts(export_to = "v2/")]
pub struct ComputerUseRequirements {
pub allow_locked_computer_use: Option<bool>,
pub allow_persistent_approval: Option<bool>,
pub default_app_access: Option<AllowDenyRequirement>,
pub macos: Option<ComputerUseMacosRequirements>,
pub windows: Option<ComputerUseWindowsRequirements>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct BrowserUseRequirements {
pub allow_history_access: Option<bool>,
pub disable_auto_review: Option<bool>,
pub allow_global_persistent_approval: Option<bool>,
pub default_origin_policy: Option<BrowserUseOriginPolicy>,
pub origins: Option<BTreeMap<String, BrowserUseOriginPolicy>>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct BrowserUseOriginPolicy {
pub access: Option<AllowDenyRequirement>,
pub downloads: Option<AllowDenyRequirement>,
pub uploads: Option<AllowDenyRequirement>,
pub full_cdp_access: Option<AllowDenyRequirement>,
pub auto_review: Option<AllowDenyRequirement>,
pub persistent_approval: Option<bool>,
pub access_approval_lifetime: Option<BrowserUseAccessApprovalLifetime>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "lowercase")]
#[ts(rename_all = "lowercase", export_to = "v2/")]
pub enum AllowDenyRequirement {
Allow,
Deny,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "lowercase")]
#[ts(rename_all = "lowercase", export_to = "v2/")]
pub enum BrowserUseAccessApprovalLifetime {
Turn,
Thread,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ComputerUseMacosRequirements {
pub bundle_ids: Option<BTreeMap<String, AllowDenyRequirement>>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ComputerUseWindowsRequirements {
pub aumids: Option<BTreeMap<String, AllowDenyRequirement>>,
pub exes: Option<Vec<ComputerUseWindowsExeRequirement>>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ComputerUseWindowsExeRequirement {
pub publisher_name: String,
pub product_name: String,
pub binary_name: Option<String>,
pub access: AllowDenyRequirement,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
@@ -2057,6 +2057,7 @@ fn config_requirements_granular_allowed_approval_policy_is_marked_experimental()
default_permissions: None,
allowed_web_search_modes: None,
allow_managed_hooks_only: None,
allow_browser_and_computer_use: None,
allow_appshots: None,
allow_remote_control: None,
computer_use: None,
+1 -1
View File
@@ -290,7 +290,7 @@ Example with notification opt-out:
- `externalAgentConfig/import/readHistories` — read completed import histories and connector candidates detected from successfully imported session histories. Successful session entries include the original imported title when one was available. Connector candidates include a normalized display `name`, the number of imported sessions that used the connector, and the source metadata field used for detection.
- `config/value/write` — write a single config key/value to the user's config.toml on disk; dotted paths such as `desktop.someKey` use the same generic write surface. Writes that overlap a managed requirement are rejected with `configRequirementReadonly`.
- `config/batchWrite` — apply multiple config edits atomically to the user's config.toml on disk, with optional `reloadUserConfig: true` to hot-reload loaded threads, including multiple `desktop.*` edits. Session-static model, reasoning-effort, Plan-mode reasoning-effort, service-tier, and personality defaults do not reload existing threads.
- `configRequirements/read` — fetch loaded requirements constraints from `requirements.toml` and/or MDM (or `null` if none are configured), including exact managed values (`cliAuthCredentialsStore`, `chatgptBaseUrl`, `sqliteHome`, `logDir`, `modelCatalogJson`, `checkForUpdateOnStartup`, `allowLoginShell`, `feedback.enabled`, and `windowsSandboxPrivateDesktop`), requirements-only developer instructions (`additionalDeveloperInstructions`, supplied independently of ordinary developer instructions), allow-lists (`allowedApprovalPolicies`, `allowedSandboxModes`, `allowedWebSearchModes`), the layered permission-profile allow map (`allowedPermissionProfiles`), the managed permission-profile default (`defaultPermissions`), lifecycle hook lockdown (`allowManagedHooksOnly`), remote-control policy (`allowRemoteControl`; `false` force-disables remote control while `true` or `null` preserves existing behavior), computer use policy (`computerUse`), Browser Use policy (`browserUse.disableAutoReview`), interactive browser import policy (`inAppBrowser.allowExternalBrowserSettingsImport`), pinned feature values (`featureRequirements`, including the default-allowed `in_app_updates` policy that administrators can set to `false`), managed lifecycle hooks (`hooks`, including command handlers with optional `additionalContextLimit` and `mcp_tool` handlers with `server`, `tool`, `input`, `timeoutSec`, and `statusMessage`), `enforceResidency`, managed automatic review (`autoReview.requiredOnModels` and `autoReview.ignoreRules`), model defaults (`models.newThread.model`, `models.newThread.modelReasoningEffort`, and `models.newThread.serviceTier`), and `network` constraints such as canonical domain/socket permissions plus `managedAllowedDomainsOnly` and `dangerFullAccessDenylistOnly`.
- `configRequirements/read` — fetch loaded requirements constraints from `requirements.toml` and/or MDM (or `null` if none are configured), including exact managed values (`cliAuthCredentialsStore`, `chatgptBaseUrl`, `sqliteHome`, `logDir`, `modelCatalogJson`, `checkForUpdateOnStartup`, `allowLoginShell`, `feedback.enabled`, and `windowsSandboxPrivateDesktop`), requirements-only developer instructions (`additionalDeveloperInstructions`, supplied independently of ordinary developer instructions), allow-lists (`allowedApprovalPolicies`, `allowedSandboxModes`, `allowedWebSearchModes`), the layered permission-profile allow map (`allowedPermissionProfiles`), the managed permission-profile default (`defaultPermissions`), lifecycle hook lockdown (`allowManagedHooksOnly`), remote-control policy (`allowRemoteControl`; `false` force-disables remote control while `true` or `null` preserves existing behavior), the Browser/Computer Use umbrella policy (`allowBrowserAndComputerUse`), computer use policy (`computerUse`, including persistent approval, default application access, and per-platform application rules), Browser Use policy (`browserUse`, including history access, origin rules, auto-review, and approval controls), interactive browser import policy (`inAppBrowser.allowExternalBrowserSettingsImport`), pinned feature values (`featureRequirements`, including the default-allowed `in_app_updates` policy that administrators can set to `false`), managed lifecycle hooks (`hooks`, including command handlers with optional `additionalContextLimit` and `mcp_tool` handlers with `server`, `tool`, `input`, `timeoutSec`, and `statusMessage`), `enforceResidency`, managed automatic review (`autoReview.requiredOnModels` and `autoReview.ignoreRules`), model defaults (`models.newThread.model`, `models.newThread.modelReasoningEffort`, and `models.newThread.serviceTier`), and `network` constraints such as canonical domain/socket permissions plus `managedAllowedDomainsOnly` and `dangerFullAccessDenylistOnly`.
### Example: Start or resume a thread
@@ -7,11 +7,17 @@ use crate::error_code::invalid_request;
use crate::outgoing_message::ConnectionRequestId;
use crate::outgoing_message::OutgoingMessageSender;
use codex_analytics::AnalyticsEventsClient;
use codex_app_server_protocol::AllowDenyRequirement;
use codex_app_server_protocol::AutoReviewRequirements;
use codex_app_server_protocol::BrowserUseAccessApprovalLifetime;
use codex_app_server_protocol::BrowserUseOriginPolicy;
use codex_app_server_protocol::BrowserUseRequirements;
use codex_app_server_protocol::CliAuthCredentialsStoreMode;
use codex_app_server_protocol::ClientResponsePayload;
use codex_app_server_protocol::ComputerUseMacosRequirements;
use codex_app_server_protocol::ComputerUseRequirements;
use codex_app_server_protocol::ComputerUseWindowsExeRequirement;
use codex_app_server_protocol::ComputerUseWindowsRequirements;
use codex_app_server_protocol::ConfigBatchWriteParams;
use codex_app_server_protocol::ConfigReadParams;
use codex_app_server_protocol::ConfigReadResponse;
@@ -420,6 +426,7 @@ fn map_requirements_toml_to_api(requirements: ConfigRequirementsToml) -> ConfigR
normalized
}),
allow_managed_hooks_only: requirements.allow_managed_hooks_only,
allow_browser_and_computer_use: requirements.allow_browser_and_computer_use,
allow_appshots: requirements.allow_appshots,
allow_remote_control: requirements.allow_remote_control,
computer_use: requirements
@@ -472,6 +479,44 @@ fn map_computer_use_requirements_to_api(
) -> ComputerUseRequirements {
ComputerUseRequirements {
allow_locked_computer_use: computer_use.allow_locked_computer_use,
allow_persistent_approval: computer_use.allow_persistent_approval,
default_app_access: computer_use
.default_app_access
.map(map_allow_deny_requirement_to_api),
macos: computer_use
.macos
.map(|macos| ComputerUseMacosRequirements {
bundle_ids: macos.bundle_ids.map(|bundle_ids| {
bundle_ids
.into_iter()
.map(|(bundle_id, requirement)| {
(bundle_id, map_allow_deny_requirement_to_api(requirement))
})
.collect()
}),
}),
windows: computer_use
.windows
.map(|windows| ComputerUseWindowsRequirements {
aumids: windows.aumids.map(|aumids| {
aumids
.into_iter()
.map(|(aumid, requirement)| {
(aumid, map_allow_deny_requirement_to_api(requirement))
})
.collect()
}),
exes: windows.exes.map(|exes| {
exes.into_iter()
.map(|exe| ComputerUseWindowsExeRequirement {
publisher_name: exe.publisher_name,
product_name: exe.product_name,
binary_name: exe.binary_name,
access: map_allow_deny_requirement_to_api(exe.access),
})
.collect()
}),
}),
}
}
@@ -479,7 +524,58 @@ fn map_browser_use_requirements_to_api(
browser_use: codex_config::BrowserUseRequirementsToml,
) -> BrowserUseRequirements {
BrowserUseRequirements {
allow_history_access: browser_use.allow_history_access,
disable_auto_review: browser_use.disable_auto_review,
allow_global_persistent_approval: browser_use.allow_global_persistent_approval,
default_origin_policy: browser_use
.default_origin_policy
.map(map_browser_use_origin_policy_to_api),
origins: browser_use.origins.map(|origins| {
origins
.into_iter()
.map(|(pattern, policy)| (pattern, map_browser_use_origin_policy_to_api(policy)))
.collect()
}),
}
}
fn map_browser_use_origin_policy_to_api(
policy: codex_config::BrowserUseOriginPolicyToml,
) -> BrowserUseOriginPolicy {
BrowserUseOriginPolicy {
access: policy.access.map(map_allow_deny_requirement_to_api),
downloads: policy.downloads.map(map_allow_deny_requirement_to_api),
uploads: policy.uploads.map(map_allow_deny_requirement_to_api),
full_cdp_access: policy
.full_cdp_access
.map(map_allow_deny_requirement_to_api),
auto_review: policy.auto_review.map(map_allow_deny_requirement_to_api),
persistent_approval: policy.persistent_approval,
access_approval_lifetime: policy
.access_approval_lifetime
.map(map_browser_use_access_approval_lifetime_to_api),
}
}
fn map_allow_deny_requirement_to_api(
requirement: codex_config::AllowDenyRequirementToml,
) -> AllowDenyRequirement {
match requirement {
codex_config::AllowDenyRequirementToml::Allow => AllowDenyRequirement::Allow,
codex_config::AllowDenyRequirementToml::Deny => AllowDenyRequirement::Deny,
}
}
fn map_browser_use_access_approval_lifetime_to_api(
lifetime: codex_config::BrowserUseAccessApprovalLifetimeToml,
) -> BrowserUseAccessApprovalLifetime {
match lifetime {
codex_config::BrowserUseAccessApprovalLifetimeToml::Turn => {
BrowserUseAccessApprovalLifetime::Turn
}
codex_config::BrowserUseAccessApprovalLifetimeToml::Thread => {
BrowserUseAccessApprovalLifetime::Thread
}
}
}
@@ -679,11 +775,26 @@ fn config_write_error(code: ConfigWriteErrorCode, message: impl Into<String>) ->
#[cfg(test)]
mod tests {
use super::map_requirements_toml_to_api;
use codex_app_server_protocol::AllowDenyRequirement;
use codex_app_server_protocol::AutoReviewRequirements;
use codex_app_server_protocol::BrowserUseAccessApprovalLifetime;
use codex_app_server_protocol::BrowserUseOriginPolicy;
use codex_app_server_protocol::BrowserUseRequirements;
use codex_app_server_protocol::ComputerUseMacosRequirements;
use codex_app_server_protocol::ComputerUseRequirements;
use codex_app_server_protocol::ComputerUseWindowsExeRequirement;
use codex_app_server_protocol::ComputerUseWindowsRequirements;
use codex_app_server_protocol::FeedbackRequirements;
use codex_app_server_protocol::WindowsSandboxSetupMode;
use codex_config::AllowDenyRequirementToml;
use codex_config::AutoReviewRequirementsToml;
use codex_config::BrowserUseAccessApprovalLifetimeToml;
use codex_config::BrowserUseOriginPolicyToml;
use codex_config::BrowserUseRequirementsToml;
use codex_config::ComputerUseMacosRequirementsToml;
use codex_config::ComputerUseRequirementsToml;
use codex_config::ComputerUseWindowsExeRequirementToml;
use codex_config::ComputerUseWindowsRequirementsToml;
use codex_config::ConfigRequirementsToml;
use codex_config::ModelsRequirementsToml;
use codex_config::NewThreadModelDefaultsToml;
@@ -786,20 +897,118 @@ mod tests {
}
#[test]
fn requirements_api_includes_computer_use_requirements() {
fn requirements_api_includes_browser_and_computer_use_requirements() {
let mapped = map_requirements_toml_to_api(ConfigRequirementsToml {
allow_browser_and_computer_use: Some(false),
browser_use: Some(BrowserUseRequirementsToml {
allow_history_access: Some(false),
disable_auto_review: Some(true),
allow_global_persistent_approval: Some(false),
default_origin_policy: Some(BrowserUseOriginPolicyToml {
access: Some(AllowDenyRequirementToml::Deny),
downloads: Some(AllowDenyRequirementToml::Allow),
uploads: Some(AllowDenyRequirementToml::Deny),
full_cdp_access: Some(AllowDenyRequirementToml::Allow),
auto_review: Some(AllowDenyRequirementToml::Deny),
persistent_approval: Some(false),
access_approval_lifetime: Some(BrowserUseAccessApprovalLifetimeToml::Turn),
}),
origins: Some(BTreeMap::from([(
"https://example.com".to_string(),
BrowserUseOriginPolicyToml {
access: Some(AllowDenyRequirementToml::Allow),
downloads: Some(AllowDenyRequirementToml::Deny),
uploads: Some(AllowDenyRequirementToml::Allow),
full_cdp_access: Some(AllowDenyRequirementToml::Deny),
auto_review: Some(AllowDenyRequirementToml::Deny),
persistent_approval: Some(true),
access_approval_lifetime: Some(
BrowserUseAccessApprovalLifetimeToml::Thread,
),
},
)])),
}),
computer_use: Some(ComputerUseRequirementsToml {
allow_locked_computer_use: Some(false),
..ComputerUseRequirementsToml::default()
allow_persistent_approval: Some(false),
default_app_access: Some(AllowDenyRequirementToml::Deny),
macos: Some(ComputerUseMacosRequirementsToml {
bundle_ids: Some(BTreeMap::from([(
"com.apple.Safari".to_string(),
AllowDenyRequirementToml::Allow,
)])),
}),
windows: Some(ComputerUseWindowsRequirementsToml {
aumids: Some(BTreeMap::from([(
"Microsoft.Paint_8wekyb3d8bbwe!App".to_string(),
AllowDenyRequirementToml::Allow,
)])),
exes: Some(vec![ComputerUseWindowsExeRequirementToml {
publisher_name: "CN=Google LLC".to_string(),
product_name: "Google Chrome".to_string(),
binary_name: Some("chrome.exe".to_string()),
access: AllowDenyRequirementToml::Deny,
}]),
}),
}),
..ConfigRequirementsToml::default()
});
assert_eq!(mapped.allow_browser_and_computer_use, Some(false));
assert_eq!(
mapped
.computer_use
.and_then(|requirements| requirements.allow_locked_computer_use),
Some(false)
mapped.browser_use,
Some(BrowserUseRequirements {
allow_history_access: Some(false),
disable_auto_review: Some(true),
allow_global_persistent_approval: Some(false),
default_origin_policy: Some(BrowserUseOriginPolicy {
access: Some(AllowDenyRequirement::Deny),
downloads: Some(AllowDenyRequirement::Allow),
uploads: Some(AllowDenyRequirement::Deny),
full_cdp_access: Some(AllowDenyRequirement::Allow),
auto_review: Some(AllowDenyRequirement::Deny),
persistent_approval: Some(false),
access_approval_lifetime: Some(BrowserUseAccessApprovalLifetime::Turn),
}),
origins: Some(BTreeMap::from([(
"https://example.com".to_string(),
BrowserUseOriginPolicy {
access: Some(AllowDenyRequirement::Allow),
downloads: Some(AllowDenyRequirement::Deny),
uploads: Some(AllowDenyRequirement::Allow),
full_cdp_access: Some(AllowDenyRequirement::Deny),
auto_review: Some(AllowDenyRequirement::Deny),
persistent_approval: Some(true),
access_approval_lifetime: Some(BrowserUseAccessApprovalLifetime::Thread),
},
)])),
})
);
assert_eq!(
mapped.computer_use,
Some(ComputerUseRequirements {
allow_locked_computer_use: Some(false),
allow_persistent_approval: Some(false),
default_app_access: Some(AllowDenyRequirement::Deny),
macos: Some(ComputerUseMacosRequirements {
bundle_ids: Some(BTreeMap::from([(
"com.apple.Safari".to_string(),
AllowDenyRequirement::Allow,
)])),
}),
windows: Some(ComputerUseWindowsRequirements {
aumids: Some(BTreeMap::from([(
"Microsoft.Paint_8wekyb3d8bbwe!App".to_string(),
AllowDenyRequirement::Allow,
)])),
exes: Some(vec![ComputerUseWindowsExeRequirement {
publisher_name: "CN=Google LLC".to_string(),
product_name: "Google Chrome".to_string(),
binary_name: Some("chrome.exe".to_string()),
access: AllowDenyRequirement::Deny,
}]),
}),
})
);
}
@@ -106,7 +106,11 @@ async fn import_policy_is_separate_from_browser_feature_and_agent_policy() -> Re
allow_external_browser_settings_import: Some(false),
}),
Some(BrowserUseRequirements {
allow_history_access: None,
disable_auto_review: Some(true),
allow_global_persistent_approval: None,
default_origin_policy: None,
origins: None,
}),
Some(BTreeMap::from([
("browser_use".to_string(), false),
@@ -2,13 +2,21 @@ use anyhow::Result;
use app_test_support::TestAppServer;
use app_test_support::test_path_buf_with_windows;
use app_test_support::test_tmp_path_buf;
use codex_app_server_protocol::AllowDenyRequirement;
use codex_app_server_protocol::AppConfig;
use codex_app_server_protocol::AppToolApproval;
use codex_app_server_protocol::ApprovalsReviewer;
use codex_app_server_protocol::AppsConfig;
use codex_app_server_protocol::AppsDefaultConfig;
use codex_app_server_protocol::AskForApproval;
use codex_app_server_protocol::BrowserUseAccessApprovalLifetime;
use codex_app_server_protocol::BrowserUseOriginPolicy;
use codex_app_server_protocol::BrowserUseRequirements;
use codex_app_server_protocol::CliAuthCredentialsStoreMode;
use codex_app_server_protocol::ComputerUseMacosRequirements;
use codex_app_server_protocol::ComputerUseRequirements;
use codex_app_server_protocol::ComputerUseWindowsExeRequirement;
use codex_app_server_protocol::ComputerUseWindowsRequirements;
use codex_app_server_protocol::ConfigBatchWriteParams;
use codex_app_server_protocol::ConfigEdit;
use codex_app_server_protocol::ConfigLayerSource;
@@ -34,6 +42,7 @@ use codex_protocol::openai_models::ReasoningEffort;
use codex_utils_absolute_path::AbsolutePathBuf;
use pretty_assertions::assert_eq;
use serde_json::json;
use std::collections::BTreeMap;
use tempfile::TempDir;
use tokio::time::timeout;
@@ -215,13 +224,52 @@ statusMessage = "Scanning file"
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn config_requirements_read_includes_browser_use_auto_review_setting() -> Result<()> {
async fn config_requirements_read_includes_browser_and_computer_use_schema() -> Result<()> {
let codex_home = TempDir::new()?;
std::fs::write(
codex_home.path().join("requirements.toml"),
r#"
allow_browser_and_computer_use = false
[browser_use]
allow_history_access = false
disable_auto_review = true
allow_global_persistent_approval = false
[browser_use.default_origin_policy]
access = "deny"
downloads = "allow"
uploads = "deny"
full_cdp_access = "allow"
auto_review = "deny"
persistent_approval = false
access_approval_lifetime = "turn"
[browser_use.origins."https://example.com"]
access = "allow"
downloads = "deny"
uploads = "allow"
full_cdp_access = "deny"
auto_review = "deny"
persistent_approval = true
access_approval_lifetime = "thread"
[computer_use]
allow_locked_computer_use = false
allow_persistent_approval = false
default_app_access = "deny"
[computer_use.macos.bundle_ids]
"com.apple.Safari" = "allow"
[computer_use.windows.aumids]
"Microsoft.Paint_8wekyb3d8bbwe!App" = "allow"
[[computer_use.windows.exes]]
publisher_name = "CN=Google LLC"
product_name = "Google Chrome"
binary_name = "chrome.exe"
access = "deny"
"#,
)?;
let mut mcp = TestAppServer::builder()
@@ -234,12 +282,64 @@ disable_auto_review = true
let request_id = mcp.send_config_requirements_read_request().await?;
let response: ConfigRequirementsReadResponse =
timeout(DEFAULT_READ_TIMEOUT, mcp.read_response(request_id)).await??;
let requirements = response
.requirements
.expect("managed requirements should be returned");
assert_eq!(requirements.allow_browser_and_computer_use, Some(false));
assert_eq!(
response
.requirements
.and_then(|requirements| requirements.browser_use)
.and_then(|browser_use| browser_use.disable_auto_review),
Some(true)
requirements.browser_use,
Some(BrowserUseRequirements {
allow_history_access: Some(false),
disable_auto_review: Some(true),
allow_global_persistent_approval: Some(false),
default_origin_policy: Some(BrowserUseOriginPolicy {
access: Some(AllowDenyRequirement::Deny),
downloads: Some(AllowDenyRequirement::Allow),
uploads: Some(AllowDenyRequirement::Deny),
full_cdp_access: Some(AllowDenyRequirement::Allow),
auto_review: Some(AllowDenyRequirement::Deny),
persistent_approval: Some(false),
access_approval_lifetime: Some(BrowserUseAccessApprovalLifetime::Turn),
}),
origins: Some(BTreeMap::from([(
"https://example.com".to_string(),
BrowserUseOriginPolicy {
access: Some(AllowDenyRequirement::Allow),
downloads: Some(AllowDenyRequirement::Deny),
uploads: Some(AllowDenyRequirement::Allow),
full_cdp_access: Some(AllowDenyRequirement::Deny),
auto_review: Some(AllowDenyRequirement::Deny),
persistent_approval: Some(true),
access_approval_lifetime: Some(BrowserUseAccessApprovalLifetime::Thread),
},
)])),
})
);
assert_eq!(
requirements.computer_use,
Some(ComputerUseRequirements {
allow_locked_computer_use: Some(false),
allow_persistent_approval: Some(false),
default_app_access: Some(AllowDenyRequirement::Deny),
macos: Some(ComputerUseMacosRequirements {
bundle_ids: Some(BTreeMap::from([(
"com.apple.Safari".to_string(),
AllowDenyRequirement::Allow,
)])),
}),
windows: Some(ComputerUseWindowsRequirements {
aumids: Some(BTreeMap::from([(
"Microsoft.Paint_8wekyb3d8bbwe!App".to_string(),
AllowDenyRequirement::Allow,
)])),
exes: Some(vec![ComputerUseWindowsExeRequirement {
publisher_name: "CN=Google LLC".to_string(),
product_name: "Google Chrome".to_string(),
binary_name: Some("chrome.exe".to_string()),
access: AllowDenyRequirement::Deny,
}]),
}),
})
);
Ok(())
}