From fb459250726f9c04cc205b80d17d2ffc6ae263b0 Mon Sep 17 00:00:00 2001 From: viyatb-oai Date: Wed, 28 Jan 2026 23:35:47 -0800 Subject: [PATCH] feat(core): wire secrets backend config --- codex-rs/Cargo.lock | 1 + codex-rs/core/Cargo.toml | 1 + codex-rs/core/config.schema.json | 29 +++++++++++++++++++++++++++++ codex-rs/core/src/config/mod.rs | 19 +++++++++++++++++++ codex-rs/core/src/config/types.rs | 8 ++++++++ codex-rs/core/src/lib.rs | 1 + codex-rs/core/src/secrets/mod.rs | 7 +++++++ 7 files changed, 66 insertions(+) create mode 100644 codex-rs/core/src/secrets/mod.rs diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 2229dc61f6..37224f9d1b 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -1475,6 +1475,7 @@ dependencies = [ "codex-otel", "codex-protocol", "codex-rmcp-client", + "codex-secrets", "codex-state", "codex-utils-absolute-path", "codex-utils-cargo-bin", diff --git a/codex-rs/core/Cargo.toml b/codex-rs/core/Cargo.toml index b336b296c6..cafa1081c8 100644 --- a/codex-rs/core/Cargo.toml +++ b/codex-rs/core/Cargo.toml @@ -37,6 +37,7 @@ codex-keyring-store = { workspace = true } codex-otel = { workspace = true } codex-protocol = { workspace = true } codex-rmcp-client = { workspace = true } +codex-secrets = { workspace = true } codex-state = { workspace = true } codex-utils-absolute-path = { workspace = true } codex-utils-pty = { workspace = true } diff --git a/codex-rs/core/config.schema.json b/codex-rs/core/config.schema.json index 03e27dceda..cd99616fe2 100644 --- a/codex-rs/core/config.schema.json +++ b/codex-rs/core/config.schema.json @@ -860,6 +860,26 @@ }, "type": "object" }, + "SecretsBackendKind": { + "enum": [ + "local" + ], + "type": "string" + }, + "SecretsConfigToml": { + "additionalProperties": false, + "properties": { + "backend": { + "allOf": [ + { + "$ref": "#/definitions/SecretsBackendKind" + } + ], + "default": null + } + }, + "type": "object" + }, "ShellEnvironmentPolicyInherit": { "oneOf": [ { @@ -1472,6 +1492,15 @@ ], "description": "Sandbox configuration to apply if `sandbox` is `WorkspaceWrite`." }, + "secrets": { + "allOf": [ + { + "$ref": "#/definitions/SecretsConfigToml" + } + ], + "default": null, + "description": "Secrets configuration. Defaults to a local encrypted file backend." + }, "shell_environment_policy": { "allOf": [ { diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index 895e54c040..d0f1fe9732 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -13,6 +13,7 @@ use crate::config::types::OtelConfig; use crate::config::types::OtelConfigToml; use crate::config::types::OtelExporterKind; use crate::config::types::SandboxWorkspaceWrite; +use crate::config::types::SecretsConfigToml; use crate::config::types::ShellEnvironmentPolicy; use crate::config::types::ShellEnvironmentPolicyToml; use crate::config::types::SkillsConfig; @@ -39,6 +40,7 @@ use crate::project_doc::DEFAULT_PROJECT_DOC_FILENAME; use crate::project_doc::LOCAL_PROJECT_DOC_FILENAME; use crate::protocol::AskForApproval; use crate::protocol::SandboxPolicy; +use crate::secrets::SecretsBackendKind; use crate::windows_sandbox::WindowsSandboxLevelExt; use codex_app_server_protocol::Tools; use codex_app_server_protocol::UserSavedConfig; @@ -228,6 +230,9 @@ pub struct Config { /// auto: Use the OS-specific keyring service if available, otherwise use a file. pub cli_auth_credentials_store_mode: AuthCredentialsStoreMode, + /// Active secrets backend. Defaults to the local encrypted file backend. + pub secrets_backend: SecretsBackendKind, + /// Definition for MCP servers that Codex can reach out to for tool calls. pub mcp_servers: Constrained>, @@ -823,6 +828,10 @@ pub struct ConfigToml { #[serde(default)] pub cli_auth_credentials_store: Option, + /// Secrets configuration. Defaults to a local encrypted file backend. + #[serde(default)] + pub secrets: Option, + /// Definition for MCP servers that Codex can reach out to for tool calls. #[serde(default)] // Uses the raw MCP input shape (custom deserialization) rather than `McpServerConfig`. @@ -1452,6 +1461,11 @@ impl Config { }); let forced_login_method = cfg.forced_login_method; + let secrets_backend = cfg + .secrets + .as_ref() + .and_then(|secrets| secrets.backend) + .unwrap_or_default(); let model = model.or(config_profile.model).or(cfg.model); @@ -1533,6 +1547,7 @@ impl Config { // The config.toml omits "_mode" because it's a config file. However, "_mode" // is important in code to differentiate the mode from the store implementation. cli_auth_credentials_store_mode: cfg.cli_auth_credentials_store.unwrap_or_default(), + secrets_backend, mcp_servers, // The config.toml omits "_mode" because it's a config file. However, "_mode" // is important in code to differentiate the mode from the store implementation. @@ -3760,6 +3775,7 @@ model_verbosity = "high" notify: None, cwd: fixture.cwd(), cli_auth_credentials_store_mode: Default::default(), + secrets_backend: SecretsBackendKind::Local, mcp_servers: Constrained::allow_any(HashMap::new()), mcp_oauth_credentials_store_mode: Default::default(), mcp_oauth_callback_port: None, @@ -3844,6 +3860,7 @@ model_verbosity = "high" notify: None, cwd: fixture.cwd(), cli_auth_credentials_store_mode: Default::default(), + secrets_backend: SecretsBackendKind::Local, mcp_servers: Constrained::allow_any(HashMap::new()), mcp_oauth_credentials_store_mode: Default::default(), mcp_oauth_callback_port: None, @@ -3943,6 +3960,7 @@ model_verbosity = "high" notify: None, cwd: fixture.cwd(), cli_auth_credentials_store_mode: Default::default(), + secrets_backend: SecretsBackendKind::Local, mcp_servers: Constrained::allow_any(HashMap::new()), mcp_oauth_credentials_store_mode: Default::default(), mcp_oauth_callback_port: None, @@ -4028,6 +4046,7 @@ model_verbosity = "high" notify: None, cwd: fixture.cwd(), cli_auth_credentials_store_mode: Default::default(), + secrets_backend: SecretsBackendKind::Local, mcp_servers: Constrained::allow_any(HashMap::new()), mcp_oauth_credentials_store_mode: Default::default(), mcp_oauth_callback_port: None, diff --git a/codex-rs/core/src/config/types.rs b/codex-rs/core/src/config/types.rs index e949d869a6..6ac7d63769 100644 --- a/codex-rs/core/src/config/types.rs +++ b/codex-rs/core/src/config/types.rs @@ -4,6 +4,7 @@ // definitions that do not contain business logic. use crate::config_loader::RequirementSource; +use crate::secrets::SecretsBackendKind; pub use codex_protocol::config_types::AltScreenMode; pub use codex_protocol::config_types::ModeKind; pub use codex_protocol::config_types::Personality; @@ -24,6 +25,13 @@ use serde::de::Error as SerdeError; pub const DEFAULT_OTEL_ENVIRONMENT: &str = "dev"; +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)] +#[schemars(deny_unknown_fields)] +pub struct SecretsConfigToml { + #[serde(default)] + pub backend: Option, +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum McpServerDisabledReason { Unknown, diff --git a/codex-rs/core/src/lib.rs b/codex-rs/core/src/lib.rs index eaf25d14e8..d6ffcdc46f 100644 --- a/codex-rs/core/src/lib.rs +++ b/codex-rs/core/src/lib.rs @@ -87,6 +87,7 @@ pub mod project_doc; mod rollout; pub(crate) mod safety; pub mod seatbelt; +pub mod secrets; pub mod shell; pub mod shell_snapshot; pub mod skills; diff --git a/codex-rs/core/src/secrets/mod.rs b/codex-rs/core/src/secrets/mod.rs new file mode 100644 index 0000000000..20221d416f --- /dev/null +++ b/codex-rs/core/src/secrets/mod.rs @@ -0,0 +1,7 @@ +pub use codex_secrets::LocalSecretsBackend; +pub use codex_secrets::SecretListEntry; +pub use codex_secrets::SecretName; +pub use codex_secrets::SecretScope; +pub use codex_secrets::SecretsBackendKind; +pub use codex_secrets::SecretsManager; +pub use codex_secrets::environment_id_from_cwd;