summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/tests/test_musicbrainz_config_policy.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node/tests/test_musicbrainz_config_policy.py')
-rw-r--r--packages/meshbay-node/tests/test_musicbrainz_config_policy.py179
1 files changed, 0 insertions, 179 deletions
diff --git a/packages/meshbay-node/tests/test_musicbrainz_config_policy.py b/packages/meshbay-node/tests/test_musicbrainz_config_policy.py
deleted file mode 100644
index 3590f01..0000000
--- a/packages/meshbay-node/tests/test_musicbrainz_config_policy.py
+++ /dev/null
@@ -1,179 +0,0 @@
-"""
-The operator's MusicBrainz User-Agent contact string — docs/musicbay.md
-§3.2/§6. Same shape as test_tmdb_config_policy.py: a signed operator
-instruction, node-wide (group_id="") rather than per-group, stored via
-roster.py's group_settings table.
-
-Unlike TMDB's token, a contact string is not a secret — MusicBrainz's usage
-policy expects it to be visible to the service it's sent to — but the
-subject signed/audited still only ever says whether one was configured
-(never the address itself), the same "yes/no" shape as tmdb_config's
-subject, to keep a personal contact out of the audit log as free text.
-"""
-
-from pathlib import Path
-
-import pytest
-
-from meshbay_common.adminop import OP_MUSICBRAINZ_CONFIG
-from meshbay_node.indexer.group_index import GroupIndex
-from meshbay_node.roster import Roster
-from meshbay_node.transport.webrtc_server import WebRTCPeerSession
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
-from conftest import one_root
-
-pytestmark = pytest.mark.asyncio
-
-
-def _session(tmp_path: Path, user_id: str, *, operator: str | None = None) -> WebRTCPeerSession:
- shared_root = tmp_path / "shared"
- shared_root.mkdir(exist_ok=True)
- index = GroupIndex(group_id="g" * 32, sk_node=Ed25519PrivateKey.generate())
- ctx = {
- "roots": one_root(shared_root),
- "index": index,
- "sk_node": index.sk_node,
- "node_user_id": operator,
- }
- session = WebRTCPeerSession.__new__(WebRTCPeerSession)
- session._ctx = ctx
- session._group_id = None
- session._user_id = user_id
- session._pk_user = ""
- session.sent = []
- session._send = session.sent.append
- session._audit = lambda *a, **k: None
- return session
-
-
-def _fake_challenge(issued: list):
- return lambda op, subject, payload=None, group_id=None: issued.append(
- (op, subject, payload, group_id))
-
-
-# ── Refused before a challenge is even issued ───────────────────────────────
-
-async def test_non_string_contact_is_refused(tmp_path):
- session = _session(tmp_path, "op", operator="op")
- session._has_admin_authority = lambda: True
- issued = []
- session._issue_admin_challenge = _fake_challenge(issued)
-
- session._do_musicbrainz_config({"contact": 12345})
-
- assert not issued
- assert [m for m in session.sent if m.get("type") == "error"]
-
-
-async def test_a_request_with_nobody_to_authorize_it_is_refused(tmp_path):
- session = _session(tmp_path, "member-1", operator="the-operator")
- session._has_admin_authority = lambda: False
-
- session._do_musicbrainz_config({"contact": "https://example.invalid/contact"})
-
- assert [m for m in session.sent if m.get("type") == "error"]
-
-
-# ── Who may change it, and what gets signed ─────────────────────────────────
-
-async def test_changing_it_needs_a_signature(tmp_path):
- session = _session(tmp_path, "op", operator="op")
- session._has_admin_authority = lambda: True
- issued = []
- session._issue_admin_challenge = _fake_challenge(issued)
-
- session._do_musicbrainz_config({})
-
- assert len(issued) == 1
- op, subject, payload, group_id = issued[0]
- assert op == OP_MUSICBRAINZ_CONFIG
- assert group_id == "", "node-wide, like tmdb_config — not tied to self._group_id"
-
-
-async def test_the_contact_itself_never_appears_in_the_signed_subject(tmp_path):
- """
- Not a secret the way a TMDB token is, but still kept out of the audited
- subject line as free text — same "yes/no configured" shape.
- """
- session = _session(tmp_path, "op", operator="op")
- session._has_admin_authority = lambda: True
- issued = []
- session._issue_admin_challenge = _fake_challenge(issued)
-
- contact = "operator@example.invalid"
- session._do_musicbrainz_config({"contact": contact})
-
- _, subject, payload, _ = issued[0]
- assert contact not in subject
- assert payload["contact"] == contact, "the real value still has to reach the exec step somehow"
-
-
-async def test_subject_reflects_whether_a_contact_was_supplied(tmp_path):
- session = _session(tmp_path, "op", operator="op")
- session._has_admin_authority = lambda: True
- issued = []
- session._issue_admin_challenge = _fake_challenge(issued)
-
- session._do_musicbrainz_config({"contact": "x"})
-
- _, subject, _, _ = issued[0]
- assert subject == "contact_configured=yes"
-
-
-async def test_subject_says_no_contact_when_none_given(tmp_path):
- session = _session(tmp_path, "op", operator="op")
- session._has_admin_authority = lambda: True
- issued = []
- session._issue_admin_challenge = _fake_challenge(issued)
-
- session._do_musicbrainz_config({})
-
- _, subject, _, _ = issued[0]
- assert subject == "contact_configured=no"
-
-
-# ── Where it is stored ──────────────────────────────────────────────────────
-
-async def test_the_setting_lives_on_the_node_and_survives_a_restart(tmp_path):
- roster = Roster(db_path=tmp_path / "roster.db")
- await roster.open()
- try:
- assert await roster.musicbrainz_contact() is None, \
- "absent must mean 'no contact configured' — no shipped default to fall back to"
- await roster.set_musicbrainz_contact("operator@example.invalid", set_by="op")
- assert await roster.musicbrainz_contact() == "operator@example.invalid"
- finally:
- await roster.close()
-
- reopened = Roster(db_path=tmp_path / "roster.db")
- await reopened.open()
- try:
- assert await reopened.musicbrainz_contact() == "operator@example.invalid"
- finally:
- await reopened.close()
-
-
-async def test_clearing_the_contact_reverts_to_unconfigured(tmp_path):
- roster = Roster(db_path=tmp_path / "roster.db")
- await roster.open()
- try:
- await roster.set_musicbrainz_contact("a-contact", set_by="op")
- assert await roster.musicbrainz_contact() == "a-contact"
-
- await roster.set_musicbrainz_contact("", set_by="op")
- assert await roster.musicbrainz_contact() is None, \
- "an explicit empty string clears the contact"
- finally:
- await roster.close()
-
-
-async def test_omitting_the_contact_leaves_it_unchanged(tmp_path):
- roster = Roster(db_path=tmp_path / "roster.db")
- await roster.open()
- try:
- await roster.set_musicbrainz_contact("a-contact", set_by="op")
- await roster.set_musicbrainz_contact(None, set_by="op")
- assert await roster.musicbrainz_contact() == "a-contact"
- finally:
- await roster.close()