Skip to content
quarry Artifact [f4e463ab68]
Login

Artifact [f4e463ab68]

Artifact f4e463ab68c7b253d584b623e900bfb5ded15c05d3fc2016fa73d1ce04cabd68:


package api

import (
	"context"
	"testing"

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

// capsFakeAccounts is fakeAccounts plus the optional CapsExplainer seam.
// Embedded rather than added to the shared fake so no existing test
// gains a method it did not ask for.
type capsFakeAccounts struct {
	*fakeAccounts
	stored map[string]map[string]string
}

func (c *capsFakeAccounts) CapsAt(account, repo string) (string, string, error) {
	s := c.stored[account][repo]
	return s, s, nil
}

// A ROLE NAME IS A READING, AND /me MUST NOT LOSE THE DIFFERENCE.
//
// jan held "Reader plus check in" on a repository. /me reported the bare
// preset name "reader", so a client reading only that row concluded the
// account could not push. It could — jva pushed with it. The nearest
// preset name is a summary, and a summary that only ever rounds DOWN
// tells somebody a door is locked when it is open, which costs them the
// work and sends them looking for a permission they already have.
//
// accounts.explain answered the same account correctly the whole time.
// Two ops describing one account's reach disagreeing is worse than
// either being wrong alone, because the reader does not know which one
// they read.
func TestMeSaysWhenAGrantHoldsMoreThanItsRoleName(t *testing.T) {
	accts := &capsFakeAccounts{
		fakeAccounts: newFakeAccounts(),
		stored:       map[string]map[string]string{},
	}
	accts.accounts["jan"] = Account{Name: "jan", Created: "2026-01-01T00:00:00Z"}
	// Reader, plus the check-in letter — the exact string jva measured.
	readerPlusCheckIn := oltp.Read.Caps() + "i"
	accts.grants["jan"] = map[string]string{"pushmatrix": "reader"}
	accts.stored["jan"] = map[string]string{"pushmatrix": readerPlusCheckIn}

	r := ops.NewRegistry()
	if err := RegisterAll(r, Deps{Version: "v", Accounts: accts}); err != nil {
		t.Fatal(err)
	}
	out, err := r.Invoke(ops.WithUser(context.Background(), "jan"), "me.account", meAccountIn{})
	if err != nil {
		t.Fatal(err)
	}
	got := out.(meAccountOut)
	if len(got.Repos) != 1 {
		t.Fatalf("me.account reported %d repositories, want 1: %+v", len(got.Repos), got.Repos)
	}
	row := got.Repos[0]
	if row.Role != "Reader" {
		t.Errorf("role = %q, want Reader", row.Role)
	}
	if row.Exact {
		t.Error("the row claims the string IS the role, so nothing tells the reader it holds more")
	}
	if len(row.Plus) == 0 {
		t.Fatal("a grant holding more than its role name reported no extras: " +
			"this is the understatement that made a client conclude the account could not push")
	}
}

// And the ordinary case still reads as exact, so the new fields are a
// qualifier and not a permanent hedge on every row.
func TestMeSaysWhenAGrantIsExactlyItsRole(t *testing.T) {
	accts := &capsFakeAccounts{
		fakeAccounts: newFakeAccounts(),
		stored:       map[string]map[string]string{},
	}
	accts.accounts["jan"] = Account{Name: "jan", Created: "2026-01-01T00:00:00Z"}
	accts.grants["jan"] = map[string]string{"ordinary": "reader"}
	accts.stored["jan"] = map[string]string{"ordinary": oltp.Read.Caps()}

	r := ops.NewRegistry()
	if err := RegisterAll(r, Deps{Version: "v", Accounts: accts}); err != nil {
		t.Fatal(err)
	}
	out, err := r.Invoke(ops.WithUser(context.Background(), "jan"), "me.account", meAccountIn{})
	if err != nil {
		t.Fatal(err)
	}
	row := out.(meAccountOut).Repos[0]
	if row.Role != "Reader" || !row.Exact || len(row.Plus) != 0 || len(row.Minus) != 0 {
		t.Errorf("an exact preset grant read as Role=%q Exact=%v Plus=%v Minus=%v, want Reader/true/empty/empty",
			row.Role, row.Exact, row.Plus, row.Minus)
	}
}

// A store with no CapsExplainer still answers the op — it just reports
// the collapsed role, which is what it did before. The seam is optional
// so a forge without it keeps working rather than losing the whole read.
func TestMeStillAnswersFromAStoreThatCannotExplain(t *testing.T) {
	accts := newFakeAccounts()
	accts.accounts["jan"] = Account{Name: "jan", Created: "2026-01-01T00:00:00Z"}
	accts.grants["jan"] = map[string]string{"ordinary": "reader"}

	r := ops.NewRegistry()
	if err := RegisterAll(r, Deps{Version: "v", Accounts: accts}); err != nil {
		t.Fatal(err)
	}
	out, err := r.Invoke(ops.WithUser(context.Background(), "jan"), "me.account", meAccountIn{})
	if err != nil {
		t.Fatal(err)
	}
	got := out.(meAccountOut)
	if len(got.Repos) != 1 || got.Repos[0].Role != "reader" {
		t.Errorf("without an explainer me.account = %+v, want one row reading reader", got.Repos)
	}
}