mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-05-08 18:34:58 +02:00
732 lines
26 KiB
Python
732 lines
26 KiB
Python
"""Tests for security config guardrails in env_check._audit_security_config."""
|
|
|
|
import logging
|
|
import os
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
# Reset pydantic settings cache before importing, so env overrides take effect
|
|
os.environ.pop("MESH_DM_TOKEN_PEPPER", None)
|
|
|
|
from services.config import get_settings, Settings
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _clear_settings_cache():
|
|
"""Bust the lru_cache so each test gets fresh Settings."""
|
|
get_settings.cache_clear()
|
|
yield
|
|
get_settings.cache_clear()
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _clean_pepper_env():
|
|
"""Remove any auto-generated pepper between tests."""
|
|
os.environ.pop("MESH_DM_TOKEN_PEPPER", None)
|
|
yield
|
|
os.environ.pop("MESH_DM_TOKEN_PEPPER", None)
|
|
|
|
|
|
class TestInsecureAdminWarning:
|
|
def test_allow_insecure_admin_without_key_logs_critical(self, caplog):
|
|
with patch.dict(os.environ, {"ALLOW_INSECURE_ADMIN": "true", "ADMIN_KEY": ""}):
|
|
get_settings.cache_clear()
|
|
from services.env_check import _audit_security_config
|
|
|
|
with caplog.at_level(logging.CRITICAL):
|
|
_audit_security_config(get_settings())
|
|
|
|
assert "ALLOW_INSECURE_ADMIN=true with no ADMIN_KEY" in caplog.text
|
|
assert "completely unauthenticated" in caplog.text
|
|
|
|
def test_admin_key_present_no_warning(self, caplog):
|
|
with patch.dict(
|
|
os.environ, {"ALLOW_INSECURE_ADMIN": "true", "ADMIN_KEY": "secret123"}
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import _audit_security_config
|
|
|
|
with caplog.at_level(logging.CRITICAL):
|
|
_audit_security_config(get_settings())
|
|
|
|
assert "ALLOW_INSECURE_ADMIN=true with no ADMIN_KEY" not in caplog.text
|
|
|
|
|
|
class TestSignatureConfigWarnings:
|
|
def test_non_strict_logs_warning(self, caplog):
|
|
with patch.dict(os.environ, {"MESH_STRICT_SIGNATURES": "false"}):
|
|
get_settings.cache_clear()
|
|
from services.env_check import _audit_security_config
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
_audit_security_config(get_settings())
|
|
|
|
assert "MESH_STRICT_SIGNATURES=false" in caplog.text
|
|
|
|
|
|
class TestTokenPepperAutoGeneration:
|
|
def test_empty_pepper_auto_generates(self, caplog, tmp_path, monkeypatch):
|
|
os.environ.pop("MESH_DM_TOKEN_PEPPER", None)
|
|
get_settings.cache_clear()
|
|
from services import env_check
|
|
|
|
monkeypatch.setattr(env_check, "_PEPPER_FILE", tmp_path / "dm_token_pepper.key")
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
env_check._audit_security_config(get_settings())
|
|
|
|
generated = os.environ.get("MESH_DM_TOKEN_PEPPER", "")
|
|
assert len(generated) == 64 # 32 bytes hex
|
|
assert "Auto-generated a random pepper" in caplog.text
|
|
|
|
def test_existing_pepper_preserved(self, caplog):
|
|
os.environ["MESH_DM_TOKEN_PEPPER"] = "my-secret-pepper"
|
|
get_settings.cache_clear()
|
|
from services.env_check import _audit_security_config
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
_audit_security_config(get_settings())
|
|
|
|
assert os.environ["MESH_DM_TOKEN_PEPPER"] == "my-secret-pepper"
|
|
assert "Auto-generated" not in caplog.text
|
|
|
|
|
|
class TestPeerSecretEnforcement:
|
|
"""P1B: MESH_PEER_PUSH_SECRET is mandatory when relay/RNS peers are configured."""
|
|
|
|
def test_empty_secret_with_peers_exits_in_strict_mode(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RELAY_PEERS": "https://peer.example",
|
|
"MESH_PEER_PUSH_SECRET": "",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import validate_env
|
|
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
validate_env(strict=True)
|
|
assert exc_info.value.code == 1
|
|
|
|
def test_placeholder_secret_with_peers_exits_in_strict_mode(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RELAY_PEERS": "https://peer.example",
|
|
"MESH_PEER_PUSH_SECRET": "change-me",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import validate_env
|
|
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
validate_env(strict=True)
|
|
assert exc_info.value.code == 1
|
|
|
|
def test_short_secret_with_peers_exits_in_strict_mode(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RELAY_PEERS": "https://peer.example",
|
|
"MESH_PEER_PUSH_SECRET": "tooshort",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import validate_env
|
|
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
validate_env(strict=True)
|
|
assert exc_info.value.code == 1
|
|
|
|
def test_empty_secret_with_rns_peers_exits_in_strict_mode(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RNS_PEERS": "rns://some-peer-hash",
|
|
"MESH_PEER_PUSH_SECRET": "",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import validate_env
|
|
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
validate_env(strict=True)
|
|
assert exc_info.value.code == 1
|
|
|
|
def test_empty_secret_with_rns_enabled_exits_in_strict_mode(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RNS_ENABLED": "true",
|
|
"MESH_PEER_PUSH_SECRET": "",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import validate_env
|
|
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
validate_env(strict=True)
|
|
assert exc_info.value.code == 1
|
|
|
|
def test_valid_secret_with_peers_passes(self, caplog):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RELAY_PEERS": "https://peer.example",
|
|
"MESH_PEER_PUSH_SECRET": "a-valid-secret-at-least-16-chars-long",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import validate_env
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
result = validate_env(strict=True)
|
|
|
|
assert result is True
|
|
assert "MESH_PEER_PUSH_SECRET is invalid" not in caplog.text
|
|
|
|
def test_no_peers_no_secret_passes(self, caplog):
|
|
"""Default posture: no peers configured, no secret needed."""
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RELAY_PEERS": "",
|
|
"MESH_RNS_PEERS": "",
|
|
"MESH_RNS_ENABLED": "false",
|
|
"MESH_PEER_PUSH_SECRET": "",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import validate_env
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
result = validate_env(strict=True)
|
|
|
|
assert result is True
|
|
assert "MESH_PEER_PUSH_SECRET is invalid" not in caplog.text
|
|
|
|
def test_empty_secret_with_peers_returns_false_in_nonstrict_mode(self, caplog):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RELAY_PEERS": "https://peer.example",
|
|
"MESH_PEER_PUSH_SECRET": "",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import validate_env
|
|
|
|
with caplog.at_level(logging.ERROR):
|
|
result = validate_env(strict=False)
|
|
|
|
assert result is False
|
|
assert "MESH_PEER_PUSH_SECRET is invalid (empty)" in caplog.text
|
|
|
|
def test_security_posture_warnings_include_missing_peer_secret(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RELAY_PEERS": "https://peer.example",
|
|
"MESH_PEER_PUSH_SECRET": "",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import get_security_posture_warnings
|
|
|
|
warnings = get_security_posture_warnings(get_settings())
|
|
|
|
assert any("MESH_PEER_PUSH_SECRET is invalid (empty)" in item for item in warnings)
|
|
|
|
def test_placeholder_peer_secret_is_flagged_in_audit(self, caplog):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RELAY_PEERS": "https://peer.example",
|
|
"MESH_PEER_PUSH_SECRET": "change-me",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import _audit_security_config
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
_audit_security_config(get_settings())
|
|
|
|
assert "MESH_PEER_PUSH_SECRET is invalid (placeholder)" in caplog.text
|
|
|
|
|
|
class TestRawSecureStorageFallbackGuard:
|
|
def test_raw_fallback_without_ack_exits_in_strict_mode(self, monkeypatch):
|
|
from services import env_check
|
|
|
|
monkeypatch.setattr(env_check, "_raw_secure_storage_fallback_requested", lambda _snapshot: True)
|
|
monkeypatch.setattr(env_check, "_raw_secure_storage_fallback_missing_ack", lambda _snapshot: True)
|
|
monkeypatch.setenv("MESH_ALLOW_RAW_SECURE_STORAGE_FALLBACK", "true")
|
|
monkeypatch.delenv("MESH_ACK_RAW_FALLBACK_AT_OWN_RISK", raising=False)
|
|
monkeypatch.delenv("MESH_SECURE_STORAGE_SECRET", raising=False)
|
|
monkeypatch.setenv("MESH_DM_TOKEN_PEPPER", "valid-test-pepper-value")
|
|
get_settings.cache_clear()
|
|
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
env_check.validate_env(strict=True)
|
|
|
|
assert exc_info.value.code == 1
|
|
|
|
def test_raw_fallback_without_ack_returns_false_in_nonstrict_mode(self, monkeypatch, caplog):
|
|
from services import env_check
|
|
|
|
monkeypatch.setattr(env_check, "_raw_secure_storage_fallback_requested", lambda _snapshot: True)
|
|
monkeypatch.setattr(env_check, "_raw_secure_storage_fallback_missing_ack", lambda _snapshot: True)
|
|
monkeypatch.setenv("MESH_ALLOW_RAW_SECURE_STORAGE_FALLBACK", "true")
|
|
monkeypatch.delenv("MESH_ACK_RAW_FALLBACK_AT_OWN_RISK", raising=False)
|
|
monkeypatch.delenv("MESH_SECURE_STORAGE_SECRET", raising=False)
|
|
monkeypatch.setenv("MESH_DM_TOKEN_PEPPER", "valid-test-pepper-value")
|
|
get_settings.cache_clear()
|
|
|
|
with caplog.at_level(logging.ERROR):
|
|
result = env_check.validate_env(strict=False)
|
|
|
|
assert result is False
|
|
assert "MESH_ACK_RAW_FALLBACK_AT_OWN_RISK=true" in caplog.text
|
|
|
|
def test_raw_fallback_with_ack_passes_strict_mode(self, monkeypatch, caplog):
|
|
from services import env_check
|
|
|
|
monkeypatch.setattr(env_check, "_raw_secure_storage_fallback_requested", lambda _snapshot: True)
|
|
monkeypatch.setattr(env_check, "_raw_secure_storage_fallback_missing_ack", lambda _snapshot: False)
|
|
monkeypatch.setenv("MESH_ALLOW_RAW_SECURE_STORAGE_FALLBACK", "true")
|
|
monkeypatch.setenv("MESH_ACK_RAW_FALLBACK_AT_OWN_RISK", "true")
|
|
monkeypatch.delenv("MESH_SECURE_STORAGE_SECRET", raising=False)
|
|
monkeypatch.setenv("MESH_DM_TOKEN_PEPPER", "valid-test-pepper-value")
|
|
get_settings.cache_clear()
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
result = env_check.validate_env(strict=True)
|
|
|
|
assert result is True
|
|
assert "with MESH_ACK_RAW_FALLBACK_AT_OWN_RISK=true leaves Wormhole keys in raw local files" in caplog.text
|
|
|
|
def test_security_posture_reports_missing_raw_fallback_ack(self, monkeypatch):
|
|
from services import env_check
|
|
|
|
monkeypatch.setattr(env_check, "_raw_secure_storage_fallback_requested", lambda _snapshot: True)
|
|
monkeypatch.setattr(env_check, "_raw_secure_storage_fallback_missing_ack", lambda _snapshot: True)
|
|
monkeypatch.setenv("MESH_ALLOW_RAW_SECURE_STORAGE_FALLBACK", "true")
|
|
monkeypatch.delenv("MESH_ACK_RAW_FALLBACK_AT_OWN_RISK", raising=False)
|
|
get_settings.cache_clear()
|
|
|
|
warnings = env_check.get_security_posture_warnings(get_settings())
|
|
|
|
assert any(
|
|
"MESH_ALLOW_RAW_SECURE_STORAGE_FALLBACK=true without MESH_ACK_RAW_FALLBACK_AT_OWN_RISK=true"
|
|
in item
|
|
for item in warnings
|
|
)
|
|
|
|
|
|
class TestCoverTrafficWarnings:
|
|
def test_disabled_cover_traffic_logs_warning_when_rns_enabled(self, caplog):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RNS_ENABLED": "true",
|
|
"MESH_RNS_COVER_INTERVAL_S": "0",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import _audit_security_config
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
_audit_security_config(get_settings())
|
|
|
|
assert "MESH_RNS_COVER_INTERVAL_S<=0 disables background RNS cover traffic" in caplog.text
|
|
|
|
def test_security_posture_warnings_include_disabled_cover_traffic(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RNS_ENABLED": "true",
|
|
"MESH_RNS_COVER_INTERVAL_S": "0",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import get_security_posture_warnings
|
|
|
|
warnings = get_security_posture_warnings(get_settings())
|
|
|
|
assert any("MESH_RNS_COVER_INTERVAL_S<=0" in item for item in warnings)
|
|
|
|
|
|
class TestDmMetadataPersistenceWarnings:
|
|
def test_metadata_persist_without_ack_logs_memory_only_warning(self, caplog):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_DM_METADATA_PERSIST": "true",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import _audit_security_config
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
_audit_security_config(get_settings())
|
|
|
|
assert "MESH_DM_METADATA_PERSIST=true without MESH_DM_METADATA_PERSIST_ACKNOWLEDGE=true" in caplog.text
|
|
|
|
def test_metadata_persist_with_ack_logs_disk_warning(self, caplog):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_DM_METADATA_PERSIST": "true",
|
|
"MESH_DM_METADATA_PERSIST_ACKNOWLEDGE": "true",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import _audit_security_config
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
_audit_security_config(get_settings())
|
|
|
|
assert "MESH_DM_METADATA_PERSIST=true — DM request/self mailbox binding metadata will be written to disk" in caplog.text
|
|
|
|
def test_security_posture_warnings_include_memory_only_warning_without_ack(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_DM_METADATA_PERSIST": "true",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import get_security_posture_warnings
|
|
|
|
warnings = get_security_posture_warnings(get_settings())
|
|
|
|
assert any(
|
|
"MESH_DM_METADATA_PERSIST=true without MESH_DM_METADATA_PERSIST_ACKNOWLEDGE=true" in item
|
|
for item in warnings
|
|
)
|
|
|
|
def test_security_posture_warnings_include_metadata_persist_when_acknowledged(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_DM_METADATA_PERSIST": "true",
|
|
"MESH_DM_METADATA_PERSIST_ACKNOWLEDGE": "true",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import get_security_posture_warnings
|
|
|
|
warnings = get_security_posture_warnings(get_settings())
|
|
|
|
assert any(
|
|
"MESH_DM_METADATA_PERSIST=true — DM request/self mailbox binding metadata will be written to disk"
|
|
in item
|
|
for item in warnings
|
|
)
|
|
|
|
|
|
class TestPrivateClearnetFallbackWarnings:
|
|
def test_clearnet_fallback_without_ack_warns_blocked_until_acknowledged(self, caplog):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_PRIVATE_CLEARNET_FALLBACK": "allow",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import _audit_security_config
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
_audit_security_config(get_settings())
|
|
|
|
assert (
|
|
"MESH_PRIVATE_CLEARNET_FALLBACK=allow without MESH_PRIVATE_CLEARNET_FALLBACK_ACKNOWLEDGE=true"
|
|
in caplog.text
|
|
)
|
|
|
|
def test_clearnet_fallback_with_ack_warns_active_downgrade(self, caplog):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_PRIVATE_CLEARNET_FALLBACK": "allow",
|
|
"MESH_PRIVATE_CLEARNET_FALLBACK_ACKNOWLEDGE": "true",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import _audit_security_config
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
_audit_security_config(get_settings())
|
|
|
|
assert (
|
|
"MESH_PRIVATE_CLEARNET_FALLBACK=allow with MESH_PRIVATE_CLEARNET_FALLBACK_ACKNOWLEDGE=true"
|
|
in caplog.text
|
|
)
|
|
|
|
def test_security_posture_reports_blocked_until_acknowledged(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_PRIVATE_CLEARNET_FALLBACK": "allow",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import get_security_posture_warnings
|
|
|
|
warnings = get_security_posture_warnings(get_settings())
|
|
|
|
assert any(
|
|
"MESH_PRIVATE_CLEARNET_FALLBACK=allow without MESH_PRIVATE_CLEARNET_FALLBACK_ACKNOWLEDGE=true"
|
|
in item
|
|
for item in warnings
|
|
)
|
|
|
|
def test_security_posture_reports_active_clearnet_downgrade_with_ack(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_PRIVATE_CLEARNET_FALLBACK": "allow",
|
|
"MESH_PRIVATE_CLEARNET_FALLBACK_ACKNOWLEDGE": "true",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import get_security_posture_warnings
|
|
|
|
warnings = get_security_posture_warnings(get_settings())
|
|
|
|
assert any(
|
|
"MESH_PRIVATE_CLEARNET_FALLBACK=allow with MESH_PRIVATE_CLEARNET_FALLBACK_ACKNOWLEDGE=true"
|
|
in item
|
|
for item in warnings
|
|
)
|
|
|
|
|
|
class TestLegacyDmGetWarnings:
|
|
def test_compatibility_snapshot_marks_legacy_dm_get_override(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_DEV_ALLOW_LEGACY_COMPAT": "true",
|
|
"MESH_ALLOW_LEGACY_DM_GET_UNTIL": "2099-01-01",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.mesh.mesh_compatibility import compatibility_status_snapshot
|
|
|
|
snapshot = compatibility_status_snapshot()
|
|
|
|
assert snapshot["sunset"]["legacy_dm_get"]["status"] == "dev_migration_override"
|
|
assert snapshot["sunset"]["legacy_dm_get"]["override_until"] == "2099-01-01"
|
|
|
|
def test_compatibility_snapshot_marks_compat_dm_invite_import_override(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_DEV_ALLOW_LEGACY_COMPAT": "true",
|
|
"MESH_ALLOW_COMPAT_DM_INVITE_IMPORT_UNTIL": "2099-01-01",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.mesh.mesh_compatibility import compatibility_status_snapshot
|
|
|
|
snapshot = compatibility_status_snapshot()
|
|
|
|
assert snapshot["sunset"]["compat_dm_invite_import"]["status"] == "dev_migration_override"
|
|
assert snapshot["sunset"]["compat_dm_invite_import"]["override_until"] == "2099-01-01"
|
|
|
|
def test_compatibility_snapshot_marks_legacy_dm1_override(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_DEV_ALLOW_LEGACY_COMPAT": "true",
|
|
"MESH_ALLOW_LEGACY_DM1_UNTIL": "2099-01-01",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.mesh.mesh_compatibility import compatibility_status_snapshot
|
|
|
|
snapshot = compatibility_status_snapshot()
|
|
|
|
assert snapshot["sunset"]["legacy_dm1"]["status"] == "dev_migration_override"
|
|
assert snapshot["sunset"]["legacy_dm1"]["override_until"] == "2099-01-01"
|
|
|
|
|
|
class TestLegacyDmSignatureCompatWarnings:
|
|
def test_security_posture_reports_legacy_dm_signature_compat(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_DEV_ALLOW_LEGACY_COMPAT": "true",
|
|
"MESH_ALLOW_LEGACY_DM_SIGNATURE_COMPAT_UNTIL": "2099-01-01",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import get_security_posture_warnings
|
|
|
|
warnings = get_security_posture_warnings(get_settings())
|
|
|
|
assert any(
|
|
"MESH_ALLOW_LEGACY_DM_SIGNATURE_COMPAT_UNTIL" in item
|
|
for item in warnings
|
|
)
|
|
|
|
def test_audit_logs_legacy_dm_signature_compat_warning(self, caplog):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_DEV_ALLOW_LEGACY_COMPAT": "true",
|
|
"MESH_ALLOW_LEGACY_DM_SIGNATURE_COMPAT_UNTIL": "2099-01-01",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import _audit_security_config
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
_audit_security_config(get_settings())
|
|
|
|
assert "MESH_ALLOW_LEGACY_DM_SIGNATURE_COMPAT_UNTIL" in caplog.text
|
|
|
|
|
|
class TestGatePlaintextPersistWarnings:
|
|
def test_security_posture_reports_active_gate_plaintext_persist(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_GATE_PLAINTEXT_PERSIST": "true",
|
|
"MESH_GATE_PLAINTEXT_PERSIST_ACKNOWLEDGE": "true",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import get_security_posture_warnings
|
|
|
|
warnings = get_security_posture_warnings(get_settings())
|
|
|
|
assert any(
|
|
"MESH_GATE_PLAINTEXT_PERSIST=true with MESH_GATE_PLAINTEXT_PERSIST_ACKNOWLEDGE=true"
|
|
in item
|
|
for item in warnings
|
|
)
|
|
|
|
|
|
class TestGateRecoveryEnvelopeWarnings:
|
|
def test_security_posture_reports_active_gate_recovery_envelope_runtime(self):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_GATE_RECOVERY_ENVELOPE_ENABLE": "true",
|
|
"MESH_GATE_RECOVERY_ENVELOPE_ENABLE_ACKNOWLEDGE": "true",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import get_security_posture_warnings
|
|
|
|
warnings = get_security_posture_warnings(get_settings())
|
|
|
|
assert any(
|
|
"MESH_GATE_RECOVERY_ENVELOPE_ENABLE=true with MESH_GATE_RECOVERY_ENVELOPE_ENABLE_ACKNOWLEDGE=true"
|
|
in item
|
|
for item in warnings
|
|
)
|
|
|
|
|
|
class TestReleaseAttestationWarnings:
|
|
def test_security_posture_reports_missing_explicit_release_attestation(self, tmp_path):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RELEASE_ATTESTATION_PATH": str(tmp_path / "missing_release_attestation.json"),
|
|
"MESH_RELEASE_DM_RELAY_SECURITY_SUITE_GREEN": "false",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services.env_check import get_security_posture_warnings
|
|
|
|
warnings = get_security_posture_warnings(get_settings())
|
|
|
|
assert any(
|
|
"MESH_RELEASE_ATTESTATION_PATH is set but the release attestation file is missing"
|
|
in item
|
|
for item in warnings
|
|
)
|
|
|
|
def test_security_posture_reports_manual_release_attestation_env_without_file(
|
|
self, monkeypatch, tmp_path
|
|
):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RELEASE_ATTESTATION_PATH": "",
|
|
"MESH_RELEASE_DM_RELAY_SECURITY_SUITE_GREEN": "true",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services import env_check
|
|
|
|
monkeypatch.setattr(
|
|
env_check,
|
|
"_DEFAULT_RELEASE_ATTESTATION_PATH",
|
|
tmp_path / "release_attestation.json",
|
|
)
|
|
|
|
warnings = env_check.get_security_posture_warnings(get_settings())
|
|
|
|
assert any(
|
|
"MESH_RELEASE_DM_RELAY_SECURITY_SUITE_GREEN=true without a file-based release attestation"
|
|
in item
|
|
for item in warnings
|
|
)
|
|
|
|
def test_audit_logs_missing_release_attestation_warning(self, monkeypatch, tmp_path, caplog):
|
|
with patch.dict(
|
|
os.environ,
|
|
{
|
|
"MESH_RELEASE_ATTESTATION_PATH": "",
|
|
"MESH_RELEASE_DM_RELAY_SECURITY_SUITE_GREEN": "false",
|
|
},
|
|
clear=False,
|
|
):
|
|
get_settings.cache_clear()
|
|
from services import env_check
|
|
|
|
monkeypatch.setattr(
|
|
env_check,
|
|
"_DEFAULT_RELEASE_ATTESTATION_PATH",
|
|
tmp_path / "release_attestation.json",
|
|
)
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
env_check._audit_security_config(get_settings())
|
|
|
|
assert "No file-based Sprint 8 release attestation is staged" in caplog.text
|