mirror of
https://github.com/openai/codex.git
synced 2026-11-13 22:47:20 +00:00
Sanitize credentials from Git remote metadata (#40713)
## Why Git remote URLs can embed usernames, passwords, or tokens. Codex carries these URLs through turn metadata and persisted thread metadata, so credentials must be removed before a remote enters those paths. ## What changed - Add `SanitizedGitUrl`, which parses Git URL and SCP-style remotes, strips authentication data, and preserves the conventional `git` SSH user. - Use sanitized remotes when collecting Git metadata, enriching model requests, discovering cloud environments, updating thread metadata, and reading legacy rollouts. Reject or omit malformed remotes instead of retaining their raw contents. - Keep API, schema, and TypeScript representations as strings while enforcing sanitization in Rust. ## Testing - Cover URL schemes, SCP and IPv6 forms, remote helpers, encoded paths, malformed values, and legacy deserialization. - Verify credentials do not appear in model requests, API responses, SQLite, or rollout files. GitOrigin-RevId: 6435efc4c45bfbfad4723ce7a0457cb00175f25c
This commit is contained in:
1 parent
399be2d6b5
commit
1bc02aea50
31 files changed
+1073
-68
No files matched your search
@@ -10,6 +10,7 @@ use std::time::SystemTime;
|
||||
use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
use codex_git_utils::GitSha;
|
||||
use codex_protocol::SanitizedGitUrl;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
@@ -309,7 +310,7 @@ fn parse_legacy_sandbox_policy(value: &str) -> serde_json::Result<SandboxPolicy>
|
||||
pub(super) fn git_info_from_parts(
|
||||
sha: Option<String>,
|
||||
branch: Option<String>,
|
||||
origin_url: Option<String>,
|
||||
origin_url: Option<SanitizedGitUrl>,
|
||||
) -> Option<GitInfo> {
|
||||
if sha.is_none() && branch.is_none() && origin_url.is_none() {
|
||||
return None;
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use chrono::Utc;
|
||||
use codex_protocol::SanitizedGitUrl;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::protocol::GitInfo;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
@@ -708,7 +709,7 @@ async fn apply_thread_git_info_patch(
|
||||
git_info
|
||||
.origin_url
|
||||
.as_ref()
|
||||
.map(|origin_url| origin_url.as_deref()),
|
||||
.map(|origin_url| origin_url.as_ref()),
|
||||
)
|
||||
.await
|
||||
.map_err(|err| ThreadStoreError::Internal {
|
||||
@@ -728,7 +729,7 @@ async fn apply_thread_git_info(
|
||||
thread_id: ThreadId,
|
||||
sha: &Option<String>,
|
||||
branch: &Option<String>,
|
||||
origin_url: &Option<String>,
|
||||
origin_url: &Option<SanitizedGitUrl>,
|
||||
) -> ThreadStoreResult<()> {
|
||||
let Some(state_db) = store.state_db().await else {
|
||||
return Err(ThreadStoreError::Internal {
|
||||
@@ -740,7 +741,7 @@ async fn apply_thread_git_info(
|
||||
thread_id,
|
||||
Some(sha.as_deref()),
|
||||
Some(branch.as_deref()),
|
||||
Some(origin_url.as_deref()),
|
||||
Some(origin_url.as_ref()),
|
||||
)
|
||||
.await
|
||||
.map_err(|err| ThreadStoreError::Internal {
|
||||
@@ -758,7 +759,7 @@ async fn apply_thread_git_info(
|
||||
fn resolve_git_info_patch(
|
||||
existing: Option<GitInfo>,
|
||||
git_info: GitInfoPatch,
|
||||
) -> (Option<String>, Option<String>, Option<String>) {
|
||||
) -> (Option<String>, Option<String>, Option<SanitizedGitUrl>) {
|
||||
let (existing_sha, existing_branch, existing_origin_url) = match existing {
|
||||
Some(info) => (
|
||||
info.commit_hash.map(|sha| sha.0),
|
||||
@@ -778,7 +779,7 @@ async fn apply_thread_git_info_to_rollout(
|
||||
thread_id: ThreadId,
|
||||
sha: &Option<String>,
|
||||
branch: &Option<String>,
|
||||
origin_url: &Option<String>,
|
||||
origin_url: &Option<SanitizedGitUrl>,
|
||||
memory_mode: Option<&str>,
|
||||
) -> ThreadStoreResult<()> {
|
||||
let mut session_meta =
|
||||
@@ -1435,7 +1436,10 @@ mod tests {
|
||||
git_info: Some(GitInfoPatch {
|
||||
sha: Some(Some("abc123".to_string())),
|
||||
branch: Some(Some("main".to_string())),
|
||||
origin_url: Some(Some("https://github.com/openai/codex".to_string())),
|
||||
origin_url: Some(Some(
|
||||
SanitizedGitUrl::try_from("https://github.com/openai/codex")
|
||||
.expect("valid git remote URL"),
|
||||
)),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1536,7 +1540,10 @@ mod tests {
|
||||
git_info: Some(GitInfoPatch {
|
||||
sha: Some(Some("abc123".to_string())),
|
||||
branch: Some(Some("main".to_string())),
|
||||
origin_url: Some(Some("https://github.com/openai/codex".to_string())),
|
||||
origin_url: Some(Some(
|
||||
SanitizedGitUrl::try_from("https://github.com/openai/codex")
|
||||
.expect("valid git remote URL"),
|
||||
)),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1596,7 +1603,10 @@ mod tests {
|
||||
git_info: Some(GitInfoPatch {
|
||||
sha: Some(Some("abc123".to_string())),
|
||||
branch: Some(Some("main".to_string())),
|
||||
origin_url: Some(Some("https://github.com/openai/codex".to_string())),
|
||||
origin_url: Some(Some(
|
||||
SanitizedGitUrl::try_from("https://github.com/openai/codex")
|
||||
.expect("valid git remote URL"),
|
||||
)),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user