Every serving principal may answer the services discovery for what it serves; the controller announces its seat (hq ADR 0197)
Grants: a principal that serves tools subscribes $SRV.PING/$SRV.INFO and those questions under each name it serves — its own and no other's; the tool runtime and people may ask. The controller answers discovery for the mesh-controller seat in NATS's services format, one endpoint per verb it serves, with the seat's description and schema. module list --json says which modules declare tools, so the console expects an announcement only from those.
This commit is contained in:
@@ -236,6 +236,8 @@ func PermissionsFor(p Principal) (Permissions, error) {
|
||||
// which this package mirrors rather than reads, and a verb the seat does not declare is a
|
||||
// subject nothing publishes.
|
||||
sub = append(sub, "mesh.seat."+ControllerSeat+".tool.>")
|
||||
// And says so (novox/hq ADR 0197): it answers discovery for the seat it serves.
|
||||
sub = append(sub, announcing(ControllerSeat)...)
|
||||
|
||||
// The two events it reacts to, and its ack subject on the stream they arrive from
|
||||
// (streams.go). **Each named, not a pattern**: `mesh.mod.*.event.>` would make the
|
||||
@@ -271,6 +273,9 @@ func PermissionsFor(p Principal) (Permissions, error) {
|
||||
return Permissions{}, err
|
||||
}
|
||||
pub = append(pub, invoked...)
|
||||
// And may ask what answers (novox/hq ADR 0197): a question every service answers about
|
||||
// itself, its replies to the asker's own inbox.
|
||||
pub = append(pub, discovering()...)
|
||||
|
||||
case KindEnrolment:
|
||||
// A leaked token is useless for anything but enrolling: it cannot read a declaration, hear
|
||||
@@ -327,6 +332,15 @@ func PermissionsFor(p Principal) (Permissions, error) {
|
||||
// away — no other principal may subscribe this namespace, and a caller's authority is
|
||||
// still granted per tool, by name, on the publish side.
|
||||
sub = append(sub, own+".tool.>")
|
||||
// It says what it serves (novox/hq ADR 0197): discovery for its own name and every seat it
|
||||
// holds a verb of, answered by the runtime that serves them.
|
||||
announced := []string{p.Module}
|
||||
for _, s := range p.Holds {
|
||||
if len(s.Serves) > 0 {
|
||||
announced = append(announced, s.Name)
|
||||
}
|
||||
}
|
||||
sub = append(sub, announcing(announced...)...)
|
||||
// Its own membership (ADR 0160): the one subject a runtime derives for itself, read
|
||||
// directly from the stream and followed live. Nothing else's.
|
||||
sub = append(sub, MembershipSubject(p.Node, p.Module))
|
||||
@@ -413,11 +427,16 @@ func PermissionsFor(p Principal) (Permissions, error) {
|
||||
// module's own principal has, for the same reason: the tools a module serves are what its
|
||||
// code answers, and a list here would be a second copy of it. Each held seat's verbs on
|
||||
// this node, as the holder's own principal would be granted them.
|
||||
var serves []string
|
||||
for _, d := range p.Carries {
|
||||
if !safeSubject.MatchString(d.Module) {
|
||||
return Permissions{}, fmt.Errorf(
|
||||
"%q cannot be part of a subject: a permission is a subject pattern, and this would widen it", d.Module)
|
||||
}
|
||||
serves = append(serves, d.Module)
|
||||
for _, s := range d.Holds {
|
||||
serves = append(serves, s.Name)
|
||||
}
|
||||
own := "mesh.mod." + d.Module
|
||||
sub = append(sub, own+".tool.>")
|
||||
// A tool that emits an event is the module's code and emits under the module's name
|
||||
@@ -444,6 +463,10 @@ func PermissionsFor(p Principal) (Permissions, error) {
|
||||
return Permissions{}, err
|
||||
}
|
||||
pub = append(pub, invoked...)
|
||||
// It says what it serves and may ask what answers (novox/hq ADR 0197): the runtime answers
|
||||
// discovery for each module and seat it carries, and the console it is asks the bus.
|
||||
sub = append(sub, announcing(serves...)...)
|
||||
pub = append(pub, discovering()...)
|
||||
// Nothing about consumers: it consumes nothing. A module's reactions to events are its
|
||||
// own long-lived process, which ADR 0175 leaves where it is; what moves here is tools.
|
||||
sub = unique(sub)
|
||||
@@ -765,3 +788,23 @@ func invokedSubjects(invokes []string) ([]string, error) {
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// announcing is what a principal that serves tools subscribes to answer the NATS services
|
||||
// protocol's discovery (novox/hq ADR 0197): the questions asked of every service, and those asked of
|
||||
// each name it serves — its own and no other's, so it cannot answer for a service it is not.
|
||||
func announcing(names ...string) []string {
|
||||
out := []string{"$SRV.PING", "$SRV.INFO"}
|
||||
for _, n := range names {
|
||||
if !safeSubject.MatchString(n) {
|
||||
continue
|
||||
}
|
||||
out = append(out, "$SRV.PING."+n, "$SRV.PING."+n+".>", "$SRV.INFO."+n, "$SRV.INFO."+n+".>")
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// discovering is what a principal publishes to ask what answers (novox/hq ADR 0197): the services
|
||||
// protocol's discovery requests, whose replies come to its own inbox.
|
||||
func discovering() []string {
|
||||
return []string{"$SRV.PING", "$SRV.PING.>", "$SRV.INFO", "$SRV.INFO.>"}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user