package oltp
import "testing"
// RFC 0026: a person's agent set to inherit holds its operator's
// letters wherever it has no string, a string narrows, and nothing
// reaches past the operator.
func TestInheritingAgentHoldsItsOperator(t *testing.T) {
db := agentRig(t)
if err := db.SetInherit("dmestas", "dmestas-coder", true); err != nil {
t.Fatal(err)
}
if err := db.Grant("dmestas", "priv", Write); err != nil {
t.Fatal(err)
}
op := letters(db.EffectiveCaps("dmestas", "priv"))
if got := letters(db.EffectiveCaps("dmestas-coder", "priv")); got != op {
t.Errorf("FAIL: with no string the agent holds %q, its operator %q", got, op)
}
if err := db.Grant("dmestas", "priv", Read); err != nil {
t.Fatal(err)
}
op = letters(db.EffectiveCaps("dmestas", "priv"))
if got := letters(db.EffectiveCaps("dmestas-coder", "priv")); got != op {
t.Errorf("FAIL: after the operator dropped to reader the agent holds %q, the operator %q", got, op)
}
t.Log("ok: inherits, and loses a letter with its operator")
}
func TestAGrantNarrowsAnInheritingAgent(t *testing.T) {
db := agentRig(t)
if err := db.SetInherit("dmestas", "dmestas-coder", true); err != nil {
t.Fatal(err)
}
if err := db.Grant("dmestas", "priv", Write); err != nil {
t.Fatal(err)
}
if _, _, err := db.AgentGrant("dmestas", "dmestas-coder", "priv", Read.Caps()); err != nil {
t.Fatal(err)
}
if got := db.EffectiveCaps("dmestas-coder", "priv"); got.HasAny("i") || !got.HasAny("o") {
t.Errorf("FAIL: narrowed to reader, the agent holds %q", letters(got))
}
// Nothing, said on purpose, is nothing: not a return to inheriting.
if _, _, err := db.AgentGrant("dmestas", "dmestas-coder", "priv", ""); err != nil {
t.Fatal(err)
}
if got := db.EffectiveCaps("dmestas-coder", "priv"); got.HasAny("o") {
t.Errorf("FAIL: narrowed to nothing on a private repository, the agent holds %q", letters(got))
}
if err := db.AgentInheritHere("dmestas", "dmestas-coder", "priv"); err != nil {
t.Fatal(err)
}
if got, op := letters(db.EffectiveCaps("dmestas-coder", "priv")), letters(db.EffectiveCaps("dmestas", "priv")); got != op {
t.Errorf("FAIL: after dropping the narrowing the agent holds %q, its operator %q", got, op)
}
t.Log("ok: a string narrows, an empty one closes, dropping it inherits again")
}
func TestOnlyWhereSetHoldsNothingUnwritten(t *testing.T) {
db := agentRig(t) // the rig's agent is only-where-set
if err := db.Grant("dmestas", "priv", Write); err != nil {
t.Fatal(err)
}
if got := db.EffectiveCaps("dmestas-coder", "priv"); got.HasAny("o") {
t.Errorf("FAIL: an only-where-set agent with no string holds %q on a private repository", letters(got))
}
t.Log("ok: only where set")
}
// The site-admin flag is no letter and is never inherited (decision 4
// makes it an opt-in, not built yet).
func TestInheritingNeverCarriesSiteAdmin(t *testing.T) {
db := agentRig(t)
if err := db.NewAgent("root-coder", "root", -1); err != nil {
t.Fatal(err)
}
if !db.EffectiveCaps("root", fleetRepo).HasAny("s") {
t.Fatal("rig: root is not a site admin")
}
if got := db.EffectiveCaps("root-coder", fleetRepo); got.HasAny("s") {
t.Errorf("FAIL: a site admin's inheriting agent holds s: %q", letters(got))
}
t.Log("ok: no s by inheritance")
}
func TestInheritingAgentOfADisabledOperatorHoldsThePublic(t *testing.T) {
db := agentRig(t)
if err := db.SetInherit("dmestas", "dmestas-coder", true); err != nil {
t.Fatal(err)
}
if err := db.Grant("dmestas", "priv", Write); err != nil {
t.Fatal(err)
}
if err := db.SetDisabled("dmestas", true); err != nil {
t.Fatal(err)
}
if got := db.EffectiveCaps("dmestas-coder", "priv"); got.HasAny("o") {
t.Errorf("FAIL: the agent of a disabled operator holds %q", letters(got))
}
t.Log("ok: a disabled operator passes on nothing")
}
// Migration: an agent made before the column reads only-where-set,
// so its reach does not widen; one made now inherits.
func TestAgentsBeforeRFC0026DoNotWiden(t *testing.T) {
db := agentRig(t)
if _, err := db.w.Exec(`INSERT INTO account (name, pwhash, admin, created, operator) VALUES ('old-bot', '', 0, ?, 'dmestas')`, now()); err != nil {
t.Fatal(err)
}
if a, _ := db.AccountByName("old-bot"); a.Inherit {
t.Error("FAIL: an agent written without the column inherits")
}
if err := db.NewAgent("new-bot", "dmestas", -1); err != nil {
t.Fatal(err)
}
if a, _ := db.AccountByName("new-bot"); !a.Inherit {
t.Error("FAIL: a new agent does not inherit")
}
t.Log("ok: old agents keep their reach, new ones inherit")
}
func TestOnlyTheOperatorSetsTheSwitch(t *testing.T) {
db := agentRig(t)
if err := db.SetInherit("jva", "dmestas-coder", true); err == nil {
t.Error("FAIL: a stranger switched another person's agent")
}
if err := db.AgentInheritHere("jva", "dmestas-coder", "pub"); err == nil {
t.Error("FAIL: a stranger dropped another person's narrowing")
}
t.Log("ok: the switch is the operator's")
}
// Review of !1147: an inheriting agent's a is its operator's, so it
// never keeps the last admin standing.
func TestAnInheritingAgentIsNotTheLastAdmin(t *testing.T) {
db := agentRig(t)
if err := db.SetInherit("dmestas", "dmestas-coder", true); err != nil {
t.Fatal(err)
}
if err := db.Grant("dmestas", "priv", RepoAdmin); err != nil {
t.Fatal(err)
}
if _, err := db.SetCapsGuarded("root", "dmestas", "priv", "o"); err == nil {
t.Errorf("FAIL: the sole admin was demoted because their inheriting agent counted as an admin")
}
t.Log("ok: the last-admin guard ignores agents")
}
// Review of !1147: removing an inheriting agent's access, by anyone,
// closes it; it never widens it to its operator's letters.
func TestARemovalNeverWidensAnInheritingAgent(t *testing.T) {
db := agentRig(t)
if err := db.SetInherit("dmestas", "dmestas-coder", true); err != nil {
t.Fatal(err)
}
if err := db.Grant("dmestas", "priv", Write); err != nil {
t.Fatal(err)
}
if _, _, err := db.AgentGrant("dmestas", "dmestas-coder", "priv", Read.Caps()); err != nil {
t.Fatal(err)
}
if _, err := db.SetCapsGuarded("root", "dmestas-coder", "priv", ""); err != nil {
t.Fatal(err)
}
if got := db.EffectiveCaps("dmestas-coder", "priv"); got.HasAny("o") || got.HasAny("i") {
t.Errorf("FAIL: an admin's removal left the agent holding %q", letters(got))
}
if _, err := db.GrantGuarded("root", "dmestas-coder", "priv", NoRole); err != nil {
t.Fatal(err)
}
if got := db.EffectiveCaps("dmestas-coder", "priv"); got.HasAny("i") {
t.Errorf("FAIL: a NoRole grant widened the agent to %q", letters(got))
}
t.Log("ok: a removal closes")
}
func TestADisabledAgentInheritsNothing(t *testing.T) {
db := agentRig(t)
if err := db.SetInherit("dmestas", "dmestas-coder", true); err != nil {
t.Fatal(err)
}
if err := db.Grant("dmestas", "priv", Write); err != nil {
t.Fatal(err)
}
if err := db.SetDisabled("dmestas-coder", true); err != nil {
t.Fatal(err)
}
if got := db.EffectiveCaps("dmestas-coder", "priv"); got.HasAny("o") {
t.Errorf("FAIL: a disabled inheriting agent resolves to %q", letters(got))
}
t.Log("ok: disabled inherits nothing")
}
// The roster and the take-private wizard see an inheriting agent where
// its operator reaches, and only there.
func TestTheRosterNamesAnInheritingAgent(t *testing.T) {
db := agentRig(t)
if err := db.SetInherit("dmestas", "dmestas-coder", true); err != nil {
t.Fatal(err)
}
if err := db.Grant("dmestas", "priv", Write); err != nil {
t.Fatal(err)
}
inherits := func(repo string) string {
hs, err := db.CapHolders(repo)
if err != nil {
t.Fatal(err)
}
for _, h := range hs {
if h.Account == "dmestas-coder" {
return h.Inherits
}
}
return ""
}
if got := inherits("priv"); got != "dmestas" {
t.Errorf("FAIL: on the operator's repository the roster has the agent inheriting from %q", got)
}
if got := inherits("pub"); got != "" {
t.Errorf("FAIL: where the operator holds nothing the roster lists the agent inheriting from %q", got)
}
names, err := db.ReachOnlyByCategory("pub")
if err != nil {
t.Fatal(err)
}
for _, n := range names {
if n == "dmestas-coder" {
t.Errorf("FAIL: the take-private wizard offers an inheriting agent a role")
}
}
t.Log("ok: roster and wizard")
}