package api
import (
"context"
"encoding/json"
"errors"
"path/filepath"
"strings"
"testing"
"time"
"craftdesign.group/quarry/internal/oltp"
"craftdesign.group/quarry/internal/ops"
)
// A Git mirror's access token: an administrator replaces or clears it,
// the mirror then says only whether one is held, the token never comes
// back from an op, and a mirror that does not follow Git refuses one.
func TestMirrorTokenOpHoldsAndNeverReturnsTheToken(t *testing.T) {
ix, _, _ := attachStore(t)
db, err := oltp.Open(filepath.Join(t.TempDir(), "o.db"))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { db.Close() })
for _, m := range []struct{ repo, url string }{{"test", "https://github.com/o/private"}, {"fossil", "https://example.invalid/f"}} {
if err := db.SetMirror(m.repo, m.url, time.Hour); err != nil {
t.Fatal(err)
}
}
if err := db.SetMirrorGit("test"); err != nil {
t.Fatal(err)
}
mirrors := oltpMirrors{db}
r := ops.NewRegistry()
caps := func(account, repo string) CapSet {
if account == "dan" {
return oltp.CapSet("a")
}
return oltp.CapSet("3")
}
if err := RegisterAll(r, Deps{Version: "v", Repos: testRepos(ix), Mirrors: mirrors, MirrorTokens: mirrors, CapsFor: caps}); err != nil {
t.Fatal(err)
}
set := func(who string, in mirrorTokenIn) (mirrorTokenOut, error) {
out, err := r.Invoke(ops.WithUser(context.Background(), who), "mirror.token", in)
if err != nil {
return mirrorTokenOut{}, err
}
return out.(mirrorTokenOut), nil
}
if _, err := set("eve", mirrorTokenIn{Repo: "test", Token: "github_pat_abc"}); !errors.Is(err, ops.ErrForbidden) {
t.Fatalf("FAIL: somebody without admin set a token: %v", err)
}
out, err := set("dan", mirrorTokenIn{Repo: "test", Token: "github_pat_abc"})
if err != nil {
t.Fatal(err)
}
body, _ := json.Marshal(out)
if !out.Mirror.GitToken || strings.Contains(string(body), "github_pat_abc") {
t.Fatalf("FAIL: after setting, the mirror reads %s", body)
}
if tok, _ := db.MirrorGitToken("test"); tok != "github_pat_abc" {
t.Fatalf("FAIL: the fetch would send %q", tok)
}
t.Log("ok: an admin sets it; the answer says it is held and does not carry it")
for _, bad := range []mirrorTokenIn{
{Repo: "test", Token: "has space"},
{Repo: "test"},
{Repo: "test", Token: "x", Clear: true},
} {
if _, err := set("dan", bad); !errors.Is(err, ops.ErrInvalid) {
t.Errorf("FAIL: %+v was accepted: %v", bad, err)
}
}
if _, err := set("dan", mirrorTokenIn{Repo: "fossil", Token: "github_pat_abc"}); !errors.Is(err, ops.ErrNotFound) {
t.Errorf("FAIL: a mirror that does not follow Git took a token: %v", err)
}
if out, err := set("dan", mirrorTokenIn{Repo: "test", Clear: true}); err != nil || out.Mirror.GitToken {
t.Fatalf("FAIL: clearing: %+v %v", out.Mirror, err)
}
t.Log("ok: a bad token, an empty ask and a Fossil mirror are refused; clearing removes it")
}
// repo.add takes a token only for a Git clone, and refuses one that is
// not a token, before anything is made.
func TestRepoAddTakesATokenOnlyForAGitClone(t *testing.T) {
ix, _, _ := attachStore(t)
r := ops.NewRegistry()
if err := RegisterAll(r, Deps{Version: "v", Repos: testRepos(ix)}); err != nil {
t.Fatal(err)
}
for _, in := range []repoAddIn{
{Name: "p", Clone: "https://example.invalid/f", GitToken: "github_pat_abc"},
{Name: "p", Clone: "https://github.com/o/p", Git: true, GitToken: "two words"},
} {
if _, err := r.Invoke(as("dan", "a"), "repo.add", in); !errors.Is(err, ops.ErrInvalid) {
t.Errorf("FAIL: %+v was accepted: %v", in, err)
}
}
t.Log("ok: a token without a Git clone, or one with a space in it, is refused")
}