Skip duplicate snapshot git config for attribution

Avoid appending Codex's runtime git config when the shell snapshot already defines the same key, preserving user hook setup instead of competing with it.

Add regression coverage for a preexisting snapshot core.hooksPath.

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Gabriel Cohen
2026-03-23 22:18:37 -07:00
parent 71ed2fdb39
commit a49e94a38d
2 changed files with 61 additions and 2 deletions

View File

@@ -172,13 +172,30 @@ fn build_runtime_git_config_appends(runtime_git_config_overrides: &[(String, Str
"\ncase \"${GIT_CONFIG_COUNT:-}\" in\n ''|*[!0-9]*) __CODEX_GIT_CONFIG_INDEX=0 ;;\n *) __CODEX_GIT_CONFIG_INDEX=\"$GIT_CONFIG_COUNT\" ;;\nesac\n",
);
script.push_str(
"__codex_has_runtime_git_config_key() {\n\
__CODEX_GIT_CONFIG_LOOKUP_KEY=\"$1\"\n\
__CODEX_GIT_CONFIG_SCAN_INDEX=0\n\
while [ \"$__CODEX_GIT_CONFIG_SCAN_INDEX\" -lt \"$__CODEX_GIT_CONFIG_INDEX\" ]; do\n\
eval \"__CODEX_GIT_CONFIG_EXISTING_KEY=\\${GIT_CONFIG_KEY_${__CODEX_GIT_CONFIG_SCAN_INDEX}-}\"\n\
if [ \"$__CODEX_GIT_CONFIG_EXISTING_KEY\" = \"$__CODEX_GIT_CONFIG_LOOKUP_KEY\" ]; then\n\
return 0\n\
fi\n\
__CODEX_GIT_CONFIG_SCAN_INDEX=$((__CODEX_GIT_CONFIG_SCAN_INDEX + 1))\n\
done\n\
return 1\n\
}\n",
);
for (key, value) in runtime_git_config_overrides {
let key = shell_single_quote(key);
let value = shell_single_quote(value);
script.push_str(&format!(
"eval \"export GIT_CONFIG_KEY_${{__CODEX_GIT_CONFIG_INDEX}}='{key}'\"\n\
"if ! __codex_has_runtime_git_config_key '{key}'; then\n\
eval \"export GIT_CONFIG_KEY_${{__CODEX_GIT_CONFIG_INDEX}}='{key}'\"\n\
eval \"export GIT_CONFIG_VALUE_${{__CODEX_GIT_CONFIG_INDEX}}='{value}'\"\n\
__CODEX_GIT_CONFIG_INDEX=$((__CODEX_GIT_CONFIG_INDEX + 1))\n"
__CODEX_GIT_CONFIG_INDEX=$((__CODEX_GIT_CONFIG_INDEX + 1))\n\
fi\n"
));
}

View File

@@ -482,3 +482,45 @@ fn maybe_wrap_shell_lc_with_snapshot_appends_runtime_git_config_after_snapshot()
"2|user.name|Pavel|core.hooksPath|/codex/hooks"
);
}
#[test]
fn maybe_wrap_shell_lc_with_snapshot_skips_duplicate_runtime_git_config_from_snapshot() {
let dir = tempdir().expect("create temp dir");
let snapshot_path = dir.path().join("snapshot.sh");
std::fs::write(
&snapshot_path,
"# Snapshot file\nexport GIT_CONFIG_COUNT='1'\nexport GIT_CONFIG_KEY_0='core.hooksPath'\nexport GIT_CONFIG_VALUE_0='/user/hooks'\n",
)
.expect("write snapshot");
let session_shell = shell_with_snapshot(
ShellType::Bash,
"/bin/bash",
snapshot_path,
dir.path().to_path_buf(),
);
let command = vec![
"/bin/bash".to_string(),
"-lc".to_string(),
"printf '%s|%s|%s|%s|%s' \"${GIT_CONFIG_COUNT:-}\" \"${GIT_CONFIG_KEY_0:-}\" \"${GIT_CONFIG_VALUE_0:-}\" \"${GIT_CONFIG_KEY_1:-}\" \"${GIT_CONFIG_VALUE_1:-}\"".to_string(),
];
let runtime_git_config_overrides =
vec![("core.hooksPath".to_string(), "/codex/hooks".to_string())];
let rewritten = maybe_wrap_shell_lc_with_snapshot(
&command,
&session_shell,
dir.path(),
&HashMap::new(),
&runtime_git_config_overrides,
);
let output = Command::new(&rewritten[0])
.args(&rewritten[1..])
.output()
.expect("run rewritten command");
assert!(output.status.success(), "command failed: {output:?}");
assert_eq!(
String::from_utf8_lossy(&output.stdout),
"1|core.hooksPath|/user/hooks||"
);
}