docs: state the exemption's canonicalization contract, and fix the smoke recipe's cwd

Copilot review round 2.

The exemption compares the WHATWG-canonicalized `URL.hostname`, so it covers
alternate spellings of three loopback *addresses* rather than three input
strings: `127.1`, `2130706433`, `0x7f.0.0.1`, `[0:0:0:0:0:0:0:1]` and a
root-anchored `127.0.0.1.` all pass. The behavior is right — the security
argument is about the address the request reaches, and all of these are the
loopback interface — but the comment described it as a literal-input match,
which it is not. It now states the contract, and six regression cases pin the
aliases alongside the existing near-miss cases.

This is also still an exact match for the SDK: `assertSecureTokenEndpoint` tests
`url.hostname` against the same three values after the same `new URL`
canonicalization, so an alias accepted here is one the SDK accepts too.

Separately, the smoke guide's fixture recipe left the shell in `clients/web`
after the build line, so the repo-root-relative paths on the next line resolved
under `clients/web` and the copy-pasted setup failed before the server started.
The build now runs in a subshell, and the block notes that the server announces
its URL on stderr and walks past a taken port.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GfHQ8vMm5NBgzbUJ6UwxmB
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-09-11 03:12:07 -04:00
commit a21fd0c161

View file

@ -335,7 +335,27 @@ describe("client config", () => {
);
});
it("does not widen the exemption beyond the three literals", () => {
it("accepts alternate spellings that canonicalize to the same addresses", () => {
// The check runs against the WHATWG-canonicalized `URL.hostname`, so the
// exemption covers these three *addresses*, not three input strings. Each
// of these reaches the loopback interface, which is what the security
// argument is about — and the SDK canonicalizes identically, so an alias
// accepted here is one it accepts for a token endpoint too.
for (const value of [
"http://127.1:8090/client-metadata.json",
"http://2130706433:8090/client-metadata.json",
"http://0x7f.0.0.1:8090/client-metadata.json",
"http://[0:0:0:0:0:0:0:1]:8090/client-metadata.json",
// WHATWG strips a root-anchored dot from an IP literal but not from a
// name, which is why this passes where `localhost.` below does not.
"http://127.0.0.1.:8090/client-metadata.json",
"http://LOCALHOST:8090/client-metadata.json",
]) {
expect(getCimdClientMetadataUrlError(value)).toBeUndefined();
}
});
it("does not widen the exemption beyond those three addresses", () => {
// `localhost.` and `*.localhost` resolve to loopback on every resolver,
// but they are outside the SDK's allow-list — so they are outside ours
// too, deliberately, rather than the two disagreeing about one URL.