Coverage for astrocyte/ingest/hmac_auth.py: 100%

17 statements  

« prev     ^ index     » next       coverage.py v7.15.0, created at 2026-07-04 05:24 +0000

1"""HMAC signature helpers for webhook ingest (M4).""" 

2 

3from __future__ import annotations 

4 

5import hashlib 

6import hmac 

7 

8 

9def compute_hmac_sha256_hex(secret: str, body: bytes) -> str: 

10 """Return lowercase hex digest of HMAC-SHA256(secret, body).""" 

11 return hmac.new(secret.encode("utf-8"), body, hashlib.sha256).hexdigest() 

12 

13 

14def normalize_signature_header(value: str) -> str: 

15 """Strip ``sha256=`` / ``sha1=`` prefix if present (GitHub-style).""" 

16 v = value.strip() 

17 for prefix in ("sha256=", "sha1="): 

18 if v.lower().startswith(prefix): 

19 return v.split("=", 1)[1].strip() 

20 return v 

21 

22 

23def verify_hmac_sha256(secret: str, body: bytes, signature_header: str) -> bool: 

24 """Constant-time compare of computed HMAC to header value (hex).""" 

25 expected = compute_hmac_sha256_hex(secret, body) 

26 got = normalize_signature_header(signature_header) 

27 if len(got) != len(expected): 

28 return False 

29 return hmac.compare_digest(expected.lower(), got.lower())