Skip to content
quarry Artifact [d7f0763ca1]
Login

Artifact [d7f0763ca1]

Artifact d7f0763ca11cdaae596cfd49d27644574ef3a7a9d968fa6e2630dda59df9e992:


package api

import (
	"context"
	"encoding/json"
	"sync"
	"testing"

	"craftdesign.group/quarry/internal/ops"
)

// remarshalT re-decodes an op's output into its typed form.
func remarshalT(t *testing.T, in, out any) {
	t.Helper()
	b, err := json.Marshal(in)
	if err != nil {
		t.Fatal(err)
	}
	if err := json.Unmarshal(b, out); err != nil {
		t.Fatal(err)
	}
}

type fakeStamp struct {
	mu  sync.Mutex
	set map[string]map[string]bool // repo -> account -> stamped
}

func newFakeStamp() *fakeStamp {
	return &fakeStamp{set: map[string]map[string]bool{}}
}

func (f *fakeStamp) SetStamp(repo, account string, on bool) (bool, error) {
	f.mu.Lock()
	defer f.mu.Unlock()
	if f.set[repo] == nil {
		f.set[repo] = map[string]bool{}
	}
	if on {
		f.set[repo][account] = true
	} else {
		delete(f.set[repo], account)
	}
	return on, nil
}

func (f *fakeStamp) Stamped(repo, account string) bool { return f.set[repo][account] }

func (f *fakeStamp) StampCount(repo string) int { return len(f.set[repo]) }

func (f *fakeStamp) StampedBy(account string) ([]string, error) {
	var out []string
	for _, repo := range []string{"alpha", "beta", "secret"} {
		if f.set[repo][account] {
			out = append(out, repo)
		}
	}
	return out, nil
}

// The rule: any signed-in account may stamp any repository it can see.
// No capability letter is involved, so an account with no grant at all
// must succeed.
func TestStampNeedsOnlyASignedInAccount(t *testing.T) {
	r := ops.NewRegistry()
	repos := testRepos(wikiIndex(t))
	mustRepo(t, repos, "test").Code = "c1"
	if err := RegisterAll(r, Deps{Version: "v", Repos: repos, Stamp: newFakeStamp()}); err != nil {
		t.Fatal(err)
	}
	ctx := ops.WithUser(context.Background(), "grantless")
	out, err := r.Invoke(ctx, "stamp.set", stampSetIn{Repo: "test", On: true})
	if err != nil {
		t.Fatalf("a signed-in account with no grant could not stamp: %v", err)
	}
	var got stampSetOut
	remarshalT(t, out, &got)
	if !got.Stamped || got.Count != 1 {
		t.Errorf("stamped=%v count=%d, want true 1", got.Stamped, got.Count)
	}
}

// Stamp must be attributable, so anonymous is refused rather than
// pooling every stranger into one shared stamp.
func TestAnonymousCannotStamp(t *testing.T) {
	r := ops.NewRegistry()
	repos := testRepos(wikiIndex(t))
	mustRepo(t, repos, "test").Code = "c1"
	if err := RegisterAll(r, Deps{Version: "v", Repos: repos, Stamp: newFakeStamp()}); err != nil {
		t.Fatal(err)
	}
	if _, err := r.Invoke(context.Background(), "stamp.set",
		stampSetIn{Repo: "test", On: true}); err == nil {
		t.Error("anonymous stamp was accepted")
	}
}

// On is a desired state, not a toggle: a retried request must land where
// the reader clicked rather than on the opposite of it.
func TestStampIsIdempotent(t *testing.T) {
	r := ops.NewRegistry()
	repos := testRepos(wikiIndex(t))
	mustRepo(t, repos, "test").Code = "c1"
	if err := RegisterAll(r, Deps{Version: "v", Repos: repos, Stamp: newFakeStamp()}); err != nil {
		t.Fatal(err)
	}
	ctx := ops.WithUser(context.Background(), "dan")
	for i := 0; i < 3; i++ {
		out, err := r.Invoke(ctx, "stamp.set", stampSetIn{Repo: "test", On: true})
		if err != nil {
			t.Fatal(err)
		}
		var got stampSetOut
		remarshalT(t, out, &got)
		if !got.Stamped || got.Count != 1 {
			t.Fatalf("attempt %d: stamped=%v count=%d", i, got.Stamped, got.Count)
		}
	}
}

// A listing is filtered by the VIEWER. Stamp is public; the existence
// of a private repository is not.
func TestStampListHidesWhatTheViewerCannotRead(t *testing.T) {
	r := ops.NewRegistry()
	ix := wikiIndex(t)
	repos := NewRepos(map[string]*Repo{
		"alpha": {Index: ix, Code: "c-alpha"},
		"beta":  {Index: ix, Code: "c-beta"},
		// Registered, and deliberately unreadable to the viewer below.
		"secret": {Index: ix, Code: "c-secret"},
	})
	fp := newFakeStamp()
	for _, n := range []string{"alpha", "beta", "secret"} {
		fp.SetStamp(n, "dan", true)
	}
	if err := RegisterAll(r, Deps{Version: "v", Repos: repos, Stamp: fp,
		CanRead: func(_ context.Context, repo string) bool { return repo != "secret" },
	}); err != nil {
		t.Fatal(err)
	}
	out, err := r.Invoke(context.Background(), "stamp.list", stampListIn{User: "dan"})
	if err != nil {
		t.Fatal(err)
	}
	var got stampListOut
	remarshalT(t, out, &got)
	for _, repo := range got.Repos {
		if repo == "secret" {
			t.Fatalf("a private repository leaked through a stamp listing: %v", got.Repos)
		}
	}
	if len(got.Repos) != 2 {
		t.Errorf("listed %v, want the two readable ones", got.Repos)
	}
}