Monorepo for Tangled tangled.org
1

Configure Feed

Select the types of activity you want to include in your feed.

knotserver/git: validate fork source

Signed-off-by: Seongmin Lee <git@boltless.me>

+51 -1
+16 -1
knotserver/git/fork.go
··· 23 23 // post-clone configure step in sb. The initial clone itself is not sandboxed 24 24 // because the target directory doesn't exist yet when the ruleset is applied. 25 25 func ForkWithSandbox(repoPath, source string, cfg *knotconfig.Config, sb sandbox.Backend) error { 26 + if !(source == "" || source[0] != '-') { 27 + return fmt.Errorf("invalid source: %q", source) 28 + } 26 29 u, err := url.Parse(source) 27 30 if err != nil { 28 31 return fmt.Errorf("failed to parse source URL: %w", err) 32 + } 33 + if u.Scheme != "https" && u.Scheme != "http" { 34 + return fmt.Errorf("invalid scheme: %q", u.Scheme) 35 + } 36 + if u.Host == "" { 37 + return fmt.Errorf("missing host: %q", source) 29 38 } 30 39 31 40 if o := optimizeClone(u, cfg); o != nil { 32 41 u = o 33 42 } 34 43 35 - cloneCmd := exec.Command("git", "clone", "--bare", u.String(), repoPath) 44 + cloneCmd := exec.Command( 45 + "git", 46 + "-c", "protocol.ext.allow=never", 47 + "clone", "--bare", u.String(), repoPath, 48 + ) 49 + cloneCmd.Env = append(cloneCmd.Env, "GIT_PROTOCOL_FROM_USER=0") 50 + cloneCmd.Env = append(cloneCmd.Env, "GIT_TERMINAL_PROMPT=0") 36 51 if err := cloneCmd.Run(); err != nil { 37 52 return fmt.Errorf("failed to bare clone repository: %w", err) 38 53 }
+33
knotserver/git/fork_test.go
··· 1 + package git 2 + 3 + import ( 4 + "os" 5 + "path/filepath" 6 + "testing" 7 + 8 + "github.com/stretchr/testify/assert" 9 + knotconfig "tangled.org/core/knotserver/config" 10 + ) 11 + 12 + func TestForkRejectsUnsafeSources(t *testing.T) { 13 + t.Parallel() 14 + 15 + for _, source := range []string{ 16 + "", 17 + "--upload-pack=touch /tmp/pwned", 18 + "-u/bin/sh", 19 + "ext::sh -c touch% /tmp/pwned", 20 + "file:///etc/passwd", 21 + "git://example.com/repo", 22 + "ssh://example.com/repo", 23 + "/etc/passwd", 24 + } { 25 + t.Run(source, func(t *testing.T) { 26 + repoPath := filepath.Join(t.TempDir(), "fork") 27 + err := Fork(repoPath, source, &knotconfig.Config{}) 28 + assert.Error(t, err, "source %q should be rejected", source) 29 + _, statErr := os.Stat(repoPath) 30 + assert.True(t, os.IsNotExist(statErr), "source %q must not create a repo", source) 31 + }) 32 + } 33 + }
+2
localinfra/knot.Dockerfile
··· 96 96 VOLUME /home/git 97 97 EXPOSE 22 5555 98 98 99 + WORKDIR /home/git 100 + 99 101 ENTRYPOINT ["/sbin/tini", "--"] 100 102 CMD ["/usr/local/bin/knot-entrypoint.sh"]