mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-05-08 02:16:41 +02:00
128 lines
4.8 KiB
Python
128 lines
4.8 KiB
Python
"""Phase 5C — auth.py log redaction tests.
|
|
|
|
Validates that:
|
|
1. Malformed MESH_SCOPED_TOKENS returns {}
|
|
2. Malformed MESH_SCOPED_TOKENS logging does not include token fragments
|
|
3. Malformed MESH_SCOPED_TOKENS logging still includes a safe signal (e.g. JSONDecodeError)
|
|
4. Valid MESH_SCOPED_TOKENS mapping still parses correctly
|
|
"""
|
|
import json
|
|
import logging
|
|
|
|
import pytest
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def _patch_settings(monkeypatch, raw_value: str):
|
|
"""Patch get_settings().MESH_SCOPED_TOKENS to return *raw_value*."""
|
|
import auth
|
|
|
|
class _FakeSettings:
|
|
MESH_SCOPED_TOKENS = raw_value
|
|
|
|
monkeypatch.setattr(auth, "get_settings", lambda: _FakeSettings())
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 1. Malformed input returns empty dict
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestMalformedReturnsEmpty:
|
|
def test_truncated_json_returns_empty(self, monkeypatch):
|
|
import auth
|
|
_patch_settings(monkeypatch, '{"tok_secret_abc": ["gate"')
|
|
assert auth._scoped_admin_tokens() == {}
|
|
|
|
def test_plain_string_returns_empty(self, monkeypatch):
|
|
import auth
|
|
_patch_settings(monkeypatch, "not-json-at-all")
|
|
assert auth._scoped_admin_tokens() == {}
|
|
|
|
def test_array_returns_empty(self, monkeypatch):
|
|
"""JSON array is valid JSON but not an object mapping."""
|
|
import auth
|
|
_patch_settings(monkeypatch, '["tok_secret_abc"]')
|
|
assert auth._scoped_admin_tokens() == {}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 2. Log output does NOT include token fragments
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestLogDoesNotLeakTokens:
|
|
def test_truncated_json_log_omits_token_value(self, monkeypatch, caplog):
|
|
import auth
|
|
secret_fragment = "tok_secret_abc"
|
|
_patch_settings(monkeypatch, f'{{"{secret_fragment}": ["gate"')
|
|
with caplog.at_level(logging.WARNING, logger="auth"):
|
|
auth._scoped_admin_tokens()
|
|
log_text = caplog.text
|
|
assert secret_fragment not in log_text
|
|
|
|
def test_garbled_json_log_omits_embedded_token(self, monkeypatch, caplog):
|
|
import auth
|
|
secret_fragment = "Bearer_xyzzy_9999"
|
|
_patch_settings(monkeypatch, f'{{"key": {secret_fragment}}}')
|
|
with caplog.at_level(logging.WARNING, logger="auth"):
|
|
auth._scoped_admin_tokens()
|
|
log_text = caplog.text
|
|
assert secret_fragment not in log_text
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 3. Log output still includes a safe observable signal
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestLogIncludesSafeSignal:
|
|
def test_json_parse_failure_logs_exception_type(self, monkeypatch, caplog):
|
|
import auth
|
|
_patch_settings(monkeypatch, "{bad json")
|
|
with caplog.at_level(logging.WARNING, logger="auth"):
|
|
auth._scoped_admin_tokens()
|
|
assert "JSONDecodeError" in caplog.text
|
|
|
|
def test_warning_level_emitted(self, monkeypatch, caplog):
|
|
import auth
|
|
_patch_settings(monkeypatch, "{bad json")
|
|
with caplog.at_level(logging.WARNING, logger="auth"):
|
|
auth._scoped_admin_tokens()
|
|
assert any(r.levelno == logging.WARNING for r in caplog.records)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 4. Valid input still parses correctly
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestValidInputParses:
|
|
def test_single_token_single_scope(self, monkeypatch):
|
|
import auth
|
|
_patch_settings(monkeypatch, json.dumps({"my-token": ["gate"]}))
|
|
result = auth._scoped_admin_tokens()
|
|
assert result == {"my-token": ["gate"]}
|
|
|
|
def test_multiple_tokens_multiple_scopes(self, monkeypatch):
|
|
import auth
|
|
payload = {"tok-a": ["gate", "dm"], "tok-b": ["wormhole"]}
|
|
_patch_settings(monkeypatch, json.dumps(payload))
|
|
result = auth._scoped_admin_tokens()
|
|
assert result == payload
|
|
|
|
def test_empty_string_returns_empty(self, monkeypatch):
|
|
import auth
|
|
_patch_settings(monkeypatch, "")
|
|
assert auth._scoped_admin_tokens() == {}
|
|
|
|
def test_whitespace_only_returns_empty(self, monkeypatch):
|
|
import auth
|
|
_patch_settings(monkeypatch, " ")
|
|
assert auth._scoped_admin_tokens() == {}
|
|
|
|
def test_scalar_scope_normalized_to_list(self, monkeypatch):
|
|
import auth
|
|
_patch_settings(monkeypatch, json.dumps({"tok": "gate"}))
|
|
result = auth._scoped_admin_tokens()
|
|
assert result == {"tok": ["gate"]}
|