fix(registry): case-fold + trim-dot in isPlatformTunnelHostname (#2425 follow-up) #2429

Merged
devops-engineer merged 1 commits from fix/platform-tunnel-hostname-normalize into main 2026-06-12 05:28:15 +00:00
2 changed files with 7 additions and 2 deletions
@@ -309,12 +309,16 @@ func validateAgentURL(rawURL string) error {
// (covers prod `*.moleculesai.app` and staging `*.staging.moleculesai.app`) and
// is overridable via MOLECULE_APP_DOMAIN for other deployments.
func isPlatformTunnelHostname(h string) bool {
// DNS is case-insensitive and FQDN-form hostnames may carry a trailing dot.
// Normalize: net/url's Hostname() does NOT lowercase and keeps a trailing dot,
// so a legitimate `WS-…MOLECULESAI.APP` or FQDN-form `ws-x.moleculesai.app.`
// would otherwise fail this case-sensitive match and get blocked (the exact
// availability bug this allowance exists to cure). DNS is case-insensitive and
// the trailing dot is the same name, so fold both before comparing.
h = strings.ToLower(strings.TrimSuffix(h, "."))
if !strings.HasPrefix(h, "ws-") {
return false
}
domain := strings.TrimSpace(os.Getenv("MOLECULE_APP_DOMAIN"))
domain := strings.ToLower(strings.TrimSpace(os.Getenv("MOLECULE_APP_DOMAIN")))
if domain == "" {
domain = "moleculesai.app"
}
@@ -985,6 +985,7 @@ func TestValidateAgentURL_PendingPlatformTunnel(t *testing.T) {
{"api.moleculesai.app", false}, // no ws- prefix
{"ws-x.fakemoleculesai.app", false}, // lookalike domain, not a subdomain
{"ws-abc123moleculesai.app", false}, // missing dot before platform domain
{"ws-x.moleculesai.app.attacker.com", false}, // parent-domain trick
} {
if got := isPlatformTunnelHostname(tc.h); got != tc.want {
t.Errorf("isPlatformTunnelHostname(%q)=%v want %v", tc.h, got, tc.want)