Diff
1diff --git a/pkg/web/git.go b/pkg/web/git.go
2index 5083d83c02d61abea32aeb2cdfc3d1e1460468c9..6f6d73469e80d3248c0546d4a7bef2652ed6e1f8 100644
3--- a/pkg/web/git.go
4+++ b/pkg/web/git.go
5@@ -347,17 +347,24 @@ func withAccess(next http.Handler) http.HandlerFunc {
6 }
7
8 case service == git.ReceivePackService:
9+ if badCredentials(err) {
10+ renderForbidden(w, r)
11+ return
12+ }
13+
14 if accessLevel < access.ReadWriteAccess {
15 askCredentials(w, r)
16 renderUnauthorized(w, r)
17 return
18 }
19
20- // Create the repo if it doesn't exist.
21- if repo == nil {
22- repo, err = be.CreateRepository(ctx, repoName, user, proto.RepositoryOptions{})
23- if err != nil {
24- logger.Error("failed to create repository", "repo", repoName, "err", err)
25+ // Create the repo if it doesn't exist, but only from the push
26+ // endpoints, not from any route that carries the service param.
27+ if repo == nil && (file == "info/refs" || file == git.ReceivePackService.String()) {
28+ var cerr error
29+ repo, cerr = be.CreateRepository(ctx, repoName, user, proto.RepositoryOptions{})
30+ if cerr != nil {
31+ logger.Error("failed to create repository", "repo", repoName, "err", cerr)
32 renderInternalServerError(w, r)
33 return
34 }
35diff --git a/testscript/testdata/http-push-create.txtar b/testscript/testdata/http-push-create.txtar
36new file mode 100644
37index 0000000000000000000000000000000000000000..444868a0059a32ceb6d0f84f3931d677c65a61b6
38--- /dev/null
39+++ b/testscript/testdata/http-push-create.txtar
40@@ -0,0 +1,29 @@
41+# vi: set ft=conf
42+
43+# FIXME: don't skip windows
44+[windows] skip 'curl makes github actions hang'
45+
46+# start soft serve
47+exec soft serve &
48+# wait for SSH server to start
49+ensureserverrunning SSH_PORT
50+
51+soft settings anon-access read-write
52+
53+# bad credentials never create a repository
54+curl http://bob:wrong@localhost:$HTTP_PORT/ghost1.git/info/refs?service=git-receive-pack
55+stdout '403.*'
56+
57+# only the push endpoints create repositories
58+curl http://localhost:$HTTP_PORT/ghost2.git/HEAD?service=git-receive-pack
59+
60+# the push advertisement still creates one
61+curl http://localhost:$HTTP_PORT/ghost3.git/info/refs?service=git-receive-pack
62+soft repo list
63+stdout 'ghost3'
64+! stdout 'ghost1'
65+! stdout 'ghost2'
66+
67+# stop the server
68+[windows] stopserver
69+[windows] ! stderr .