from __future__ import annotations import hashlib import importlib.util import sys import unittest from pathlib import Path ROOT = Path(__file__).resolve().parents[1] def load_script(name: str, relative_path: str): spec = importlib.util.spec_from_file_location(name, ROOT / relative_path) if spec is None or spec.loader is None: raise RuntimeError(f"cannot load {relative_path}") module = importlib.util.module_from_spec(spec) sys.modules[name] = module spec.loader.exec_module(module) return module preflight = load_script("verify_staging_hubspot_webhook", "scripts/verify_staging_hubspot_webhook.py") replay = load_script("replay_hubspot_contact_inbound", "scripts/replay_hubspot_contact_inbound.py") class HubSpotWebhookV1SigningTests(unittest.TestCase): def test_preflight_uses_v1_secret_prefix_signature(self): body = b'[{"eventId":"probe"}]' expected = hashlib.sha256(b"client-secret" + body).hexdigest() self.assertEqual(preflight.SIGNATURE_HEADER, "X-HubSpot-Signature") self.assertEqual(preflight.sign(body, "client-secret"), expected) def test_replay_uses_v1_secret_prefix_signature(self): body = b'[{"eventId":"replay"}]' expected = hashlib.sha256(b"client-secret" + body).hexdigest() self.assertEqual(replay.sign_webhook(body, "client-secret"), expected) if __name__ == "__main__": unittest.main()