all repos

mugit @ 3d9ab8a0e8b7a5eb03fb193389aa71eeb4b21327

馃惍 git server that your cow will love
2 files changed, 39 insertions(+), 15 deletions(-)
improve error messaging in ssh
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-01-21 01:49:14 +0200
Authored at: 2026-01-21 00:50:01 +0200
Change ID: nnnnrqovvonmukovzpopkpqyvmzwkvtn
Parent: a00560c
M internal/git/gitservice/gitservice.go
路路路
        29
        29
         		return fmt.Errorf("start git-upload-pack: %w", err)

      
        30
        30
         	}

      
        31
        31
         

      
        32
        
        -	if err := packLine(out, "# service=git-upload-pack\n"); err != nil {

      
        
        32
        +	if err := PackLine(out, "# service=git-upload-pack\n"); err != nil {

      
        33
        33
         		return fmt.Errorf("write pack line: %w", err)

      
        34
        34
         	}

      
        35
        
        -	if err := packFlush(out); err != nil {

      
        
        35
        +	if err := PackFlush(out); err != nil {

      
        36
        36
         		return fmt.Errorf("flush pack: %w", err)

      
        37
        37
         	}

      
        38
        38
         

      路路路
        64
        64
         	})

      
        65
        65
         }

      
        66
        66
         

      
        67
        
        -func ReceivePack(dir string, in io.Reader, out io.Writer) error {

      
        
        67
        +func ReceivePack(dir string, in io.Reader, out, stderr io.Writer) error {

      
        68
        68
         	return gitCmd("receive-pack", config{

      
        69
        69
         		Dir:    dir,

      
        70
        70
         		Stdin:  in,

      
        71
        71
         		Stdout: out,

      
        
        72
        +		Stderr: stderr,

      
        72
        73
         	})

      
        73
        74
         }

      
        74
        75
         

      路路路
        79
        80
         	ExtraArgs    []string

      
        80
        81
         	Stdin        io.Reader

      
        81
        82
         	Stdout       io.Writer

      
        
        83
        +	Stderr       io.Writer

      
        82
        84
         }

      
        83
        85
         

      
        84
        86
         func gitCmd(service string, c config) error {

      路路路
        115
        117
         	if err != nil {

      
        116
        118
         		return err

      
        117
        119
         	}

      
        118
        
        -	cmd.Stderr = cmd.Stdout

      
        
        120
        +	if c.Stderr != nil {

      
        
        121
        +		cmd.Stderr = c.Stderr

      
        
        122
        +	} else {

      
        
        123
        +		cmd.Stderr = cmd.Stdout

      
        
        124
        +	}

      
        119
        125
         

      
        120
        126
         	if err := cmd.Start(); err != nil {

      
        121
        127
         		return fmt.Errorf("start %s: %w", service, err)

      路路路
        149
        155
         	return nil

      
        150
        156
         }

      
        151
        157
         

      
        152
        
        -func packLine(w io.Writer, s string) error {

      
        
        158
        +// PackLine writes a pkt-line formatted string.

      
        
        159
        +func PackLine(w io.Writer, s string) error {

      
        153
        160
         	_, err := fmt.Fprintf(w, "%04x%s", len(s)+4, s)

      
        154
        161
         	return err

      
        155
        162
         }

      
        156
        163
         

      
        157
        
        -func packFlush(w io.Writer) error {

      
        
        164
        +// PackFlush writes a flush packet.

      
        
        165
        +func PackFlush(w io.Writer) error {

      
        158
        166
         	_, err := fmt.Fprint(w, "0000")

      
        159
        167
         	return err

      
        160
        168
         }

      
        
        169
        +

      
        
        170
        +// PackSideband writes a message to sideband channel (displays as "remote: <msg>" in git client).

      
        
        171
        +// Channel 2 = progress/info, Channel 3 = error.

      
        
        172
        +func PackSideband(w io.Writer, channel byte, msg string) error {

      
        
        173
        +	return PackLine(w, string(channel)+msg)

      
        
        174
        +}

      
        
        175
        +

      
        
        176
        +// PackError writes an ERR packet for protocol-level errors.

      
        
        177
        +// Git displays this as: fatal: remote error: <msg>

      
        
        178
        +func PackError(w io.Writer, msg string) error {

      
        
        179
        +	return PackLine(w, "ERR "+msg)

      
        
        180
        +}

      
M internal/ssh/server.go
路路路
        81
        81
         	repoPath = filepath.Join(s.c.Repo.Dir, filepath.Clean(repoPath))

      
        82
        82
         	_, err := git.Open(repoPath, "")

      
        83
        83
         	if err != nil {

      
        84
        
        -		s.error(sess, err)

      
        
        84
        +		slog.Error("ssh: failed to open repo", "err", err)

      
        
        85
        +		s.repoNotFound(sess)

      
        85
        86
         		return

      
        86
        87
         	}

      
        87
        
        -

      
        88
        
        -	fmt.Println(repoPath)

      
        89
        88
         

      
        90
        89
         	switch gitCmd {

      
        91
        90
         	case "git-upload-pack":

      路路路
        96
        95
         		sess.Exit(0)

      
        97
        96
         	case "git-receive-pack":

      
        98
        97
         		if !authorized {

      
        99
        
        -			s.repoNotFound(sess)

      
        
        98
        +			s.unauthorized(sess)

      
        100
        99
         			return

      
        101
        100
         		}

      
        102
        101
         

      
        103
        
        -		if err := gitservice.ReceivePack(repoPath, sess, sess); err != nil {

      
        
        102
        +		if err := gitservice.ReceivePack(repoPath, sess, sess, sess.Stderr()); err != nil {

      
        104
        103
         			s.error(sess, err)

      
        105
        104
         			return

      
        106
        105
         		}

      路路路
        108
        107
         

      
        109
        108
         	default:

      
        110
        109
         		slog.Error("ssh unsupported command", "cmd", cmd)

      
        111
        
        -		fmt.Fprintln(sess, "Unsupported command")

      
        
        110
        +		gitservice.PackError(sess, "Unsupported command.")

      
        112
        111
         		sess.Exit(1)

      
        113
        112
         	}

      
        114
        113
         }

      路路路
        127
        126
         }

      
        128
        127
         

      
        129
        128
         func (s *Server) repoNotFound(sess ssh.Session) {

      
        130
        
        -	fmt.Fprintln(sess, "Sorry but repo you're looking for is not found.")

      
        
        129
        +	gitservice.PackError(sess, "Repository not found.")

      
        
        130
        +	sess.Exit(1)

      
        
        131
        +}

      
        
        132
        +

      
        
        133
        +func (s *Server) unauthorized(sess ssh.Session) {

      
        
        134
        +	gitservice.PackError(sess, "You are not authorized to push to this repository.")

      
        131
        135
         	sess.Exit(1)

      
        132
        136
         }

      
        133
        137
         

      
        134
        138
         func (s *Server) error(sess ssh.Session, err error) {

      
        135
        
        -	fmt.Fprintln(sess, "unexpected server error")

      
        136
        
        -	sess.Exit(1)

      
        137
        139
         	slog.Error("error on ssh side", "err", err)

      
        
        140
        +	gitservice.PackError(sess, "Unexpected server error.")

      
        
        141
        +	sess.Exit(1)

      
        138
        142
         }