Repository navigation
fix(www): apply domain-specificity precedence in Shield rule matching - #516
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The Shield matching contract said overlapping rules were "first-wins" with servers ordering "specific-before-general", but neither the publisher nor the matchers implemented a precedence semantic:
noneif that rule's domains did not cover the host — even when a later rule did cover it.For a feed like
[pin [email protected] for domain-a, block [email protected] global], a request from domain-b was blocked according to the simulator and served the requested version by the edge. The two implementations could disagree about whether a domain is protected, and the outcome depended on incidental rule order.Change
packages/unpkg-www/src/shield.tsnow applies explicit precedence, mirrored exactly by the Shield API (edge_matching.py, already deployed) and locked by the shared conformance fixture:*; a longer matching domain (app.example.com) beats a shorter parent (example.com); a rule's specificity is its strongest matching domain. Absentdomainsis global; an empty list covers nothing.blockbeatspin.Also aligned with the API matcher on malformed feed fields, which precedence makes more consequential: pins with an empty
to, empty or unknown actions, a non-listfrom, a non-stringpkg, and a present-but-non-listdomains(covers nothing instead of silently widening to global) are all ignored on both sides.No change to rule loading, KV caching, cache keys, TTLs, or the block stub. Non-Shield traffic is untouched: the matcher returns before host parsing when the package has no rules, and a
nonedecision leaves the request byte-identical.Behavior
(*) The old result here depended on rule order; the block was skipped whenever the domain-a rule was listed first.
Tests
unpkg-www: 136 tests pass.pnpm run buildpasses.[email protected](global block listed first, domain pins fordomain-a.test/b.test, deeper pin forapp.b.test): domain requests received the pinned bytes withno-store, other domains received the 403 block, deeper subdomains followed the more specific pin, and referrer-less requests were served unshielded with normal caching. The staging feed was restored to empty afterwards.