Diff
1diff --git a/server/git/errors.go b/server/git/errors.go
2new file mode 100644
3index 0000000000000000000000000000000000000000..fa4a8bda254f4920718807f3cecf3989936616a4
4--- /dev/null
5+++ b/server/git/errors.go
6@@ -0,0 +1,23 @@
7+package git
8+
9+import "errors"
10+
11+var (
12+ // ErrNotAuthed represents unauthorized access.
13+ ErrNotAuthed = errors.New("you are not authorized to do this")
14+
15+ // ErrSystemMalfunction represents a general system error returned to clients.
16+ ErrSystemMalfunction = errors.New("something went wrong")
17+
18+ // ErrInvalidRepo represents an attempt to access a non-existent repo.
19+ ErrInvalidRepo = errors.New("invalid repo")
20+
21+ // ErrInvalidRequest represents an invalid request.
22+ ErrInvalidRequest = errors.New("invalid request")
23+
24+ // ErrMaxConnections represents a maximum connection limit being reached.
25+ ErrMaxConnections = errors.New("too many connections, try again later")
26+
27+ // ErrTimeout is returned when the maximum read timeout is exceeded.
28+ ErrTimeout = errors.New("I/O timeout reached")
29+)
30diff --git a/server/git/git.go b/server/git/git.go
31index e0f1e664ba43dde68c35d652088c89aa1c1dcb03..8baa54a3282226b37e0bdfe8cae988bbf6274873 100644
32--- a/server/git/git.go
33+++ b/server/git/git.go
34@@ -2,7 +2,6 @@ package git
35
36 import (
37 "context"
38- "errors"
39 "fmt"
40 "io"
41 "path/filepath"
42@@ -14,27 +13,6 @@ import (
43 gitm "github.com/gogs/git-module"
44 )
45
46-var (
47-
48- // ErrNotAuthed represents unauthorized access.
49- ErrNotAuthed = errors.New("you are not authorized to do this")
50-
51- // ErrSystemMalfunction represents a general system error returned to clients.
52- ErrSystemMalfunction = errors.New("something went wrong")
53-
54- // ErrInvalidRepo represents an attempt to access a non-existent repo.
55- ErrInvalidRepo = errors.New("invalid repo")
56-
57- // ErrInvalidRequest represents an invalid request.
58- ErrInvalidRequest = errors.New("invalid request")
59-
60- // ErrMaxConnections represents a maximum connection limit being reached.
61- ErrMaxConnections = errors.New("too many connections, try again later")
62-
63- // ErrTimeout is returned when the maximum read timeout is exceeded.
64- ErrTimeout = errors.New("I/O timeout reached")
65-)
66-
67 // WritePktline encodes and writes a pktline to the given writer.
68 func WritePktline(w io.Writer, v ...interface{}) error {
69 msg := fmt.Sprintln(v...)
70diff --git a/server/git/service.go b/server/git/service.go
71index fb5dbf5acb5340174d178d2fb3c20f38cf4a7098..e0d6877b736c24aeef3754a7ab88c8a5ff8565d7 100644
72--- a/server/git/service.go
73+++ b/server/git/service.go
74@@ -9,7 +9,6 @@ import (
75 "os/exec"
76 "strings"
77
78- "github.com/charmbracelet/log"
79 "golang.org/x/sync/errgroup"
80 )
81
82@@ -112,7 +111,6 @@ func gitServiceHandler(ctx context.Context, svc Service, scmd ServiceCommand) er
83 }
84 }
85
86- log.Debugf("git service command in %q: %s", cmd.Dir, cmd.String())
87 if err := cmd.Start(); err != nil {
88 if errors.Is(err, os.ErrNotExist) {
89 return ErrInvalidRepo
90diff --git a/server/ssh/cmd/git.go b/server/ssh/cmd/git.go
91index d2886514a9b4b7a8d7c9b0fbf752804353dbc5d8..b40b53fa14a0a9b68e49c963b5fb56e12e298652 100644
92--- a/server/ssh/cmd/git.go
93+++ b/server/ssh/cmd/git.go
94@@ -209,16 +209,17 @@ func gitRunE(cmd *cobra.Command, args []string) error {
95
96 repoPath := filepath.Join(reposDir, repoDir)
97 service := git.Service(cmd.Name())
98+ stdin := cmd.InOrStdin()
99+ stdout := cmd.OutOrStdout()
100+ stderr := cmd.ErrOrStderr()
101 scmd := git.ServiceCommand{
102- Stdin: cmd.InOrStdin(),
103- Stdout: s,
104- Stderr: s.Stderr(),
105+ Stdin: stdin,
106+ Stdout: stdout,
107+ Stderr: stderr,
108 Env: envs,
109 Dir: repoPath,
110 }
111
112- logger.Debug("git middleware", "cmd", service, "access", accessLevel.String())
113-
114 switch service {
115 case git.ReceivePackService:
116 receivePackCounter.WithLabelValues(name).Inc()
117@@ -237,16 +238,19 @@ func gitRunE(cmd *cobra.Command, args []string) error {
118 }
119
120 if err := service.Handler(ctx, scmd); err != nil {
121+ logger.Error("failed to handle git service", "service", service, "err", err, "repo", name)
122 defer func() {
123 if repo == nil {
124 // If the repo was created, but the request failed, delete it.
125 be.DeleteRepository(ctx, name) // nolint: errcheck
126 }
127 }()
128+
129 return git.ErrSystemMalfunction
130 }
131
132 if err := git.EnsureDefaultBranch(ctx, scmd); err != nil {
133+ logger.Error("failed to ensure default branch", "err", err, "repo", name)
134 return git.ErrSystemMalfunction
135 }
136
137@@ -279,7 +283,7 @@ func gitRunE(cmd *cobra.Command, args []string) error {
138 if errors.Is(err, git.ErrInvalidRepo) {
139 return git.ErrInvalidRepo
140 } else if err != nil {
141- logger.Error("git middleware", "err", err)
142+ logger.Error("failed to handle git service", "service", service, "err", err, "repo", name)
143 return git.ErrSystemMalfunction
144 }
145
146@@ -322,7 +326,7 @@ func gitRunE(cmd *cobra.Command, args []string) error {
147 }
148
149 if err := service.Handler(ctx, scmd); err != nil {
150- logger.Error("git middleware", "err", err)
151+ logger.Error("failed to handle lfs service", "service", service, "err", err, "repo", name)
152 return git.ErrSystemMalfunction
153 }
154
155diff --git a/server/ssh/middleware.go b/server/ssh/middleware.go
156index 209ed1dd048a275c159125772d5a0a9ca2fea2b0..9a387f49b50f6d3f206a201d6b81905953275c30 100644
157--- a/server/ssh/middleware.go
158+++ b/server/ssh/middleware.go
159@@ -1,6 +1,9 @@
160 package ssh
161
162 import (
163+ "fmt"
164+ "time"
165+
166 "github.com/charmbracelet/log"
167 "github.com/charmbracelet/soft-serve/server/backend"
168 "github.com/charmbracelet/soft-serve/server/config"
169@@ -49,7 +52,6 @@ func CommandMiddleware(sh ssh.Handler) ssh.Handler {
170
171 ctx := s.Context()
172 cfg := config.FromContext(ctx)
173- logger := log.FromContext(ctx)
174
175 args := s.Command()
176 cliCommandCounter.WithLabelValues(cmd.CommandName(args)).Inc()
177@@ -110,7 +112,6 @@ func CommandMiddleware(sh ssh.Handler) ssh.Handler {
178 }
179
180 if err := rootCmd.ExecuteContext(ctx); err != nil {
181- logger.Error("error executing command", "err", err)
182 s.Exit(1) // nolint: errcheck
183 return
184 }
185@@ -118,3 +119,49 @@ func CommandMiddleware(sh ssh.Handler) ssh.Handler {
186 sh(s)
187 }
188 }
189+
190+// LoggingMiddleware logs the ssh connection and command.
191+func LoggingMiddleware(sh ssh.Handler) ssh.Handler {
192+ return func(s ssh.Session) {
193+ ctx := s.Context()
194+ logger := log.FromContext(ctx).WithPrefix("ssh")
195+ ct := time.Now()
196+ hpk := sshutils.MarshalAuthorizedKey(s.PublicKey())
197+ ptyReq, _, isPty := s.Pty()
198+ addr := s.RemoteAddr().String()
199+ user := proto.UserFromContext(ctx)
200+ logArgs := []interface{}{
201+ "addr",
202+ addr,
203+ "cmd",
204+ s.Command(),
205+ }
206+
207+ if user != nil {
208+ logArgs = append([]interface{}{
209+ "username",
210+ user.Username(),
211+ }, logArgs...)
212+ }
213+
214+ if isPty {
215+ logArgs = []interface{}{
216+ "term", ptyReq.Term,
217+ "width", ptyReq.Window.Width,
218+ "height", ptyReq.Window.Height,
219+ }
220+ }
221+
222+ if config.IsVerbose() {
223+ logArgs = append(logArgs,
224+ "key", hpk,
225+ "envs", s.Environ(),
226+ )
227+ }
228+
229+ msg := fmt.Sprintf("user %q", s.User())
230+ logger.Debug(msg+" connected", logArgs...)
231+ sh(s)
232+ logger.Debug(msg+" disconnected", append(logArgs, "duration", time.Since(ct))...)
233+ }
234+}
235diff --git a/server/ssh/ssh.go b/server/ssh/ssh.go
236index bd4fd4a899d2831886050a043056ba9779be2ae1..d02824da59c88a2383639e037db278f9c78f114b 100644
237--- a/server/ssh/ssh.go
238+++ b/server/ssh/ssh.go
239@@ -18,7 +18,6 @@ import (
240 "github.com/charmbracelet/ssh"
241 "github.com/charmbracelet/wish"
242 bm "github.com/charmbracelet/wish/bubbletea"
243- lm "github.com/charmbracelet/wish/logging"
244 rm "github.com/charmbracelet/wish/recover"
245 "github.com/muesli/termenv"
246 "github.com/prometheus/client_golang/prometheus"
247@@ -74,12 +73,10 @@ func NewSSHServer(ctx context.Context) (*SSHServer, error) {
248 bm.MiddlewareWithProgramHandler(SessionHandler, termenv.ANSI256),
249 // CLI middleware.
250 CommandMiddleware,
251+ // Logging middleware.
252+ LoggingMiddleware,
253 // Context middleware.
254 ContextMiddleware(cfg, dbx, datastore, be, logger),
255- // Logging middleware.
256- lm.MiddlewareWithLogger(
257- &loggerAdapter{logger, log.DebugLevel},
258- ),
259 ),
260 }
261
262diff --git a/server/web/git.go b/server/web/git.go
263index 121b85795d2e4a0dfa7aa2dafd6f6e0c8990b5ea..4d4dde8b2f4df382eac9b7328cdd92af7bb34f95 100644
264--- a/server/web/git.go
265+++ b/server/web/git.go
266@@ -75,7 +75,6 @@ var (
267 func withParams(h http.Handler) http.Handler {
268 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
269 ctx := r.Context()
270- logger := log.FromContext(ctx)
271 cfg := config.FromContext(ctx)
272 vars := mux.Vars(r)
273 repo := vars["repo"]