83 lines
2.8 KiB
Python
83 lines
2.8 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import hashlib
|
||
|
|
import hmac
|
||
|
|
|
||
|
|
from reuse_surface.hub.webhooks import push_touches_registry_index, verify_signature
|
||
|
|
|
||
|
|
SECRET = "shh"
|
||
|
|
|
||
|
|
|
||
|
|
def _sign(body: bytes, secret: str = SECRET) -> str:
|
||
|
|
return hmac.new(secret.encode("utf-8"), body, hashlib.sha256).hexdigest()
|
||
|
|
|
||
|
|
|
||
|
|
def test_verify_signature_valid():
|
||
|
|
body = b'{"commits": []}'
|
||
|
|
assert verify_signature(SECRET, body, _sign(body)) is True
|
||
|
|
|
||
|
|
|
||
|
|
def test_verify_signature_wrong_secret():
|
||
|
|
body = b'{"commits": []}'
|
||
|
|
assert verify_signature("different-secret", body, _sign(body)) is False
|
||
|
|
|
||
|
|
|
||
|
|
def test_verify_signature_tampered_body():
|
||
|
|
body = b'{"commits": []}'
|
||
|
|
signature = _sign(body)
|
||
|
|
assert verify_signature(SECRET, b'{"commits": [1]}', signature) is False
|
||
|
|
|
||
|
|
|
||
|
|
def test_verify_signature_missing_signature():
|
||
|
|
assert verify_signature(SECRET, b"{}", None) is False
|
||
|
|
|
||
|
|
|
||
|
|
def test_verify_signature_empty_secret_rejects():
|
||
|
|
body = b"{}"
|
||
|
|
# Even if a caller accidentally computed a signature with an empty
|
||
|
|
# secret, verify_signature must not accept it -- an unconfigured
|
||
|
|
# secret is not the same as "verification not needed".
|
||
|
|
assert verify_signature("", body, _sign(body, secret="")) is False
|
||
|
|
|
||
|
|
|
||
|
|
def test_push_touches_registry_index_added():
|
||
|
|
payload = {"commits": [{"added": ["registry/indexes/capabilities.yaml"], "modified": [], "removed": []}]}
|
||
|
|
assert push_touches_registry_index(payload) is True
|
||
|
|
|
||
|
|
|
||
|
|
def test_push_touches_registry_index_modified():
|
||
|
|
payload = {"commits": [{"added": [], "modified": ["registry/indexes/federated.yaml"], "removed": []}]}
|
||
|
|
assert push_touches_registry_index(payload) is True
|
||
|
|
|
||
|
|
|
||
|
|
def test_push_touches_registry_index_removed():
|
||
|
|
payload = {"commits": [{"added": [], "modified": [], "removed": ["registry/indexes/capabilities.yaml"]}]}
|
||
|
|
assert push_touches_registry_index(payload) is True
|
||
|
|
|
||
|
|
|
||
|
|
def test_push_does_not_touch_registry_index():
|
||
|
|
payload = {"commits": [{"added": ["README.md"], "modified": ["src/main.py"], "removed": []}]}
|
||
|
|
assert push_touches_registry_index(payload) is False
|
||
|
|
|
||
|
|
|
||
|
|
def test_push_touches_registry_index_across_multiple_commits():
|
||
|
|
payload = {
|
||
|
|
"commits": [
|
||
|
|
{"added": ["README.md"], "modified": [], "removed": []},
|
||
|
|
{"added": [], "modified": ["registry/indexes/capabilities.yaml"], "removed": []},
|
||
|
|
]
|
||
|
|
}
|
||
|
|
assert push_touches_registry_index(payload) is True
|
||
|
|
|
||
|
|
|
||
|
|
def test_push_touches_registry_index_empty_commits():
|
||
|
|
assert push_touches_registry_index({"commits": []}) is False
|
||
|
|
assert push_touches_registry_index({}) is False
|
||
|
|
|
||
|
|
|
||
|
|
def test_push_touches_registry_index_ignores_similarly_named_paths():
|
||
|
|
# a path that merely starts with "registry" but isn't under
|
||
|
|
# registry/indexes/ must not match
|
||
|
|
payload = {"commits": [{"added": ["registry/capabilities/capability.foo.md"], "modified": [], "removed": []}]}
|
||
|
|
assert push_touches_registry_index(payload) is False
|