Skip to content
quarry Artifact [756b7dad57]
Login

Artifact [756b7dad57]

Artifact 756b7dad57818b6379a499be561d4f03d33ed2a572cf0137167a7ebe94abe450:


package api

import (
	"errors"
	"testing"

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

// RFC 0021, Testing: Forge agents (the doors). agent.new with
// operator forge is a site admin's and needs answerable; any site admin
// mints, revokes and reassigns; a forge agent holding s passes
// account.add and the deed paths and is refused on making or altering
// a forge agent and on any s flag change.
func TestForgeAgentIsASiteAdminsToMakeAndManage(t *testing.T) {
	r, db, _ := agentCoreRig(t, 5)
	if _, err := r.Invoke(asUser("jva"), "agent.new", agentNewIn{Name: "fbot", Operator: "forge", Answerable: "dmestas"}); !errors.Is(err, ops.ErrForbidden) {
		t.Errorf("FAIL: a person created a forge agent: %v", err)
	}
	if _, err := r.Invoke(asUser("dmestas"), "agent.new", agentNewIn{Name: "fbot", Operator: "forge"}); !errors.Is(err, ops.ErrInvalid) {
		t.Errorf("FAIL: a forge agent without answerable: %v", err)
	}
	if _, err := r.Invoke(asUser("dmestas"), "agent.new", agentNewIn{Name: "fbot", Operator: "forge", Answerable: "jva"}); !errors.Is(err, ops.ErrInvalid) {
		t.Errorf("FAIL: a person without the flag became answerable: %v", err)
	}
	out, err := r.Invoke(asUser("dmestas"), "agent.new", agentNewIn{Name: "fbot", Operator: "forge", Answerable: "dmestas"})
	if err != nil {
		t.Fatalf("FAIL: %v", err)
	}
	if out.(agentOut).Operator != "forge" || db.Operator("fbot") != "forge" {
		t.Errorf("FAIL: created %+v, operator %q", out, db.Operator("fbot"))
	}
	// Tokens: any site admin mints and revokes; a person does not.
	minted, err := r.Invoke(asUser("dmestas"), "agent.token.new", agentTokenNewIn{Agent: "fbot", Name: "s", Scopes: "api", Days: 30})
	if err != nil {
		t.Fatalf("FAIL: the site admin could not mint for a forge agent: %v", err)
	}
	if _, err := r.Invoke(asUser("jva"), "agent.token.new", agentTokenNewIn{Agent: "fbot", Name: "x", Scopes: "api"}); !errors.Is(err, ops.ErrForbidden) {
		t.Errorf("FAIL: a person minted for a forge agent: %v", err)
	}
	if _, err := r.Invoke(asUser("jva"), "agent.token.revoke", agentTokenRevokeIn{Agent: "fbot", ID: minted.(agentTokenNewOut).Token.ID}); !errors.Is(err, ops.ErrForbidden) {
		t.Errorf("FAIL: a person revoked a forge agent's token: %v", err)
	}
	if _, err := r.Invoke(asUser("dmestas"), "agent.token.revoke", agentTokenRevokeIn{Agent: "fbot", ID: minted.(agentTokenNewOut).Token.ID}); err != nil {
		t.Errorf("FAIL: the site admin could not revoke: %v", err)
	}
	// The answerable admin: any site admin reassigns.
	if err := db.AddAccount("root2", "a-long-enough-password", true); err != nil {
		t.Fatal(err)
	}
	if _, err := r.Invoke(asUser("jva"), "account.answerable", accountAnswerableIn{Name: "fbot", Answerable: "root2"}); !errors.Is(err, ops.ErrForbidden) {
		t.Errorf("FAIL: a person reassigned the answerable admin: %v", err)
	}
	if _, err := r.Invoke(asUser("root2"), "account.answerable", accountAnswerableIn{Name: "fbot", Answerable: "root2"}); err != nil {
		t.Errorf("FAIL: a site admin could not reassign: %v", err)
	}
	out, err = r.Invoke(asUser("dmestas"), "agent.list", agentListIn{Operator: "forge"})
	if err != nil {
		t.Fatal(err)
	}
	if rows := out.(agentListOut).Agents; len(rows) != 1 || rows[0].Answerable != "root2" || rows[0].Operator != "forge" {
		t.Errorf("FAIL: the fleet list: %+v", rows)
	}
	// Disabling the answerable admin: the agent works, nobody answers.
	if _, err := r.Invoke(asUser("dmestas"), "account.disable", accountDisableIn{Name: "root2", On: true}); err != nil {
		t.Fatal(err)
	}
	out, _ = r.Invoke(asUser("dmestas"), "agent.list", agentListIn{Operator: "forge"})
	if rows := out.(agentListOut).Agents; rows[0].Answerable != "" || rows[0].Disabled != "" {
		t.Errorf("FAIL: after the admin's disabling: %+v", rows)
	} else {
		t.Log("ok: a forge agent is a site admin's to make, mint for, revoke and reassign; its admin's loss leaves it working")
	}
}

func TestForgeAgentHoldingSStopsAtOtherForgeAgentsAndTheFlag(t *testing.T) {
	r, db, owners := agentCoreRig(t, 5)
	// The migration shape: a site admin re-marked as a forge agent,
	// keeping the flag.
	if err := db.AddAccount("zeitgeist", "a-long-enough-password", true); err != nil {
		t.Fatal(err)
	}
	if _, err := r.Invoke(asUser("jva"), "account.agent", accountAgentIn{Name: "zeitgeist", Operator: "forge", Answerable: "dmestas"}); !errors.Is(err, ops.ErrForbidden) {
		t.Errorf("FAIL: a person re-marked a forge agent: %v", err)
	}
	if _, err := r.Invoke(asUser("dmestas"), "account.agent", accountAgentIn{Name: "zeitgeist", Operator: "forge"}); !errors.Is(err, ops.ErrInvalid) {
		t.Errorf("FAIL: re-marking without answerable: %v", err)
	}
	if _, err := r.Invoke(asUser("dmestas"), "account.agent", accountAgentIn{Name: "zeitgeist", Operator: "forge", Answerable: "dmestas"}); err != nil {
		t.Fatalf("FAIL: %v", err)
	}
	z, _ := db.AccountByName("zeitgeist")
	if !z.Admin || z.Operator != "forge" {
		t.Fatalf("FAIL: re-marked reads %+v", z)
	}
	if _, ok := db.Authenticate("zeitgeist", "a-long-enough-password"); !ok {
		t.Error("FAIL: re-marking retired the password before the cutover")
	}
	// What a site admin may, it may: a person's account, a person's
	// agent, a deed.
	if _, err := r.Invoke(asUser("zeitgeist"), "account.add", accountAddIn{Name: "newperson", Password: "a-long-enough-password"}); err != nil {
		t.Errorf("FAIL: a forge agent with s could not add a person: %v", err)
	}
	if _, err := r.Invoke(asUser("zeitgeist"), "account.agent", accountAgentIn{Name: "newperson", Operator: "jva"}); err != nil {
		t.Errorf("FAIL: a forge agent with s could not mark a person's agent: %v", err)
	}
	if err := db.Grant("zeitgeist", "test", oltp.RepoAdmin); err != nil {
		t.Fatal(err)
	}
	owners.owner["test"] = ""
	if _, err := r.Invoke(asUser("zeitgeist"), "repo.claim", repoClaimIn{Repo: "test"}); err != nil {
		t.Errorf("FAIL: a forge agent could not claim an unheld repository: %v", err)
	}
	if owners.owner["test"] != "zeitgeist" {
		t.Errorf("FAIL: the deed went to %q", owners.owner["test"])
	}
	d := Deps{Owners: owners, Accounts: acctAdapter{db}}
	if err := d.refuseUnlessTheirs(asUser("zeitgeist"), "test", "destroy"); err != nil {
		t.Errorf("FAIL: a forge agent holding the deed was refused a deed act: %v", err)
	}
	// Its own tokens, yes; another forge agent, never.
	if _, err := r.Invoke(asUser("zeitgeist"), "agent.token.new", agentTokenNewIn{Agent: "zeitgeist", Name: "own", Scopes: "api"}); err != nil {
		t.Errorf("FAIL: a forge agent could not mint its own token: %v", err)
	}
	if _, err := r.Invoke(asUser("dmestas"), "agent.new", agentNewIn{Name: "fbot", Operator: "forge", Answerable: "dmestas"}); err != nil {
		t.Fatal(err)
	}
	refused := map[string]any{
		"agent.new":          agentNewIn{Name: "fbot2", Operator: "forge", Answerable: "dmestas"},
		"account.agent":      accountAgentIn{Name: "fbot", Operator: "jva"},
		"account.answerable": accountAnswerableIn{Name: "fbot", Answerable: "dmestas"},
		"agent.token.new":    agentTokenNewIn{Agent: "fbot", Name: "x", Scopes: "api"},
		"agent.delete":       agentNameIn{Name: "fbot"},
		"account.add":        accountAddIn{Name: "newadmin", Password: "a-long-enough-password", Admin: true},
		"account.invite":     accountInviteIn{Name: "invitedadmin", Admin: true},
	}
	for op, in := range refused {
		if _, err := r.Invoke(asUser("zeitgeist"), op, in); !errors.Is(err, ops.ErrForbidden) {
			t.Errorf("FAIL: %s by a forge agent: %v", op, err)
		}
	}
	// Re-marking a person as a forge agent is also making one.
	if _, err := r.Invoke(asUser("zeitgeist"), "account.agent", accountAgentIn{Name: "jva", Operator: "forge", Answerable: "dmestas"}); !errors.Is(err, ops.ErrForbidden) {
		t.Errorf("FAIL: a forge agent re-marked a person as a forge agent: %v", err)
	}
	// Re-inviting a pending site admin without the flag would clear it.
	if _, err := r.Invoke(asUser("dmestas"), "account.invite", accountInviteIn{Name: "pendingadmin", Admin: true}); err != nil {
		t.Fatal(err)
	}
	if _, err := r.Invoke(asUser("zeitgeist"), "account.invite", accountInviteIn{Name: "pendingadmin"}); !errors.Is(err, ops.ErrForbidden) {
		t.Errorf("FAIL: a forge agent re-invited a site admin without the flag: %v", err)
	}
	if a, _ := db.AccountByName("fbot"); a.Operator != "forge" {
		t.Error("FAIL: the other forge agent was altered")
	}
	if a, _ := db.AccountByName("pendingadmin"); !a.Admin {
		t.Error("FAIL: the pending admin lost the flag")
	} else {
		t.Log("ok: a forge agent with s passes account.add and the deed paths, never another forge agent or an s flag")
	}
}