Ask a node's engine for a fresh setuid search at the terminal (hq issue 361)
After the operator removes by hand what the last search found, no apply says so and nothing searched again until the next day. node setuid-search <node> signs the ask as a hand-over is, under its own context, on a subject only the node's engine hears and only the controller may publish.
This commit is contained in:
@@ -297,6 +297,11 @@ func AskReportSubject(node string) string { return "mesh.node." + node + ".ask.r
|
||||
// the mesh's key (link.SignedHandOver), and the engine verifies it before reading anything out of it.
|
||||
func AskHandOverSubject(node string) string { return "mesh.node." + node + ".ask.hand-over" }
|
||||
|
||||
// AskSetuidSearchSubject is where the controller's terminal asks one machine's node-engine to throw its last
|
||||
// search for setuid programs away and start a full one (novox/hq issue 361): a request answered once, signed as
|
||||
// a hand-over is (link.SetuidSearchContext), for the same reason.
|
||||
func AskSetuidSearchSubject(node string) string { return "mesh.node." + node + ".ask.setuid-search" }
|
||||
|
||||
// inbox is a principal's own reply space. No user is ever granted a bare `_INBOX.>` (design 25
|
||||
// §4): with one account, inbox privacy is the permission list or it is nothing, so each user's
|
||||
// inbox is derived from its own identity and its permissions name that prefix and no other.
|
||||
@@ -573,7 +578,9 @@ func PermissionsFor(p Principal) (Permissions, error) {
|
||||
AskReportSubject(p.Node),
|
||||
// And the controller's terminal asking it to hand a directory used as found to the mesh (novox/hq
|
||||
// issue 356), which it answers on the request's reply: the one request a node is asked.
|
||||
AskHandOverSubject(p.Node)}
|
||||
AskHandOverSubject(p.Node),
|
||||
// And asking it for a fresh search for setuid programs (novox/hq issue 361), answered the same way.
|
||||
AskSetuidSearchSubject(p.Node)}
|
||||
// The node-engine witnesses the core builds it places (novox/hq to-be 45 §8, ADR 0236; the
|
||||
// contract is lease/witness.go): it asks its own machine's node tools PING, and, where the
|
||||
// machine runs the controller, reads the lease's one key — read, never written.
|
||||
|
||||
@@ -112,7 +112,9 @@ func TestOnlyWhatCanBeAskedMayAnswer(t *testing.T) {
|
||||
t.Fatal("a module cannot answer a tool call on its own namespace")
|
||||
}
|
||||
node, _ := PermissionsFor(Principal{Kind: KindNode, Node: "one", PasswordHash: "x"})
|
||||
if !node.AllowResponses || !slices.Contains(node.Subscribe, AskHandOverSubject("one")) {
|
||||
if !node.AllowResponses || !slices.Contains(node.Subscribe, AskHandOverSubject("one")) ||
|
||||
!slices.Contains(node.Subscribe, AskSetuidSearchSubject("one")) ||
|
||||
slices.Contains(node.Subscribe, AskSetuidSearchSubject("two")) {
|
||||
t.Fatalf("a node cannot answer the hand-over it is asked: %v %v", node.AllowResponses, node.Subscribe)
|
||||
}
|
||||
person, _ := PermissionsFor(Principal{Kind: KindPerson, Node: "one", Module: "jo", PasswordHash: "x"})
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ accounts {
|
||||
} }
|
||||
{ user: "node.one", password: "$2a$11$nnnnnnnnnnnnnnnnnnnnnn", permissions: {
|
||||
publish: { allow: ["$JS.ACK.NODES.one.>", "$JS.API.CONSUMER.INFO.NODES.one", "$SRV.PING.node-tools.one", "mesh.control.one.>"] }
|
||||
subscribe: { allow: ["_DELIVER.one", "_DELIVER.one.>", "_INBOX.node.one.>", "mesh.node.one.ask.hand-over", "mesh.node.one.ask.report", "mesh.node.one.declare"] }
|
||||
subscribe: { allow: ["_DELIVER.one", "_DELIVER.one.>", "_INBOX.node.one.>", "mesh.node.one.ask.hand-over", "mesh.node.one.ask.report", "mesh.node.one.ask.setuid-search", "mesh.node.one.declare"] }
|
||||
allow_responses: { max: 1, ttl: "1m" }
|
||||
} }
|
||||
{ user: "one.nats", password: "$2a$11$bbbbbbbbbbbbbbbbbbbbbb", permissions: {
|
||||
|
||||
@@ -91,6 +91,11 @@ var WritersTable = []WriterRow{
|
||||
{State: "a hand-over asked of a machine", Writer: "controller, at its terminal", KeptIn: "the machine, beside its state",
|
||||
Others: "the engine verifies the mesh's signature and records it, or refuses",
|
||||
Subjects: []string{"mesh.node.*.ask.hand-over"}, Writes: isController},
|
||||
// The operator asking a machine's engine for a fresh search for setuid programs, at the controller's
|
||||
// terminal (novox/hq issue 361): signed as a hand-over is, under a signing context of its own.
|
||||
{State: "a fresh setuid search asked of a machine", Writer: "controller, at its terminal",
|
||||
KeptIn: "the machine, which throws its last search away", Others: "the engine verifies the mesh's signature and starts it, or refuses",
|
||||
Subjects: []string{"mesh.node.*.ask.setuid-search"}, Writes: isController},
|
||||
{State: "a machine's applied state and its report", Writer: "the node-engine's apply queue",
|
||||
KeptIn: "the machine; the report on the bus", Others: "the reconcile and a delivery enqueue, never apply",
|
||||
// And its health statement between reports (novox/hq ADR 0240): the same writer stating the same
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
var designRows = []string{
|
||||
"a machine's declaration",
|
||||
"a hand-over asked of a machine",
|
||||
"a fresh setuid search asked of a machine",
|
||||
"a machine's applied state and its report",
|
||||
"the controller lease",
|
||||
"plans and their tiers",
|
||||
@@ -170,3 +171,18 @@ func TestAHandOverAskHasOnePublisher(t *testing.T) {
|
||||
t.Fatalf("the controller may not ask a hand-over: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// **A fresh setuid search asked of a machine has one publisher, the controller** (novox/hq issue 361), as a
|
||||
// hand-over has.
|
||||
func TestASetuidSearchAskHasOnePublisher(t *testing.T) {
|
||||
for _, p := range []Principal{
|
||||
{Kind: KindNode, Node: "laptop"},
|
||||
{Kind: KindNodeTools, Node: "laptop", Module: RuntimeModule},
|
||||
{Kind: KindModule, Node: "laptop", Module: "notes"},
|
||||
} {
|
||||
err := CheckWriters(p, []string{AskSetuidSearchSubject("laptop")})
|
||||
if err == nil || !strings.Contains(err.Error(), "a fresh setuid search asked of a machine") {
|
||||
t.Errorf("%s may ask a setuid search: %v", p.Username(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user