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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6431,9 +6431,13 @@
]
},
"forced_chatgpt_workspace_id": {
"type": [
"string",
"null"
"anyOf": [
{
"$ref": "#/definitions/v2/ForcedChatgptWorkspaceIds"
},
{
"type": "null"
}
]
},
"forced_login_method": {
Expand Down Expand Up @@ -6918,6 +6922,16 @@
"object",
"null"
]
},
"forcedChatgptWorkspaceId": {
"anyOf": [
{
"$ref": "#/definitions/v2/ForcedChatgptWorkspaceIds"
},
{
"type": "null"
}
]
}
},
"type": "object"
Expand Down Expand Up @@ -7643,6 +7657,20 @@
],
"type": "object"
},
"ForcedChatgptWorkspaceIds": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"type": "string"
},
"type": "array"
}
],
"description": "Workspace IDs that ChatGPT auth is allowed to use.\n\nThe config parser accepts the historical single-string form and the newer list form for deployments that allow multiple ChatGPT workspaces."
},
"ForcedLoginMethod": {
"enum": [
"chatgpt",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3048,9 +3048,13 @@
]
},
"forced_chatgpt_workspace_id": {
"type": [
"string",
"null"
"anyOf": [
{
"$ref": "#/definitions/ForcedChatgptWorkspaceIds"
},
{
"type": "null"
}
]
},
"forced_login_method": {
Expand Down Expand Up @@ -3535,6 +3539,16 @@
"object",
"null"
]
},
"forcedChatgptWorkspaceId": {
"anyOf": [
{
"$ref": "#/definitions/ForcedChatgptWorkspaceIds"
},
{
"type": "null"
}
]
}
},
"type": "object"
Expand Down Expand Up @@ -4260,6 +4274,20 @@
],
"type": "object"
},
"ForcedChatgptWorkspaceIds": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"type": "string"
},
"type": "array"
}
],
"description": "Workspace IDs that ChatGPT auth is allowed to use.\n\nThe config parser accepts the historical single-string form and the newer list form for deployments that allow multiple ChatGPT workspaces."
},
"ForcedLoginMethod": {
"enum": [
"chatgpt",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,13 @@
]
},
"forced_chatgpt_workspace_id": {
"type": [
"string",
"null"
"anyOf": [
{
"$ref": "#/definitions/ForcedChatgptWorkspaceIds"
},
{
"type": "null"
}
]
},
"forced_login_method": {
Expand Down Expand Up @@ -577,6 +581,20 @@
}
]
},
"ForcedChatgptWorkspaceIds": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"type": "string"
},
"type": "array"
}
],
"description": "Workspace IDs that ChatGPT auth is allowed to use.\n\nThe config parser accepts the historical single-string form and the newer list form for deployments that allow multiple ChatGPT workspaces."
},
"ForcedLoginMethod": {
"enum": [
"chatgpt",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,34 @@
"object",
"null"
]
},
"forcedChatgptWorkspaceId": {
"anyOf": [
{
"$ref": "#/definitions/ForcedChatgptWorkspaceIds"
},
{
"type": "null"
}
]
}
},
"type": "object"
},
"ForcedChatgptWorkspaceIds": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"type": "string"
},
"type": "array"
}
],
"description": "Workspace IDs that ChatGPT auth is allowed to use.\n\nThe config parser accepts the historical single-string form and the newer list form for deployments that allow multiple ChatGPT workspaces."
},
"NetworkDomainPermission": {
"enum": [
"allow",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// 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.

/**
* Workspace IDs that ChatGPT auth is allowed to use.
*
* The config parser accepts the historical single-string form and the newer
* list form for deployments that allow multiple ChatGPT workspaces.
*/
export type ForcedChatgptWorkspaceIds = string | Array<string>;
1 change: 1 addition & 0 deletions codex-rs/app-server-protocol/schema/typescript/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type { ExecCommandApprovalParams } from "./ExecCommandApprovalParams";
export type { ExecCommandApprovalResponse } from "./ExecCommandApprovalResponse";
export type { ExecPolicyAmendment } from "./ExecPolicyAmendment";
export type { FileChange } from "./FileChange";
export type { ForcedChatgptWorkspaceIds } from "./ForcedChatgptWorkspaceIds";
export type { ForcedLoginMethod } from "./ForcedLoginMethod";
export type { FunctionCallOutputBody } from "./FunctionCallOutputBody";
export type { FunctionCallOutputContentItem } from "./FunctionCallOutputContentItem";
Expand Down
3 changes: 2 additions & 1 deletion codex-rs/app-server-protocol/schema/typescript/v2/Config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +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 { ForcedChatgptWorkspaceIds } from "../ForcedChatgptWorkspaceIds";
import type { ForcedLoginMethod } from "../ForcedLoginMethod";
import type { ReasoningEffort } from "../ReasoningEffort";
import type { ReasoningSummary } from "../ReasoningSummary";
Expand All @@ -20,4 +21,4 @@ export type Config = {model: string | null, review_model: string | null, model_c
* [UNSTABLE] Optional default for where approval requests are routed for
* review.
*/
approvals_reviewer: ApprovalsReviewer | null, sandbox_mode: SandboxMode | null, sandbox_workspace_write: SandboxWorkspaceWrite | null, forced_chatgpt_workspace_id: string | null, forced_login_method: ForcedLoginMethod | null, web_search: WebSearchMode | null, tools: ToolsV2 | null, profile: string | null, profiles: { [key in string]?: ProfileV2 }, instructions: string | null, developer_instructions: string | null, compact_prompt: string | null, model_reasoning_effort: ReasoningEffort | null, model_reasoning_summary: ReasoningSummary | null, model_verbosity: Verbosity | null, service_tier: ServiceTier | null, analytics: AnalyticsConfig | null} & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null });
approvals_reviewer: ApprovalsReviewer | null, sandbox_mode: SandboxMode | null, sandbox_workspace_write: SandboxWorkspaceWrite | null, forced_chatgpt_workspace_id: ForcedChatgptWorkspaceIds | null, forced_login_method: ForcedLoginMethod | null, web_search: WebSearchMode | null, tools: ToolsV2 | null, profile: string | null, profiles: { [key in string]?: ProfileV2 }, instructions: string | null, developer_instructions: string | null, compact_prompt: string | null, model_reasoning_effort: ReasoningEffort | null, model_reasoning_summary: ReasoningSummary | null, model_verbosity: Verbosity | null, service_tier: ServiceTier | null, analytics: AnalyticsConfig | null} & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null });
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// 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 { ForcedChatgptWorkspaceIds } from "../ForcedChatgptWorkspaceIds";
import type { WebSearchMode } from "../WebSearchMode";
import type { AskForApproval } from "./AskForApproval";
import type { ResidencyRequirement } from "./ResidencyRequirement";
import type { SandboxMode } from "./SandboxMode";

