Skip to content

Commit 0b4eacd

Browse files
committed
fix(coderd): don't hang on first gitauth clone
Previously, the `coder git ssh` command would hang on the API, which was endlessly polling the database for oauth tokens that expire in the future. Some oAuth implementations (including GitHub by default) will not give back a token expiry date, and the absence of a token expiry date became the zero date in the database. Follow-up calls to `git clone` would succeed because the non-listen path doesn't check expiry, perhaps by mistake. In addition to fixing the zero date issue, this PR removes the PubSub which added too much complexity when the polling interval is 1 second.
1 parent d3a9d7c commit 0b4eacd

File tree

1 file changed

+9
-38
lines changed

1 file changed

+9
-38
lines changed

coderd/workspaceagents.go

+9-38
Original file line numberDiff line numberDiff line change
@@ -1737,40 +1737,15 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request)
17371737
}
17381738

17391739
if listen {
1740-
// If listening we await a new token...
1741-
authChan := make(chan struct{}, 1)
1742-
cancelFunc, err := api.Pubsub.Subscribe("gitauth", func(ctx context.Context, message []byte) {
1743-
ids := strings.Split(string(message), "|")
1744-
if len(ids) != 2 {
1745-
return
1746-
}
1747-
if ids[0] != gitAuthConfig.ID {
1748-
return
1749-
}
1750-
if ids[1] != workspace.OwnerID.String() {
1751-
return
1752-
}
1753-
select {
1754-
case authChan <- struct{}{}:
1755-
default:
1756-
}
1757-
})
1758-
if err != nil {
1759-
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
1760-
Message: "Failed to listen for git auth token.",
1761-
Detail: err.Error(),
1762-
})
1763-
return
1764-
}
1765-
defer cancelFunc()
1740+
// Since we're ticking frequently and this sign-in operation is rare,
1741+
// we are OK with polling to avoid the complexity of pubsub.
17661742
ticker := time.NewTicker(time.Second)
17671743
defer ticker.Stop()
17681744
for {
17691745
select {
17701746
case <-ctx.Done():
17711747
return
17721748
case <-ticker.C:
1773-
case <-authChan:
17741749
}
17751750
gitAuthLink, err := api.Database.GetGitAuthLink(ctx, database.GetGitAuthLinkParams{
17761751
ProviderID: gitAuthConfig.ID,
@@ -1786,7 +1761,12 @@ func (api *API) workspaceAgentsGitAuth(rw http.ResponseWriter, r *http.Request)
17861761
})
17871762
return
17881763
}
1789-
if gitAuthLink.OAuthExpiry.Before(database.Now()) {
1764+
1765+
// Expiry may be unset if the application doesn't configure tokens
1766+
// to expire.
1767+
// See
1768+
// https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app.
1769+
if gitAuthLink.OAuthExpiry.Before(database.Now()) && !gitAuthLink.OAuthExpiry.IsZero() {
17901770
continue
17911771
}
17921772
if gitAuthConfig.ValidateURL != "" {
@@ -1932,20 +1912,11 @@ func (api *API) gitAuthCallback(gitAuthConfig *gitauth.Config) http.HandlerFunc
19321912
}
19331913
}
19341914

1935-
err = api.Pubsub.Publish("gitauth", []byte(fmt.Sprintf("%s|%s", gitAuthConfig.ID, apiKey.UserID)))
1936-
if err != nil {
1937-
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
1938-
Message: "Failed to publish auth update.",
1939-
Detail: err.Error(),
1940-
})
1941-
return
1942-
}
1943-
19441915
redirect := state.Redirect
19451916
if redirect == "" {
1917+
// This is a nicely rendered screen on the frontend
19461918
redirect = "/gitauth"
19471919
}
1948-
// This is a nicely rendered screen on the frontend
19491920
http.Redirect(rw, r, redirect, http.StatusTemporaryRedirect)
19501921
}
19511922
}

0 commit comments

Comments
 (0)