mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-06-03 04:48:03 +02:00
684 lines
24 KiB
Python
684 lines
24 KiB
Python
"""S13D Legacy Gate Envelope Fallback Cleanup.
|
|
|
|
Tests:
|
|
- existing gate without explicit field fails closed even with stored history
|
|
- new gate defaults to legacy fallback disabled
|
|
- setter/getter round-trip works with explicit acknowledgement on enable
|
|
- when flag is false, _gate_envelope_decrypt() does NOT attempt Phase 1 or node-local fallback
|
|
- when flag is true, current fallback chain remains available
|
|
- field is independent of envelope_policy
|
|
- admin setter requires scoped gate/admin auth, not proof-based member auth
|
|
- enabling fallback is explicit and time-bounded
|
|
- do not overclaim that disabling legacy fallback preserves readability for all old messages
|
|
- do not modify decrypt fast-path order or envelope_policy behavior
|
|
"""
|
|
|
|
import base64
|
|
import os
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
|
|
# ── Fixtures ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
def _make_phase1_envelope(gate_id: str) -> str:
|
|
"""Create an envelope encrypted with Phase 1 (gate-name-only) key."""
|
|
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
|
from cryptography.hazmat.primitives import hashes
|
|
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
|
|
gate_key = gate_id.strip().lower()
|
|
ikm = gate_key.encode("utf-8")
|
|
info = b"gate_envelope_aes256gcm"
|
|
key = HKDF(
|
|
algorithm=hashes.SHA256(),
|
|
length=32,
|
|
salt=b"shadowbroker-gate-envelope-v1",
|
|
info=info,
|
|
).derive(ikm)
|
|
nonce = os.urandom(12)
|
|
aad = f"gate_envelope|{gate_key}".encode("utf-8")
|
|
ct = AESGCM(key).encrypt(nonce, b"phase1-secret-message", aad)
|
|
return base64.b64encode(nonce + ct).decode("ascii")
|
|
|
|
|
|
def _make_phase2_envelope(gate_id: str, gate_secret: str) -> str:
|
|
"""Create an envelope encrypted with Phase 2 (per-gate secret) key."""
|
|
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
|
from cryptography.hazmat.primitives import hashes
|
|
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
|
|
gate_key = gate_id.strip().lower()
|
|
ikm = gate_secret.encode("utf-8")
|
|
info = f"gate_envelope_aes256gcm|{gate_key}".encode("utf-8")
|
|
key = HKDF(
|
|
algorithm=hashes.SHA256(),
|
|
length=32,
|
|
salt=b"shadowbroker-gate-envelope-v1",
|
|
info=info,
|
|
).derive(ikm)
|
|
nonce = os.urandom(12)
|
|
aad = f"gate_envelope|{gate_key}".encode("utf-8")
|
|
ct = AESGCM(key).encrypt(nonce, b"phase2-secret-message", aad)
|
|
return base64.b64encode(nonce + ct).decode("ascii")
|
|
|
|
|
|
# ── GateManager field behavior ───────────────────────────────────────────
|
|
|
|
|
|
def test_existing_gate_without_field_and_no_history_fails_closed():
|
|
"""A gate with no history and no explicit legacy_envelope_fallback must fail closed."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
|
|
gate_manager.gates["__test_s13d_legacy"] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Legacy Gate",
|
|
"description": "",
|
|
"rules": {"min_overall_rep": 0, "min_gate_rep": {}},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "test-secret",
|
|
}
|
|
try:
|
|
assert gate_manager.get_legacy_envelope_fallback("__test_s13d_legacy") is False
|
|
finally:
|
|
gate_manager.gates.pop("__test_s13d_legacy", None)
|
|
|
|
|
|
def test_existing_gate_without_field_and_history_still_fails_closed():
|
|
"""A gate with stored history but no explicit flag must still fail closed."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
|
|
gate_manager.gates["__test_s13d_history"] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "History Gate",
|
|
"description": "",
|
|
"rules": {"min_overall_rep": 0, "min_gate_rep": {}},
|
|
"created_at": 0,
|
|
"message_count": 3,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "test-secret",
|
|
}
|
|
try:
|
|
assert gate_manager.get_legacy_envelope_fallback("__test_s13d_history") is False
|
|
finally:
|
|
gate_manager.gates.pop("__test_s13d_history", None)
|
|
|
|
|
|
def test_new_gate_defaults_to_legacy_fallback_disabled():
|
|
"""create_gate must set legacy_envelope_fallback=False on new gates."""
|
|
from services.mesh.mesh_reputation import gate_manager, ALLOW_DYNAMIC_GATES
|
|
import services.mesh.mesh_reputation as rep_mod
|
|
|
|
old = rep_mod.ALLOW_DYNAMIC_GATES
|
|
rep_mod.ALLOW_DYNAMIC_GATES = True
|
|
try:
|
|
ok, _ = gate_manager.create_gate("test-node", "test-s13d-new", "S13D New Gate")
|
|
assert ok
|
|
assert gate_manager.gates["test-s13d-new"].get("legacy_envelope_fallback") is False
|
|
assert gate_manager.get_legacy_envelope_fallback("test-s13d-new") is False
|
|
finally:
|
|
gate_manager.gates.pop("test-s13d-new", None)
|
|
rep_mod.ALLOW_DYNAMIC_GATES = old
|
|
|
|
|
|
def test_getter_setter_round_trip():
|
|
"""Stored true flags do not re-enable the removed legacy fallback path."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
|
|
gate_manager.gates["__test_s13d_rt"] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "RT Gate",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "test-secret",
|
|
"legacy_envelope_fallback": True,
|
|
}
|
|
try:
|
|
assert gate_manager.get_legacy_envelope_fallback("__test_s13d_rt") is False
|
|
ok, _ = gate_manager.set_legacy_envelope_fallback("__test_s13d_rt", False)
|
|
assert ok
|
|
assert gate_manager.get_legacy_envelope_fallback("__test_s13d_rt") is False
|
|
ok, detail = gate_manager.set_legacy_envelope_fallback(
|
|
"__test_s13d_rt",
|
|
True,
|
|
acknowledge_legacy_risk=True,
|
|
)
|
|
assert not ok
|
|
assert "removed" in detail
|
|
assert gate_manager.get_legacy_envelope_fallback("__test_s13d_rt") is False
|
|
finally:
|
|
gate_manager.gates.pop("__test_s13d_rt", None)
|
|
|
|
|
|
def test_setter_rejects_enable():
|
|
"""Re-enabling fallback is no longer allowed."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
|
|
gate_manager.gates["__test_s13d_ack"] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Ack Gate",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "test-secret",
|
|
"legacy_envelope_fallback": False,
|
|
}
|
|
try:
|
|
ok, detail = gate_manager.set_legacy_envelope_fallback("__test_s13d_ack", True)
|
|
assert not ok
|
|
assert "removed" in detail
|
|
assert gate_manager.get_legacy_envelope_fallback("__test_s13d_ack") is False
|
|
finally:
|
|
gate_manager.gates.pop("__test_s13d_ack", None)
|
|
|
|
|
|
def test_enabled_fallback_expires():
|
|
"""Expired fallback state must fail closed even if the stored flag is still true."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
|
|
gate_manager.gates["__test_s13d_expired"] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Expired Gate",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "",
|
|
"legacy_envelope_fallback": True,
|
|
"legacy_envelope_fallback_expires_at": 1,
|
|
}
|
|
try:
|
|
assert gate_manager.get_legacy_envelope_fallback("__test_s13d_expired") is False
|
|
finally:
|
|
gate_manager.gates.pop("__test_s13d_expired", None)
|
|
|
|
|
|
def test_setter_rejects_unknown_gate():
|
|
"""Setting fallback on a nonexistent gate returns failure."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
|
|
ok, detail = gate_manager.set_legacy_envelope_fallback("__nonexistent_s13d", False)
|
|
assert not ok
|
|
assert "not found" in detail.lower()
|
|
|
|
|
|
def test_getter_returns_false_for_unknown_gate():
|
|
"""Unknown gate must fail closed instead of assuming legacy fallback."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
|
|
assert gate_manager.get_legacy_envelope_fallback("__nonexistent_s13d") is False
|
|
|
|
|
|
# ── Decrypt gating ───────────────────────────────────────────────────────
|
|
|
|
|
|
def test_fallback_false_blocks_phase1_decrypt():
|
|
"""When legacy_envelope_fallback is False, Phase 1 envelope must NOT decrypt."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
from services.mesh.mesh_gate_mls import _gate_envelope_decrypt
|
|
|
|
gate_id = "__test_s13d_nofb"
|
|
gate_manager.gates[gate_id] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "No Fallback",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "", # no Phase 2 secret
|
|
"legacy_envelope_fallback": False,
|
|
}
|
|
try:
|
|
token = _make_phase1_envelope(gate_id)
|
|
result = _gate_envelope_decrypt(gate_id, token)
|
|
# Phase 1 must be blocked — result must be None
|
|
assert result is None
|
|
finally:
|
|
gate_manager.gates.pop(gate_id, None)
|
|
|
|
|
|
def test_fallback_true_does_not_allow_phase1_decrypt():
|
|
"""Stored legacy_envelope_fallback=True must not decrypt Phase 1 envelopes."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
from services.mesh.mesh_gate_mls import _gate_envelope_decrypt
|
|
|
|
gate_id = "__test_s13d_yesfb"
|
|
gate_manager.gates[gate_id] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Yes Fallback",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "", # no Phase 2 secret
|
|
"legacy_envelope_fallback": True,
|
|
}
|
|
try:
|
|
token = _make_phase1_envelope(gate_id)
|
|
result = _gate_envelope_decrypt(gate_id, token)
|
|
assert result is None
|
|
finally:
|
|
gate_manager.gates.pop(gate_id, None)
|
|
|
|
|
|
def test_phase2_decrypt_unaffected_by_fallback_flag():
|
|
"""Phase 2 decrypt must work regardless of the fallback flag."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
from services.mesh.mesh_gate_mls import _gate_envelope_decrypt
|
|
|
|
gate_id = "__test_s13d_p2"
|
|
secret = "test-phase2-secret-s13d"
|
|
gate_manager.gates[gate_id] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Phase2 Gate",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": secret,
|
|
"legacy_envelope_fallback": False,
|
|
}
|
|
try:
|
|
token = _make_phase2_envelope(gate_id, secret)
|
|
result = _gate_envelope_decrypt(gate_id, token)
|
|
assert result == "phase2-secret-message"
|
|
finally:
|
|
gate_manager.gates.pop(gate_id, None)
|
|
|
|
|
|
def test_phase2_decrypt_works_with_fallback_enabled():
|
|
"""Phase 2 decrypt still works when legacy fallback is True."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
from services.mesh.mesh_gate_mls import _gate_envelope_decrypt
|
|
|
|
gate_id = "__test_s13d_p2yes"
|
|
secret = "test-phase2-secret-s13d-yes"
|
|
gate_manager.gates[gate_id] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Phase2 Yes",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": secret,
|
|
"legacy_envelope_fallback": True,
|
|
}
|
|
try:
|
|
token = _make_phase2_envelope(gate_id, secret)
|
|
result = _gate_envelope_decrypt(gate_id, token)
|
|
assert result == "phase2-secret-message"
|
|
finally:
|
|
gate_manager.gates.pop(gate_id, None)
|
|
|
|
|
|
# ── Independence from envelope_policy ────────────────────────────────────
|
|
|
|
|
|
def test_field_independent_of_envelope_policy():
|
|
"""legacy_envelope_fallback and envelope_policy are independently settable."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
|
|
gate_id = "__test_s13d_indep"
|
|
gate_manager.gates[gate_id] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Independent",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "secret",
|
|
"envelope_policy": "envelope_always",
|
|
"legacy_envelope_fallback": True,
|
|
}
|
|
try:
|
|
# Change fallback, envelope_policy unaffected
|
|
gate_manager.set_legacy_envelope_fallback(gate_id, False)
|
|
assert gate_manager.get_legacy_envelope_fallback(gate_id) is False
|
|
assert gate_manager.get_envelope_policy(gate_id) == "envelope_always"
|
|
|
|
# Change envelope_policy, fallback unaffected
|
|
gate_manager.set_envelope_policy(gate_id, "envelope_disabled")
|
|
assert gate_manager.get_envelope_policy(gate_id) == "envelope_disabled"
|
|
assert gate_manager.get_legacy_envelope_fallback(gate_id) is False
|
|
finally:
|
|
gate_manager.gates.pop(gate_id, None)
|
|
|
|
|
|
def test_envelope_policy_disabled_does_not_reenable_removed_fallback():
|
|
"""envelope_policy=envelope_disabled does not re-enable removed fallback."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
|
|
gate_id = "__test_s13d_notimplied"
|
|
gate_manager.gates[gate_id] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Not Implied",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "",
|
|
"envelope_policy": "envelope_disabled",
|
|
"legacy_envelope_fallback": True,
|
|
}
|
|
try:
|
|
assert gate_manager.get_legacy_envelope_fallback(gate_id) is False
|
|
assert gate_manager.get_envelope_policy(gate_id) == "envelope_disabled"
|
|
finally:
|
|
gate_manager.gates.pop(gate_id, None)
|
|
|
|
|
|
# ── Admin auth ───────────────────────────────────────────────────────────
|
|
|
|
|
|
def test_admin_endpoint_exists_in_mesh_public():
|
|
"""The legacy_envelope_fallback PUT endpoint must exist in mesh_public router."""
|
|
from routers.mesh_public import router
|
|
|
|
paths = [r.path for r in router.routes if hasattr(r, "path")]
|
|
assert "/api/mesh/gate/{gate_id}/legacy_envelope_fallback" in paths
|
|
|
|
|
|
def test_admin_endpoint_exists_in_main():
|
|
"""The legacy_envelope_fallback PUT endpoint must exist in main app."""
|
|
import main
|
|
|
|
paths = [r.path for r in main.app.routes if hasattr(r, "path")]
|
|
assert "/api/mesh/gate/{gate_id}/legacy_envelope_fallback" in paths
|
|
|
|
|
|
def test_admin_endpoint_rejects_unauthenticated():
|
|
"""The admin endpoint must reject requests without gate admin scope."""
|
|
from fastapi.testclient import TestClient
|
|
import main
|
|
|
|
client = TestClient(main.app, raise_server_exceptions=False)
|
|
resp = client.put(
|
|
"/api/mesh/gate/infonet/legacy_envelope_fallback",
|
|
json={"legacy_envelope_fallback": False},
|
|
)
|
|
assert resp.status_code == 403
|
|
data = resp.json()
|
|
assert data["ok"] is False
|
|
assert "admin" in data["detail"].lower() or "scope" in data["detail"].lower()
|
|
|
|
|
|
def test_admin_endpoint_rejects_non_boolean():
|
|
"""The admin endpoint must reject non-boolean values."""
|
|
from fastapi.testclient import TestClient
|
|
import main
|
|
|
|
client = TestClient(main.app, raise_server_exceptions=False)
|
|
# Simulate scoped auth
|
|
with patch.object(main, "_check_scoped_auth", return_value=(True, "")):
|
|
resp = client.put(
|
|
"/api/mesh/gate/infonet/legacy_envelope_fallback",
|
|
json={"legacy_envelope_fallback": "yes"},
|
|
)
|
|
data = resp.json()
|
|
assert data["ok"] is False
|
|
assert "boolean" in data["detail"].lower()
|
|
|
|
|
|
def test_admin_endpoint_rejects_enable_without_ack():
|
|
"""The admin endpoint rejects enabling the removed fallback path."""
|
|
from fastapi.testclient import TestClient
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
import main
|
|
|
|
gate_id = "__test_s13d_admin_ack"
|
|
gate_manager.gates[gate_id] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Admin Ack Test",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "secret",
|
|
"legacy_envelope_fallback": False,
|
|
}
|
|
try:
|
|
client = TestClient(main.app, raise_server_exceptions=False)
|
|
with patch.object(main, "_check_scoped_auth", return_value=(True, "")):
|
|
resp = client.put(
|
|
f"/api/mesh/gate/{gate_id}/legacy_envelope_fallback",
|
|
json={"legacy_envelope_fallback": True},
|
|
)
|
|
data = resp.json()
|
|
assert data["ok"] is False
|
|
assert "removed" in data["detail"]
|
|
finally:
|
|
gate_manager.gates.pop(gate_id, None)
|
|
|
|
|
|
def test_admin_endpoint_accepts_valid_boolean():
|
|
"""The admin endpoint must accept a valid boolean and update the gate."""
|
|
from fastapi.testclient import TestClient
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
import main
|
|
|
|
gate_id = "__test_s13d_admin"
|
|
gate_manager.gates[gate_id] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Admin Test",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "secret",
|
|
"legacy_envelope_fallback": True,
|
|
}
|
|
try:
|
|
client = TestClient(main.app, raise_server_exceptions=False)
|
|
with patch.object(main, "_check_scoped_auth", return_value=(True, "")):
|
|
resp = client.put(
|
|
f"/api/mesh/gate/{gate_id}/legacy_envelope_fallback",
|
|
json={"legacy_envelope_fallback": False},
|
|
)
|
|
data = resp.json()
|
|
assert data["ok"] is True
|
|
assert gate_manager.get_legacy_envelope_fallback(gate_id) is False
|
|
finally:
|
|
gate_manager.gates.pop(gate_id, None)
|
|
|
|
|
|
def test_admin_endpoint_rejects_enable_with_ack():
|
|
"""The admin endpoint rejects fallback enablement even with legacy-risk ack."""
|
|
from fastapi.testclient import TestClient
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
import main
|
|
|
|
gate_id = "__test_s13d_admin_enable"
|
|
gate_manager.gates[gate_id] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Admin Enable Test",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "secret",
|
|
"legacy_envelope_fallback": False,
|
|
}
|
|
try:
|
|
client = TestClient(main.app, raise_server_exceptions=False)
|
|
with patch.object(main, "_check_scoped_auth", return_value=(True, "")):
|
|
resp = client.put(
|
|
f"/api/mesh/gate/{gate_id}/legacy_envelope_fallback",
|
|
json={"legacy_envelope_fallback": True, "acknowledge_legacy_risk": True},
|
|
)
|
|
data = resp.json()
|
|
assert data["ok"] is False
|
|
assert "removed" in data["detail"]
|
|
assert gate_manager.get_legacy_envelope_fallback(gate_id) is False
|
|
finally:
|
|
gate_manager.gates.pop(gate_id, None)
|
|
|
|
|
|
# ── No overclaim ─────────────────────────────────────────────────────────
|
|
|
|
|
|
def test_removed_fallback_keeps_old_phase1_messages_unreadable():
|
|
"""Removed legacy fallback keeps Phase 1 messages unreadable."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
from services.mesh.mesh_gate_mls import _gate_envelope_decrypt
|
|
|
|
gate_id = "__test_s13d_break"
|
|
gate_manager.gates[gate_id] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Break Test",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "",
|
|
"legacy_envelope_fallback": True,
|
|
}
|
|
try:
|
|
token = _make_phase1_envelope(gate_id)
|
|
# Unreadable even if an old stored flag says fallback is enabled.
|
|
assert _gate_envelope_decrypt(gate_id, token) is None
|
|
# Disable fallback — same message becomes unreadable
|
|
gate_manager.set_legacy_envelope_fallback(gate_id, False)
|
|
assert _gate_envelope_decrypt(gate_id, token) is None
|
|
finally:
|
|
gate_manager.gates.pop(gate_id, None)
|
|
|
|
|
|
# ── Decrypt fast-path order preserved ────────────────────────────────────
|
|
|
|
|
|
def test_decrypt_fast_path_order_unchanged():
|
|
"""gate_envelope fast path in decrypt_gate_message_for_local_identity
|
|
still runs before MLS fallback when the gate explicitly opts into envelope_always."""
|
|
from services.mesh.mesh_gate_mls import (
|
|
_gate_envelope_encrypt,
|
|
_gate_envelope_hash,
|
|
decrypt_gate_message_for_local_identity,
|
|
)
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
|
|
gate_id = "__test_s13d_order"
|
|
secret = "test-order-secret-s13d"
|
|
gate_manager.gates[gate_id] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Order Test",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": secret,
|
|
"envelope_policy": "envelope_always",
|
|
"legacy_envelope_fallback": False,
|
|
}
|
|
try:
|
|
message_nonce = "dummy-nonce"
|
|
token = _gate_envelope_encrypt(gate_id, "phase2-secret-message", message_nonce=message_nonce)
|
|
result = decrypt_gate_message_for_local_identity(
|
|
gate_id=gate_id,
|
|
epoch=1,
|
|
ciphertext="dummy-ct",
|
|
nonce=message_nonce,
|
|
gate_envelope=token,
|
|
envelope_hash=_gate_envelope_hash(token),
|
|
)
|
|
assert result["ok"] is True
|
|
assert result["plaintext"] == "phase2-secret-message"
|
|
assert result["identity_scope"] == "gate_envelope"
|
|
finally:
|
|
gate_manager.gates.pop(gate_id, None)
|
|
|
|
|
|
def test_envelope_policy_behavior_unchanged_by_fallback():
|
|
"""envelope_policy controls member view exposure, not decrypt behavior.
|
|
Changing fallback must not alter envelope_policy semantics."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
|
|
gate_id = "__test_s13d_policy_unchanged"
|
|
gate_manager.gates[gate_id] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Policy Unchanged",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "secret",
|
|
"envelope_policy": "envelope_recovery",
|
|
"legacy_envelope_fallback": False,
|
|
}
|
|
try:
|
|
# envelope_policy getter must still work normally
|
|
assert gate_manager.get_envelope_policy(gate_id) == "envelope_recovery"
|
|
# Changing fallback must not touch envelope_policy
|
|
gate_manager.set_legacy_envelope_fallback(gate_id, True, acknowledge_legacy_risk=True)
|
|
assert gate_manager.get_envelope_policy(gate_id) == "envelope_recovery"
|
|
finally:
|
|
gate_manager.gates.pop(gate_id, None)
|
|
|
|
|
|
# ── Edge cases ───────────────────────────────────────────────────────────
|
|
|
|
|
|
def test_empty_gate_id_getter_returns_true():
|
|
"""Empty gate_id must return True (backward compat default)."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
|
|
assert gate_manager.get_legacy_envelope_fallback("") is False
|
|
|
|
|
|
def test_case_insensitive_gate_lookup():
|
|
"""Gate lookup must be case-insensitive."""
|
|
from services.mesh.mesh_reputation import gate_manager
|
|
|
|
gate_manager.gates["__test_s13d_case"] = {
|
|
"creator_node_id": "test",
|
|
"display_name": "Case Test",
|
|
"description": "",
|
|
"rules": {},
|
|
"created_at": 0,
|
|
"message_count": 0,
|
|
"fixed": False,
|
|
"sort_order": 1000,
|
|
"gate_secret": "secret",
|
|
"legacy_envelope_fallback": False,
|
|
}
|
|
try:
|
|
assert gate_manager.get_legacy_envelope_fallback("__TEST_S13D_CASE") is False
|
|
finally:
|
|
gate_manager.gates.pop("__test_s13d_case", None)
|