@@ -11,9 +11,34 @@ import { fileExistsAtPath } from "../../../utils/fs"
1111import * as fileSearch from "../../../services/search/file-search"
1212
1313import { RepoPerTaskCheckpointService } from "../RepoPerTaskCheckpointService"
14+ import { BLOCKED_ENV_KEYS } from "../ShadowCheckpointService"
1415
1516const tmpDir = path . join ( os . tmpdir ( ) , "CheckpointService" )
1617
18+ // simple-git ≥3.36 blocks env vars it considers code-execution vectors.
19+ // Strip them for the duration of this test suite so tests pass for developers
20+ // who have GIT_EDITOR, GIT_SSH_COMMAND, etc. configured globally.
21+ // Safe under vitest's default "forks" pool (each worker has its own process.env);
22+ // would be fragile under "threads" pool where workers share the same process.
23+ const savedEnv : Partial < Record < string , string > > = { }
24+
25+ beforeAll ( ( ) => {
26+ for ( const key of BLOCKED_ENV_KEYS ) {
27+ savedEnv [ key ] = process . env [ key ]
28+ delete process . env [ key ]
29+ }
30+ } )
31+
32+ afterAll ( ( ) => {
33+ for ( const key of BLOCKED_ENV_KEYS ) {
34+ if ( savedEnv [ key ] !== undefined ) {
35+ process . env [ key ] = savedEnv [ key ]
36+ } else {
37+ delete process . env [ key ]
38+ }
39+ }
40+ } )
41+
1742const initWorkspaceRepo = async ( {
1843 workspaceDir,
1944 userName = "Roo Code" ,
@@ -35,6 +60,7 @@ const initWorkspaceRepo = async ({
3560 await git . init ( )
3661 await git . addConfig ( "user.name" , userName )
3762 await git . addConfig ( "user.email" , userEmail )
63+ await git . addConfig ( "commit.gpgSign" , "false" )
3864
3965 // Create test file.
4066 const testFile = path . join ( workspaceDir , testFileName )
@@ -390,6 +416,7 @@ describe.each([[RepoPerTaskCheckpointService, "RepoPerTaskCheckpointService"]])(
390416 await mainGit . init ( )
391417 await mainGit . addConfig ( "user.name" , "Roo Code" )
392418 await mainGit . addConfig ( "user.email" , "support@roocode.com" )
419+ await mainGit . addConfig ( "commit.gpgSign" , "false" )
393420
394421 // Create a nested repo inside the workspace.
395422 const nestedRepoPath = path . join ( workspaceDir , "nested-project" )
@@ -398,6 +425,7 @@ describe.each([[RepoPerTaskCheckpointService, "RepoPerTaskCheckpointService"]])(
398425 await nestedGit . init ( )
399426 await nestedGit . addConfig ( "user.name" , "Roo Code" )
400427 await nestedGit . addConfig ( "user.email" , "support@roocode.com" )
428+ await nestedGit . addConfig ( "commit.gpgSign" , "false" )
401429
402430 // Add a file to the nested repo.
403431 const nestedFile = path . join ( nestedRepoPath , "nested-file.txt" )
@@ -460,6 +488,7 @@ describe.each([[RepoPerTaskCheckpointService, "RepoPerTaskCheckpointService"]])(
460488 await mainGit . init ( )
461489 await mainGit . addConfig ( "user.name" , "Roo Code" )
462490 await mainGit . addConfig ( "user.email" , "support@roocode.com" )
491+ await mainGit . addConfig ( "commit.gpgSign" , "false" )
463492
464493 // Create a test file in the main workspace.
465494 const mainFile = path . join ( workspaceDir , "main-file.txt" )
@@ -873,6 +902,47 @@ describe.each([[RepoPerTaskCheckpointService, "RepoPerTaskCheckpointService"]])(
873902 }
874903 } )
875904
905+ it ( "isolates checkpoint operations from simple-git blocked environment variables" , async ( ) => {
906+ const testShadowDir = path . join ( tmpDir , `shadow-blocked-env-test-${ Date . now ( ) } ` )
907+ const testWorkspaceDir = path . join ( tmpDir , `workspace-blocked-env-test-${ Date . now ( ) } ` )
908+ await initWorkspaceRepo ( { workspaceDir : testWorkspaceDir } )
909+
910+ // beforeAll strips PREFIX, so it is always undefined here; set it to exercise isolation.
911+ process . env . PREFIX = path . join ( tmpDir , "git-prefix" )
912+
913+ try {
914+ const testService = await klass . create ( {
915+ taskId : `test-blocked-env-${ Date . now ( ) } ` ,
916+ shadowDir : testShadowDir ,
917+ workspaceDir : testWorkspaceDir ,
918+ log : ( ) => { } ,
919+ } )
920+ await testService . initShadowGit ( )
921+
922+ const testWorkspaceFile = path . join ( testWorkspaceDir , "test.txt" )
923+ await fs . writeFile ( testWorkspaceFile , "Modified with PREFIX set" )
924+ const commit = await testService . saveCheckpoint ( "Checkpoint with PREFIX set" )
925+ expect ( commit ?. commit ) . toBeTruthy ( )
926+
927+ // Verify the checkpoint is accessible and contains the expected change
928+ const diff = await testService . getDiff ( { to : commit ! . commit } )
929+ expect ( diff ) . toHaveLength ( 1 )
930+ expect ( diff [ 0 ] . paths . relative ) . toBe ( "test.txt" )
931+ expect ( diff [ 0 ] . content . after ) . toBe ( "Modified with PREFIX set" )
932+
933+ // Verify we can restore the checkpoint
934+ await fs . writeFile ( testWorkspaceFile , "Another modification" )
935+ await testService . restoreCheckpoint ( commit ! . commit )
936+ expect ( await fs . readFile ( testWorkspaceFile , "utf-8" ) ) . toBe ( "Modified with PREFIX set" )
937+ } finally {
938+ // beforeAll guarantees PREFIX was undefined at test start, so always delete it.
939+ delete process . env . PREFIX
940+
941+ await fs . rm ( testShadowDir , { recursive : true , force : true } )
942+ await fs . rm ( testWorkspaceDir , { recursive : true , force : true } )
943+ }
944+ } )
945+
876946 it ( "isolates checkpoint operations from GIT_DIR environment variable" , async ( ) => {
877947 // This test verifies the fix for the issue where GIT_DIR environment variable
878948 // causes checkpoint commits to go to the wrong repository.
@@ -886,6 +956,7 @@ describe.each([[RepoPerTaskCheckpointService, "RepoPerTaskCheckpointService"]])(
886956 await externalGit . init ( )
887957 await externalGit . addConfig ( "user.name" , "External User" )
888958 await externalGit . addConfig ( "user.email" , "external@example.com" )
959+ await externalGit . addConfig ( "commit.gpgSign" , "false" )
889960
890961 // Create and commit a file in the external repo
891962 const externalFile = path . join ( externalGitDir , "external.txt" )
@@ -976,6 +1047,7 @@ describe("worktree path comparison", () => {
9761047 await mainGit . init ( )
9771048 await mainGit . addConfig ( "user.name" , "Roo Code" )
9781049 await mainGit . addConfig ( "user.email" , "support@roocode.com" )
1050+ await mainGit . addConfig ( "commit.gpgSign" , "false" )
9791051
9801052 await fs . writeFile ( path . join ( workspaceDir , "main.txt" ) , "main content" )
9811053 await mainGit . add ( "main.txt" )
@@ -1011,6 +1083,7 @@ describe("worktree path comparison", () => {
10111083 await mainGit . init ( )
10121084 await mainGit . addConfig ( "user.name" , "Roo Code" )
10131085 await mainGit . addConfig ( "user.email" , "support@roocode.com" )
1086+ await mainGit . addConfig ( "commit.gpgSign" , "false" )
10141087
10151088 await fs . writeFile ( path . join ( workspaceDir , "main.txt" ) , "main content" )
10161089 await mainGit . add ( "main.txt" )
0 commit comments