From a98deff8298fcca1eb93c8824fcf61ff954916bd Mon Sep 17 00:00:00 2001 From: Ugur Cekmez Date: Mon, 1 Jun 2026 21:19:26 +0300 Subject: [PATCH] test(cross-impl): make the Python signer parity check run for real MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sole cross-language signer wire-vector test always skipped: it imported eep_signer (not installed in test.sh or the cross-impl CI job) and, even when present, called verify() with a `now` kwarg the Python signer does not accept — skipping on the TypeError. Rewrite it to assert sign() reproduces the recorded fixture signature (deterministic, no frozen-time dependency), and to FAIL rather than skip when EEP_REQUIRE_PYTHON_SIGNER=1. Install eep-signer-python and set that flag in test.sh and both CI workflows so the parity check can never silently no-op where it is meant to run. Surfaced by the EEP protocol audit (finding python-signer-crossimpl-check-dead). Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Ugur Cekmez --- .github/workflows/publish.yml | 6 ++- .github/workflows/test.yml | 6 ++- test.sh | 2 +- tests/cross-impl/test_conformance_fixtures.py | 46 ++++++++++--------- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b497f27..cf70835 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -177,7 +177,11 @@ jobs: - name: Run cross-implementation protocol tests run: | pip install -r tests/cross-impl/requirements.txt - EEP_BASE_URL=http://localhost:3002 python -m pytest tests/cross-impl -v + # Install the Python reference signer so the cross-language signing-parity + # check runs for real instead of skipping. EEP_REQUIRE_PYTHON_SIGNER=1 turns + # a missing import into a failure rather than a silent skip. + pip install ./packages/eep-signer-python + EEP_REQUIRE_PYTHON_SIGNER=1 EEP_BASE_URL=http://localhost:3002 python -m pytest tests/cross-impl -v - name: Stop publisher if: always() diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3e6d230..62d6d2d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -351,7 +351,11 @@ jobs: - name: Run cross-implementation protocol tests run: | pip install -r tests/cross-impl/requirements.txt - EEP_BASE_URL=http://localhost:3002 python -m pytest tests/cross-impl -v + # Install the Python reference signer so the cross-language signing-parity + # check runs for real instead of skipping. EEP_REQUIRE_PYTHON_SIGNER=1 turns + # a missing import into a failure rather than a silent skip. + pip install ./packages/eep-signer-python + EEP_REQUIRE_PYTHON_SIGNER=1 EEP_BASE_URL=http://localhost:3002 python -m pytest tests/cross-impl -v - name: Stop publisher if: always() diff --git a/test.sh b/test.sh index afa2fce..cfde708 100755 --- a/test.sh +++ b/test.sh @@ -89,7 +89,7 @@ if [ "$RUN_FULL" = true ]; then fi set +e - (cd "$ROOT_DIR" && pip install -r tests/cross-impl/requirements.txt -q && EEP_BASE_URL="${EEP_BASE_URL:-http://localhost:3002}" python3 -m pytest tests/cross-impl -v) + (cd "$ROOT_DIR" && pip install -r tests/cross-impl/requirements.txt -q && pip install -e packages/eep-signer-python -q && EEP_REQUIRE_PYTHON_SIGNER=1 EEP_BASE_URL="${EEP_BASE_URL:-http://localhost:3002}" python3 -m pytest tests/cross-impl -v) TEST_EXIT_CODE=$? set -e diff --git a/tests/cross-impl/test_conformance_fixtures.py b/tests/cross-impl/test_conformance_fixtures.py index 530b1ad..4d32092 100644 --- a/tests/cross-impl/test_conformance_fixtures.py +++ b/tests/cross-impl/test_conformance_fixtures.py @@ -16,6 +16,7 @@ import hashlib import hmac import json +import os from pathlib import Path import pytest @@ -99,34 +100,35 @@ def test_signed_bundle_round_trips(entry: dict) -> None: # ─── Python signer parity (when available) ─────────────────────────── -def test_python_signer_verifies_valid_fixture() -> None: - """If eep_signer is importable, the valid-fresh-signature fixture - MUST verify with the same wire format the TS signer produces.""" +def test_python_signer_matches_recorded_wire_format() -> None: + """The Python signer MUST reproduce the exact ``webhook-signature`` + recorded in the canonical fixture (which the TS signer produced) — + a genuine cross-language parity check, not an inline self-recompute. + + Uses ``sign()`` rather than ``verify()`` so the check is independent + of wall-clock freshness and cannot silently skip on a frozen-time + technicality. When ``EEP_REQUIRE_PYTHON_SIGNER=1`` (set by CI and + ``test.sh --full``, which install the package), a missing import is a + FAILURE rather than a skip, so this parity check can never quietly + no-op where it is meant to run. + """ try: from eep_signer import EEPSigner # type: ignore - except Exception: + except Exception as exc: # pragma: no cover - exercised via env in CI + if os.environ.get("EEP_REQUIRE_PYTHON_SIGNER") == "1": + raise AssertionError( + f"eep_signer must be importable when EEP_REQUIRE_PYTHON_SIGNER=1: {exc}" + ) pytest.skip("eep_signer not installed in this environment") bundle = FIXTURES_DIR / "signature/valid-fresh-signature" body = (bundle / "body.txt").read_text() headers = json.loads((bundle / "headers.json").read_text()) secret = (bundle / "secret.txt").read_text().strip() - now = int((bundle / "now.txt").read_text().strip()) - signer = EEPSigner(secret) - # Force the verifier's "now" to the fixture's frozen time. The - # Python signer's verify() should accept an explicit `now` arg, or - # at minimum a generous tolerance window for offline tests. If - # neither is available, we skip rather than fail. - try: - ok = signer.verify( - headers["webhook-id"], - headers["webhook-timestamp"], - headers["webhook-signature"], - body, - now=now, # type: ignore[arg-type] - ) - except TypeError: - pytest.skip("eep_signer.verify() does not accept `now` kwarg; can't pin time offline") - - assert ok is True + produced = EEPSigner(secret).sign( + headers["webhook-id"], + headers["webhook-timestamp"], + body, + ) + assert produced == headers["webhook-signature"]