chore: move app URL parsing to its own package (#11651)

* chore: move app url parsing to it's own package
This commit is contained in:
Steven Masley
2024-01-17 10:41:42 -06:00
committed by GitHub
parent 1aee8da4b6
commit b246f08d84
32 changed files with 165 additions and 133 deletions
+26
View File
@@ -59,6 +59,28 @@ func (i *Validator[T]) Type() string {
return i.Value.Type()
}
func (i *Validator[T]) MarshalYAML() (interface{}, error) {
m, ok := any(i.Value).(yaml.Marshaler)
if !ok {
return i.Value, nil
}
return m.MarshalYAML()
}
func (i *Validator[T]) UnmarshalYAML(n *yaml.Node) error {
return n.Decode(i.Value)
}
func (i *Validator[T]) MarshalJSON() ([]byte, error) {
return json.Marshal(i.Value)
}
func (i *Validator[T]) UnmarshalJSON(b []byte) error {
return json.Unmarshal(b, i.Value)
}
func (i *Validator[T]) Underlying() pflag.Value { return i.Value }
// values.go contains a standard set of value types that can be used as
// Option Values.
@@ -378,6 +400,7 @@ func (s *Struct[T]) String() string {
return string(byt)
}
// nolint:revive
func (s *Struct[T]) MarshalYAML() (interface{}, error) {
var n yaml.Node
err := n.Encode(s.Value)
@@ -387,6 +410,7 @@ func (s *Struct[T]) MarshalYAML() (interface{}, error) {
return n, nil
}
// nolint:revive
func (s *Struct[T]) UnmarshalYAML(n *yaml.Node) error {
// HACK: for compatibility with flags, we use nil slices instead of empty
// slices. In most cases, nil slices and empty slices are treated
@@ -403,10 +427,12 @@ func (s *Struct[T]) Type() string {
return fmt.Sprintf("struct[%T]", s.Value)
}
// nolint:revive
func (s *Struct[T]) MarshalJSON() ([]byte, error) {
return json.Marshal(s.Value)
}
// nolint:revive
func (s *Struct[T]) UnmarshalJSON(b []byte) error {
return json.Unmarshal(b, &s.Value)
}
+5 -1
View File
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/mitchellh/go-wordwrap"
"github.com/spf13/pflag"
"golang.org/x/xerrors"
"gopkg.in/yaml.v3"
)
@@ -74,13 +75,16 @@ func (optSet *OptionSet) MarshalYAML() (any, error) {
Value: opt.YAML,
HeadComment: comment,
}
_, isValidator := opt.Value.(interface{ Underlying() pflag.Value })
var valueNode yaml.Node
if opt.Value == nil {
valueNode = yaml.Node{
Kind: yaml.ScalarNode,
Value: "null",
}
} else if m, ok := opt.Value.(yaml.Marshaler); ok {
} else if m, ok := opt.Value.(yaml.Marshaler); ok && !isValidator {
// Validators do a wrap, and should be handled by the else statement.
v, err := m.MarshalYAML()
if err != nil {
return nil, xerrors.Errorf(
+6 -7
View File
@@ -53,8 +53,6 @@ import (
"gopkg.in/yaml.v3"
"tailscale.com/tailcfg"
"github.com/coder/pretty"
"cdr.dev/slog"
"cdr.dev/slog/sloggers/sloghuman"
"github.com/coder/coder/v2/buildinfo"
@@ -75,7 +73,6 @@ import (
"github.com/coder/coder/v2/coderd/devtunnel"
"github.com/coder/coder/v2/coderd/externalauth"
"github.com/coder/coder/v2/coderd/gitsshkey"
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/coderd/httpmw"
"github.com/coder/coder/v2/coderd/oauthpki"
"github.com/coder/coder/v2/coderd/prometheusmetrics"
@@ -89,6 +86,7 @@ import (
"github.com/coder/coder/v2/coderd/util/slice"
stringutil "github.com/coder/coder/v2/coderd/util/strings"
"github.com/coder/coder/v2/coderd/workspaceapps"
"github.com/coder/coder/v2/coderd/workspaceapps/appurl"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/codersdk/drpc"
"github.com/coder/coder/v2/cryptorand"
@@ -99,6 +97,7 @@ import (
"github.com/coder/coder/v2/provisionersdk"
sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
"github.com/coder/coder/v2/tailnet"
"github.com/coder/pretty"
"github.com/coder/retry"
"github.com/coder/wgtunnel/tunnelsdk"
)
@@ -434,11 +433,11 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
if vals.WildcardAccessURL.String() == "" {
// Suffixed wildcard access URL.
u, err := url.Parse(fmt.Sprintf("*--%s", tunnel.URL.Hostname()))
wu := fmt.Sprintf("*--%s", tunnel.URL.Hostname())
err = vals.WildcardAccessURL.Set(wu)
if err != nil {
return xerrors.Errorf("parse wildcard url: %w", err)
return xerrors.Errorf("set wildcard access url %q: %w", wu, err)
}
vals.WildcardAccessURL = clibase.URL(*u)
}
}
@@ -513,7 +512,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
appHostname := vals.WildcardAccessURL.String()
var appHostnameRegex *regexp.Regexp
if appHostname != "" {
appHostnameRegex, err = httpapi.CompileHostnamePattern(appHostname)
appHostnameRegex, err = appurl.CompileHostnamePattern(appHostname)
if err != nil {
return xerrors.Errorf("parse wildcard access URL %q: %w", appHostname, err)
}
+13
View File
@@ -29,6 +29,7 @@ import (
"time"
"github.com/go-chi/chi/v5"
"github.com/spf13/pflag"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
@@ -1552,6 +1553,18 @@ func TestServer(t *testing.T) {
// ValueSource is not going to be correct on the `want`, so just
// match that field.
wantConfig.Options[i].ValueSource = gotConfig.Options[i].ValueSource
// If there is a wrapped value with a validator, unwrap it.
// The underlying doesn't compare well since it compares go pointers,
// and not the actual value.
if validator, isValidator := wantConfig.Options[i].Value.(interface{ Underlying() pflag.Value }); isValidator {
wantConfig.Options[i].Value = validator.Underlying()
}
if validator, isValidator := gotConfig.Options[i].Value.(interface{ Underlying() pflag.Value }); isValidator {
gotConfig.Options[i].Value = validator.Underlying()
}
assert.Equal(
t, wantConfig.Options[i],
gotConfig.Options[i],
+1 -1
View File
@@ -167,7 +167,7 @@ NETWORKING OPTIONS:
--secure-auth-cookie bool, $CODER_SECURE_AUTH_COOKIE
Controls if the 'Secure' property is set on browser session cookies.
--wildcard-access-url url, $CODER_WILDCARD_ACCESS_URL
--wildcard-access-url string, $CODER_WILDCARD_ACCESS_URL
Specifies the wildcard hostname to use for workspace applications in
the form "*.example.com".
+2 -2
View File
@@ -4,8 +4,8 @@ networking:
accessURL:
# Specifies the wildcard hostname to use for workspace applications in the form
# "*.example.com".
# (default: <unset>, type: url)
wildcardAccessURL:
# (default: <unset>, type: string)
wildcardAccessURL: ""
# Specifies the custom docs URL.
# (default: <unset>, type: url)
docsURL: