Expose auto-review ignore rules in config requirements (#37519)

## What changed

- Add `ignoreRules` to `AutoReviewRequirements` in the app-server v2 protocol and generated schemas.
- Return configured `auto_review.ignore_rules` values from `configRequirements/read`.
- Document that listed models ignore saved command-prefix approvals.

## Testing

- Extend config mapping and RPC tests to cover `ignore_rules`.

GitOrigin-RevId: ed74fbba7693176fe09b161bbee2cb27847e0e1e
This commit is contained in:
Won Park
2026-08-08 01:32:05 +00:00
committed by copyberry
parent e734a1a5c1
commit 2e3a1702c2
10 changed files with 49 additions and 13 deletions

View File

@@ -7387,6 +7387,15 @@
},
"AutoReviewRequirements": {
"properties": {
"ignoreRules": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"requiredOnModels": {
"items": {
"type": "string"

View File

@@ -1246,6 +1246,15 @@
},
"AutoReviewRequirements": {
"properties": {
"ignoreRules": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"requiredOnModels": {
"items": {
"type": "string"

View File

@@ -61,6 +61,15 @@
},
"AutoReviewRequirements": {
"properties": {
"ignoreRules": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"requiredOnModels": {
"items": {
"type": "string"

View File

@@ -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 AutoReviewRequirements = { requiredOnModels: Array<string> | null, };
export type AutoReviewRequirements = { requiredOnModels: Array<string> | null, ignoreRules: Array<string> | null, };

View File

@@ -413,6 +413,7 @@ pub struct ConfigRequirements {
#[ts(export_to = "v2/")]
pub struct AutoReviewRequirements {
pub required_on_models: Option<Vec<String>>,
pub ignore_rules: Option<Vec<String>>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]

View File

@@ -278,7 +278,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 (`sqliteHome`, `logDir`, `modelCatalogJson`, `checkForUpdateOnStartup`, `allowLoginShell`, `feedback.enabled`, and `windowsSandboxPrivateDesktop`), 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`), 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`), 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 (`sqliteHome`, `logDir`, `modelCatalogJson`, `checkForUpdateOnStartup`, `allowLoginShell`, `feedback.enabled`, and `windowsSandboxPrivateDesktop`), 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`), 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
@@ -871,9 +871,10 @@ Managed `requirements.toml` can require automatic review for specific models:
```toml
[auto_review]
required_on_models = ["protected-model"]
ignore_rules = ["protected-model"]
```
Listed models always start with `approvalPolicy: "on-request"` and `approvalsReviewer: "auto_review"`, even when clients provide incompatible startup values. Full Access is automatically downgraded to workspace-write access. Incompatible runtime overrides or disabled Guardian automatic review are rejected.
Models in `required_on_models` always start with `approvalPolicy: "on-request"` and `approvalsReviewer: "auto_review"`, even when clients provide incompatible startup values. Full Access is automatically downgraded to workspace-write access. Incompatible runtime overrides or disabled Guardian automatic review are rejected. Models in `ignore_rules` ignore saved command-prefix approvals.
```json
{ "method": "turn/start", "id": 30, "params": {

View File

@@ -420,6 +420,7 @@ fn map_requirements_toml_to_api(requirements: ConfigRequirementsToml) -> ConfigR
.auto_review
.map(|auto_review| AutoReviewRequirements {
required_on_models: auto_review.required_on_models,
ignore_rules: auto_review.ignore_rules,
}),
models: requirements.models.map(|models| ModelsRequirements {
new_thread: models.new_thread.map(|new_thread| NewThreadModelDefaults {
@@ -652,6 +653,7 @@ 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::AutoReviewRequirements;
use codex_app_server_protocol::FeedbackRequirements;
use codex_app_server_protocol::WindowsSandboxSetupMode;
use codex_config::AutoReviewRequirementsToml;
@@ -728,7 +730,7 @@ mod tests {
let mapped = map_requirements_toml_to_api(ConfigRequirementsToml {
auto_review: Some(AutoReviewRequirementsToml {
required_on_models: Some(vec!["gpt-protected".to_string()]),
ignore_rules: None,
ignore_rules: Some(vec!["gpt-protected".to_string()]),
}),
models: Some(ModelsRequirementsToml {
new_thread: Some(NewThreadModelDefaultsToml {
@@ -741,11 +743,11 @@ mod tests {
});
assert_eq!(
mapped
.auto_review
.expect("managed automatic-review requirements")
.required_on_models,
Some(vec!["gpt-protected".to_string()])
mapped.auto_review,
Some(AutoReviewRequirements {
required_on_models: Some(vec!["gpt-protected".to_string()]),
ignore_rules: Some(vec!["gpt-protected".to_string()]),
})
);
let models = mapped.models.expect("managed model requirements");
let defaults = models.new_thread.expect("new-thread defaults");

View File

@@ -187,6 +187,7 @@ async fn config_requirements_read_includes_model_auto_review_and_new_thread_defa
r#"
[auto_review]
required_on_models = ["gpt-protected", "gpt-sensitive"]
ignore_rules = ["gpt-protected"]
[models.new_thread]
model = "gpt-managed"
@@ -205,16 +206,20 @@ service_tier = "fast"
timeout(DEFAULT_READ_TIMEOUT, mcp.read_response(request_id)).await??;
let requirements = response.requirements.expect("managed requirements");
let auto_review = requirements
.auto_review
.expect("managed automatic-review requirements");
assert_eq!(
requirements
.auto_review
.expect("managed automatic-review requirements")
.required_on_models,
auto_review.required_on_models,
Some(vec![
"gpt-protected".to_string(),
"gpt-sensitive".to_string()
])
);
assert_eq!(
auto_review.ignore_rules,
Some(vec!["gpt-protected".to_string()])
);
let models = requirements.models.expect("managed model requirements");
let defaults = models.new_thread.expect("managed new-thread defaults");
assert_eq!(defaults.model.as_deref(), Some("gpt-managed"));