A person may be issued, listed and revoked
Design 25 §7's first item, which existed as a permission model and as nothing a person could actually be given. There is a record now, and three commands. Their authority is a list of tools and nothing else. Not a module: they hold no seat, nothing is addressed to them, nothing is delivered to them, and they have no consumer to acknowledge. What they have is permission to ask — which is why there is no scope and no node in the record. Stating what somebody may call replaces what was there rather than adding to it: a list that could only grow is a permission nobody can take back. Forgetting somebody takes their credential with them, because a person's row gone with their bus user left behind is a credential that still works and that nothing derives — the worst of both, since it keeps working and nobody can explain why. The credential is printed once and the mesh keeps only a hash, the same contract a token has. And it starts working at the next composition rather than immediately, because the bus's users are a file — said out loud in both the issue and the revoke messages, since "revoked" that still works for another minute is worth knowing about. Four properties held by test, each a way of being wrong that would not announce itself: a person may publish exactly the tool subjects they were given and nothing on control, nodes or events; they cannot answer a request; changing the list removes what is no longer named; and forgetting them revokes them.
This commit is contained in:
@@ -163,3 +163,70 @@ func (i *Inventory) SeedBusUser(ctx context.Context, u BusUser, password string)
|
||||
u.Username, u.Kind, u.Node, u.Module, string(hash))
|
||||
return err
|
||||
}
|
||||
|
||||
// A person who may call the mesh's tools (novox/hq design 25 §7).
|
||||
//
|
||||
// **Their authority is a list of tools and nothing else.** Not a module: they hold no seat, nothing is
|
||||
// addressed to them, nothing is delivered to them, and they have no consumer to acknowledge. What
|
||||
// they have is permission to ask.
|
||||
|
||||
// Person is somebody who may reach the mesh's tools.
|
||||
type Person struct {
|
||||
Name string
|
||||
// Invokes are the tools they may call, each `<module>.<tool>`, or the single entry `*` for an
|
||||
// administrator.
|
||||
Invokes []string
|
||||
}
|
||||
|
||||
// RecordPerson adds somebody, or changes what they may call.
|
||||
//
|
||||
// Replacing rather than merging: what a person may call is stated in full, so a change that meant to
|
||||
// remove a tool does remove it. A list that could only grow is a permission nobody can take back.
|
||||
func (i *Inventory) RecordPerson(ctx context.Context, p Person) error {
|
||||
if p.Name == "" {
|
||||
return errors.New("a person needs a name: it becomes their user on the bus")
|
||||
}
|
||||
if len(p.Invokes) == 0 {
|
||||
return fmt.Errorf(
|
||||
"%s may call nothing, so there is no reason for them to reach the mesh. Name the tools, "+
|
||||
"or `*` for an administrator", p.Name)
|
||||
}
|
||||
_, err := i.store.Pool().Exec(ctx,
|
||||
`insert into person (name, invokes) values ($1, $2)
|
||||
on conflict (name) do update set invokes = excluded.invokes`,
|
||||
p.Name, p.Invokes)
|
||||
return err
|
||||
}
|
||||
|
||||
// People is everybody who may reach the mesh's tools.
|
||||
func (i *Inventory) People(ctx context.Context) ([]Person, error) {
|
||||
rows, err := i.store.Pool().Query(ctx, `select name, invokes from person order by name`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []Person
|
||||
for rows.Next() {
|
||||
var p Person
|
||||
if err := rows.Scan(&p.Name, &p.Invokes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, p)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
// ForgetPerson removes somebody and the credential they were given.
|
||||
//
|
||||
// **Both, or neither is a revocation.** A person's row gone and their bus user left behind is a
|
||||
// credential that still works and that nothing derives, which is the worst of both: it keeps working
|
||||
// and nobody can explain why.
|
||||
func (i *Inventory) ForgetPerson(ctx context.Context, name string) error {
|
||||
if name == "" {
|
||||
return errors.New("forgetting nobody would forget everybody")
|
||||
}
|
||||
if _, err := i.store.Pool().Exec(ctx, `delete from person where name = $1`, name); err != nil {
|
||||
return err
|
||||
}
|
||||
return i.ForgetBusUser(ctx, "person."+name)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user