-
Notifications
You must be signed in to change notification settings - Fork 1
🛡️ Sentinel: Secure bootstrapping and input validation hardening #249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2e45a13
c761d0f
0e59a33
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| import os | ||
| import sys | ||
| from unittest.mock import MagicMock, patch | ||
|
|
||
| import pytest | ||
|
|
||
| # We need to import main to test it, but we want to test its behavior when run | ||
| import main | ||
|
|
||
|
|
||
| def test_main_reloads_token_from_env(monkeypatch): | ||
| """ | ||
| Verify that main() reloads TOKEN from environment variables after load_dotenv(). | ||
| This ensures that secrets from .env are picked up even if the module was imported earlier. | ||
| """ | ||
| # 1. Setup initial state | ||
| monkeypatch.setenv("TOKEN", "initial_token") | ||
| # Force reload main to pick up initial token | ||
| import importlib | ||
| importlib.reload(main) | ||
| assert main.TOKEN == "initial_token" | ||
Check noticeCode scanning / Bandit Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
Check noticeCode scanning / Bandit Possible hardcoded password: 'initial_token' Note test
Possible hardcoded password: 'initial_token'
|
||
|
|
||
| # 2. Mock dependencies | ||
| # Mock load_dotenv to simulate loading a .env file that changes TOKEN | ||
| def mock_load_dotenv(): | ||
| os.environ["TOKEN"] = "loaded_from_env_file" | ||
Check noticeCode scanning / Bandit Possible hardcoded password: 'loaded_from_env_file' Note test
Possible hardcoded password: 'loaded_from_env_file'
|
||
|
|
||
| # Mock other parts of main to prevent actual execution | ||
| mock_args = MagicMock() | ||
| mock_args.profiles = "p1" | ||
| mock_args.folder_url = None | ||
| mock_args.dry_run = True # Dry run to exit early | ||
| mock_args.no_delete = False | ||
| mock_args.plan_json = None | ||
|
|
||
| # Mock check_env_permissions to avoid filesystem checks | ||
| mock_check_perms = MagicMock() | ||
|
|
||
| # Mock warm_up_cache to avoid network calls | ||
| mock_warm_up = MagicMock() | ||
|
|
||
| # Mock sync_profile to avoid logic | ||
| mock_sync = MagicMock(return_value=True) | ||
|
|
||
| # Apply mocks | ||
| # Patch main.load_dotenv because main.py imports it as 'from dotenv import load_dotenv' | ||
| with patch("main.load_dotenv", side_effect=mock_load_dotenv) as mock_load_dotenv_call, \ | ||
| patch("main.parse_args", return_value=mock_args), \ | ||
| patch("main.check_env_permissions", mock_check_perms), \ | ||
| patch("main.warm_up_cache", mock_warm_up), \ | ||
| patch("main.sync_profile", mock_sync), \ | ||
| patch("sys.stdin.isatty", return_value=False): # Non-interactive | ||
|
|
||
| # 3. Run main() | ||
| # This should call load_dotenv (our mock), which updates env var, | ||
| # then main should update global TOKEN from env var. | ||
| with pytest.raises(SystemExit): | ||
| main.main() | ||
|
|
||
| # 4. Verify | ||
| # load_dotenv must have been called | ||
| assert mock_load_dotenv_call.called | ||
Check noticeCode scanning / Bandit Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
|
||
|
|
||
| # check_env_permissions must have been called BEFORE load_dotenv | ||
| # We can check order by checking if check_perms was called | ||
| # But verifying exact order is hard with separate mocks unless we use a manager | ||
| # However, if main.TOKEN is updated, we know the logic ran. | ||
|
Comment on lines
+64
to
+67
|
||
|
|
||
| assert main.TOKEN == "loaded_from_env_file" | ||
Check noticeCode scanning / Bandit Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
Check noticeCode scanning / Bandit Possible hardcoded password: 'loaded_from_env_file' Note test
Possible hardcoded password: 'loaded_from_env_file'
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -72,5 +72,23 @@ | |
| is False | ||
| ), f"Bidi character {description} (U+{ord(char):04X}) should be blocked in '{test_name}'" | ||
|
|
||
| # Case 8: Path Traversal (Security Hardening) | ||
| # Block '.' and '..' which could be used for path traversal | ||
| path_traversal_cases = [".", ".."] | ||
| for pt_name in path_traversal_cases: | ||
| pt_data = {"group": {"group": pt_name}} | ||
| assert ( | ||
| main.validate_folder_data(pt_data, f"http://pt-{pt_name}.com") is False | ||
|
Comment on lines
+80
to
+81
Check noticeCode scanning / Bandit Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
|
||
| ), f"Path traversal name '{pt_name}' should be blocked" | ||
|
|
||
| # Case 9: Command Option Injection (Security Hardening) | ||
| # Block names starting with '-' which could be interpreted as flags | ||
| option_injection_cases = ["-flag", "--flag", "-v", "--verbose"] | ||
| for opt_name in option_injection_cases: | ||
| opt_data = {"group": {"group": opt_name}} | ||
| assert ( | ||
| main.validate_folder_data(opt_data, f"http://opt-{opt_name}.com") is False | ||
|
Comment on lines
+89
to
+90
Check noticeCode scanning / Bandit Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
|
||
| ), f"Option injection name '{opt_name}' should be blocked" | ||
|
|
||
|
Comment on lines
+75
to
+92
|
||
| finally: | ||
| main.log = original_log | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider updating the function's docstring (lines 702-711) to document the newly added security protections. The docstring mentions "path traversal" but doesn't specify that it blocks "." and ".." patterns. It also doesn't mention the new command option injection protection (names starting with "-"). Adding these details would improve code maintainability and help future developers understand the complete security model.