give: take only a value a person holds, ask the desk by name, let the controller alone ask it, and announce every value given

The review of 2026-10-09 (M4):
- give refuses broker (the bus account issue mints) and any own secret the mesh may make itself;
- the desk's prompt is asked by module, secret and machine, never with words of the caller's, and the
  bus denies the prompt's subjects to every principal but the controller, however wide its grant, so the
  prompt's 'the controller asks' is the bus's word (Permissions.PublishDeny, broker.ControllerOnly);
- secret accept with a value is refused through a verb: a value comes from the terminal or the desk;
- every value given for an own secret, at the terminal or the desk, raises the urgent condition
  secret-given on every channel, until the operator silences it.
This commit is contained in:
2026-10-09 16:22:47 +02:00
parent 5689553406
commit be59f29f46
7 changed files with 250 additions and 13 deletions
+28
View File
@@ -0,0 +1,28 @@
package inventory
import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
)
// `give` takes only a value nobody but a person has (the review of 2026-10-09, M4): never the module's bus
// account, which `issue` mints, nor a secret the mesh may make itself.
func TestOnlyASecretThePersonHoldsIsGivenAtTheDesk(t *testing.T) {
m := catalogue.Manifest{Module: "telegram", OwnSecrets: catalogue.OwnSecrets{
"telegram-token": {Path: "/s/telegram-token"},
"broker": {Path: "/s/broker"},
"session": {Path: "/s/session", Taken: catalogue.TakenAtStart},
}}
if err := GivableAtDesk(m, "telegram-token"); err != nil {
t.Errorf("the bot token was refused: %v", err)
}
for _, name := range []string{"broker", "session", "chat-id"} {
if err := GivableAtDesk(m, name); err == nil {
t.Errorf("%s was givable", name)
} else if name != "chat-id" && !strings.Contains(err.Error(), "the mesh makes") {
t.Errorf("%s: %v", name, err)
}
}
}
+22 -2
View File
@@ -561,8 +561,28 @@ func (i *Inventory) DeclaresOwnSecret(ctx context.Context, module, name string)
if err != nil {
return err
}
if _, ok := m.OwnSecrets[name]; !ok {
return fmt.Errorf("%s does not declare %q as an own secret; %s", module, name, declaresOwn(m))
return GivableAtDesk(m, name)
}
// BrokerSecret is the own secret that is a module's bus account, which `issue` mints.
const BrokerSecret = "broker"
// GivableAtDesk refuses, in words, an own secret a module does not declare, and one the mesh makes itself
// (the review of 2026-10-09, M4): the module's bus account, which `issue` mints, and any the mesh may make
// in place of a value given (catalogue.OwnSecret.MeshMayMake). The desk takes only what a person holds and
// the mesh cannot make — a bot's token — so nobody is asked to type the mesh's own credential into a prompt.
func GivableAtDesk(m catalogue.Manifest, name string) error {
own, ok := m.OwnSecrets[name]
if !ok {
return fmt.Errorf("%s does not declare %q as an own secret; %s", m.Module, name, declaresOwn(m))
}
switch {
case name == BrokerSecret:
return fmt.Errorf("%q is %s's account on the bus, which the mesh makes (`issue`), never a value a person gives",
name, m.Module)
case own.MeshMayMake():
return fmt.Errorf("%q of %s is a secret the mesh makes itself (it may replace a value given at the module's "+
"start, ADR 0228); a person gives it only at the controller's terminal, with `secret accept`", name, m.Module)
}
return nil
}