@@ -20,6 +20,12 @@ const SLOW_THRESHOLD_MS: u64 = 2_500;
2020#[ cfg( target_os = "windows" ) ]
2121const CREATE_NO_WINDOW : u32 = 0x0800_0000 ;
2222
23+ #[ derive( Clone , Copy ) ]
24+ enum GitEnvironment {
25+ User ,
26+ AnonymousProbe ,
27+ }
28+
2329pub fn git_version ( ) -> Option < String > {
2430 run_git ( [ "--version" ] , None , Duration :: from_secs ( 5 ) )
2531 . ok ( )
@@ -70,10 +76,11 @@ pub fn test_node(node: &NodeDefinition, previous: &HealthSummary) -> HealthSumma
7076 for _ in 0 ..2 {
7177 let started = Instant :: now ( ) ;
7278 let config = format ! ( "url.{}.insteadOf=https://github.com/" , node. rewrite_base) ;
73- let result = run_git (
79+ let result = run_git_with_environment (
7480 [ "-c" , config. as_str ( ) , "ls-remote" , TEST_REPOSITORY , "HEAD" ] ,
7581 None ,
7682 COMMAND_TIMEOUT ,
83+ GitEnvironment :: AnonymousProbe ,
7784 ) ;
7885 let elapsed = started. elapsed ( ) . as_millis ( ) as u64 ;
7986 next. attempt_count = next. attempt_count . saturating_add ( 1 ) ;
@@ -483,25 +490,25 @@ fn affects_github_https(rewrite_prefix: &str) -> bool {
483490}
484491
485492pub fn effective_urls ( config_path : & Path , original_url : & str ) -> Result < ( String , String ) , String > {
486- effective_urls_with_global_config ( config_path, original_url, None )
493+ effective_urls_with_environment ( config_path, original_url, GitEnvironment :: User )
487494}
488495
489496pub fn effective_urls_isolated (
490497 config_path : & Path ,
491498 original_url : & str ,
492499) -> Result < ( String , String ) , String > {
493- effective_urls_with_global_config ( config_path, original_url, Some ( config_path ) )
500+ effective_urls_with_environment ( config_path, original_url, GitEnvironment :: AnonymousProbe )
494501}
495502
496- fn effective_urls_with_global_config (
503+ fn effective_urls_with_environment (
497504 config_path : & Path ,
498505 original_url : & str ,
499- global_config : Option < & Path > ,
506+ environment : GitEnvironment ,
500507) -> Result < ( String , String ) , String > {
501508 let temp = tempfile:: tempdir ( ) . map_err ( |error| format ! ( "无法创建诊断目录:{error}" ) ) ?;
502509 let directory = temp. path ( ) . to_string_lossy ( ) ;
503510 let include = format ! ( "include.path={}" , config_path. display( ) ) ;
504- let init = run_git_with_global_config (
511+ let init = run_git_with_environment (
505512 [
506513 "-c" ,
507514 include. as_str ( ) ,
@@ -510,14 +517,14 @@ fn effective_urls_with_global_config(
510517 "init" ,
511518 "-q" ,
512519 ] ,
513- None ,
520+ Some ( temp . path ( ) ) ,
514521 Duration :: from_secs ( 8 ) ,
515- global_config ,
522+ environment ,
516523 ) ?;
517524 if !init. status . success ( ) {
518525 return Err ( command_error ( & init) ) ;
519526 }
520- let add = run_git_with_global_config (
527+ let add = run_git_with_environment (
521528 [
522529 "-c" ,
523530 include. as_str ( ) ,
@@ -528,14 +535,14 @@ fn effective_urls_with_global_config(
528535 "origin" ,
529536 original_url,
530537 ] ,
531- None ,
538+ Some ( temp . path ( ) ) ,
532539 Duration :: from_secs ( 8 ) ,
533- global_config ,
540+ environment ,
534541 ) ?;
535542 if !add. status . success ( ) {
536543 return Err ( command_error ( & add) ) ;
537544 }
538- let fetch = run_git_with_global_config (
545+ let fetch = run_git_with_environment (
539546 [
540547 "-c" ,
541548 include. as_str ( ) ,
@@ -545,11 +552,11 @@ fn effective_urls_with_global_config(
545552 "get-url" ,
546553 "origin" ,
547554 ] ,
548- None ,
555+ Some ( temp . path ( ) ) ,
549556 Duration :: from_secs ( 8 ) ,
550- global_config ,
557+ environment ,
551558 ) ?;
552- let push = run_git_with_global_config (
559+ let push = run_git_with_environment (
553560 [
554561 "-c" ,
555562 include. as_str ( ) ,
@@ -560,9 +567,9 @@ fn effective_urls_with_global_config(
560567 "--push" ,
561568 "origin" ,
562569 ] ,
563- None ,
570+ Some ( temp . path ( ) ) ,
564571 Duration :: from_secs ( 8 ) ,
565- global_config ,
572+ environment ,
566573 ) ?;
567574 if !fetch. status . success ( ) || !push. status . success ( ) {
568575 return Err ( "无法解析 Git 有效地址" . into ( ) ) ;
@@ -679,32 +686,70 @@ fn run_git<const N: usize>(
679686 current_dir : Option < & Path > ,
680687 timeout : Duration ,
681688) -> Result < Output , String > {
682- run_git_with_global_config ( args, current_dir, timeout, None )
689+ run_git_with_environment ( args, current_dir, timeout, GitEnvironment :: User )
683690}
684691
685- fn run_git_with_global_config < const N : usize > (
692+ fn run_git_with_environment < const N : usize > (
686693 args : [ & str ; N ] ,
687694 current_dir : Option < & Path > ,
688695 timeout : Duration ,
689- global_config : Option < & Path > ,
696+ environment : GitEnvironment ,
690697) -> Result < Output , String > {
698+ let isolation = match environment {
699+ GitEnvironment :: User => None ,
700+ GitEnvironment :: AnonymousProbe => {
701+ let directory =
702+ tempfile:: tempdir ( ) . map_err ( |error| format ! ( "无法创建 Git 隔离目录:{error}" ) ) ?;
703+ fs:: write ( directory. path ( ) . join ( "global.gitconfig" ) , "" )
704+ . map_err ( |error| format ! ( "无法创建 Git 隔离配置:{error}" ) ) ?;
705+ Some ( directory)
706+ }
707+ } ;
691708 let mut command = Command :: new ( "git" ) ;
692- // GitBoost's own probes and configuration checks are operational noise, not user traffic.
693- command. env ( "GIT_TRACE2_EVENT" , "0" ) ;
694709 command
695710 . args ( args)
711+ // GitBoost's own probes and configuration checks are operational noise, not user traffic.
712+ . env ( "GIT_TRACE2_EVENT" , "0" )
696713 . env ( "GIT_TERMINAL_PROMPT" , "0" )
697714 . stdout ( Stdio :: piped ( ) )
698715 . stderr ( Stdio :: piped ( ) ) ;
699- if let Some ( config) = global_config {
716+
717+ if let Some ( directory) = isolation. as_ref ( ) {
718+ for ( key, _) in std:: env:: vars_os ( ) {
719+ if key
720+ . to_string_lossy ( )
721+ . to_ascii_uppercase ( )
722+ . starts_with ( "GIT_" )
723+ {
724+ command. env_remove ( key) ;
725+ }
726+ }
700727 command
701- . env ( "GIT_CONFIG_GLOBAL" , config)
702- . env ( "GIT_CONFIG_NOSYSTEM" , "1" ) ;
728+ . env_remove ( "SSH_ASKPASS" )
729+ . env_remove ( "SSH_ASKPASS_REQUIRE" )
730+ . env ( "HOME" , directory. path ( ) )
731+ . env ( "USERPROFILE" , directory. path ( ) )
732+ . env ( "XDG_CONFIG_HOME" , directory. path ( ) )
733+ . env (
734+ "GIT_CONFIG_GLOBAL" ,
735+ directory. path ( ) . join ( "global.gitconfig" ) ,
736+ )
737+ . env ( "GIT_CONFIG_NOSYSTEM" , "1" )
738+ . env ( "GIT_CONFIG_COUNT" , "1" )
739+ . env ( "GIT_CONFIG_KEY_0" , "credential.helper" )
740+ . env ( "GIT_CONFIG_VALUE_0" , "" )
741+ . env ( "GIT_TRACE2_EVENT" , "0" )
742+ . env ( "GIT_TERMINAL_PROMPT" , "0" ) ;
703743 }
704- hide_console ( & mut command) ;
705744 if let Some ( directory) = current_dir {
706745 command. current_dir ( directory) ;
746+ } else if let Some ( directory) = isolation. as_ref ( ) {
747+ command. current_dir ( directory. path ( ) ) ;
707748 }
749+ if matches ! ( environment, GitEnvironment :: AnonymousProbe ) {
750+ command. env_remove ( "HOMEDRIVE" ) . env_remove ( "HOMEPATH" ) ;
751+ }
752+ hide_console ( & mut command) ;
708753 let mut child = command
709754 . spawn ( )
710755 . map_err ( |error| format ! ( "无法启动系统 Git:{error}" ) ) ?;
@@ -801,42 +846,83 @@ mod tests {
801846
802847 #[ test]
803848 fn isolated_effective_urls_ignore_the_registered_live_config ( ) {
849+ const MARKER : & str = "GITBOOST_ISOLATED_URLS_CHILD" ;
850+ if std:: env:: var_os ( MARKER ) . is_none ( ) {
851+ let directory = tempfile:: tempdir ( ) . unwrap ( ) ;
852+ let live = directory. path ( ) . join ( "live.gitconfig" ) ;
853+ let global = directory. path ( ) . join ( "global.gitconfig" ) ;
854+ fs:: write (
855+ & live,
856+ "[url \" https://old.example/https://github.com/openai/codex\" ]\n \t insteadOf = https://github.com/openai/codex\n [credential]\n \t helper = inherited-helper\n " ,
857+ )
858+ . unwrap ( ) ;
859+ fs:: write (
860+ & global,
861+ format ! (
862+ "[include]\n \t path = \" {}\" \n " ,
863+ escape_subsection( & live. to_string_lossy( ) )
864+ ) ,
865+ )
866+ . unwrap ( ) ;
867+ let status = Command :: new ( std:: env:: current_exe ( ) . unwrap ( ) )
868+ . args ( [
869+ "--exact" ,
870+ "git::tests::isolated_effective_urls_ignore_the_registered_live_config" ,
871+ "--nocapture" ,
872+ ] )
873+ . env ( MARKER , "1" )
874+ . env ( "GIT_CONFIG_GLOBAL" , & global)
875+ . env ( "GIT_CONFIG_NOSYSTEM" , "1" )
876+ . env ( "GIT_CONFIG_COUNT" , "2" )
877+ . env (
878+ "GIT_CONFIG_KEY_0" ,
879+ "url.https://dynamic.example/https://github.com/openai/codex.git.insteadOf" ,
880+ )
881+ . env ( "GIT_CONFIG_VALUE_0" , "https://github.com/openai/codex.git" )
882+ . env ( "GIT_CONFIG_KEY_1" , "credential.helper" )
883+ . env ( "GIT_CONFIG_VALUE_1" , "dynamic-helper" )
884+ . env ( "GIT_DIR" , directory. path ( ) . join ( "missing.git" ) )
885+ . env ( "GIT_WORK_TREE" , directory. path ( ) )
886+ . env ( "GIT_ASKPASS" , directory. path ( ) . join ( "missing-askpass" ) )
887+ . env ( "SSH_ASKPASS" , directory. path ( ) . join ( "missing-ssh-askpass" ) )
888+ . status ( )
889+ . unwrap ( ) ;
890+ assert ! ( status. success( ) , "isolated Git environment test failed" ) ;
891+ return ;
892+ }
893+
804894 let directory = tempfile:: tempdir ( ) . unwrap ( ) ;
805- let live = directory. path ( ) . join ( "live.gitconfig" ) ;
806895 let candidate = directory. path ( ) . join ( "candidate.gitconfig" ) ;
807- let global = directory. path ( ) . join ( "global.gitconfig" ) ;
808- fs:: write (
809- & live,
810- "[url \" https://old.example/https://github.com/openai/codex\" ]\n \t insteadOf = https://github.com/openai/codex\n " ,
811- )
812- . unwrap ( ) ;
813896 fs:: write (
814897 & candidate,
815898 "[url \" https://new.example/https://github.com/openai/codex\" ]\n \t insteadOf = https://github.com/openai/codex\n " ,
816899 )
817900 . unwrap ( ) ;
818- fs:: write (
819- & global,
820- format ! (
821- "[include]\n \t path = \" {}\" \n " ,
822- escape_subsection( & live. to_string_lossy( ) )
823- ) ,
824- )
825- . unwrap ( ) ;
826901
827902 let original = "https://github.com/openai/codex.git" ;
828- let ( conflicted, _) =
829- effective_urls_with_global_config ( & candidate, original, Some ( & global) ) . unwrap ( ) ;
830- assert_eq ! (
831- conflicted,
832- "https://old.example/https://github.com/openai/codex.git"
833- ) ;
834-
835903 let ( fetch, _) = effective_urls_isolated ( & candidate, original) . unwrap ( ) ;
836904 assert_eq ! (
837905 fetch,
838906 "https://new.example/https://github.com/openai/codex.git"
839907 ) ;
908+
909+ let helpers = run_git_with_environment (
910+ [ "config" , "--get-all" , "credential.helper" ] ,
911+ None ,
912+ Duration :: from_secs ( 5 ) ,
913+ GitEnvironment :: AnonymousProbe ,
914+ )
915+ . unwrap ( ) ;
916+ assert ! ( helpers. status. success( ) ) ;
917+ assert_eq ! ( String :: from_utf8_lossy( & helpers. stdout) . trim( ) , "" ) ;
918+
919+ std:: env:: remove_var ( "GIT_DIR" ) ;
920+ std:: env:: remove_var ( "GIT_WORK_TREE" ) ;
921+ let ( conflicted, _) = effective_urls ( & candidate, original) . unwrap ( ) ;
922+ assert_eq ! (
923+ conflicted,
924+ "https://dynamic.example/https://github.com/openai/codex.git"
925+ ) ;
840926 }
841927
842928 #[ test]
0 commit comments