78af6d4755
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m29s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 11s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 8s
build / build (push) Successful in 19s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m30s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 11s
Testy / Kontrola składni wszystkich warstw (push) Successful in 7s
Zabezpieczenie DETEKCYJNE (nie prewencyjne): kilka unikalnych, wiarygodnie wyglądających rekordów-pułapek w bazach. Nie zmieniają interpretacji (odsiewamy je z wyników), ale jeśli pojawią się w cudzej kopii — są dowodem pochodzenia, a przy wariancie na kopię — wskazują ŹRÓDŁO wycieku. `canary.py`: pułapkę rozpoznajemy po MARKERZE (unikalny ciąg z ENV, nieobecny w realnych danych). `screen(rows, query_value)`: - ODSIEWA rekordy z markerem z wyników — i to na WYJŚCIU z warstwy danych (`/search`), więc nie dotrą wyżej ani do promptu LLM (LOG-30), niezależnie od dostawcy (Excel/SQL); - TRIPWIRE: gdy zapytanie celuje wprost w marker (enumeracja bazy, nie liczenie horoskopu) → log warning. Bez `CANARY_MARKERS` — przezroczyste, zero kosztu dla normalnego ruchu. Rejestr wariant→kopia (traitor tracing) i wstrzyknięcie do REALNYCH baz to krok właściciela (poza kodem — nie ruszamy kupionych plików automatycznie); instrukcja: docs/canary-registry.md. Mechanizm zbudowany i przetestowany na syntetycznych pułapkach. Testy: +7 (przezroczystość bez markerów, odsiewanie, tripwire, marker w dowolnym polu, endpoint odsiewa przed zwrotem). Pierwsze testy w usłudze `data`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
62 lines
2.5 KiB
Python
62 lines
2.5 KiB
Python
"""Rekordy-pułapki (canary) — DAN-26.
|
|
|
|
Testujemy sam MECHANIZM na syntetycznych pułapkach: prawdziwe markery i injekcja
|
|
do baz przychodzą od właściciela produktu. Regresja byłaby CICHA i podwójnie zła:
|
|
albo pułapka wycieka do interpretacji/LLM (zdradza się i psuje wynik), albo
|
|
przestaje odsiewać i nie wiadomo o tym.
|
|
"""
|
|
import pathlib
|
|
|
|
from app import canary
|
|
|
|
MAIN = (pathlib.Path(__file__).resolve().parents[1] / "app" / "main.py").read_text(encoding="utf-8")
|
|
|
|
MARK = "ASTROLOLO-CANARY-7f3a9" # unikalny — nie wystąpi w realnych danych
|
|
ROWS = [
|
|
{"significator": "Ma Ari", "effect": "odważny, impulsywny"},
|
|
{"significator": "Ve Tau " + MARK, "effect": "pułapka — nie dotknie interpretacji"},
|
|
{"significator": "Su Leo", "effect": "dumny, twórczy"},
|
|
]
|
|
|
|
|
|
def test_no_markers_is_transparent():
|
|
"""Bez skonfigurowanych markerów — zero ingerencji, zero kosztu."""
|
|
out, rep = canary.screen(ROWS, "cokolwiek", markers=[])
|
|
assert out == ROWS and rep["active"] is False
|
|
|
|
|
|
def test_canary_row_is_fenced_from_results():
|
|
"""Pułapka znika z wyników — nie opuści warstwy danych (a więc i promptu LLM)."""
|
|
out, rep = canary.screen(ROWS, "Ve Tau", markers=[MARK])
|
|
assert rep["active"] and rep["removed"] == 1
|
|
assert all(MARK not in str(r) for r in out) # nigdzie nie ma markera
|
|
assert len(out) == 2 and {"significator": "Su Leo", "effect": "dumny, twórczy"} in out
|
|
|
|
|
|
def test_real_results_pass_through_untouched():
|
|
out, _ = canary.screen(ROWS, "Ari", markers=[MARK])
|
|
assert {"significator": "Ma Ari", "effect": "odważny, impulsywny"} in out
|
|
|
|
|
|
def test_tripwire_when_query_targets_a_marker():
|
|
"""Zapytanie CELUJĄCE w marker = ktoś enumeruje bazę, nie liczy horoskopu."""
|
|
_, rep = canary.screen(ROWS, "Ve Tau " + MARK, markers=[MARK])
|
|
assert rep["tripwire"] is True
|
|
|
|
|
|
def test_normal_query_does_not_trip():
|
|
_, rep = canary.screen(ROWS, "Ma Ari", markers=[MARK])
|
|
assert rep["tripwire"] is False
|
|
|
|
|
|
def test_marker_matched_in_any_string_field():
|
|
rows = [{"significator": "X", "effect": "opis " + MARK, "extra": 5}]
|
|
out, rep = canary.screen(rows, "X", markers=[MARK])
|
|
assert out == [] and rep["removed"] == 1 # marker w polu 'effect' też łapiemy
|
|
|
|
|
|
def test_endpoint_fences_before_returning():
|
|
"""/search odsiewa pułapki na wyjściu z warstwy danych (niezależnie od dostawcy)."""
|
|
assert "canary.screen(result.rows, query.value)" in MAIN
|
|
assert "result.rows = visible" in MAIN
|