Time out stalled GitHub clones after ten minutes
Progress streams now stay open until a job ends, so a hung clone would otherwise hold its job and stream forever.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
@@ -178,8 +179,8 @@ func (s *Server) githubAuthFor(sid string) githubAuth {
|
|||||||
|
|
||||||
// gitClone builds the clone command. The token travels in environment-provided git config,
|
// gitClone builds the clone command. The token travels in environment-provided git config,
|
||||||
// never in the URL or arguments, so it cannot leak through process lists or error output.
|
// never in the URL or arguments, so it cannot leak through process lists or error output.
|
||||||
func gitClone(repoURL, dest, token string) *exec.Cmd {
|
func gitClone(ctx context.Context, repoURL, dest, token string) *exec.Cmd {
|
||||||
cmd := exec.Command("git", "clone", "--depth=1", "--single-branch", "--quiet", "--", repoURL, dest)
|
cmd := exec.CommandContext(ctx, "git", "clone", "--depth=1", "--single-branch", "--quiet", "--", repoURL, dest)
|
||||||
// Ignore the host's git config and credential helpers: only the visitor's own token may
|
// Ignore the host's git config and credential helpers: only the visitor's own token may
|
||||||
// ever authenticate a clone.
|
// ever authenticate a clone.
|
||||||
cmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0", "GIT_CONFIG_NOSYSTEM=1", "GIT_CONFIG_GLOBAL=/dev/null",
|
cmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0", "GIT_CONFIG_NOSYSTEM=1", "GIT_CONFIG_GLOBAL=/dev/null",
|
||||||
|
|||||||
+1
-1
@@ -135,7 +135,7 @@ func TestGitCloneKeepsTokenOutOfArgsAndIgnoresHostCredentials(t *testing.T) {
|
|||||||
if _, err := exec.LookPath("git"); err != nil {
|
if _, err := exec.LookPath("git"); err != nil {
|
||||||
t.Skip("git not installed")
|
t.Skip("git not installed")
|
||||||
}
|
}
|
||||||
cmd := gitClone("https://github.com/o/r", t.TempDir(), "ghu_secret")
|
cmd := gitClone(t.Context(), "https://github.com/o/r", t.TempDir(), "ghu_secret")
|
||||||
if strings.Contains(strings.Join(cmd.Args, " "), "ghu_secret") {
|
if strings.Contains(strings.Join(cmd.Args, " "), "ghu_secret") {
|
||||||
t.Fatal("token appears in git arguments")
|
t.Fatal("token appears in git arguments")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"embed"
|
"embed"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -49,6 +50,7 @@ const (
|
|||||||
idleExpiry = time.Hour // snapshots unused and jobs untouched for this long are dropped
|
idleExpiry = time.Hour // snapshots unused and jobs untouched for this long are dropped
|
||||||
maxSnapshots = 8 // ponytail: fixed caps sized for the 2GB container; make them configurable if memory changes
|
maxSnapshots = 8 // ponytail: fixed caps sized for the 2GB container; make them configurable if memory changes
|
||||||
maxIndexing = 2 // concurrent index runs; each already uses every CPU
|
maxIndexing = 2 // concurrent index runs; each already uses every CPU
|
||||||
|
cloneTimeout = 10 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
var sseKeepAlive = 15 * time.Second // variable so tests can shorten it
|
var sseKeepAlive = 15 * time.Second // variable so tests can shorten it
|
||||||
@@ -186,9 +188,14 @@ func (s *Server) createJob(w http.ResponseWriter, r *http.Request) {
|
|||||||
token := s.githubAuthFor(owner).token
|
token := s.githubAuthFor(owner).token
|
||||||
go func() {
|
go func() {
|
||||||
checkout := filepath.Join(root, "repo")
|
checkout := filepath.Join(root, "repo")
|
||||||
output, err := gitClone(url, checkout, token).CombinedOutput()
|
ctx, cancel := context.WithTimeout(context.Background(), cloneTimeout)
|
||||||
|
output, err := gitClone(ctx, url, checkout, token).CombinedOutput()
|
||||||
|
cancel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
text := string(output)
|
text := string(output)
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
text = "timed out after " + cloneTimeout.String()
|
||||||
|
}
|
||||||
if token != "" {
|
if token != "" {
|
||||||
text = strings.ReplaceAll(text, token, "***")
|
text = strings.ReplaceAll(text, token, "***")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user