diff --git a/cli/open.go b/cli/open.go index 10a58f1c3693a..ef62e1542d0bf 100644 --- a/cli/open.go +++ b/cli/open.go @@ -301,6 +301,10 @@ func (r *RootCmd) openApp() *serpent.Command { pathAppURL := strings.TrimPrefix(region.PathAppURL, baseURL.String()) appURL := buildAppLinkURL(baseURL, ws, agt, foundApp, region.WildcardHostname, pathAppURL) + if foundApp.External { + appURL = replacePlaceholderExternalSessionTokenString(client, appURL) + } + // Check if we're inside a workspace. Generally, we know // that if we're inside a workspace, `open` can't be used. insideAWorkspace := inv.Environ.Get("CODER") == "true" @@ -314,7 +318,7 @@ func (r *RootCmd) openApp() *serpent.Command { if !testOpenError { err = open.Run(appURL) } else { - err = xerrors.New("test.open-error") + err = xerrors.New("test.open-error: " + appURL) } return err }, @@ -511,3 +515,15 @@ func buildAppLinkURL(baseURL *url.URL, workspace codersdk.Workspace, agent coder } return u.String() } + +// replacePlaceholderExternalSessionTokenString replaces any $SESSION_TOKEN +// strings in the URL with the actual session token. +// This is consistent behavior with the frontend. See: site/src/modules/resources/AppLink/AppLink.tsx +func replacePlaceholderExternalSessionTokenString(client *codersdk.Client, appURL string) string { + if !strings.Contains(appURL, "$SESSION_TOKEN") { + return appURL + } + + // We will just re-use the existing session token we're already using. + return strings.ReplaceAll(appURL, "$SESSION_TOKEN", client.SessionToken()) +} diff --git a/cli/open_test.go b/cli/open_test.go index 23a4316b75c31..e36d20a59aaf4 100644 --- a/cli/open_test.go +++ b/cli/open_test.go @@ -381,4 +381,29 @@ func TestOpenApp(t *testing.T) { w.RequireError() w.RequireContains("region not found") }) + + t.Run("ExternalAppSessionToken", func(t *testing.T) { + t.Parallel() + + client, ws, _ := setupWorkspaceForAgent(t, func(agents []*proto.Agent) []*proto.Agent { + agents[0].Apps = []*proto.App{ + { + Slug: "app1", + Url: "https://example.com/app1?token=$SESSION_TOKEN", + External: true, + }, + } + return agents + }) + inv, root := clitest.New(t, "open", "app", ws.Name, "app1", "--test.open-error") + clitest.SetupConfig(t, client, root) + pty := ptytest.New(t) + inv.Stdin = pty.Input() + inv.Stdout = pty.Output() + + w := clitest.StartWithWaiter(t, inv) + w.RequireError() + w.RequireContains("test.open-error") + w.RequireContains(client.SessionToken()) + }) }
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: