mirror of
https://github.com/kuhyx/signal-bot.git
synced 2026-11-11 16:43:49 +01:00
!dodaj is unwired: register_add_command is no longer called, its aliases
are gone from aliases.json, and the word is an unknown one like any
other -- answered with "Nie znam !dodaj", storing nothing. The ingest
path itself (pack_add, pack_ingest, pack_store, the stripper) stays,
tested at 100%, because the approval queue that replaces the direct
write will reuse every piece of it: !dodaj lands in pending/, and the
tagger view gets approve / reject.
The eight e2e scenarios that proved the direct write, the media
generation step and prove_the_add_photo_invariants leave with it;
64852ae has them for the queue to bring back in their new shape. One
scenario takes their place and pins the disabled state.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
126 lines
4.5 KiB
Python
126 lines
4.5 KiB
Python
# Copyright (c) 2026 Krzysztof Rudnicki. MIT licence.
|
|
"""Where the personal-data gate learns its forbidden words from.
|
|
|
|
Worth its own test because ``!add_photo`` made one of those sources
|
|
*writable from a group chat*, and the failure mode is silent and permanent:
|
|
a label that is also a word in this repository would put that word on the
|
|
forbidden list and refuse every commit from then on, fixable only by
|
|
hand-editing an album the committer cannot see.
|
|
|
|
Driven entirely through ``forbidden()``, which is what the gate itself calls.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
import pytest
|
|
|
|
if TYPE_CHECKING:
|
|
from types import ModuleType
|
|
|
|
REPO = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
@pytest.fixture
|
|
def sources() -> ModuleType:
|
|
"""Import scripts/personal_data_sources.py, which is not a package."""
|
|
path = REPO / "scripts" / "personal_data_sources.py"
|
|
spec = importlib.util.spec_from_file_location("personal_data_sources", path)
|
|
assert spec is not None
|
|
assert spec.loader is not None
|
|
module = importlib.util.module_from_spec(spec)
|
|
sys.modules[spec.name] = module
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
def _album(
|
|
root: Path,
|
|
*,
|
|
triggers: list[str] | None = None,
|
|
custom: dict[str, Any] | None = None,
|
|
corrupt_custom: bool = False,
|
|
) -> Path:
|
|
root.mkdir(parents=True, exist_ok=True)
|
|
people = [{"key": "p1", "triggers": triggers or ["!zenon"]}]
|
|
(root / "people.json").write_text(
|
|
json.dumps({"groups": ["g"], "people": people}), encoding="utf-8"
|
|
)
|
|
if corrupt_custom:
|
|
(root / "custom.json").write_text("{ not json", encoding="utf-8")
|
|
elif custom is not None:
|
|
(root / "custom.json").write_text(json.dumps(custom), encoding="utf-8")
|
|
return root
|
|
|
|
|
|
def _words(sources: ModuleType, root: Path, monkeypatch: pytest.MonkeyPatch) -> set[str]:
|
|
monkeypatch.setenv("PHOTO_PACK_DIR", str(root))
|
|
words, _ = sources.forbidden(set())
|
|
return set(words)
|
|
|
|
|
|
def test_a_people_trigger_is_forbidden(
|
|
sources: ModuleType, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
assert "zenon" in _words(sources, _album(tmp_path / "pack"), monkeypatch)
|
|
|
|
|
|
def test_a_custom_label_is_forbidden_too(
|
|
sources: ModuleType, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
"""A label can be a name -- "ciocia_hania" is one however it got there."""
|
|
root = _album(tmp_path / "pack", custom={"t1": ["ciocia_hania"]})
|
|
assert "ciocia_hania" in _words(sources, root, monkeypatch)
|
|
|
|
|
|
def test_a_label_that_is_a_command_word_is_not_forbidden(
|
|
sources: ModuleType, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
"""The wedge: "!add_photo kot" must not outlaw "kot" in aliases.json."""
|
|
root = _album(tmp_path / "pack", custom={"t1": ["kot"], "t2": ["ciocia_hania"]})
|
|
words = _words(sources, root, monkeypatch)
|
|
assert "kot" not in words
|
|
assert "ciocia_hania" in words
|
|
|
|
|
|
@pytest.mark.parametrize("label", ["losowe", "papiez", "komendy", "staty"])
|
|
def test_no_command_word_can_be_outlawed_by_a_label(
|
|
sources: ModuleType, tmp_path: Path, monkeypatch: pytest.MonkeyPatch, label: str
|
|
) -> None:
|
|
"""Generalised: every alias in the table, not just the one that bit."""
|
|
root = _album(tmp_path / "pack", custom={"t1": [label]})
|
|
assert label not in _words(sources, root, monkeypatch)
|
|
|
|
|
|
def test_a_people_trigger_is_never_excused_by_the_vocabulary(
|
|
sources: ModuleType, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
"""Only custom labels get the subtraction.
|
|
|
|
A curated real name turning up in this repository is precisely the leak
|
|
the gate exists to fail on, so it stays forbidden even when it collides.
|
|
"""
|
|
root = _album(tmp_path / "pack", triggers=["!kot"])
|
|
assert "kot" in _words(sources, root, monkeypatch)
|
|
|
|
|
|
def test_an_album_with_no_custom_file_still_works(
|
|
sources: ModuleType, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
"""Other sources (the database, .env) contribute too, so this is membership."""
|
|
words = _words(sources, _album(tmp_path / "pack"), monkeypatch)
|
|
assert "zenon" in words
|
|
|
|
|
|
def test_a_corrupt_custom_file_is_ignored_rather_than_fatal(
|
|
sources: ModuleType, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
) -> None:
|
|
"""Refusing every commit because an album file got truncated is backwards."""
|
|
root = _album(tmp_path / "pack", corrupt_custom=True)
|
|
assert "zenon" in _words(sources, root, monkeypatch)
|