Skip to content
quarry Artifact [5849b1b349]
Login

Artifact [5849b1b349]

Artifact 5849b1b349db99527c12e52e214bdaf2863b9e953adf5c3d0035d76241bd553e:


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",
		"[email protected]:o/r.git",
		"[email protected]:r",
		"ssh://[email protected]/r",
		"ssh://%[email protected]/r",
		"ssh://[email protected]/x%41",
		"ssh://[email protected]/x?",
		"ssh://[email protected]/x#",
		"[email protected]:x",
		"ssh://[email protected]:6379/x",
		"git@github:x",
		"git@localhost:x",
	} {
		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)
		}
	}
}