Cache cloud requirements (#11305)

We're loading these from the web on every startup. This puts them in a
local file with a 1hr TTL.

We sign the downloaded requirements with a key compiled into the Codex
CLI to prevent unsophisticated tampering (determined circumvention is
outside of our threat model: after all, one could just compile Codex
without any of these checks).

If any of the following are true, we ignore the local cache and re-fetch
from Cloud:
* The signature is invalid for the payload (== requirements, sign time,
ttl, user identity)
* The identity does not match the auth'd user's identity
* The TTL has expired
* We cannot parse requirements.toml from the payload
This commit is contained in:
gt-oai
2026-02-11 14:06:41 +00:00
committed by GitHub
parent f5d4a21098
commit 886d9377d3
7 changed files with 666 additions and 29 deletions

View File

@@ -905,6 +905,7 @@ impl CodexMessageProcessor {
let auth_manager = self.auth_manager.clone();
let cloud_requirements = self.cloud_requirements.clone();
let chatgpt_base_url = self.config.chatgpt_base_url.clone();
let codex_home = self.config.codex_home.clone();
let cli_overrides = self.cli_overrides.clone();
let auth_url = server.auth_url.clone();
tokio::spawn(async move {
@@ -939,6 +940,7 @@ impl CodexMessageProcessor {
cloud_requirements.as_ref(),
auth_manager.clone(),
chatgpt_base_url,
codex_home.clone(),
);
sync_default_client_residency_requirement(
&cli_overrides,
@@ -1011,6 +1013,7 @@ impl CodexMessageProcessor {
let auth_manager = self.auth_manager.clone();
let cloud_requirements = self.cloud_requirements.clone();
let chatgpt_base_url = self.config.chatgpt_base_url.clone();
let codex_home = self.config.codex_home.clone();
let cli_overrides = self.cli_overrides.clone();
let auth_url = server.auth_url.clone();
tokio::spawn(async move {
@@ -1045,6 +1048,7 @@ impl CodexMessageProcessor {
cloud_requirements.as_ref(),
auth_manager.clone(),
chatgpt_base_url,
codex_home.clone(),
);
sync_default_client_residency_requirement(
&cli_overrides,
@@ -1212,6 +1216,7 @@ impl CodexMessageProcessor {
self.cloud_requirements.as_ref(),
self.auth_manager.clone(),
self.config.chatgpt_base_url.clone(),
self.config.codex_home.clone(),
);
sync_default_client_residency_requirement(
&self.cli_overrides,
@@ -5516,8 +5521,9 @@ fn replace_cloud_requirements_loader(
cloud_requirements: &RwLock<CloudRequirementsLoader>,
auth_manager: Arc<AuthManager>,
chatgpt_base_url: String,
codex_home: std::path::PathBuf,
) {
let loader = cloud_requirements_loader(auth_manager, chatgpt_base_url);
let loader = cloud_requirements_loader(auth_manager, chatgpt_base_url, codex_home);
if let Ok(mut guard) = cloud_requirements.write() {
*guard = loader;
} else {