Skip to content
quarry Artifact [cae832edf3]
Login

Artifact [cae832edf3]

Artifact cae832edf3179790599b738c5057c17d7bf25bb5e0a120ac4f109dfeabb0d7aa:


package oltp

import (
	"strings"
	"testing"
)

// RFC 0021, Testing: Forge agents (the store's half). A forge agent is
// made or re-marked only with a site admin answerable, keeps what a
// person's agent may not hold, resolves with no operator term, may be
// deeded, and answers to nobody when its admin is gone.
func TestForgeAgentCreationAndRemark(t *testing.T) {
	db := agentRig(t)
	// Creation needs an answerable site admin: not nobody, not a
	// person without the flag, not an agent.
	for _, bad := range []string{"", "jva", "dmestas-coder", "nobody"} {
		if err := db.NewForgeAgent("fbot", bad); err == nil {
			t.Errorf("FAIL: NewForgeAgent took %q as answerable", bad)
		}
	}
	if err := db.NewForgeAgent("fbot", "root"); err != nil {
		t.Fatalf("FAIL: %v", err)
	}
	a, _ := db.AccountByName("fbot")
	if a.Operator != "forge" || a.Answerable != "root" || a.Admin || a.Pending {
		t.Errorf("FAIL: new forge agent reads %+v", a)
	}
	if db.IsAgent("fbot") || !db.IsForgeAgent("fbot") {
		t.Error("FAIL: a forge agent reads as a person's agent, or not as the forge's")
	}
	if _, ok := db.Authenticate("fbot", ""); ok {
		t.Error("FAIL: a forge agent signed in with an empty password")
	}
	// SetOperator never writes forge: the forge path is the only one.
	if err := db.SetOperator("jva", "forge"); !IsRefusal(err) {
		t.Errorf("FAIL: SetOperator took forge: %v", err)
	}
	// Neither path takes a forge agent as a person's operator.
	if err := db.NewAgent("fbot-child", "fbot", -1); !IsRefusal(err) {
		t.Errorf("FAIL: a forge agent became an operator: %v", err)
	}
	if err := db.SetOperator("jva", "fbot"); !IsRefusal(err) {
		t.Errorf("FAIL: SetOperator took a forge agent as operator: %v", err)
	}

	// The migration case: a site admin with a password, deeds, a team
	// it alone owns and a session is re-marked and keeps all of it.
	if err := db.AddAccount("zeitgeist", "a-long-enough-password", true); err != nil {
		t.Fatal(err)
	}
	if err := db.SetOwner("pub", "zeitgeist"); err != nil {
		t.Fatal(err)
	}
	if err := db.AddTeam("ops", "Ops", "", "zeitgeist"); err != nil {
		t.Fatal(err)
	}
	if err := db.Grant("zeitgeist", "priv", RepoAdmin); err != nil {
		t.Fatal(err)
	}
	if err := db.SetForgeAgent("zeitgeist", "root"); err != nil {
		t.Fatalf("FAIL: re-mark refused: %v", err)
	}
	z, _ := db.AccountByName("zeitgeist")
	if z.Operator != "forge" || z.Answerable != "root" || !z.Admin {
		t.Errorf("FAIL: re-marked reads %+v", z)
	}
	if owner, _ := db.OwnerOf("pub"); owner != "zeitgeist" {
		t.Errorf("FAIL: the deed moved to %q", owner)
	}
	if _, ok := db.Authenticate("zeitgeist", "a-long-enough-password"); !ok {
		t.Error("FAIL: re-marking cleared the password before cutover")
	}
	if !db.EffectiveCaps("zeitgeist", "").HasAny("s") {
		t.Error("FAIL: the re-marked agent lost s")
	}
	if !db.EffectiveCaps("zeitgeist", "priv").HasAny("a") {
		t.Error("FAIL: the re-marked agent lost its grant")
	}
	// No operator term: a grant on the agent resolves as given, with
	// nobody's letters to intersect.
	if err := db.Grant("fbot", "priv", Write); err != nil {
		t.Fatal(err)
	}
	if got := letters(db.EffectiveCaps("fbot", "priv")); !db.EffectiveCaps("fbot", "priv").HasAny("i") {
		t.Errorf("FAIL: forge agent on priv resolves to %q, not developer", got)
	}
	// A forge agent operating a person's agent is the one holding
	// refused on re-mark.
	if err := db.NewAgent("jva-bot", "jva", -1); err != nil {
		t.Fatal(err)
	}
	if err := db.SetForgeAgent("jva", "root"); !IsRefusal(err) {
		t.Errorf("FAIL: an operator of agents became a forge agent: %v", err)
	}
	// An admin cannot answer for itself, and an admin who answers for
	// forge agents is not re-marked out from under them.
	if err := db.AddAccount("admin4", "a-long-enough-password", true); err != nil {
		t.Fatal(err)
	}
	if err := db.SetForgeAgent("admin4", "admin4"); !IsRefusal(err) {
		t.Errorf("FAIL: an account answered for itself: %v", err)
	}
	if a, _ := db.AccountByName("admin4"); a.Operator != "" || a.Answerable != "" {
		t.Errorf("FAIL: the refused re-mark wrote %+v", a)
	}
	if err := db.SetForgeAgent("root", "admin4"); !IsRefusal(err) || !strings.Contains(err.Error(), "fbot") {
		t.Errorf("FAIL: the admin answering for fbot was re-marked, or the refusal does not name fbot: %v", err)
	}
	// Deeds: SetOwner accepts a forge agent.
	if err := db.SetOwner("priv", "fbot"); err != nil {
		t.Errorf("FAIL: SetOwner refused a forge agent: %v", err)
	} else {
		t.Log("ok: created and re-marked with an answerable admin, holdings and s kept, deeded")
	}
}

