N1-router: another account's /start offered the desk an unlink of the operator's account in its first hour, and a desk click, which a program on the desk machine can forge, unlinked it and barred it for a day, again and again. An unlink at the desk in the first hour now bars nothing: any account, the operator's too, links again at once with a code from the desk; the day's bar stays for an account removed by its own approval or by root, and root's allow-link lifts any bar. The words say which. Lows: the controller's root-free word is asked before the work is taken (it waited up to 10 s inside it) and the answer is judged with that fresh word; inside the work only a recent word is read, and a failed ask drops the old one. An answer whose effect the content rule withholds is not offered. mesh-sdk moves to 16984aa. Each test failed before its fix.
536 lines
22 KiB
Go
536 lines
22 KiB
Go
package main
|
|
|
|
// The findings of the review of 2026-10-09, each held here by a test that failed before its fix.
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/asks"
|
|
)
|
|
|
|
// H3: approval rests on the controller's positive, recent word that no agent can become root where the router
|
|
// and the channel run (its verb root-free), asked live. Every other answer fails closed.
|
|
func TestApprovalNeedsTheControllersWordThatRootIsFree(t *testing.T) {
|
|
for name, tc := range map[string]struct {
|
|
setup func(h *Holder)
|
|
want string
|
|
}{
|
|
"a router that does not know its machine": {func(h *Holder) { h.Node = "" }, "does not know which machine"},
|
|
"a channel whose machine is not said": {func(h *Holder) {
|
|
k, _ := h.Bench.Kind("telegram")
|
|
k.Node = ""
|
|
h.Bench.SetKinds([]KindInfo{k})
|
|
}, "has not said which machine"},
|
|
"a controller that does not answer": {func(h *Holder) {
|
|
h.RootFree = func([]string) (map[string]RootVerdict, error) { return nil, errors.New("no responders") }
|
|
}, "could not be asked: no responders"},
|
|
"a machine the answer leaves out": {func(h *Holder) {
|
|
h.RootFree = func([]string) (map[string]RootVerdict, error) { return map[string]RootVerdict{}, nil }
|
|
}, "said nothing of whether an agent can become root on anchor"},
|
|
"a machine not free": {func(h *Holder) { rootFreeOf[h]["anchor"] = "the agent account is not judged" },
|
|
"may become root on anchor"},
|
|
"the router's own machine not free": {func(h *Holder) {
|
|
h.Node = "router-machine"
|
|
rootFreeOf[h]["router-machine"] = "execute is served there"
|
|
}, "may become root on router-machine"},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
h, tg, _, c, store, w := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
|
|
settle(h, c)
|
|
release := ticketFor(tg.sends[0], "Release")
|
|
if release == "" {
|
|
t.Fatal("not offered while root was free")
|
|
}
|
|
tc.setup(h)
|
|
out, err := h.Chosen("telegram", choiceOf(release, "42", c.now()))
|
|
if out != "refused" || err == nil || !strings.Contains(err.Error(), tc.want) {
|
|
t.Fatalf("%s %v, want refused for %q", out, err, tc.want)
|
|
}
|
|
if len(w.of("mesh-delivery")) != 0 {
|
|
t.Error("a warrant was issued")
|
|
}
|
|
if got := h.carriers(asks.Approve); len(got) != 0 {
|
|
t.Errorf("approval still carried on %v", got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// H3: the word is asked of the controller's verb, as this module, and read from its answer.
|
|
func TestTheRootWordIsAskedOfTheControllersVerb(t *testing.T) {
|
|
h, _, _, _, _, _ := newRouter(t)
|
|
h.RootFree = nil
|
|
var asked []string
|
|
h.Ask = func(key string, body any) (json.RawMessage, error) {
|
|
asked = append(asked, key)
|
|
raw, _ := json.Marshal(body)
|
|
if !strings.Contains(string(raw), `"machines":["anchor"]`) {
|
|
t.Errorf("asked about %s", raw)
|
|
}
|
|
return json.RawMessage(`{"machines":[{"machine":"anchor","free":true,"why":"judged","judged":"2026-10-09T10:00:00Z"}]}`), nil
|
|
}
|
|
info, _ := h.Bench.Kind("telegram")
|
|
if why := h.rootFree(info, false); why != "" {
|
|
t.Fatalf("free not read: %s", why)
|
|
}
|
|
if len(asked) != 1 || asked[0] != "seat:mesh-controller.root-free" {
|
|
t.Errorf("asked %v", asked)
|
|
}
|
|
h.Ask = func(string, any) (json.RawMessage, error) { return json.RawMessage(`not json`), nil }
|
|
if why := h.rootFree(info, false); !strings.Contains(why, "could not be read") {
|
|
t.Errorf("an unreadable answer was a pass: %q", why)
|
|
}
|
|
h.Ask = nil
|
|
if why := h.rootFree(info, false); why == "" {
|
|
t.Error("no way to ask was a pass")
|
|
}
|
|
}
|
|
|
|
// H3: a message rendered while root is not free offers no approval; a word kept for rendering is never the
|
|
// word an answer is judged on.
|
|
func TestAMessageRenderedWhileRootIsNotFreeOffersNoApproval(t *testing.T) {
|
|
h, tg, _, c, store, _ := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
|
|
settle(h, c)
|
|
rec := h.openAsk(h.open["ask.mesh-delivery.d-1"])
|
|
if got := h.offers(rec, "telegram"); len(got) != 3 {
|
|
t.Fatalf("offers %v", got)
|
|
}
|
|
rootFreeOf[h]["anchor"] = "not judged"
|
|
c.pass(RootFreeKept)
|
|
if got := h.offers(rec, "telegram"); len(got) != 0 {
|
|
t.Errorf("rendered with an approval while root is not free: %v", got)
|
|
}
|
|
// Free again, but the kept word is not: the answer asks anew and is taken.
|
|
delete(rootFreeOf[h], "anchor")
|
|
out, err := h.Chosen("telegram", choiceOf(ticketFor(tg.sends[0], "Release"), "42", c.now()))
|
|
if err != nil || out != "chosen" {
|
|
t.Errorf("judged on a kept word: %s %v", out, err)
|
|
}
|
|
}
|
|
|
|
// H3: a capability the controller's word no longer says stays no longer than the word is fresh: a router that
|
|
// cannot read the kinds again promises no verified sender.
|
|
func TestAStaleWordOnTheKindsPromisesNoVerifiedSender(t *testing.T) {
|
|
h, _, _, c, store, _ := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
if !h.Bench.Promises("telegram", "verified-sender") {
|
|
t.Fatal("not promised while fresh")
|
|
}
|
|
c.pass(KindsFresh + time.Second)
|
|
h.Bench.Stand("telegram", Standing{Ready: true, At: c.now()})
|
|
if h.Bench.Promises("telegram", "verified-sender") || len(h.carriers(asks.Approve)) != 0 {
|
|
t.Error("a stale word still promises a verified sender")
|
|
}
|
|
if !h.Bench.Promises("telegram", "choice") {
|
|
t.Error("a stale word stopped the channel sending")
|
|
}
|
|
}
|
|
|
|
// C6: a link's code is marked secret on every path to a channel, the desk's own role included, so the channel
|
|
// keeps no copy (the review found it dropped where the desk's role sends).
|
|
func TestALinksCodeIsSecretOnEveryPath(t *testing.T) {
|
|
c := start()
|
|
bench := NewBench(c.now)
|
|
bench.SetKinds([]KindInfo{
|
|
{Kind: "telegram", Module: "telegram", Node: "anchor", Capabilities: []string{"reaches-away", "choice", "verified-sender", "exact-render"}},
|
|
{Kind: "desktop", Module: "desk-channel", Node: "anchor", Capabilities: []string{"choice", "exact-render", "private"}},
|
|
})
|
|
bench.Stand("telegram", Standing{Ready: true, At: c.now()})
|
|
bench.Stand("desktop", Standing{Ready: true, At: c.now()})
|
|
var mu sync.Mutex
|
|
put := map[string][]asks.Message{}
|
|
publish := func(subject string, body any, id string) error {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
if m, ok := body.(asks.Message); ok {
|
|
put[subject] = append(put[subject], m)
|
|
}
|
|
return nil
|
|
}
|
|
h := &Holder{Away: &SeatChannel{Bench: bench, Role: RoleAway, Publish: publish},
|
|
Desk: &SeatChannel{Bench: bench, Role: RoleDesk, Publish: publish}, Bench: bench, Publish: publish,
|
|
Asks: newMemAsks(), Node: "anchor", Now: c.now, Logf: t.Logf, Zone: func() *time.Location { return time.UTC }}
|
|
h.init()
|
|
h.Link("telegram", asks.LinkAsked{ID: "l1", At: c.now(), Sender: asks.Sender{Identity: "42", Display: "Jo", Authenticated: true}})
|
|
shown := put[asks.ChannelSubject(asks.Send, "desktop")]
|
|
if len(shown) != 1 || !strings.Contains(shown[0].Body, "send this code") {
|
|
t.Fatalf("the code was not shown on the desk: %+v", put)
|
|
}
|
|
if !shown[0].Secret {
|
|
t.Error("the code went to the desk not marked secret: the channel would keep a copy")
|
|
}
|
|
}
|
|
|
|
// L1: a warrant's message id is new each time: one anyone could foresee lets another publisher on the stream
|
|
// take it first, and the bus would drop the warrant as a duplicate.
|
|
func TestAWarrantsMessageIdCannotBeForeseen(t *testing.T) {
|
|
h, tg, _, c, store, _ := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
var ids []string
|
|
h.Publish = func(subject string, body any, id string) error {
|
|
if _, ok := body.(asks.Warrant); ok {
|
|
ids = append(ids, id)
|
|
}
|
|
return nil
|
|
}
|
|
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
|
|
settle(h, c)
|
|
if out, err := h.Chosen("telegram", choiceOf(ticketFor(tg.sends[0], "Release"), "42", c.now())); out != "chosen" {
|
|
t.Fatalf("%s %v", out, err)
|
|
}
|
|
_ = h.tell(*store.asks["mesh-delivery.d-1"].Warrant)
|
|
if len(ids) != 2 || ids[0] == ids[1] {
|
|
t.Fatalf("ids %v", ids)
|
|
}
|
|
for _, id := range ids {
|
|
if strings.Contains(id, "d-1") || strings.Contains(id, "mesh-delivery") {
|
|
t.Errorf("the id %q is made of what anyone knows of the ask", id)
|
|
}
|
|
}
|
|
}
|
|
|
|
// M2: an ask's message says who asks, as the bus proves it, what each answer does, and what happens if nobody
|
|
// answers.
|
|
func TestAnAsksMessageSaysWhoAsksWhatEachAnswerDoesAndWhatExpiryDoes(t *testing.T) {
|
|
h, tg, _, c, store, _ := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
|
|
settle(h, c)
|
|
body := tg.sends[0].Body
|
|
for _, want := range []string{"Asked by mesh-delivery.", "Release: the delivery goes on.", "Stop: the delivery ends.",
|
|
"Silence for a week: nothing more is said of it for a week.",
|
|
"If nobody answers by " + c.now().Add(2*time.Hour-BurstWindow).In(time.UTC).Format("15:04") + ": the delivery stays held."} {
|
|
if !strings.Contains(body, want) {
|
|
t.Errorf("the message does not say %q:\n%s", want, body)
|
|
}
|
|
}
|
|
}
|
|
|
|
// M3: the router's own unlink binds the account it asks about: an approval from that account, after another was
|
|
// linked in its place, unlinks nothing.
|
|
func TestAnUnlinkUnlinksOnlyTheAccountItNamed(t *testing.T) {
|
|
h, tg, _, c, store, _ := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
if _, err := h.Unlink("telegram"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
unlink := ticketFor(tg.sends[len(tg.sends)-1], "Unlink")
|
|
delete(store.ids, identityKey("telegram", "42"))
|
|
store.ids[identityKey("telegram", "77")] = Identity{Kind: "telegram", Identity: "77", Display: "Al",
|
|
Linked: c.now().Add(-2 * time.Hour), ApproveFrom: c.now().Add(-time.Hour)}
|
|
_, _ = h.Chosen("telegram", choiceOf(unlink, "42", c.now()))
|
|
if _, still := store.ids[identityKey("telegram", "77")]; !still {
|
|
t.Error("an approval to unlink 42 unlinked 77")
|
|
}
|
|
if got := store.asks; len(got) == 0 {
|
|
t.Fatal("no ask")
|
|
}
|
|
for _, rec := range store.asks {
|
|
if rec.Act != nil && rec.Act.Identity != "42" {
|
|
t.Errorf("the ask binds %q", rec.Act.Identity)
|
|
}
|
|
}
|
|
}
|
|
|
|
// M3: a link is checked again as it is made: an approved relink does not link a second account of a kind.
|
|
func TestALinkIsNotMadeWhileAnotherAccountIsLinked(t *testing.T) {
|
|
h, tg, dt, c, store, _ := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
_, _ = h.Unlink("telegram")
|
|
_, _ = h.Chosen("telegram", choiceOf(ticketFor(tg.sends[len(tg.sends)-1], "Unlink"), "42", c.now()))
|
|
h.Link("telegram", asks.LinkAsked{ID: "l9", At: c.now(), Sender: asks.Sender{Identity: "666", Display: "Eve", Authenticated: true}})
|
|
code := codeOf(t, dt.sends[len(dt.sends)-1])
|
|
_ = h.Prove("telegram", asks.Code{Sender: asks.Sender{Identity: "666", Authenticated: true}, Code: code})
|
|
asked := tg.sends[len(tg.sends)-1]
|
|
// Meanwhile root linked another account (allowed at the machine).
|
|
store.ids[identityKey("telegram", "77")] = Identity{Kind: "telegram", Identity: "77", Linked: c.now(), ApproveFrom: c.now().Add(time.Hour)}
|
|
_, _ = h.Chosen("telegram", choiceOf(ticketFor(asked, "Allow"), "42", c.now()))
|
|
if _, linked := store.ids[identityKey("telegram", "666")]; linked {
|
|
t.Errorf("a second account of a kind was linked: %v", store.ids)
|
|
}
|
|
}
|
|
|
|
// M3: an account unlinked less than a day ago is not linked again by a code: no code is shown for it.
|
|
func TestAnUnlinkedAccountDoesNotComeBackByACodeWithinADay(t *testing.T) {
|
|
h, tg, dt, c, store, _ := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
_, _ = h.Unlink("telegram")
|
|
_, _ = h.Chosen("telegram", choiceOf(ticketFor(tg.sends[len(tg.sends)-1], "Unlink"), "42", c.now()))
|
|
shown := len(dt.sends)
|
|
h.Link("telegram", asks.LinkAsked{ID: "l1", At: c.now(), Sender: asks.Sender{Identity: "42", Display: "Jo", Authenticated: true}})
|
|
if _, pending := store.links["telegram"]; pending {
|
|
t.Error("a link was begun for the account unlinked an hour ago")
|
|
}
|
|
for _, m := range dt.sends[shown:] {
|
|
if strings.Contains(m.Body, "send this code") {
|
|
t.Error("a code was shown for it")
|
|
}
|
|
}
|
|
if len(store.ids) != 0 {
|
|
t.Error("linked again")
|
|
}
|
|
}
|
|
|
|
// H4: an account still in its first hour cannot approve yet, so whoever is at the desk may unlink it — asked
|
|
// there when another account asks to be linked — and past its hour the desk no longer can.
|
|
func TestAnAccountInItsFirstHourIsUnlinkedFromTheDesk(t *testing.T) {
|
|
h, tg, dt, c, store, w := newRouter(t)
|
|
link(h, store, c, "666", c.now().Add(-10*time.Minute)) // an account the operator did not link
|
|
h.Link("telegram", asks.LinkAsked{ID: "l1", At: c.now(), Sender: asks.Sender{Identity: "42", Display: "Jo", Authenticated: true}})
|
|
if reply := tg.sends[len(tg.sends)-1]; !strings.Contains(reply.Body, "unlink it at your desk") {
|
|
t.Fatalf("the sender was not told how: %q", reply.Body)
|
|
}
|
|
asked := dt.sends[len(dt.sends)-1]
|
|
if labelsOf(asked) != "Unlink it" || !strings.Contains(asked.Body, "number 666") {
|
|
t.Fatalf("the desk was not asked: %+v", asked)
|
|
}
|
|
ch := choiceOf(ticketFor(asked, "Unlink it"), "g14", c.now())
|
|
ch.Sender.Authenticated = false
|
|
if out, err := h.Chosen("desktop", ch); err != nil || out != "chosen" {
|
|
t.Fatalf("%s %v", out, err)
|
|
}
|
|
if len(store.ids) != 0 {
|
|
t.Errorf("not unlinked: %v", store.ids)
|
|
}
|
|
if len(w.of(SelfAsker)) != 0 {
|
|
t.Error("the router's own act was told to an asker")
|
|
}
|
|
// Past its hour, no question goes to the desk.
|
|
h2, tg2, dt2, c2, store2, _ := newRouter(t)
|
|
link(h2, store2, c2, "666", c2.now().Add(-2*time.Hour))
|
|
h2.Link("telegram", asks.LinkAsked{ID: "l1", At: c2.now(), Sender: asks.Sender{Identity: "42", Authenticated: true}})
|
|
for _, m := range dt2.sends {
|
|
if labelsOf(m) == "Unlink it" {
|
|
t.Error("the desk was asked to unlink an account past its first hour")
|
|
}
|
|
}
|
|
if !strings.Contains(tg2.sends[len(tg2.sends)-1].Body, "own approval, or as root") {
|
|
t.Errorf("%q", tg2.sends[len(tg2.sends)-1].Body)
|
|
}
|
|
}
|
|
|
|
// H4 (C4): while the desk cannot show a code now — its notifications paused — no link is begun and no code is
|
|
// made or queued; the sender is told why.
|
|
func TestNoLinkIsBegunWhileTheDeskCannotShowTheCode(t *testing.T) {
|
|
h, tg, dt, c, store, _ := newRouter(t)
|
|
h.Bench.Stand("desktop", Standing{Ready: false, Why: "notifications are paused on the desk", At: c.now()})
|
|
h.Link("telegram", asks.LinkAsked{ID: "l1", At: c.now(), Sender: asks.Sender{Identity: "42", Display: "Jo", Authenticated: true}})
|
|
if _, pending := store.links["telegram"]; pending {
|
|
t.Error("a link was begun")
|
|
}
|
|
if len(dt.sends) != 0 {
|
|
t.Errorf("something was put to the desk: %+v", dt.sends)
|
|
}
|
|
if reply := tg.sends[len(tg.sends)-1].Body; !strings.Contains(reply, "notifications are paused on the desk") {
|
|
t.Errorf("the sender was not told why: %q", reply)
|
|
}
|
|
}
|
|
|
|
// L5: links are bounded per account, and kept in the router's state: a stranger's tries do not stop the
|
|
// operator's link, and a restart forgets no count.
|
|
func TestLinksAreBoundedPerAccountAndTheCountIsKept(t *testing.T) {
|
|
h, tg, dt, c, store, _ := newRouter(t)
|
|
eve := asks.Sender{Identity: "666", Display: "Eve", Authenticated: true}
|
|
for i := 0; i < LinksAnHour; i++ {
|
|
h.Link("telegram", asks.LinkAsked{ID: "e" + string(rune('0'+i)), At: c.now(), Sender: eve})
|
|
}
|
|
shown := len(dt.sends)
|
|
h.Link("telegram", asks.LinkAsked{ID: "jo", At: c.now(), Sender: asks.Sender{Identity: "42", Display: "Jo", Authenticated: true}})
|
|
if len(dt.sends) != shown+1 || !strings.Contains(dt.sends[len(dt.sends)-1].Body, "(number 42)") {
|
|
t.Fatalf("a stranger's tries stopped the operator's link: %q", tg.sends[len(tg.sends)-1].Body)
|
|
}
|
|
// A router started again on the same state still counts the stranger's tries.
|
|
h2, tg2, dt2, c2, _, _ := newRouter(t)
|
|
h2.Asks = store
|
|
c2.pass(c.now().Sub(c2.now()))
|
|
stand(h2, c2)
|
|
before := len(dt2.sends)
|
|
h2.Link("telegram", asks.LinkAsked{ID: "e9", At: c2.now(), Sender: eve})
|
|
if len(dt2.sends) != before || !strings.Contains(tg2.sends[len(tg2.sends)-1].Body, "Try again in an hour") {
|
|
t.Error("a restart forgot the count")
|
|
}
|
|
}
|
|
|
|
// L7: two answers to one ask arriving at once — on two routers sharing the state — make exactly one warrant.
|
|
func TestTwoAnswersAtOnceMakeOneWarrant(t *testing.T) {
|
|
h1, tg, _, c, store, w1 := newRouter(t)
|
|
link(h1, store, c, "42", c.now().Add(-2*time.Hour))
|
|
submit(t, h1, "mesh-delivery", heldAsk(c, "d-1"))
|
|
settle(h1, c)
|
|
release, stop := ticketFor(tg.sends[0], "Release"), ticketFor(tg.sends[0], "Stop")
|
|
h2, _, _, _, _, w2 := newRouter(t)
|
|
h2.Asks = store
|
|
h2.Now = h1.Now
|
|
if err := h2.loadAsks(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var wg sync.WaitGroup
|
|
outs := make([]string, 2)
|
|
for i, pick := range []struct {
|
|
h *Holder
|
|
ticket string
|
|
}{{h1, release}, {h2, stop}} {
|
|
wg.Add(1)
|
|
go func(i int, h *Holder, ticket string) {
|
|
defer wg.Done()
|
|
outs[i], _ = h.Chosen("telegram", choiceOf(ticket, "42", c.now()))
|
|
}(i, pick.h, pick.ticket)
|
|
}
|
|
wg.Wait()
|
|
n := len(w1.of("mesh-delivery")) + len(w2.of("mesh-delivery"))
|
|
if n != 1 {
|
|
t.Fatalf("%d warrants for one ask (%v)", n, outs)
|
|
}
|
|
if (outs[0] == "chosen") == (outs[1] == "chosen") {
|
|
t.Errorf("not exactly one chosen: %v", outs)
|
|
}
|
|
}
|
|
|
|
// The confirmation review of 2026-10-09, N1-router: another account's /start offers the desk an unlink of the
|
|
// operator's account while it is in its first hour; a desk click — which a program on the desk machine can forge
|
|
// — unlinked it and barred it for a day, again and again, so the operator never approved anything. A desk
|
|
// unlink in the first hour bars nothing: the operator links again at once with a code from the desk, and the
|
|
// next link waits for nobody. The bar is for an account removed deliberately later.
|
|
func TestAnUnlinkFromTheDeskInTheFirstHourBarsNothing(t *testing.T) {
|
|
h, tg, dt, c, store, _ := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-10*time.Minute)) // the operator's own, linked just now
|
|
h.Link("telegram", asks.LinkAsked{ID: "l1", At: c.now(), Sender: asks.Sender{Identity: "666", Display: "X", Authenticated: true}})
|
|
asked := dt.sends[len(dt.sends)-1]
|
|
ch := choiceOf(ticketFor(asked, "Unlink it"), "g14", c.now()) // a click nobody can prove was the operator's
|
|
ch.Sender.Authenticated = false
|
|
if out, err := h.Chosen("desktop", ch); err != nil || out != "chosen" {
|
|
t.Fatalf("%s %v", out, err)
|
|
}
|
|
if len(store.ids) != 0 {
|
|
t.Fatalf("not unlinked: %v", store.ids)
|
|
}
|
|
if u := h.recentUnlink("telegram"); u != nil {
|
|
t.Errorf("a desk unlink in the first hour bars relinking: %+v", u)
|
|
}
|
|
// The operator sends /start again: a code is shown at once, and the code links without waiting for anybody.
|
|
c.pass(time.Minute)
|
|
stand(h, c)
|
|
h.Link("telegram", asks.LinkAsked{ID: "l2", At: c.now(), Sender: asks.Sender{Identity: "42", Display: "Jo", Authenticated: true}})
|
|
code := ""
|
|
for _, m := range dt.sends {
|
|
if strings.Contains(m.Body, "number 42") && strings.Contains(m.Body, "send this code") {
|
|
code = codeIn(t, m.Body)
|
|
}
|
|
}
|
|
if code == "" {
|
|
t.Fatalf("no code was shown to relink the operator's account; said %q", tg.sends[len(tg.sends)-1].Body)
|
|
}
|
|
if a := h.Prove("telegram", asks.Code{Sender: asks.Sender{Identity: "42", Authenticated: true}, Code: code, Purpose: "link"}); !a.Accepted ||
|
|
!strings.Contains(a.Words, "Linked") {
|
|
t.Fatalf("the operator's code was not taken at once: %+v", a)
|
|
}
|
|
}
|
|
|
|
// And break-glass lifts any bar: root's allow-link at the router's machine, with no link waiting, ends a day's bar.
|
|
func TestBreakGlassLiftsABarOnRelinking(t *testing.T) {
|
|
h, tg, _, c, store, _ := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
_, _ = h.Unlink("telegram")
|
|
_, _ = h.Chosen("telegram", choiceOf(ticketFor(tg.sends[len(tg.sends)-1], "Unlink"), "42", c.now()))
|
|
if h.recentUnlink("telegram") == nil {
|
|
t.Fatal("the control: a deliberate unlink bars relinking for a day")
|
|
}
|
|
h.StateDir = t.TempDir()
|
|
was := fileOwner
|
|
t.Cleanup(func() { fileOwner = was })
|
|
fileOwner = func(os.FileInfo) uint32 { return 0 }
|
|
_ = os.WriteFile(filepath.Join(h.StateDir, "allow-link.telegram"), nil, 0o600)
|
|
h.Tick()
|
|
if u := h.recentUnlink("telegram"); u != nil {
|
|
t.Errorf("root's allow-link left the bar: %+v", u)
|
|
}
|
|
}
|
|
|
|
// codeIn is the six digits a link's notice shows, "123 456".
|
|
func codeIn(t *testing.T, body string) string {
|
|
t.Helper()
|
|
m := regexp.MustCompile(`(\d{3}) (\d{3})\.`).FindStringSubmatch(body)
|
|
if m == nil {
|
|
t.Fatalf("no code in %q", body)
|
|
}
|
|
return m[1] + m[2]
|
|
}
|
|
|
|
// The confirmation review of 2026-10-09 (low): the router asked the controller's root-free word — up to ten
|
|
// seconds — while holding its work, so every ask, answer and link waited behind one slow controller. It now
|
|
// asks before it takes the work, and judges with the word it was given then.
|
|
func TestTheRootFreeWordIsNotAskedWhileTheWorkIsHeld(t *testing.T) {
|
|
h, tg, _, c, store, w := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
|
|
settle(h, c)
|
|
release := ticketFor(tg.sends[0], "Release")
|
|
asking, slow := make(chan struct{}), make(chan struct{})
|
|
var once sync.Once
|
|
free := h.RootFree
|
|
h.RootFree = func(machines []string) (map[string]RootVerdict, error) {
|
|
once.Do(func() { close(asking); <-slow })
|
|
return free(machines)
|
|
}
|
|
done := make(chan string, 1)
|
|
go func() {
|
|
out, _ := h.Chosen("telegram", choiceOf(release, "42", c.now()))
|
|
done <- out
|
|
}()
|
|
<-asking
|
|
linked := make(chan struct{})
|
|
go func() {
|
|
h.Link("telegram", asks.LinkAsked{ID: "l9", At: c.now(), Sender: asks.Sender{Identity: "77", Authenticated: true}})
|
|
close(linked)
|
|
}()
|
|
select {
|
|
case <-linked:
|
|
case <-time.After(2 * time.Second):
|
|
close(slow)
|
|
t.Fatal("a link waited for the controller's root-free word: the work was held while it was asked")
|
|
}
|
|
close(slow)
|
|
if out := <-done; out != "chosen" || len(w.of("mesh-delivery")) != 1 {
|
|
t.Fatalf("the answer after the word: %s, %v", out, w.of("mesh-delivery"))
|
|
}
|
|
}
|
|
|
|
// The confirmation review of 2026-10-09 (low, on M2): an answer whose line — what it does — the content rule
|
|
// withholds is not offered either; its button went out alone, and a tap would choose what was not shown.
|
|
func TestAnAnswerWhoseEffectIsWithheldIsNotOffered(t *testing.T) {
|
|
h, _, _, c, store, _ := newRouter(t)
|
|
link(h, store, c, "42", c.now().Add(-2*time.Hour))
|
|
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
|
|
key := askKey("mesh-delivery", "d-1")
|
|
h.mu.Lock()
|
|
e := h.asks[key]
|
|
e.rec.Ask.Options[0].Does = "the delivery reads /etc/shadow"
|
|
h.asks[key] = e
|
|
r := h.open["ask."+key]
|
|
h.mu.Unlock()
|
|
m := h.sayOn(r, "asked", "telegram")
|
|
for _, a := range m.Actions {
|
|
if a.Label == "Release" {
|
|
t.Errorf("Release was offered with its effect withheld: %+v", m.Actions)
|
|
}
|
|
}
|
|
if strings.Contains(m.Body, "/etc/shadow") {
|
|
t.Errorf("the withheld words were said: %q", m.Body)
|
|
}
|
|
if len(m.Actions) == 0 {
|
|
t.Error("the answers whose effect was said were not offered either")
|
|
}
|
|
}
|