give: test that a trusted party's secret given at the terminal is announced before it is kept, and refuse an unknown machine before anybody types
The terminal path's order is one function, keepGiven, so the test fails when the announcement before a trusted party's secret is removed, and when a failed announcement still keeps it. give also refuses a machine the mesh does not know, as the secret's or as the desk, before the prompt (the final review).
This commit is contained in:
@@ -39,6 +39,9 @@ const deskPromptWithin = 25
|
|||||||
type deskGive struct {
|
type deskGive struct {
|
||||||
// declares refuses a module or a secret the mesh would refuse, before anybody is asked to type.
|
// declares refuses a module or a secret the mesh would refuse, before anybody is asked to type.
|
||||||
declares func(module, name string) error
|
declares func(module, name string) error
|
||||||
|
// known refuses a machine the mesh does not know, before anybody is asked to type; nil knows every one
|
||||||
|
// (a test that does not look).
|
||||||
|
known func(machine string) error
|
||||||
// trusted says a module runs as an account of its own: its secret is never taken at a desk (below). Nil is
|
// trusted says a module runs as an account of its own: its secret is never taken at a desk (below). Nil is
|
||||||
// never (a test that does not look).
|
// never (a test that does not look).
|
||||||
trusted func(module string) (bool, error)
|
trusted func(module string) (bool, error)
|
||||||
@@ -63,6 +66,14 @@ func (d deskGive) give(node, module, name, desk string) (string, error) {
|
|||||||
return "", fmt.Errorf("%s is not named", what)
|
return "", fmt.Errorf("%s is not named", what)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if d.known != nil {
|
||||||
|
for what, machine := range map[string]string{"the machine the secret is for": node, "the desk": desk} {
|
||||||
|
if err := d.known(machine); err != nil {
|
||||||
|
return "", fmt.Errorf("nobody was asked to type anything: %s, %s, is not a machine this mesh knows: %w",
|
||||||
|
what, machine, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := d.declares(module, name); err != nil {
|
if err := d.declares(module, name); err != nil {
|
||||||
return "", fmt.Errorf("nobody was asked to type anything: %w", err)
|
return "", fmt.Errorf("nobody was asked to type anything: %w", err)
|
||||||
}
|
}
|
||||||
@@ -164,7 +175,11 @@ func giveAtDesk(ctx context.Context, node, module, name, desk string) error {
|
|||||||
defer open.Close()
|
defer open.Close()
|
||||||
d := deskGive{
|
d := deskGive{
|
||||||
declares: func(module, name string) error { return open.inventory.DeclaresOwnSecret(ctx, module, name) },
|
declares: func(module, name string) error { return open.inventory.DeclaresOwnSecret(ctx, module, name) },
|
||||||
trusted: func(module string) (bool, error) { return open.inventory.RunsAsItsOwnAccount(ctx, module) },
|
known: func(machine string) error {
|
||||||
|
_, err := open.inventory.NodeByName(ctx, machine)
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
trusted: func(module string) (bool, error) { return open.inventory.RunsAsItsOwnAccount(ctx, module) },
|
||||||
ask: func(machine string, args map[string]any) (json.RawMessage, error) {
|
ask: func(machine string, args map[string]any) (json.RawMessage, error) {
|
||||||
var result json.RawMessage
|
var result json.RawMessage
|
||||||
err := onTheBus(func(conn *nats.Conn) error {
|
err := onTheBus(func(conn *nats.Conn) error {
|
||||||
|
|||||||
@@ -293,3 +293,69 @@ func TestOnlyTheDeskMachinesLauncherMayAnswerItsPrompt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// N1-give at the controller's terminal (the confirmation review of 2026-10-09): a trusted party's secret is
|
||||||
|
// announced before it is kept, and not kept when the announcement fails; another module's is kept first and
|
||||||
|
// a failed announcement is said, not undone.
|
||||||
|
func TestATrustedPartysSecretGivenAtTheTerminalIsAnnouncedBeforeItIsKept(t *testing.T) {
|
||||||
|
var order []string
|
||||||
|
announce := func(fail bool) func() error {
|
||||||
|
return func() error {
|
||||||
|
order = append(order, "announce")
|
||||||
|
if fail {
|
||||||
|
return errors.New("no channel")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keep := func() (bool, error) { order = append(order, "keep"); return false, nil }
|
||||||
|
|
||||||
|
order = nil
|
||||||
|
if _, unannounced, err := keepGiven(true, announce(false), keep); err != nil || unannounced != nil ||
|
||||||
|
strings.Join(order, ",") != "announce,keep" {
|
||||||
|
t.Errorf("trusted: %v %v, order %v; want announced, then kept", unannounced, err, order)
|
||||||
|
}
|
||||||
|
order = nil
|
||||||
|
if _, _, err := keepGiven(true, announce(true), keep); err == nil || strings.Join(order, ",") != "announce" {
|
||||||
|
t.Errorf("trusted, announcement failed: %v, order %v; want refused and nothing kept", err, order)
|
||||||
|
}
|
||||||
|
order = nil
|
||||||
|
if _, unannounced, err := keepGiven(false, announce(true), keep); err != nil || unannounced == nil ||
|
||||||
|
strings.Join(order, ",") != "keep,announce" {
|
||||||
|
t.Errorf("not trusted: %v %v, order %v; want kept, then the failed announcement said", unannounced, err, order)
|
||||||
|
}
|
||||||
|
order = nil
|
||||||
|
failing := func() (bool, error) { order = append(order, "keep"); return false, errors.New("store away") }
|
||||||
|
if _, _, err := keepGiven(false, announce(false), failing); err == nil || strings.Join(order, ",") != "keep" {
|
||||||
|
t.Errorf("not trusted, keep failed: %v, order %v; want refused and nothing announced", err, order)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A machine the mesh does not know, as the secret's or as the desk, is refused before anybody is asked to type.
|
||||||
|
func TestAGiveNamingAMachineTheMeshDoesNotKnowAsksNobody(t *testing.T) {
|
||||||
|
for _, unknown := range []string{"elsewhere", "nodesk"} {
|
||||||
|
d, accepted, acts, asked := aDesk(t, func(map[string]any) (json.RawMessage, error) {
|
||||||
|
t.Fatal("the desk was asked")
|
||||||
|
return nil, nil
|
||||||
|
})
|
||||||
|
d.known = func(machine string) error {
|
||||||
|
if machine == unknown {
|
||||||
|
return errors.New("no node " + machine)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
node, desk := "anchor", "laptop"
|
||||||
|
if unknown == "elsewhere" {
|
||||||
|
node = unknown
|
||||||
|
} else {
|
||||||
|
desk = unknown
|
||||||
|
}
|
||||||
|
_, err := d.give(node, "telegram", "telegram-token", desk)
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "nobody was asked") || !strings.Contains(err.Error(), unknown) {
|
||||||
|
t.Errorf("%s: %v", unknown, err)
|
||||||
|
}
|
||||||
|
if len(*accepted)+len(*acts)+len(*asked) != 0 {
|
||||||
|
t.Errorf("%s: something happened: %v %v %v", unknown, *accepted, *acts, *asked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -115,20 +115,18 @@ func secretCommand(ctx context.Context, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if trusted {
|
untilStart, unannounced, err := keepGiven(trusted,
|
||||||
if err := announceSecretGiven(ctx, node, module, name, "at the controller's terminal"); err != nil {
|
func() error { return announceSecretGiven(ctx, node, module, name, "at the controller's terminal") },
|
||||||
|
func() (bool, error) { return open.inventory.AcceptGivenSecret(ctx, node, module, name, value) })
|
||||||
|
if err != nil {
|
||||||
|
if trusted && unannounced != nil {
|
||||||
return fmt.Errorf("%s runs as an account of its own, and the change of its %s could not be announced on "+
|
return fmt.Errorf("%s runs as an account of its own, and the change of its %s could not be announced on "+
|
||||||
"your channels first, so nothing was kept: %w", module, name, err)
|
"your channels first, so nothing was kept: %w", module, name, err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
untilStart, err := open.inventory.AcceptGivenSecret(ctx, node, module, name, value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !trusted {
|
if unannounced != nil {
|
||||||
if err := announceSecretGiven(ctx, node, module, name, "at the controller's terminal"); err != nil {
|
fmt.Printf(" this change could NOT be announced on the operator's channels: %v\n", unannounced)
|
||||||
fmt.Printf(" this change could NOT be announced on the operator's channels: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Not printed back, and there is nowhere it could be printed from: it is sealed to that
|
// Not printed back, and there is nowhere it could be printed from: it is sealed to that
|
||||||
// machine and the mesh cannot read it again.
|
// machine and the mesh cannot read it again.
|
||||||
@@ -487,3 +485,23 @@ func whoAsked() string {
|
|||||||
}
|
}
|
||||||
return "the mesh"
|
return "the mesh"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// keepGiven keeps a value given at the controller's terminal, and announces it on the operator's channels
|
||||||
|
// (the confirmation review of 2026-10-09, N1-give). **A trusted party's — a module running as an account of its
|
||||||
|
// own: the router, a verified channel — is announced before it is kept, and not kept when the announcement
|
||||||
|
// fails**: a channel whose token changed unheard of answers for somebody else. Any other module's is kept first
|
||||||
|
// and announced after, and a failed announcement is said (unannounced) without undoing it.
|
||||||
|
func keepGiven(trusted bool, announce func() error, keep func() (bool, error)) (untilStart bool, unannounced, err error) {
|
||||||
|
if trusted {
|
||||||
|
if err := announce(); err != nil {
|
||||||
|
return false, err, err
|
||||||
|
}
|
||||||
|
untilStart, err = keep()
|
||||||
|
return untilStart, nil, err
|
||||||
|
}
|
||||||
|
untilStart, err = keep()
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
return untilStart, announce(), nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user