Skip to content

Commit 949782b

Browse files
committed
Reject comma-separated forced workspace config
codex-rs/config/src/config_toml.rs: add a custom forced_chatgpt_workspace_id deserializer that keeps single-string and list forms but rejects comma-separated strings with guidance to use a TOML list, plus focused parser tests. codex-rs/core/config.schema.json: refresh the generated config schema description for the workspace allowlist shape.
1 parent 4bb912b commit 949782b

2 files changed

Lines changed: 75 additions & 3 deletions

File tree

codex-rs/config/src/config_toml.rs

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ use schemars::JsonSchema;
5656
use serde::Deserialize;
5757
use serde::Deserializer;
5858
use serde::Serialize;
59+
use serde::de::Error as SerdeError;
5960

6061
const RESERVED_MODEL_PROVIDER_IDS: [&str; 4] = [
6162
AMAZON_BEDROCK_PROVIDER_ID,
@@ -86,8 +87,8 @@ const fn default_hide_agent_reasoning() -> Option<bool> {
8687
Some(false)
8788
}
8889

89-
/// Backward-compatible shape for workspace restrictions in config.toml.
90-
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema)]
90+
/// Backward-compatible shape for ChatGPT workspace login restrictions in config.toml.
91+
#[derive(Serialize, Debug, Clone, PartialEq, JsonSchema)]
9192
#[serde(untagged)]
9293
pub enum ForcedChatgptWorkspaceIds {
9394
Single(String),
@@ -103,6 +104,30 @@ impl ForcedChatgptWorkspaceIds {
103104
}
104105
}
105106

107+
impl<'de> Deserialize<'de> for ForcedChatgptWorkspaceIds {
108+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
109+
where
110+
D: Deserializer<'de>,
111+
{
112+
#[derive(Deserialize)]
113+
#[serde(untagged)]
114+
enum Repr {
115+
Single(String),
116+
Multiple(Vec<String>),
117+
}
118+
119+
match Repr::deserialize(deserializer)? {
120+
Repr::Single(value) if value.contains(',') => Err(D::Error::custom(
121+
"forced_chatgpt_workspace_id must be a single workspace ID string or a TOML list \
122+
of strings; comma-separated strings are not supported. Use \
123+
`forced_chatgpt_workspace_id = [\"workspace-a\", \"workspace-b\"]` instead.",
124+
)),
125+
Repr::Single(value) => Ok(Self::Single(value)),
126+
Repr::Multiple(values) => Ok(Self::Multiple(values)),
127+
}
128+
}
129+
}
130+
106131
/// Base config deserialized from ~/.codex/config.toml.
107132
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, JsonSchema)]
108133
#[schemars(deny_unknown_fields)]
@@ -980,3 +1005,50 @@ pub fn validate_oss_provider(provider: &str) -> std::io::Result<()> {
9801005
)),
9811006
}
9821007
}
1008+
1009+
#[cfg(test)]
1010+
mod tests {
1011+
use super::*;
1012+
use pretty_assertions::assert_eq;
1013+
1014+
#[test]
1015+
fn forced_chatgpt_workspace_id_accepts_single_string() {
1016+
let config: ConfigToml = toml::from_str(r#"forced_chatgpt_workspace_id = "workspace-a""#)
1017+
.expect("single workspace id should deserialize");
1018+
1019+
assert_eq!(
1020+
config
1021+
.forced_chatgpt_workspace_id
1022+
.expect("workspace id should be set")
1023+
.into_vec(),
1024+
vec!["workspace-a".to_string()]
1025+
);
1026+
}
1027+
1028+
#[test]
1029+
fn forced_chatgpt_workspace_id_accepts_string_list() {
1030+
let config: ConfigToml =
1031+
toml::from_str(r#"forced_chatgpt_workspace_id = ["workspace-a", "workspace-b"]"#)
1032+
.expect("workspace id list should deserialize");
1033+
1034+
assert_eq!(
1035+
config
1036+
.forced_chatgpt_workspace_id
1037+
.expect("workspace ids should be set")
1038+
.into_vec(),
1039+
vec!["workspace-a".to_string(), "workspace-b".to_string()]
1040+
);
1041+
}
1042+
1043+
#[test]
1044+
fn forced_chatgpt_workspace_id_rejects_comma_separated_string() {
1045+
let err = toml::from_str::<ConfigToml>(
1046+
r#"forced_chatgpt_workspace_id = "workspace-a,workspace-b""#,
1047+
)
1048+
.expect_err("comma-separated string should be rejected");
1049+
1050+
let message = err.to_string();
1051+
assert!(message.contains("TOML list of strings"));
1052+
assert!(message.contains("comma-separated strings are not supported"));
1053+
}
1054+
}

codex-rs/core/config.schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@
857857
"type": "array"
858858
}
859859
],
860-
"description": "Backward-compatible shape for workspace restrictions in config.toml."
860+
"description": "Backward-compatible shape for ChatGPT workspace login restrictions in config.toml."
861861
},
862862
"ForcedLoginMethod": {
863863
"enum": [

0 commit comments

Comments
 (0)