all repos

mugit @ 7218955

🐮 git server that your cow will love

mugit/internal/ssh/ssh_test.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
ssh: make sure there's no shell injections with SSH_ORIGINAL_COMMAND, 1 month ago
1
package ssh
2
3
import (
4
	"strings"
5
	"testing"
6
7
	"olexsmir.xyz/mugit/internal/config"
8
	"olexsmir.xyz/x/is"
9
)
10
11
var validKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl"
12
13
func TestNewShell(t *testing.T) {
14
	tests := []struct {
15
		name    string
16
		keys    []string
17
		wantErr string
18
	}{
19
		{"valid key", []string{validKey}, ""},
20
		{"invalid key", []string{"invalid-key"}, "ssh: no key found"},
21
		{"multiple keys", []string{validKey, validKey}, ""},
22
		{"no keys", []string{}, ""},
23
	}
24
25
	for _, tt := range tests {
26
		t.Run(tt.name, func(t *testing.T) {
27
			cfg := &config.Config{SSH: config.SSHConfig{Keys: tt.keys}}
28
			shell, err := NewShell(cfg)
29
			if tt.wantErr == "" {
30
				is.Err(t, err, nil)
31
				is.Equal(t, len(shell.keys), len(cfg.SSH.Keys))
32
			} else {
33
				is.Err(t, err, tt.wantErr)
34
			}
35
		})
36
	}
37
}
38
39
func TestShellParseCommand(t *testing.T) {
40
	cfg := &config.Config{
41
		SSH: config.SSHConfig{
42
			Keys: []string{validKey},
43
		},
44
	}
45
46
	shell, err := NewShell(cfg)
47
	is.Err(t, err, nil)
48
49
	tests := []struct {
50
		cmd        string
51
		wantGitCmd string
52
		wantRepo   string
53
		wantErr    string
54
	}{
55
		{"git-upload-pack 'myrepo'", "git-upload-pack", "myrepo", ""},
56
		{"git-upload-pack \"myrepo\"", "git-upload-pack", "myrepo", ""},
57
		{"git-upload-pack myrepo", "git-upload-pack", "myrepo", ""},
58
		{"git-upload-archive 'archive-repo'", "git-upload-archive", "archive-repo", ""},
59
		{"git-upload-pack", "", "", "invalid command"},
60
		{"git-upload-pack ''", "", "", "empty repository name"},
61
		{"git-receive-pack repo.git && echo hi", "", "", "invalid command"},
62
		{"echo hi", "", "", "invalid command"},
63
		{"", "", "", "invalid command"},
64
	}
65
66
	for _, tt := range tests {
67
		t.Run(tt.cmd, func(t *testing.T) {
68
			gitCmd, repo, err := shell.parseCommand(tt.cmd)
69
			if tt.wantErr == "" {
70
				is.Err(t, err, nil)
71
				is.Equal(t, gitCmd, tt.wantGitCmd)
72
				is.Equal(t, repo, tt.wantRepo)
73
			} else {
74
				is.Err(t, err, tt.wantErr)
75
			}
76
		})
77
	}
78
}
79
80
func TestShellAuthorizedKeys(t *testing.T) {
81
	shell, err := NewShell(&config.Config{
82
		SSH: config.SSHConfig{Keys: []string{validKey}},
83
	})
84
	is.Err(t, err, nil)
85
86
	result := shell.AuthorizedKeys("/usr/bin/mugit")
87
	if !strings.Contains(result, `command="/usr/bin/mugit shell",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty`) {
88
		t.Errorf("AuthorizedKeys() missing expected format\ngot: %s", result)
89
	}
90
	if !strings.Contains(result, validKey) {
91
		t.Errorf("AuthorizedKeys() missing SSH key\ngot: %s", result)
92
	}
93
}