fix: allow ports in wildcard url configuration (#11657)

* fix: allow ports in wildcard url configuration

This just forwards the port to the ui that generates urls.
Our existing parsing + regex already supported ports for
subdomain app requests.
This commit is contained in:
Steven Masley
2024-01-18 09:44:05 -06:00
committed by GitHub
parent 1f0e6ba6c6
commit 6bb1a34a37
12 changed files with 203 additions and 31 deletions
+14 -9
View File
@@ -3,7 +3,6 @@ package agentapi
import (
"context"
"database/sql"
"fmt"
"net/url"
"strings"
"sync/atomic"
@@ -108,19 +107,14 @@ func (a *ManifestAPI) GetManifest(ctx context.Context, _ *agentproto.GetManifest
return nil, xerrors.Errorf("fetching workspace agent data: %w", err)
}
appHost := appurl.ApplicationURL{
appSlug := appurl.ApplicationURL{
AppSlugOrPort: "{{port}}",
AgentName: workspaceAgent.Name,
WorkspaceName: workspace.Name,
Username: owner.Username,
}
vscodeProxyURI := a.AccessURL.Scheme + "://" + strings.ReplaceAll(a.AppHostname, "*", appHost.String())
if a.AppHostname == "" {
vscodeProxyURI += a.AccessURL.Hostname()
}
if a.AccessURL.Port() != "" {
vscodeProxyURI += fmt.Sprintf(":%s", a.AccessURL.Port())
}
vscodeProxyURI := vscodeProxyURI(appSlug, a.AccessURL, a.AppHostname)
var gitAuthConfigs uint32
for _, cfg := range a.ExternalAuthConfigs {
@@ -155,6 +149,17 @@ func (a *ManifestAPI) GetManifest(ctx context.Context, _ *agentproto.GetManifest
}, nil
}
func vscodeProxyURI(app appurl.ApplicationURL, accessURL *url.URL, appHost string) string {
// This will handle the ports from the accessURL or appHost.
appHost = appurl.SubdomainAppHost(appHost, accessURL)
// If there is no appHost, then we want to use the access url as the proxy uri.
if appHost == "" {
appHost = accessURL.Host
}
// Return the url with a scheme and any wildcards replaced with the app slug.
return accessURL.Scheme + "://" + strings.ReplaceAll(appHost, "*", app.String())
}
func dbAgentMetadataToProtoDescription(metadata []database.WorkspaceAgentMetadatum) []*agentproto.WorkspaceAgentMetadata_Description {
ret := make([]*agentproto.WorkspaceAgentMetadata_Description, len(metadata))
for i, metadatum := range metadata {
+94
View File
@@ -0,0 +1,94 @@
package agentapi
import (
"fmt"
"net/url"
"testing"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/coderd/workspaceapps/appurl"
)
func Test_vscodeProxyURI(t *testing.T) {
t.Parallel()
coderAccessURL, err := url.Parse("https://coder.com")
require.NoError(t, err)
accessURLWithPort, err := url.Parse("https://coder.com:8080")
require.NoError(t, err)
basicApp := appurl.ApplicationURL{
Prefix: "prefix",
AppSlugOrPort: "slug",
AgentName: "agent",
WorkspaceName: "workspace",
Username: "user",
}
cases := []struct {
Name string
App appurl.ApplicationURL
AccessURL *url.URL
AppHostname string
Expected string
}{
{
// No hostname proxies through the access url.
Name: "NoHostname",
AccessURL: coderAccessURL,
AppHostname: "",
App: basicApp,
Expected: coderAccessURL.String(),
},
{
Name: "NoHostnameAccessURLPort",
AccessURL: accessURLWithPort,
AppHostname: "",
App: basicApp,
Expected: accessURLWithPort.String(),
},
{
Name: "Hostname",
AccessURL: coderAccessURL,
AppHostname: "*.apps.coder.com",
App: basicApp,
Expected: fmt.Sprintf("https://%s.apps.coder.com", basicApp.String()),
},
{
Name: "HostnameWithAccessURLPort",
AccessURL: accessURLWithPort,
AppHostname: "*.apps.coder.com",
App: basicApp,
Expected: fmt.Sprintf("https://%s.apps.coder.com:%s", basicApp.String(), accessURLWithPort.Port()),
},
{
Name: "HostnameWithPort",
AccessURL: coderAccessURL,
AppHostname: "*.apps.coder.com:4444",
App: basicApp,
Expected: fmt.Sprintf("https://%s.apps.coder.com:%s", basicApp.String(), "4444"),
},
{
// Port from hostname takes precedence over access url port.
Name: "HostnameWithPortAccessURLWithPort",
AccessURL: accessURLWithPort,
AppHostname: "*.apps.coder.com:4444",
App: basicApp,
Expected: fmt.Sprintf("https://%s.apps.coder.com:%s", basicApp.String(), "4444"),
},
}
for _, c := range cases {
c := c
t.Run(c.Name, func(t *testing.T) {
t.Parallel()
require.NotNilf(t, c.AccessURL, "AccessURL is required")
output := vscodeProxyURI(c.App, c.AccessURL, c.AppHostname)
require.Equal(t, c.Expected, output)
})
}
}