fix(cli): replace $SESSION_TOKEN placeholder for external apps (#17048)

Fixes an oversight in https://github.com/coder/coder/pull/17032

The FE has logic to replace the string `$SESSION_TOKEN` with a
newly-minted session token.
This adds corresponding logic to the `coder open app` command.
This commit is contained in:
Cian Johnston
2025-03-24 09:03:30 +00:00
committed by GitHub
parent 77fe10ead8
commit 674f60fc5b
2 changed files with 42 additions and 1 deletions

View File

@ -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())
}

View File

@ -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())
})
}