Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .config/simple-scan/state
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[window]
width=600
height=480
is-maximized=false
is-fullscreen=false

[scanner]
scan-type=batch
128 changes: 128 additions & 0 deletions tests/test_check_secrets.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,134 @@ def test_main_cli_invalid_target(self):
main()
self.assertEqual(cm.exception.code, 1)

def test_main_cli_clean_without_quiet(self):
with tempfile.TemporaryDirectory() as tmp_dir:
tmp_path = Path(tmp_dir)
(tmp_path / "clean.txt").write_text("Hello world\n")

test_args = ["check_secrets.py", "-t", str(tmp_path)]
with patch("sys.argv", test_args):
captured = io.StringIO()
with patch("sys.stdout", captured):
main()
self.assertIn("[OK] Secret Scanner: No SSH private keys or secrets found", captured.getvalue())

def test_main_cli_clean_with_quiet(self):
with tempfile.TemporaryDirectory() as tmp_dir:
tmp_path = Path(tmp_dir)
(tmp_path / "clean.txt").write_text("Hello world\n")

test_args = ["check_secrets.py", "-t", str(tmp_path), "-q"]
with patch("sys.argv", test_args):
captured = io.StringIO()
with patch("sys.stdout", captured):
main()
self.assertEqual(captured.getvalue(), "")

def test_main_cli_with_secrets_and_json(self):
with tempfile.TemporaryDirectory() as tmp_dir:
tmp_path = Path(tmp_dir)
(tmp_path / "secret.env").write_text("OPENAI_API_KEY=sk-proj-1234567890abcdefghijklmnopqrstuvwxyz123456\n")

test_args = ["check_secrets.py", "-t", str(tmp_path), "--json"]
with patch("sys.argv", test_args):
captured = io.StringIO()
with patch("sys.stdout", captured):
main()
data = json.loads(captured.getvalue())
self.assertFalse(data["clean"])
self.assertEqual(data["total_secrets_found"], 1)
self.assertIn("secret.env", data["results"])

def test_main_cli_with_secrets_plain_output(self):
with tempfile.TemporaryDirectory() as tmp_dir:
tmp_path = Path(tmp_dir)
(tmp_path / "secret.env").write_text("OPENAI_API_KEY=sk-proj-1234567890abcdefghijklmnopqrstuvwxyz123456\n")

test_args = ["check_secrets.py", "-t", str(tmp_path)]
with patch("sys.argv", test_args):
captured = io.StringIO()
with patch("sys.stdout", captured):
main()
output = captured.getvalue()
self.assertIn("[WARNING] Secret Scanner detected 1 potential secret(s)", output)
self.assertIn("File: secret.env", output)
self.assertIn("OpenAI / Anthropic API Key", output)

def test_ssh_key_file_read_error(self):
with tempfile.TemporaryDirectory() as tmp_dir:
key_file = Path(tmp_dir) / "id_rsa"
key_file.write_text("dummy")

# Mock read_text to raise an exception
with patch.object(Path, "read_text", side_effect=PermissionError("Permission denied")):
findings = scan_file_for_secrets(key_file)
self.assertEqual(len(findings), 1)
self.assertEqual(findings[0]["type"], "SSH Private Key File")
self.assertIn("unread: Permission denied", findings[0]["detail"])

def test_ssh_key_empty_file(self):
with tempfile.TemporaryDirectory() as tmp_dir:
key_file = Path(tmp_dir) / "id_ecdsa"
key_file.write_text("")
findings = scan_file_for_secrets(key_file)
self.assertEqual(len(findings), 1)
self.assertEqual(findings[0]["snippet"], "")

def test_file_read_errors_handled_gracefully(self):
with tempfile.TemporaryDirectory() as tmp_dir:
sample_file = Path(tmp_dir) / "test.txt"
sample_file.write_text("some content")

# Mock open to fail
with patch("builtins.open", side_effect=PermissionError("Access denied")):
findings = scan_file_for_secrets(sample_file)
self.assertEqual(findings, [])

def test_scan_path_with_ignored_subdirectories(self):
with tempfile.TemporaryDirectory() as tmp_dir:
root = Path(tmp_dir)
git_dir = root / ".git"
git_dir.mkdir()
(git_dir / "secret_in_git.txt").write_text("OPENAI_API_KEY=sk-proj-1234567890abcdefghijklmnopqrstuvwxyz123456\n")

cache_dir = root / "Cache"
cache_dir.mkdir()
(cache_dir / "secret_in_cache.txt").write_text("OPENAI_API_KEY=sk-proj-1234567890abcdefghijklmnopqrstuvwxyz123456\n")

normal_file = root / "script.sh"
normal_file.write_text("echo 'hello'\n")

results = scan_path(root)
self.assertEqual(len(results), 0)

def test_scan_path_single_file_in_ignores(self):
with tempfile.TemporaryDirectory() as tmp_dir:
readme = Path(tmp_dir) / "README.md"
readme.write_text("OPENAI_API_KEY=sk-proj-1234567890abcdefghijklmnopqrstuvwxyz123456\n")

results = scan_path(readme)
self.assertEqual(len(results), 0)

def test_additional_placeholder_cases(self):
self.assertTrue(is_placeholder("your_password_here"))
self.assertTrue(is_placeholder("YOUR_AWS_KEY"))
self.assertTrue(is_placeholder("changeme"))
self.assertTrue(is_placeholder("undefined"))
self.assertTrue(is_placeholder("null"))
self.assertTrue(is_placeholder("none"))
self.assertTrue(is_placeholder("foo"))
self.assertTrue(is_placeholder("bar"))
self.assertTrue(is_placeholder("123456"))
self.assertTrue(is_placeholder("000000000"))

def test_line_comment_and_blank_lines_skipped(self):
with tempfile.TemporaryDirectory() as tmp_dir:
f = Path(tmp_dir) / "test.conf"
f.write_text("\n\n# AKIAIOSFODNN7EXAMPLE this is a comment\n \n")
findings = scan_file_for_secrets(f)
self.assertEqual(len(findings), 0)


if __name__ == "__main__":
unittest.main()
143 changes: 143 additions & 0 deletions tests/test_jf_file_compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,149 @@ def test_sync_directories_invalid_compare_mode(self):
compare_mode="unsupported_mode",
)

def test_normalize_extensions_and_patterns(self):
from jfFileCompare import _normalize_extensions, _normalize_patterns
self.assertEqual(_normalize_extensions(None), ())
self.assertEqual(_normalize_extensions([]), ())
self.assertEqual(_normalize_extensions(["mp4", ".MKV", "JPG"]), (".jpg", ".mkv", ".mp4"))

self.assertEqual(_normalize_patterns(None), ())
self.assertEqual(_normalize_patterns([]), ())
self.assertEqual(_normalize_patterns([" antigravity ", "TEST", ""]), ("antigravity", "test"))

def test_hash_candidates_parallel_empty_and_large_file(self):
from jfFileCompare import hash_candidates_parallel
with tempfile.TemporaryDirectory() as tmp_dir:
root = Path(tmp_dir)
self.assertEqual(hash_candidates_parallel(root, []), {})

# Create large file > 3MB to exercise head/middle/tail sample hashing
large_file = root / "large.bin"
large_file.write_bytes(b"A" * (4 * 1024 * 1024))

hashes_sample = hash_candidates_parallel(root, ["large.bin"], mode="sample_hash")
self.assertIn("large.bin", hashes_sample)
self.assertEqual(len(hashes_sample["large.bin"]), 64)

hashes_full = hash_candidates_parallel(root, ["large.bin"], mode="full_hash")
self.assertIn("large.bin", hashes_full)
self.assertEqual(len(hashes_full["large.bin"]), 64)

def test_probe_metadata_empty_and_nonexistent_parent(self):
with tempfile.TemporaryDirectory() as tmp_dir:
root = Path(tmp_dir)
self.assertEqual(probe_metadata(root, []), {})

# Parent exists but is not a directory (it's a file)
fake_parent = root / "fake_file"
fake_parent.write_text("not a dir")
meta = probe_metadata(root, ["fake_file/child.txt"])
self.assertEqual(meta, {})

def test_print_cli_command_mirror_and_size_only(self):
captured_output = io.StringIO()
sys.stdout = captured_output
try:
print_cli_command(
Path("/tmp/src"),
Path("/tmp/dst"),
mirror=True,
compare_mode="size_only",
exclude_extensions=[".tmp", ".bak"],
exclude_patterns=["temp"],
)
finally:
sys.stdout = sys.__stdout__

output = captured_output.getvalue()
self.assertIn("--delete", output)
self.assertIn(" --size-only", output)
self.assertIn("/PURGE", output)
self.assertIn('--exclude="*temp*"', output)

def test_sync_directories_nested_directory_creation(self):
with tempfile.TemporaryDirectory() as src_dir, tempfile.TemporaryDirectory() as dst_dir:
src = Path(src_dir)
dst = Path(dst_dir)

nested_file = src / "deep" / "nested" / "folder" / "video.mp4"
nested_file.parent.mkdir(parents=True)
nested_file.write_text("deep video")

captured_output = io.StringIO()
sys.stdout = captured_output
try:
sync_directories(
src_dir=str(src),
dst_dir=str(dst),
direction="push",
compare_mode="mtime_size",
include_extensions=[".mp4"],
sync=True,
dry_run=False,
)
finally:
sys.stdout = sys.__stdout__

output = captured_output.getvalue()
self.assertIn("[EXECUTING] CREATE: deep/nested/folder/video.mp4", output)
self.assertTrue((dst / "deep" / "nested" / "folder" / "video.mp4").exists())

def test_workers_directly_in_process(self):
from jfFileCompare import _sample_hash_worker, _full_hash_worker
with tempfile.TemporaryDirectory() as tmp_dir:
root = Path(tmp_dir)
small_file = root / "small.txt"
small_file.write_bytes(b"hello world")

rel, h_small = _sample_hash_worker(str(small_file), str(root))
self.assertEqual(rel, "small.txt")
self.assertEqual(len(h_small), 64)

rel_full, h_full = _full_hash_worker(str(small_file), str(root))
self.assertEqual(rel_full, "small.txt")
self.assertEqual(len(h_full), 64)

# Test large file with > 3MB to exercise head, middle, tail branches
large_file = root / "large.bin"
large_file.write_bytes(b"X" * (4 * 1024 * 1024))
rel_large, h_large = _sample_hash_worker(str(large_file), str(root))
self.assertEqual(rel_large, "large.bin")
self.assertEqual(len(h_large), 64)

def test_sync_directories_size_mismatch_and_orphan_deletion(self):
with tempfile.TemporaryDirectory() as src_dir, tempfile.TemporaryDirectory() as dst_dir:
src = Path(src_dir)
dst = Path(dst_dir)

# Size mismatch
(src / "diff_size.txt").write_text("1234567890")
(dst / "diff_size.txt").write_text("123")

# Orphan file
(dst / "orphan.txt").write_text("orphan")

captured_output = io.StringIO()
sys.stdout = captured_output
try:
sync_directories(
src_dir=str(src),
dst_dir=str(dst),
direction="push",
compare_mode="mtime_size",
sync=True,
dry_run=False,
delete_orphan_dst=True,
)
finally:
sys.stdout = sys.__stdout__

output = captured_output.getvalue()
self.assertIn("[EXECUTING] UPDATE: diff_size.txt", output)
self.assertIn("[EXECUTING] DELETE: orphan.txt", output)
self.assertFalse((dst / "orphan.txt").exists())
self.assertEqual((dst / "diff_size.txt").read_text(), "1234567890")


if __name__ == "__main__":
unittest.main()
Loading