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
7 changes: 7 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,10 @@
**Prevention:**
1. Implement strict validation on all data items from external lists (`is_valid_rule`).
2. Filter out items containing dangerous characters (`<`, `>`, `"` etc.) or control codes.

## 2026-05-15 - [Inconsistent Redaction in Debug Logs]

Check notice

Code scanning / Remark-lint (reported by Codacy)

Warn when references to undefined definitions are found. Note

[no-undefined-references] Found reference to undefined definition

Check notice

Code scanning / Remark-lint (reported by Codacy)

Warn when shortcut reference links are used. Note

[no-shortcut-reference-link] Use the trailing [] on reference links
**Vulnerability:** While `sanitize_for_log` existed, it was not applied to `log.debug(e.response.text)` calls in exception handlers. This meant enabling debug logs could expose raw secrets returned by the API in error messages, bypassing the redaction mechanism.
**Learning:** Security controls (like redaction helpers) must be applied consistently at all exit points, especially in verbose/debug paths which are often overlooked during security reviews.
**Prevention:**
1. Audit all logging calls, especially `DEBUG` level ones, for potential secret exposure.
2. Wrapper functions or custom loggers can help enforce sanitization automatically, reducing reliance on manual application of helper functions.
13 changes: 10 additions & 3 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
# 1. Constants – tweak only here
# --------------------------------------------------------------------------- #
API_BASE = "https://api.controld.com/profiles"
USER_AGENT = "Control-D-Sync/0.1.0"


def sanitize_for_log(text: Any) -> str:
Expand Down Expand Up @@ -184,11 +185,17 @@
headers={
"Accept": "application/json",
"Authorization": f"Bearer {TOKEN}",
"User-Agent": USER_AGENT,
},
timeout=30,
follow_redirects=False,
)

_gh = httpx.Client(timeout=30)
_gh = httpx.Client(

Check warning

Code scanning / Prospector (reported by Codacy)

expected 2 blank lines after class or function definition, found 1 (E305) Warning

expected 2 blank lines after class or function definition, found 1 (E305)

Check warning

Code scanning / Pylint (reported by Codacy)

Constant name "_gh" doesn't conform to UPPER_CASE naming style Warning

Constant name "_gh" doesn't conform to UPPER_CASE naming style
headers={"User-Agent": USER_AGENT},
timeout=30,
follow_redirects=False,
)
MAX_RESPONSE_SIZE = 10 * 1024 * 1024 # 10 MB limit for external resources

# --------------------------------------------------------------------------- #
Expand Down Expand Up @@ -309,7 +316,7 @@
except (httpx.HTTPError, httpx.TimeoutException) as e:
if attempt == max_retries - 1:
if hasattr(e, 'response') and e.response is not None:
log.debug(f"Response content: {e.response.text}")
log.debug(f"Response content: {sanitize_for_log(e.response.text)}")

Check warning

Code scanning / Prospector (reported by Codacy)

Use lazy % formatting in logging functions (logging-fstring-interpolation) Warning

Use lazy % formatting in logging functions (logging-fstring-interpolation)

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Use lazy % formatting in logging functions Note

Use lazy % formatting in logging functions
raise
wait_time = delay * (2 ** attempt)
log.warning(f"Request failed (attempt {attempt + 1}/{max_retries}): {e}. Retrying in {wait_time}s...")
Expand Down Expand Up @@ -653,7 +660,7 @@
sys.stderr.write("\n")
log.error(f"Failed to push batch {batch_idx} for folder {sanitize_for_log(folder_name)}: {sanitize_for_log(e)}")
if hasattr(e, 'response') and e.response is not None:
log.debug(f"Response content: {e.response.text}")
log.debug(f"Response content: {sanitize_for_log(e.response.text)}")

Check warning

Code scanning / Prospector (reported by Codacy)

Use lazy % formatting in logging functions (logging-fstring-interpolation) Warning

Use lazy % formatting in logging functions (logging-fstring-interpolation)

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Use lazy % formatting in logging functions Note