export type ConfigRequirements = {allowedApprovalPolicies: Array<AskForApproval> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWebSearchModes: Array<WebSearchMode> | null, featureRequirements: { [key in string]?: boolean } | null, enforceResidency: ResidencyRequirement | null};
export type ConfigRequirements = {allowedApprovalPolicies: Array<AskForApproval> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWebSearchModes: Array<WebSearchMode> | null, featureRequirements: { [key in string]?: boolean } | null, enforceResidency: ResidencyRequirement | null, forcedChatgptWorkspaceId: ForcedChatgptWorkspaceIds | null};
3 changes: 2 additions & 1 deletion codex-rs/app-server-protocol/src/protocol/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::path::PathBuf;

use codex_git_utils::GitSha;
use codex_protocol::ThreadId;
use codex_protocol::config_types::ForcedChatgptWorkspaceIds;
use codex_protocol::config_types::ForcedLoginMethod;
use codex_protocol::config_types::ReasoningSummary;
use codex_protocol::config_types::SandboxMode;
Expand Down Expand Up @@ -198,7 +199,7 @@ pub struct UserSavedConfig {
pub approval_policy: Option<AskForApproval>,
pub sandbox_mode: Option<SandboxMode>,
pub sandbox_settings: Option<SandboxSettings>,
pub forced_chatgpt_workspace_id: Option<String>,
pub forced_chatgpt_workspace_id: Option<ForcedChatgptWorkspaceIds>,
pub forced_login_method: Option<ForcedLoginMethod>,
pub model: Option<String>,
pub model_reasoning_effort: Option<ReasoningEffort>,
Expand Down
5 changes: 4 additions & 1 deletion codex-rs/app-server-protocol/src/protocol/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use codex_protocol::approvals::NetworkPolicyRuleAction as CoreNetworkPolicyRuleA
use codex_protocol::config_types::ApprovalsReviewer as CoreApprovalsReviewer;
use codex_protocol::config_types::CollaborationMode;
use codex_protocol::config_types::CollaborationModeMask as CoreCollaborationModeMask;
use codex_protocol::config_types::ForcedChatgptWorkspaceIds;
use codex_protocol::config_types::ForcedLoginMethod;
use codex_protocol::config_types::ModeKind;
use codex_protocol::config_types::Personality;
Expand Down Expand Up @@ -744,7 +745,7 @@ pub struct Config {
pub approvals_reviewer: Option<ApprovalsReviewer>,
pub sandbox_mode: Option<SandboxMode>,
pub sandbox_workspace_write: Option<SandboxWorkspaceWrite>,
pub forced_chatgpt_workspace_id: Option<String>,
pub forced_chatgpt_workspace_id: Option<ForcedChatgptWorkspaceIds>,
pub forced_login_method: Option<ForcedLoginMethod>,
pub web_search: Option<WebSearchMode>,
pub tools: Option<ToolsV2>,
Expand Down Expand Up @@ -872,6 +873,7 @@ pub struct ConfigRequirements {
pub enforce_residency: Option<ResidencyRequirement>,
#[experimental("configRequirements/read.network")]
pub network: Option<NetworkRequirements>,
pub forced_chatgpt_workspace_id: Option<ForcedChatgptWorkspaceIds>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
Expand Down Expand Up @@ -7699,6 +7701,7 @@ mod tests {
feature_requirements: None,
enforce_residency: None,
network: None,
forced_chatgpt_workspace_id: None,
});

assert_eq!(reason, Some("askForApproval.granular"));
Expand Down
7 changes: 4 additions & 3 deletions codex-rs/app-server/src/codex_message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1627,13 +1627,14 @@ impl CodexMessageProcessor {
}
}

if let Some(expected_workspace) = self.config.forced_chatgpt_workspace_id.as_deref()
&& chatgpt_account_id != expected_workspace
if let Some(allowed_workspace_ids) = self.config.forced_chatgpt_workspace_id.as_ref()
&& !allowed_workspace_ids.contains(&chatgpt_account_id)
{
let allowed_description = allowed_workspace_ids.description();
let error = JSONRPCErrorError {
code: INVALID_REQUEST_ERROR_CODE,
message: format!(
"External auth must use workspace {expected_workspace}, but received {chatgpt_account_id:?}."
"External auth must use {allowed_description}, but received {chatgpt_account_id:?}."
),
data: None,
};
Expand Down
18 changes: 18 additions & 0 deletions codex-rs/app-server/src/config_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ fn map_requirements_toml_to_api(requirements: ConfigRequirementsToml) -> ConfigR
.enforce_residency
.map(map_residency_requirement_to_api),
network: requirements.network.map(map_network_requirements_to_api),
forced_chatgpt_workspace_id: requirements.forced_chatgpt_workspace_id,
}
}