func TestForgeAgentAnswerableAndItsLoss(t *testing.T) {
	db := agentRig(t)
	if err := db.AddAccount("root2", "a-long-enough-password", true); err != nil {
		t.Fatal(err)
	}
	if err := db.NewForgeAgent("fbot", "root"); err != nil {
		t.Fatal(err)
	}
	if err := db.SetAnswerable("dmestas-coder", "root"); !IsRefusal(err) {
		t.Errorf("FAIL: a person's agent took an answerable admin: %v", err)
	}
	if err := db.SetAnswerable("fbot", "jva"); !IsRefusal(err) {
		t.Errorf("FAIL: a person without the flag became answerable: %v", err)
	}
	if err := db.SetAnswerable("fbot", "root2"); err != nil {
		t.Fatalf("FAIL: %v", err)
	}
	if got := db.Answerable("fbot"); got != "root2" {
		t.Errorf("FAIL: answerable reads %q", got)
	}
	v, _, err := db.MintToken("fbot", TokenSpec{Name: "s", Scopes: []string{ScopeAPI}})
	if err != nil {
		t.Fatal(err)
	}
	// Disabling the answerable admin leaves the agent working and
	// names nobody; re-enabling names them again.
	if err := db.SetDisabled("root2", true); err != nil {
		t.Fatal(err)
	}
	if a, _ := db.AccountByName("fbot"); a.Disabled != "" || a.Suspended != "" {
		t.Errorf("FAIL: the agent was shut with its admin: %+v", a)
	}
	if _, ok := db.ResolveToken("fbot", v, ScopeAPI); !ok {
		t.Error("FAIL: the agent's token stopped with its admin")
	}
	if got := db.Answerable("fbot"); got != "" {
		t.Errorf("FAIL: a disabled admin still answers: %q", got)
	}
	if err := db.SetDisabled("root2", false); err != nil {
		t.Fatal(err)
	}
	if got := db.Answerable("fbot"); got != "root2" {
		t.Errorf("FAIL: the reopened admin does not answer: %q", got)
	}
	// Deleting the admin clears the stored name; the agent stays.
	if err := db.DeleteAccount("root2"); err != nil {
		t.Fatal(err)
	}
	if a, ok := db.AccountByName("fbot"); !ok || a.Answerable != "" || a.Disabled != "" {
		t.Errorf("FAIL: after the admin's deletion the agent reads %+v", a)
	}
	if _, ok := db.ResolveToken("fbot", v, ScopeAPI); !ok {
		t.Error("FAIL: the agent's token stopped with its admin's deletion")
	} else {
		t.Log("ok: answerable reassigned by any admin; its loss leaves the agent working, answering to nobody")
	}
	// Clearing the mark drops the answerable name with it.
	if err := db.SetOperator("fbot", ""); err != nil {
		t.Fatal(err)
	}
	if a, _ := db.AccountByName("fbot"); a.Operator != "" || a.Answerable != "" {
		t.Errorf("FAIL: cleared mark reads %+v", a)
	}
}

// The two a guards hold for a forge agent with its answerable admin in
// the operator's place.
func TestForgeAgentGuardsUseTheAnswerableAdmin(t *testing.T) {
	db := agentRig(t)
	if err := db.NewForgeAgent("fbot", "root"); err != nil {
		t.Fatal(err)
	}
	for _, who := range []string{"root", "fbot", "jva"} {
		if err := db.Grant(who, "pub", RepoAdmin); err != nil {
			t.Fatal(err)
		}
	}
	if _, err := db.GrantGuarded("fbot", "root", "pub", Read); !IsRefusal(err) {
		t.Errorf("FAIL: the forge agent lowered its answerable admin: %v", err)
	}
	if _, err := db.GrantGuarded("fbot", "jva", "pub", Read); err != nil {
		t.Errorf("FAIL: the forge agent could not lower a third account: %v", err)
	}
	// The guard resolves the admin as the badge does: once root no
	// longer answers (disabled), fbot is not held off root's letters.
	if err := db.SetDisabled("root", true); err != nil {
		t.Fatal(err)
	}
	if _, err := db.GrantGuarded("fbot", "root", "pub", Read); err != nil {
		t.Errorf("FAIL: the guard shields an admin who no longer answers: %v", err)
	}
	if err := db.SetDisabled("root", false); err != nil {
		t.Fatal(err)
	}
	// fbot holds admin on pub and nothing on priv: it cannot write
	// developer on priv.
	if _, err := db.SetCapsGuarded("fbot", "jva", "priv", Write.Caps()); !IsRefusal(err) {
		t.Errorf("FAIL: the forge agent granted letters it does not resolve to: %v", err)
	} else {
		t.Log("ok: the guards hold with the answerable admin in the operator's place")
	}
}