The origin gate for the two decisions that let a run act on a URL: a
scripted state's entry url, and the URL a request step resolves to.
An origin is scheme + host + port, so that is what gets compared:
hostMatchesFilters decides the host (it canonicalizes www. and honors
--allowed-hosts / --include-subdomains), and the seed decides the scheme
and the port. Matching on hostname alone let http://app.test:4000 through
a filter whose whole purpose was to confine a run to https://app.test —
a different port and a downgraded scheme are different servers, and for a
request step that means a POST at a machine the user never named.
URL.port is already normalized ("" for a scheme's default), so
https://a.test and https://a.test:443 compare equal without special
casing.
Both the pre-launch validation in states.ts and the runtime request gate
in the state driver call this, so a states file that validates cannot be
widened at runtime and a run cannot abort on something the runtime would
have allowed.
Route crawling deliberately does not use this gate.scheduleRoute in
service.ts and the link filter in link-discovery.ts match on the
hostname alone, so a crawl seeded at http://app.test:3000 will follow and
capture a link to https://app.test or http://app.test:8080. The two
answer different questions: crawling navigates and screenshots, and within
one deployment an http→https or cross-port link is ordinary rather than
suspicious, while this gate authorizes driving a scripted state at a URL and
sending a request step's POST or DELETE at it. --allowed-hosts and
--include-subdomains are documented as hostname filters, and hostname is
what bounds a crawl.
The origin gate for the two decisions that let a run act on a URL: a scripted state's entry
url, and the URL arequeststep resolves to.An origin is scheme + host + port, so that is what gets compared:
hostMatchesFiltersdecides the host (it canonicalizeswww.and honors--allowed-hosts/--include-subdomains), and the seed decides the scheme and the port. Matching on hostname alone lethttp://app.test:4000through a filter whose whole purpose was to confine a run tohttps://app.test— a different port and a downgraded scheme are different servers, and for arequeststep that means a POST at a machine the user never named.URL.portis already normalized (""for a scheme's default), sohttps://a.testandhttps://a.test:443compare equal without special casing.Both the pre-launch validation in
states.tsand the runtime request gate in the state driver call this, so a states file that validates cannot be widened at runtime and a run cannot abort on something the runtime would have allowed.Route crawling deliberately does not use this gate.
scheduleRouteinservice.tsand the link filter inlink-discovery.tsmatch on the hostname alone, so a crawl seeded athttp://app.test:3000will follow and capture a link tohttps://app.testorhttp://app.test:8080. The two answer different questions: crawling navigates and screenshots, and within one deployment an http→https or cross-port link is ordinary rather than suspicious, while this gate authorizes driving a scripted state at a URL and sending arequeststep's POST or DELETE at it.--allowed-hostsand--include-subdomainsare documented as hostname filters, and hostname is what bounds a crawl.