Expand Down Expand Up @@ -567,6 +568,12 @@ mod tests {
codex_core::config_loader::WebSearchModeRequirement::Cached,
]),
guardian_policy_config: None,
forced_chatgpt_workspace_id: Some(
codex_protocol::config_types::ForcedChatgptWorkspaceIds::Multiple(vec![
"workspace-a".to_string(),
"workspace-b".to_string(),
]),
),
feature_requirements: Some(codex_core::config_loader::FeatureRequirementsToml {
entries: std::collections::BTreeMap::from([
("apps".to_string(), false),
Expand Down Expand Up @@ -642,6 +649,15 @@ mod tests {
mapped.enforce_residency,
Some(codex_app_server_protocol::ResidencyRequirement::Us),
);
assert_eq!(
mapped.forced_chatgpt_workspace_id,
Some(
codex_protocol::config_types::ForcedChatgptWorkspaceIds::Multiple(vec![
"workspace-a".to_string(),
"workspace-b".to_string(),
])
),
);
assert_eq!(
mapped.network,
Some(NetworkRequirements {
Expand Down Expand Up @@ -676,6 +692,7 @@ mod tests {
allowed_sandbox_modes: None,
allowed_web_search_modes: None,
guardian_policy_config: None,
forced_chatgpt_workspace_id: None,
feature_requirements: None,
mcp_servers: None,
apps: None,
Expand Down Expand Up @@ -733,6 +750,7 @@ mod tests {
allowed_sandbox_modes: None,
allowed_web_search_modes: Some(Vec::new()),
guardian_policy_config: None,
forced_chatgpt_workspace_id: None,
feature_requirements: None,
mcp_servers: None,
apps: None,
Expand Down
3 changes: 2 additions & 1 deletion codex-rs/cli/src/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use codex_login::login_with_api_key;
use codex_login::logout;
use codex_login::run_device_code_login;
use codex_login::run_login_server;
use codex_protocol::config_types::ForcedChatgptWorkspaceIds;
use codex_protocol::config_types::ForcedLoginMethod;
use codex_utils_cli::CliConfigOverrides;
use std::fs::OpenOptions;
Expand Down Expand Up @@ -112,7 +113,7 @@ fn print_login_server_start(actual_port: u16, auth_url: &str) {

pub async fn login_with_chatgpt(
codex_home: PathBuf,
forced_chatgpt_workspace_id: Option<String>,
forced_chatgpt_workspace_id: Option<ForcedChatgptWorkspaceIds>,
cli_auth_credentials_store_mode: AuthCredentialsStoreMode,
) -> std::io::Result<()> {
let opts = ServerOptions::new(
Expand Down
Loading
Loading