mirror of
https://github.com/openai/codex.git
synced 2026-11-06 20:20:34 +00:00
Add a feature-gated account check for CLI thread resume (#58890)
## What changed Add the disabled-by-default `cli_resume_account_check` feature. When enabled for `codex-tui` and `codex_exec`, reject resuming or attaching to a local thread if its recorded creator user or workspace differs from the current ChatGPT account. Return an error directing the user to sign in with the original account. Carry creator IDs through stored thread metadata and check them before loading resume history. Preserve existing behavior for untagged threads, other clients, and authentication modes without a comparable ChatGPT account. ## Testing Add integration coverage for account and workspace mismatches, matching accounts, legacy and paginated history, ID and path lookup, and the feature's default and bypass behavior. Verify that switching back to the original account permits attachment to a loaded thread and that creator metadata remains unchanged. GitOrigin-RevId: a3ab089254703417dde0890a5f8d6326c4cbb75a
This commit is contained in:
@@ -1115,6 +1115,14 @@ fn stored_thread_from_state(
|
||||
});
|
||||
|
||||
Ok(StoredThread {
|
||||
creator_user_id: created
|
||||
.creator_user_id
|
||||
.clone()
|
||||
.or_else(|| metadata.and_then(|metadata| metadata.creator_user_id.clone())),
|
||||
creator_account_id: created
|
||||
.creator_account_id
|
||||
.clone()
|
||||
.or_else(|| metadata.and_then(|metadata| metadata.creator_account_id.clone())),
|
||||
originator: (!created.originator.is_empty()).then(|| created.originator.clone()),
|
||||
thread_id,
|
||||
extra_config: created.extra_config.clone(),
|
||||
|
||||
@@ -140,6 +140,8 @@ pub(super) fn stored_thread_from_rollout_item(
|
||||
let rollout_path = codex_rollout::plain_rollout_path(item.path.as_path());
|
||||
|
||||
Some(StoredThread {
|
||||
creator_user_id: None,
|
||||
creator_account_id: None,
|
||||
thread_id,
|
||||
extra_config: None,
|
||||
rollout_path: Some(rollout_path),
|
||||
|
||||
@@ -323,6 +323,8 @@ async fn read_thread_from_rollout_path(
|
||||
})?;
|
||||
thread.rollout_path = Some(codex_rollout::plain_rollout_path(path.as_path()));
|
||||
let meta_line = read_required_session_meta_line(path.as_path()).await?;
|
||||
thread.creator_user_id = meta_line.meta.creator_user_id;
|
||||
thread.creator_account_id = meta_line.meta.creator_account_id;
|
||||
thread.forked_from_id = meta_line.meta.forked_from_id;
|
||||
thread.parent_thread_id = meta_line.meta.parent_thread_id;
|
||||
thread.history_mode = meta_line.meta.history_mode;
|
||||
@@ -411,6 +413,14 @@ async fn stored_thread_from_metadata(
|
||||
.unwrap_or(metadata.history_mode);
|
||||
let name = thread_name_from_metadata(store, &metadata, history_mode).await;
|
||||
let mut thread = stored_thread_from_state_metadata(store, metadata, parent_thread_id);
|
||||
if let Some(meta) = &session_meta {
|
||||
thread.creator_user_id = thread
|
||||
.creator_user_id
|
||||
.or_else(|| meta.creator_user_id.clone());
|
||||
thread.creator_account_id = thread
|
||||
.creator_account_id
|
||||
.or_else(|| meta.creator_account_id.clone());
|
||||
}
|
||||
thread.originator = thread.originator.or_else(|| {
|
||||
session_meta
|
||||
.map(|meta| meta.originator)
|
||||
@@ -440,6 +450,8 @@ pub(super) fn stored_thread_from_state_metadata(
|
||||
let permission_profile =
|
||||
permission_profile_from_metadata_value(&metadata.sandbox_policy, metadata.cwd.as_path());
|
||||
StoredThread {
|
||||
creator_user_id: metadata.creator_user_id,
|
||||
creator_account_id: metadata.creator_account_id,
|
||||
thread_id: metadata.id,
|
||||
extra_config: None,
|
||||
rollout_path: Some(rollout_path),
|
||||
@@ -543,6 +555,8 @@ fn stored_thread_from_meta_line(
|
||||
.unwrap_or(created_at);
|
||||
let rollout_path = codex_rollout::plain_rollout_path(path.as_path());
|
||||
StoredThread {
|
||||
creator_user_id: meta_line.meta.creator_user_id,
|
||||
creator_account_id: meta_line.meta.creator_account_id,
|
||||
thread_id: meta_line.meta.id,
|
||||
extra_config: None,
|
||||
rollout_path: Some(rollout_path),
|
||||
|
||||
@@ -615,6 +615,12 @@ pub struct ThreadOccurrenceSearchPage {
|
||||
/// Store-owned thread metadata used by list/read/resume responses.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct StoredThread {
|
||||
/// Recorded creator user, when available from the backing store.
|
||||
#[serde(default)]
|
||||
pub creator_user_id: Option<String>,
|
||||
/// Recorded creator workspace, when available from the backing store.
|
||||
#[serde(default)]
|
||||
pub creator_account_id: Option<String>,
|
||||
/// Originator recorded at creation, if available from the backing store.
|
||||
#[serde(default)]
|
||||
pub originator: Option<String>,
|
||||
|
||||
Reference in New Issue
Block a user