7f353b73 reworded ValidateDownloadURL's rejection from "下载地址必须是
受信任域名上的 HTTPS URL" to "下载地址必须是合法的 HTTPS URL" when
the IP-literal refusal was removed, but missed that the string is a
test contract: paramAliasExpectedCaptureBoundaryError treats the URL
validation stop as the expected capture boundary for drive +download
and +version-download fixture runs. The stale assertion failed those
subtests and the alias-count invariant (58 active, want 64), which
also failed the Coverage jobs running the same tests.
- update the boundary matcher to the new message
Confirmed with the product team that the official GUI client applies no
client-side SSRF interception to downloads, so the IP-literal refusal
was the last remaining client-side interception beyond transport
hygiene. Dedicated deployments make every host dimension (domain,
port, network location) unenumerable, and an IP-literal host is just
another network location.
- ValidateDownloadURL accepts any HTTPS host, IP literals included;
HTTPS scheme, userinfo refusal, and per-hop redirect re-validation
stay as the transport baseline
- this retires the third and last interception layer after the host
allowlist removal and the dial-time public-IP refusal (be52ca5d)
- upload targets stay unaffected: trustedUploadHost keeps rejecting
non-DingTalk/OSS hosts, so local file bytes cannot be PUT to an IP
- regressions: IP-literal URLs pass validation on the shared and chat
download paths; userinfo and plain-HTTP URLs stay rejected
Customer round-2 testing on the dedicated deployment (Jingbo) found the
storage domain resolving to a customer-intranet address (10.254.87.52),
which the dial-time public-IP policy refused: dedicated storage can be
deployed inside the customer network, so its resolved network location
is as unenumerable as its domain and port.
- delete the public-IP policy, the IANA special-purpose denylist, and
the NAT64 embedded-IPv4 re-validation introduced in 617b780a;
downloads now dial the service-issued host directly, still ignoring
environment proxies
- align with the official GUI client, which applies no client-side
SSRF interception to downloads: no command accepts a user-supplied
download URL, TLS hostname verification pins the connection to the
requested domain, redirects are re-validated per hop, and credential
headers are stripped once a redirect leaves the original origin
- uploads keep the static DingTalk/OSS default-port trust boundary
- simplify SetSecureDownloadDialTargetForTest to a single dial seam
Review finding on 1ba6bec8: relaxing ValidateDownloadURL to accept
non-default HTTPS ports also widened upload targets, because the upload
validator reuses it and only re-imposed the host trust set.
- validateUploadURL now also rejects non-default ports, making the
upload trust boundary identical to the pre-removal policy (trusted
DingTalk/OSS hosts on the default port)
- DingTalk/OSS upload endpoints always serve HTTPS on 443, so unlike
dedicated-deployment downloads there is no legitimate non-default
port scenario for uploads
- regressions: trusted-host:8443 upload targets are rejected for both
public-cloud and dedicated hosts
Customer testing on a dedicated deployment found real download URLs served
on a non-default HTTPS port (e.g. 8443) by the dedicated storage domain,
which the inherited default-port-only rule rejected.
- drop the 443-only restriction from ValidateDownloadURL; HTTPS scheme,
domain-only hosts (no IP literals), and no-userinfo rules stay
- the port is not a trust signal: SSRF protection lives at dial time in
the port-agnostic public-IP policy
- redirect hygiene unchanged: a port change is a cross-origin redirect
and still strips service credential headers (new regression guard)
- dedicated-deployment regression: same host on a non-default port is
accepted by URL validation and downloads successfully
- re-validate NAT64 well-known prefix answers (64:ff9b::/96) against the
embedded IPv4 address: DNS64-synthesized answers for public IPv4-only
hosts keep working while embedded loopback/private/special addresses
are refused before dialing
- refuse NAT64 local-use (64:ff9b:1::/48) outright: the IPv4 embedding
is deployment-specific and cannot be extracted reliably
- refuse Teredo (2001::/32) outright as part of the transition-mechanism
audit; 6to4 (2002::/16) was already refused and IPv4-mapped addresses
are normalized via Unmap before checks
- add dial-layer regression: a hostile AAAA answer embedding 127.0.0.1
fails before any dial attempt
- restore the pre-existing DingTalk/OSS trusted host requirement for
upload target URLs via a dedicated upload validator
- extend the dial-time non-public IP denylist with IANA special-purpose
ranges (0.0.0.0/8, 192.88.99.0/24, 100::/64, 2002::/16, 3fff::/20,
5f00::/16)
- document that download credential headers follow the service-issued
URL as-is on the first hop (same authenticated response issues both);
cross-host redirects keep stripping them
Bind coverage repair to the stable PR head and merge identity plus protected-main containment without treating the live base SHA projection as permanent identity.
Add semantic regression coverage for base advancement and update the governance documentation.
GitHub omits merge-related repository settings from tokens without Contents write. Accept only the exact dual omission in read-only admission, and require the dedicated App to observe the reviewed values before any auto-merge mutation.