1010from tgit .commit import (
1111 CommitArgs ,
1212 CommitData ,
13+ PotentialSecret ,
1314 TemplateParams ,
1415 get_changed_files_from_status ,
1516 get_file_change_sizes ,
@@ -61,17 +62,24 @@ class TestCommitData:
6162
6263 def test_commit_data_creation (self ):
6364 """Test creating CommitData instance."""
64- data = CommitData (type = "feat" , scope = "auth" , msg = "add login functionality" , is_breaking = False )
65+ data = CommitData (type = "feat" , scope = "auth" , msg = "add login functionality" , is_breaking = False , secrets = [] )
6566 assert data .type == "feat"
6667 assert data .scope == "auth"
6768 assert data .msg == "add login functionality"
6869 assert data .is_breaking is False
6970
7071 def test_commit_data_with_none_scope (self ):
7172 """Test CommitData with None scope."""
72- data = CommitData (type = "fix" , scope = None , msg = "fix bug" , is_breaking = False )
73+ data = CommitData (type = "fix" , scope = None , msg = "fix bug" , is_breaking = False , secrets = [] )
7374 assert data .scope is None
7475
76+ def test_commit_data_with_secrets (self ):
77+ """Test CommitData with suspected secrets."""
78+ secret = PotentialSecret (file = "config.env" , description = "looks like api key" )
79+ data = CommitData (type = "chore" , scope = None , msg = "update config" , is_breaking = False , secrets = [secret ])
80+ assert len (data .secrets ) == 1
81+ assert data .secrets [0 ].file == "config.env"
82+
7583
7684class TestGetChangedFilesFromStatus :
7785 """Test get_changed_files_from_status function."""
@@ -296,7 +304,7 @@ def test_generate_commit_with_ai_success(self, mock_settings, mock_template, moc
296304
297305 # Mock the response
298306 mock_response = Mock ()
299- mock_commit_data = CommitData (type = "feat" , scope = "auth" , msg = "add login" , is_breaking = False )
307+ mock_commit_data = CommitData (type = "feat" , scope = "auth" , msg = "add login" , is_breaking = False , secrets = [] )
300308 mock_response .output_parsed = mock_commit_data
301309 mock_client .responses .parse .return_value = mock_response
302310
@@ -334,7 +342,7 @@ def test_generate_commit_with_ai_reasoning_model(self, mock_settings, mock_templ
334342 mock_settings .model = "o1-mini"
335343
336344 mock_response = Mock ()
337- mock_commit_data = CommitData (type = "fix" , scope = None , msg = "correct bug" , is_breaking = False )
345+ mock_commit_data = CommitData (type = "fix" , scope = None , msg = "correct bug" , is_breaking = False , secrets = [] )
338346 mock_response .output_parsed = mock_commit_data
339347 mock_client .responses .parse .return_value = mock_response
340348
@@ -396,7 +404,7 @@ def test_get_ai_command_success(self, mock_settings, mock_get_commit_command, mo
396404 mock_repo_instance .active_branch .name = "main"
397405 mock_settings .commit .emoji = True
398406
399- mock_commit_data = CommitData (type = "feat" , scope = "auth" , msg = "add login" , is_breaking = False )
407+ mock_commit_data = CommitData (type = "feat" , scope = "auth" , msg = "add login" , is_breaking = False , secrets = [] )
400408 mock_generate .return_value = mock_commit_data
401409 mock_get_commit_command .return_value = "git commit -m 'feat(auth): add login'"
402410
@@ -406,6 +414,63 @@ def test_get_ai_command_success(self, mock_settings, mock_get_commit_command, mo
406414 mock_generate .assert_called_once ()
407415 mock_get_commit_command .assert_called_once_with ("feat" , "auth" , "add login" , use_emoji = True , is_breaking = False )
408416
417+ @patch ("tgit.commit.click.confirm" )
418+ @patch ("tgit.commit.Path.cwd" )
419+ @patch ("tgit.commit.git.Repo" )
420+ @patch ("tgit.commit.get_filtered_diff_files" )
421+ @patch ("tgit.commit._generate_commit_with_ai" )
422+ @patch ("tgit.commit.get_commit_command" )
423+ @patch ("tgit.commit.settings" )
424+ def test_get_ai_command_detected_secrets_abort (self , mock_settings , mock_get_commit_command , mock_generate , mock_get_files , mock_repo , mock_cwd , mock_confirm ):
425+ """Test get_ai_command aborts when secrets are detected and user declines."""
426+ mock_cwd .return_value = Path (tempfile .gettempdir ())
427+ mock_repo_instance = Mock ()
428+ mock_repo .return_value = mock_repo_instance
429+ mock_get_files .return_value = (["src/file.py" ], [])
430+ mock_repo_instance .git .diff .return_value = "diff content"
431+ mock_repo_instance .active_branch .name = "main"
432+ mock_settings .commit .emoji = True
433+
434+ secret = PotentialSecret (file = "src/file.py" , description = "possible api key" )
435+ mock_commit_data = CommitData (type = "feat" , scope = "auth" , msg = "add login" , is_breaking = False , secrets = [secret ])
436+ mock_generate .return_value = mock_commit_data
437+ mock_confirm .return_value = False
438+
439+ result = get_ai_command ()
440+
441+ assert result is None
442+ mock_confirm .assert_called_once_with ("Detected potential secrets. Continue with commit?" , default = False )
443+ mock_get_commit_command .assert_not_called ()
444+
445+ @patch ("tgit.commit.click.confirm" )
446+ @patch ("tgit.commit.Path.cwd" )
447+ @patch ("tgit.commit.git.Repo" )
448+ @patch ("tgit.commit.get_filtered_diff_files" )
449+ @patch ("tgit.commit._generate_commit_with_ai" )
450+ @patch ("tgit.commit.get_commit_command" )
451+ @patch ("tgit.commit.settings" )
452+ def test_get_ai_command_detected_secrets_continue (self , mock_settings , mock_get_commit_command , mock_generate , mock_get_files , mock_repo , mock_cwd , mock_confirm ):
453+ """Test get_ai_command continues when secrets are detected and user agrees."""
454+ mock_cwd .return_value = Path (tempfile .gettempdir ())
455+ mock_repo_instance = Mock ()
456+ mock_repo .return_value = mock_repo_instance
457+ mock_get_files .return_value = (["src/file.py" ], [])
458+ mock_repo_instance .git .diff .return_value = "diff content"
459+ mock_repo_instance .active_branch .name = "main"
460+ mock_settings .commit .emoji = True
461+
462+ secret = PotentialSecret (file = "src/file.py" , description = "possible api key" )
463+ mock_commit_data = CommitData (type = "feat" , scope = "auth" , msg = "add login" , is_breaking = False , secrets = [secret ])
464+ mock_generate .return_value = mock_commit_data
465+ mock_get_commit_command .return_value = "git commit -m 'feat(auth): add login'"
466+ mock_confirm .return_value = True
467+
468+ result = get_ai_command ()
469+
470+ assert result == "git commit -m 'feat(auth): add login'"
471+ mock_confirm .assert_called_once_with ("Detected potential secrets. Continue with commit?" , default = False )
472+ mock_get_commit_command .assert_called_once_with ("feat" , "auth" , "add login" , use_emoji = True , is_breaking = False )
473+
409474 @patch ("tgit.commit.Path.cwd" )
410475 @patch ("tgit.commit.git.Repo" )
411476 @patch ("tgit.commit.get_filtered_diff_files" )
0 commit comments