codersdk/deployment_registry_test.go
Rama main · réplica de lectura del repositorio original.
package codersdk_test
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/serpent"
)
func TestNormalizeTemplateBuilderRegistryURL(t *testing.T) {
t.Parallel()
t.Run("Accepts", func(t *testing.T) {
t.Parallel()
cases := []struct {
name string
in string
want string
}{
{"Empty", "", ""},
{"WhitespaceOnly", " ", ""},
{"BareHost", "registry.coder.com", "registry.coder.com"},
{"SurroundingSpaceTrimmed", " mirror.internal ", "mirror.internal"},
{"HostPort", "mirror.example.com:8443", "mirror.example.com:8443"},
{"IPv6HostPort", "[::1]:8443", "[::1]:8443"},
// An accidental scheme and trailing slash are stripped rather than
// rejected, so a value pasted as a URL still resolves to a host.
{"HTTPSStripped", "https://mirror.example.com", "mirror.example.com"},
{"HTTPStripped", "http://mirror.example.com", "mirror.example.com"},
{"TrailingSlashStripped", "mirror.example.com/", "mirror.example.com"},
{"SchemePortAndSlash", "https://mirror.example.com:8443/", "mirror.example.com:8443"},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got, err := codersdk.NormalizeTemplateBuilderRegistryURL(tc.in)
require.NoError(t, err)
require.Equal(t, tc.want, got)
})
}
})
t.Run("Rejects", func(t *testing.T) {
t.Parallel()
cases := []struct {
name string
in string
}{
{"Path", "mirror.example.com/coder"},
{"NonHTTPScheme", "git://mirror.example.com"},
{"UppercaseScheme", "HTTPS://mirror.example.com"},
{"SchemeAndPath", "https://mirror.example.com/coder"},
{"Query", "mirror.example.com?a=b"},
{"Fragment", "mirror.example.com#frag"},
{"DoubledScheme", "https://https://mirror.example.com"},
{"InteriorSpace", "mirror .example.com"},
{"PortOnly", ":8443"},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
_, err := codersdk.NormalizeTemplateBuilderRegistryURL(tc.in)
require.ErrorContains(t, err, "bare host")
})
}
})
t.Run("RejectsCredentialsWithoutEcho", func(t *testing.T) {
t.Parallel()
// Userinfo survives the scheme strip and must be rejected, not accepted,
// and the rejection must not echo the credential.
_, err := codersdk.NormalizeTemplateBuilderRegistryURL("https://user:s3cr3t-token@mirror.example.com")
require.ErrorContains(t, err, "bare host")
require.NotContains(t, err.Error(), "s3cr3t-token")
})
}
// TestDeploymentValues_Validate_TemplateBuilderRegistryURL covers the config
// boundary: a malformed CODER_TEMPLATE_BUILDER_REGISTRY_URL must fail at server
// start naming the option, but must not block boot when the builder is disabled.
func TestDeploymentValues_Validate_TemplateBuilderRegistryURL(t *testing.T) {
t.Parallel()
cases := []struct {
name string
url string
disabled bool
wantErr string
}{
{name: "EmptyOK"},
{name: "BareHostOK", url: "mirror.internal.example"},
{name: "HostPortOK", url: "mirror.internal.example:8443"},
// A scheme is stripped, not rejected, so an existing deployment that set
// a scheme'd value keeps booting after upgrade.
{name: "SchemeStrippedOK", url: "https://mirror.internal.example"},
{name: "PathRejected", url: "mirror.internal.example/coder", wantErr: "bare host"},
{name: "CredentialsRejected", url: "https://user:tok@mirror.example.com", wantErr: "bare host"},
// A disabled template builder must not block boot on an inert value, so
// tightening the check in an upgrade cannot take down a disabled deployment.
{name: "DisabledSkipsValidation", url: "https://user:tok@mirror.example.com/bad", disabled: true},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
dv := defaultDeploymentValues(t)
dv.TemplateBuilder.Disabled = serpent.Bool(tc.disabled)
dv.TemplateBuilder.RegistryURL = serpent.String(tc.url)
err := dv.Validate()
if tc.wantErr == "" {
require.NoError(t, err)
return
}
require.ErrorContains(t, err, tc.wantErr)
})
}
}