Follow-up to #14. PR #19 added {id}/{path:path} placeholder support to is_trusted_endpoint (the trust gate). The body-hook tamper allowlist is gated by a separate code path — set_intercept_url_allowlist and the _url_allowlist matcher in interceptor.py — which is still exact-match only.
Where
# src/provably/intercept/interceptor.py:60
def set_intercept_url_allowlist(urls: list[str] | None) -> None:
...
_url_allowlist = {
normalize_url_for_trust(str(u or "").strip()) for u in urls if (u or "").strip()
}
# src/provably/intercept/interceptor.py:265
if _url_allowlist is not None and nurl not in _url_allowlist:
return response
...
tamper = _url_allowlist is not None and nurl in _url_allowlist
nurl in _url_allowlist is set membership on the normalized URL, so a registered https://api.example.com/customers/{id} does not match a concrete https://api.example.com/customers/42.
Impact
With trust-gate patterns + allowlist exact-match, consumers with templated routes must:
- register patterns in
trusted_endpoints (clean), AND
- enumerate concrete URLs separately for
set_intercept_url_allowlist.
Parity with the trust gate lets the same templated entries cover both.
Suggested implementation
Same syntax: {name} for one segment, {name:path} for subtree. Store registered strings as-is (do not normalize placeholders away). Matcher walks the set: exact-match first, then pattern-match. Extract the matching helper PR #19 added to trusted_endpoints.py into a shared util so both code paths use it.
Follow-up to #14. PR #19 added
{id}/{path:path}placeholder support tois_trusted_endpoint(the trust gate). The body-hook tamper allowlist is gated by a separate code path —set_intercept_url_allowlistand the_url_allowlistmatcher ininterceptor.py— which is still exact-match only.Where
nurl in _url_allowlistis set membership on the normalized URL, so a registeredhttps://api.example.com/customers/{id}does not match a concretehttps://api.example.com/customers/42.Impact
With trust-gate patterns + allowlist exact-match, consumers with templated routes must:
trusted_endpoints(clean), ANDset_intercept_url_allowlist.Parity with the trust gate lets the same templated entries cover both.
Suggested implementation
Same syntax:
{name}for one segment,{name:path}for subtree. Store registered strings as-is (do not normalize placeholders away). Matcher walks the set: exact-match first, then pattern-match. Extract the matching helper PR #19 added totrusted_endpoints.pyinto a shared util so both code paths use it.