Use lazy % formatting in logging functions
return None

# Optimization 3: Parallelize batch processing
Expand Down
95 changes: 95 additions & 0 deletions tests/test_security_hardening.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import logging

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing module docstring Warning test

Missing module docstring

Check warning

Code scanning / Pylint (reported by Codacy)

Missing module docstring Warning test

Missing module docstring
import pytest

Check warning

Code scanning / Prospector (reported by Codacy)

Unable to import 'pytest' (import-error) Warning test

Unable to import 'pytest' (import-error)
from unittest.mock import MagicMock, patch

Check warning

Code scanning / Pylint (reported by Codacy)

standard import "from unittest.mock import MagicMock, patch" should be placed before "import pytest" Warning test

standard import "from unittest.mock import MagicMock, patch" should be placed before "import pytest"

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

standard import "from unittest.mock import MagicMock, patch" should be placed before "import pytest" Warning test

standard import "from unittest.mock import MagicMock, patch" should be placed before "import pytest"
import httpx

Check warning

Code scanning / Prospector (reported by Codacy)

Unable to import 'httpx' (import-error) Warning test

Unable to import 'httpx' (import-error)
import main

# Mock httpx.HTTPError to include a response with sensitive data
def create_mock_error(status_code, text, request_url="https://example.com"):

Check warning

Code scanning / Pylint (reported by Codacy)

Missing function docstring Warning test

Missing function docstring

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing function or method docstring Warning test

Missing function or method docstring
response = MagicMock(spec=httpx.Response)
response.status_code = status_code
response.text = text
response.request = MagicMock(spec=httpx.Request)
response.request.url = request_url

# Use HTTPStatusError which accepts request and response
error = httpx.HTTPStatusError(f"HTTP Error {status_code}", request=response.request, response=response)

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (107/100) Warning test

Line too long (107/100)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (107/100) Warning test

Line too long (107/100)
return error

def test_retry_request_sanitizes_token_in_debug_logs(caplog):

Check warning

Code scanning / Pylint (reported by Codacy)

Missing function docstring Warning test

Missing function docstring

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing function or method docstring Warning test

Missing function or method docstring
# Setup sensitive data
sensitive_token = "SECRET_TOKEN_123"

Check notice

Code scanning / Bandit

Possible hardcoded password: 'SECRET_TOKEN_123' Note test

Possible hardcoded password: 'SECRET_TOKEN_123'
main.TOKEN = sensitive_token

# Configure logging to capture DEBUG
caplog.set_level(logging.DEBUG)

# Mock a request function that always raises an error with the token in response
mock_func = MagicMock()
error_text = f"Invalid token: {sensitive_token}"
mock_func.side_effect = create_mock_error(401, error_text)

# Call _retry_request (it re-raises the exception)
with pytest.raises(httpx.HTTPError):
# Set retries to 1 to fail fast
main._retry_request(mock_func, max_retries=1, delay=0)

Check warning

Code scanning / Prospector (reported by Codacy)

Access to a protected member _retry_request of a client class (protected-access) Warning test

Access to a protected member _retry_request of a client class (protected-access)

Check notice

Code scanning / Pylint (reported by Codacy)

Access to a protected member _retry_request of a client class Note test

Access to a protected member _retry_request of a client class

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Access to a protected member _retry_request of a client class Note test

Access to a protected member _retry_request of a client class

# Check logs
assert "Response content:" in caplog.text

Check notice

Code 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 notice

Code scanning / Bandit (reported by Codacy)

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.
assert sensitive_token not in caplog.text

Check notice

Code 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 notice

Code scanning / Bandit (reported by Codacy)

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.
assert "[REDACTED]" in caplog.text

Check notice

Code 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 notice

Code scanning / Bandit (reported by Codacy)

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.

def test_push_rules_sanitizes_token_in_debug_logs(caplog):

Check warning

Code scanning / Pylint (reported by Codacy)

Missing function docstring Warning test

Missing function docstring

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing function or method docstring Warning test

Missing function or method docstring
# Setup sensitive data
sensitive_token = "SECRET_TOKEN_456"

Check notice

Code scanning / Bandit

Possible hardcoded password: 'SECRET_TOKEN_456' Note test

Possible hardcoded password: 'SECRET_TOKEN_456'
main.TOKEN = sensitive_token

# Configure logging to capture DEBUG
caplog.set_level(logging.DEBUG)

# Mock dependencies
mock_client = MagicMock(spec=httpx.Client)

# Let's mock client.post to raise error
error_text = f"Bad Rule with token {sensitive_token}"
mock_client.post.side_effect = create_mock_error(400, error_text)

# Patch time.sleep to avoid waiting
with patch("time.sleep"):
res = main.push_rules(
profile_id="p1",
folder_name="f1",
folder_id="fid1",
do=0,
status=1,
hostnames=["rule1"],
existing_rules=set(),
client=mock_client
)

# push_rules catches the error and returns False (or continues if batch failed)
assert res is False

Check notice

Code 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 notice

Code scanning / Bandit (reported by Codacy)

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 logs
assert "Response content:" in caplog.text

Check notice

Code 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 notice

Code scanning / Bandit (reported by Codacy)

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.
assert sensitive_token not in caplog.text

Check notice

Code 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 notice

Code scanning / Bandit (reported by Codacy)

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.
assert "[REDACTED]" in caplog.text

Check notice

Code 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 notice

Code scanning / Bandit (reported by Codacy)

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.

def test_api_client_configuration():

Check warning

Code scanning / Pylint (reported by Codacy)

Missing function docstring Warning test

Missing function docstring

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing function or method docstring Warning test

Missing function or method docstring
# Setup token
main.TOKEN = "test_token"

Check notice

Code scanning / Bandit

Possible hardcoded password: 'test_token' Note test

Possible hardcoded password: 'test_token'

with main._api_client() as client:

Check warning

Code scanning / Prospector (reported by Codacy)

Access to a protected member _api_client of a client class (protected-access) Warning test

Access to a protected member _api_client of a client class (protected-access)

Check notice

Code scanning / Pylint (reported by Codacy)

Access to a protected member _api_client of a client class Note test

Access to a protected member _api_client of a client class

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Access to a protected member _api_client of a client class Note test

Access to a protected member _api_client of a client class
# Check User-Agent
assert client.headers["User-Agent"] == "Control-D-Sync/0.1.0"

Check notice

Code 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 notice

Code scanning / Bandit (reported by Codacy)

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 Authorization
assert client.headers["Authorization"] == "Bearer test_token"

Check notice

Code 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 notice

Code scanning / Bandit (reported by Codacy)

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 follow_redirects (in httpx < 0.20 it was allow_redirects, now follow_redirects)
assert client.follow_redirects is False

Check notice

Code 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 notice

Code scanning / Bandit (reported by Codacy)

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.

def test_gh_client_configuration():

Check warning

Code scanning / Pylint (reported by Codacy)

Missing function docstring Warning test

Missing function docstring

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing function or method docstring Warning test

Missing function or method docstring
client = main._gh

Check warning

Code scanning / Prospector (reported by Codacy)

Access to a protected member _gh of a client class (protected-access) Warning test

Access to a protected member _gh of a client class (protected-access)

Check notice

Code scanning / Pylint (reported by Codacy)

Access to a protected member _gh of a client class Note test

Access to a protected member _gh of a client class

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Access to a protected member _gh of a client class Note test

Access to a protected member _gh of a client class
# Check User-Agent
assert client.headers["User-Agent"] == "Control-D-Sync/0.1.0"

Check notice

Code 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 notice

Code scanning / Bandit (reported by Codacy)

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 follow_redirects
assert client.follow_redirects is False

Check notice

Code 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 notice

Code scanning / Bandit (reported by Codacy)

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.
Loading