package oltp
import (
"errors"
"strings"
"testing"
"golang.org/x/crypto/ssh"
)
// The first enable makes a key, keeps the private half sealed and shows
// the public half; a change of branch keeps the key; disabling deletes
// it, and each step is in the settings log with its actor and via.
func TestAGitMirrorKeepsItsKeySealedAndLogsEachChange(t *testing.T) {
db := heldDB(t)
m, err := db.SetGitMirror("proj", "[email protected]:alice/proj.git", "", "alice", "TK1")
if err != nil {
t.Fatal(err)
}
if m.Branch != "main" {
t.Errorf("FAIL: default branch %q", m.Branch)
}
pub, _, _, _, err := ssh.ParseAuthorizedKey([]byte(m.PublicKey))
if err != nil || pub.Type() != ssh.KeyAlgoED25519 {
t.Fatalf("FAIL: public key %q: %v", m.PublicKey, err)
}
var sealed string
if err := db.db.QueryRow(`SELECT key_sealed FROM git_mirror WHERE repo = 'proj'`).Scan(&sealed); err != nil {
t.Fatal(err)
}
if strings.Contains(sealed, "PRIVATE KEY") {
t.Fatal("FAIL: the private key is stored readable")
}
plain, err := db.seal.open(sealed)
if err != nil {
t.Fatal(err)
}
signer, err := ssh.ParsePrivateKey([]byte(plain))
if err != nil {
t.Fatalf("FAIL: the sealed key is not an OpenSSH key: %v", err)
}
if string(signer.PublicKey().Marshal()) != string(pub.Marshal()) {
t.Error("FAIL: the shown public key is not the sealed key's")
}
m2, err := db.SetGitMirror("proj", "[email protected]:alice/proj.git", "trunk", "alice", "")
if err != nil {
t.Fatal(err)
}
if m2.PublicKey != m.PublicKey {
t.Error("FAIL: changing the branch made a new key")
}
if on, err := db.DisableGitMirror("proj", "bob", ""); err != nil || !on {
t.Fatalf("FAIL: disable: %v %v", on, err)
}
if _, ok, _ := db.GitMirrorOf("proj"); ok {
t.Error("FAIL: the mirror outlived its disable")
}
var left int
db.db.QueryRow(`SELECT count(*) FROM git_mirror`).Scan(&left)
if left != 0 {
t.Error("FAIL: the key outlived the disable")
}
if on, err := db.DisableGitMirror("proj", "bob", ""); err != nil || on {
t.Errorf("FAIL: disabling nothing: %v %v", on, err)
}
log, err := db.SettingsLog("proj", 20)
if err != nil {
t.Fatal(err)
}
got := map[string]int{}
for _, c := range log {
got[c.Field+" "+c.Was+">"+c.Now+" "+c.Actor+" "+c.Via]++
}
for _, want := range []string{
"git-mirror off>on alice TK1",
"git-mirror-remote >[email protected]:alice/proj.git alice TK1",
"git-mirror-branch >main alice TK1",
"git-mirror-branch main>trunk alice ",
"git-mirror on>off bob ",
} {
if got[want] != 1 {
t.Errorf("FAIL: settings log lacks %q (has %v)", want, got)
}
}
if len(log) != 5 {
t.Errorf("FAIL: %d log rows, want 5", len(log))
}
}
// A private repository and a taken-down one cannot be mirrored.
func TestAGitMirrorIsRefusedWherePublishingIsNot(t *testing.T) {
db := heldDB(t)
if err := db.AddRepo("secret", t.TempDir(), "", Private); err != nil {
t.Fatal(err)
}
if _, err := db.SetGitMirror("secret", "[email protected]:a/b.git", "", "alice", ""); !errors.Is(err, ErrMirrorRefused) {
t.Errorf("FAIL: private: %v", err)
}
if err := db.SetTakedown(Takedown{Repo: "proj", Strength: Disabled, Category: "copyright", Actor: "dmestas"}); err != nil {
t.Fatal(err)
}
if _, err := db.SetGitMirror("proj", "[email protected]:a/b.git", "", "alice", ""); !errors.Is(err, ErrHeld) {
t.Errorf("FAIL: taken down: %v", err)
}
var n int
db.db.QueryRow(`SELECT count(*) FROM git_mirror`).Scan(&n)
if n != 0 {
t.Errorf("FAIL: %d mirrors kept after refusals", n)
}
}
func TestOnlyAnSSHRemoteWithNoOptionInItIsKept(t *testing.T) {
for _, ok := range []string{
"[email protected]:owner/repo.git",
"[email protected]:group/sub/repo",
"ssh://[email protected]/owner/repo.git",
"ssh://[email protected]:2222/~/repo.git",
} {
if err := CheckGitRemote(ok); err != nil {
t.Errorf("FAIL: %q refused: %v", ok, err)
}
}
for _, bad := range []string{
"",
"https://github.com/owner/repo.git",
"ssh://git:[email protected]/owner/repo.git",
"github.com:owner/repo.git",
"git@-oProxyCommand=evil:repo",
"ssh://-oProxyCommand=evil/repo",
"[email protected]:-u/repo",
"[email protected]:owner/repo with space",
"[email protected]:../etc",
"[email protected]:",
"file:///tmp/repo",
"ext::sh -c evil",
} {
if err := CheckGitRemote(bad); !errors.Is(err, ErrMirrorRefused) {
t.Errorf("FAIL: %q kept: %v", bad, err)
}
}
for _, bad := range []string{"-f", ".hidden", "a..b", "main.lock", "a b", "a/", "/a"} {
if err := checkGitBranch(bad); err == nil {
t.Errorf("FAIL: branch %q kept", bad)
}
}
}