Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b016cc62b |
+2
-18
@@ -469,24 +469,8 @@ func PermissionsFor(p Principal) (Permissions, error) {
|
|||||||
// request once, so the runtime announces everything it carries under its own name.
|
// request once, so the runtime announces everything it carries under its own name.
|
||||||
sub = append(sub, announcing(append([]string{RuntimeModule}, serves...)...)...)
|
sub = append(sub, announcing(append([]string{RuntimeModule}, serves...)...)...)
|
||||||
pub = append(pub, discovering()...)
|
pub = append(pub, discovering()...)
|
||||||
// **And it consumes for the modules it carries** (novox/hq ADR 0198, which changes ADR 0175's
|
// Nothing about consumers: it consumes nothing. A module's reactions to events are its
|
||||||
// "it consumes nothing"): a module's long-running code is a bundle this runtime launches, and
|
// own long-lived process, which ADR 0175 leaves where it is; what moves here is tools.
|
||||||
// the runtime is its bus — it reads the module's own durable consumer and acknowledges what
|
|
||||||
// the module's code took. Exactly the grants the module's own principal has for that consumer,
|
|
||||||
// on its name and no other's: asking about it, pulling from it, acknowledging it. The
|
|
||||||
// consumer is still the controller's to make, from the module's own principal.
|
|
||||||
for _, d := range p.Carries {
|
|
||||||
own := Principal{Kind: KindModule, Node: p.Node, Module: d.Module, Emits: d.Emits,
|
|
||||||
Consumes: d.Consumes, Serves: d.Serves, Holds: d.Holds, Uses: d.Uses, Watches: d.Watches}
|
|
||||||
if _, consumes := ConsumerFor(own); !consumes {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
stream, durable := consumerStream(own), consumerDurable(own)
|
|
||||||
pub = append(pub,
|
|
||||||
"$JS.API.CONSUMER.INFO."+stream+"."+durable,
|
|
||||||
"$JS.API.CONSUMER.MSG.NEXT."+stream+"."+durable,
|
|
||||||
"$JS.ACK."+stream+"."+durable+".>")
|
|
||||||
}
|
|
||||||
sub = unique(sub)
|
sub = unique(sub)
|
||||||
pub = unique(pub)
|
pub = unique(pub)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ func TestAModulePullsItsOwnConsumerAndNoOthers(t *testing.T) {
|
|||||||
// their tools (novox/hq ADR 0175): every carried module's tool namespace, every held seat's verbs
|
// their tools (novox/hq ADR 0175): every carried module's tool namespace, every held seat's verbs
|
||||||
// on this node, every module's membership on this node, and a call to anything. Nothing it
|
// on this node, every module's membership on this node, and a call to anything. Nothing it
|
||||||
// consumes, because it reacts to nothing.
|
// consumes, because it reacts to nothing.
|
||||||
func TestTheRuntimeServesTheUnionAndConsumesForItsModules(t *testing.T) {
|
func TestTheRuntimeServesTheUnionAndConsumesNothing(t *testing.T) {
|
||||||
filter := Seat{Name: "node-packet-filter", Scope: "node", Serves: []string{"rules", "reload"}}
|
filter := Seat{Name: "node-packet-filter", Scope: "node", Serves: []string{"rules", "reload"}}
|
||||||
p := Principal{Kind: KindNodeTools, Node: "anchor", Module: RuntimeModule, Carries: []Declared{
|
p := Principal{Kind: KindNodeTools, Node: "anchor", Module: RuntimeModule, Carries: []Declared{
|
||||||
{Module: "nftables", Holds: []Seat{filter}, Serves: []string{"firewall_rules"}},
|
{Module: "nftables", Holds: []Seat{filter}, Serves: []string{"firewall_rules"}},
|
||||||
@@ -408,33 +408,22 @@ func TestTheRuntimeServesTheUnionAndConsumesForItsModules(t *testing.T) {
|
|||||||
t.Errorf("the runtime may not publish %s: %v", want, perms.Publish)
|
t.Errorf("the runtime may not publish %s: %v", want, perms.Publish)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// It reads the consumer of every carried module that consumes — that module's, by its name, as
|
// Nothing of what a carried module consumes, and no consumer of its own to ack.
|
||||||
// the module's own principal could (novox/hq ADR 0198) — and of no module that consumes nothing.
|
for _, s := range perms.Subscribe {
|
||||||
for _, want := range []string{
|
if strings.Contains(s, ".event.") || strings.HasPrefix(s, "_DELIVER.") {
|
||||||
"$JS.API.CONSUMER.INFO.EVENTS.anchor_zsh",
|
t.Errorf("the runtime was granted a delivery it has no consumer for: %s", s)
|
||||||
"$JS.API.CONSUMER.MSG.NEXT.EVENTS.anchor_zsh",
|
|
||||||
"$JS.ACK.EVENTS.anchor_zsh.>",
|
|
||||||
} {
|
|
||||||
if !contains(perms.Publish, want) {
|
|
||||||
t.Errorf("the runtime may not read zsh's consumer: %s missing from %v", want, perms.Publish)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, s := range perms.Publish {
|
for _, s := range perms.Publish {
|
||||||
if (strings.HasPrefix(s, "$JS.ACK.") || strings.Contains(s, "CONSUMER")) && !strings.Contains(s, "anchor_zsh") {
|
if strings.HasPrefix(s, "$JS.ACK.") || strings.Contains(s, "CONSUMER") {
|
||||||
t.Errorf("the runtime was granted a consumer no carried module of it consumes on: %s", s)
|
t.Errorf("the runtime was granted a consumer's subject and has no consumer: %s", s)
|
||||||
}
|
|
||||||
}
|
|
||||||
// It pulls; nothing is pushed to it, and it subscribes no event subject directly.
|
|
||||||
for _, s := range perms.Subscribe {
|
|
||||||
if strings.Contains(s, ".event.") || strings.HasPrefix(s, "_DELIVER.") {
|
|
||||||
t.Errorf("the runtime was granted a delivery: %s", s)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !perms.AllowResponses {
|
if !perms.AllowResponses {
|
||||||
t.Error("the runtime answers what it is asked, and may not reply")
|
t.Error("the runtime answers what it is asked, and may not reply")
|
||||||
}
|
}
|
||||||
if _, needed := ConsumerFor(p); needed {
|
if _, needed := ConsumerFor(p); needed {
|
||||||
t.Error("a consumer would be made for the runtime itself; it reads its modules' consumers, never one of its own")
|
t.Error("a consumer would be made for the runtime, which consumes nothing")
|
||||||
}
|
}
|
||||||
// Each subject once in each list: the file is read as the mesh's authority model. One subject may
|
// Each subject once in each list: the file is read as the mesh's authority model. One subject may
|
||||||
// stand in both — the runtime answers discovery on `$SRV.INFO` and, as the console, asks it
|
// stand in both — the runtime answers discovery on `$SRV.INFO` and, as the console, asks it
|
||||||
|
|||||||
@@ -87,6 +87,12 @@ func (m Manifest) Resolve(built []Built) (Manifest, error) {
|
|||||||
loads := append([]string(nil), a.Loads...)
|
loads := append([]string(nil), a.Loads...)
|
||||||
if a.Loads == nil && len(m.Tools) > 0 {
|
if a.Loads == nil && len(m.Tools) > 0 {
|
||||||
loads = append([]string(nil), a.Entrypoints...)
|
loads = append([]string(nil), a.Entrypoints...)
|
||||||
|
// A bundle compiled to a binary has no entrypoints: the binary is what it is, and what
|
||||||
|
// the runtime starts to serve it (novox/hq ADR 0193). So a Go tools bundle is served
|
||||||
|
// as Go — the runtime execs it — exactly as a TypeScript one is through its launcher.
|
||||||
|
if bin := BinaryOf(a); bin != "" {
|
||||||
|
loads = []string{bin}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// **Kept, never routed** (ADR 0155): the builder publishes to the store at the address
|
// **Kept, never routed** (ADR 0155): the builder publishes to the store at the address
|
||||||
// it reached it by, and a manifest carrying that address names an installation —
|
// it reached it by, and a manifest carrying that address names an installation —
|
||||||
@@ -242,6 +248,11 @@ func (b *Build) problems(module string) []string {
|
|||||||
for _, e := range a.Entrypoints {
|
for _, e := range a.Entrypoints {
|
||||||
found = found || e == load
|
found = found || e == load
|
||||||
}
|
}
|
||||||
|
// A bundle compiled to a binary is one executable: the runtime loads that or nothing
|
||||||
|
// (novox/hq ADR 0193).
|
||||||
|
if bin := BinaryOf(a); bin != "" {
|
||||||
|
found = load == bin
|
||||||
|
}
|
||||||
if !found {
|
if !found {
|
||||||
problems = append(problems, fmt.Sprintf(
|
problems = append(problems, fmt.Sprintf(
|
||||||
"%s: %q says the runtime loads %q, which is not among its entrypoints — "+
|
"%s: %q says the runtime loads %q, which is not among its entrypoints — "+
|
||||||
|
|||||||
@@ -389,3 +389,46 @@ func TestARuntimeCompiledToABinaryRunsItself(t *testing.T) {
|
|||||||
t.Errorf("the Go runtime is not told what to serve or whose it is: %v %v", env, process["user"])
|
t.Errorf("the Go runtime is not told what to serve or whose it is: %v %v", env, process["user"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// novox/hq ADR 0193: a Go tools bundle is served — its binary is what the runtime starts, delivered
|
||||||
|
// like any tools bundle, named to the runtime where a TypeScript bundle names its launcher.
|
||||||
|
func TestAGoToolsBundleIsServedByItsBinary(t *testing.T) {
|
||||||
|
with := Rendering{ArtifactStore: "anchor.internal:5101",
|
||||||
|
Needed: map[string]map[string]string{RuntimeModule: {"broker": "sealed-credential"}}}
|
||||||
|
lamp := Manifest{Module: "lamp", Version: "1", Tools: []string{"on"},
|
||||||
|
Build: &Build{Artifacts: []Artifact{{Name: "tools", Kind: ArtifactBundle, Language: "go",
|
||||||
|
System: "arch", From: "cmd/lamp-tools"}}}}
|
||||||
|
if p := lamp.Build.problems("lamp"); len(p) != 0 {
|
||||||
|
t.Fatalf("a Go tools bundle was refused: %v", p)
|
||||||
|
}
|
||||||
|
lamp, err := lamp.Resolve([]Built{{Name: "tools", Kind: ArtifactBundle,
|
||||||
|
Reference: ArtifactStoreScheme + "lamp/tools/blobs/" + bundleDigest, Digest: bundleDigest}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if fmt.Sprint(lamp.Bundles[0].Loads) != "[lamp-tools]" {
|
||||||
|
t.Fatalf("the runtime loads %v from a Go bundle, want its binary", lamp.Bundles[0].Loads)
|
||||||
|
}
|
||||||
|
out, err := Resolution{Node: "anchor", Account: "ops", Modules: []Manifest{lamp, theRuntime(t)}}.Declaration(with)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if fileNamed(out, "lamp."+BundleID("tools")) == nil {
|
||||||
|
t.Errorf("the Go bundle is not delivered: %v", ids(out))
|
||||||
|
}
|
||||||
|
env := fileNamed(out, RuntimeModule+"."+RuntimeProcessID())["env"].(map[string]string)
|
||||||
|
if env[RuntimeToolModules] != "lamp="+BundlePath("lamp", "tools")+"/lamp-tools" {
|
||||||
|
t.Errorf("the runtime is told %q, want the binary", env[RuntimeToolModules])
|
||||||
|
}
|
||||||
|
|
||||||
|
// An artifact may say it explicitly; naming anything but the binary is refused.
|
||||||
|
said := Manifest{Module: "lamp", Version: "1", Build: &Build{Artifacts: []Artifact{{Name: "tools",
|
||||||
|
Kind: ArtifactBundle, Language: "go", System: "arch", Binary: "lamp", Loads: []string{"lamp"}}}}}
|
||||||
|
if p := said.Build.problems("lamp"); len(p) != 0 {
|
||||||
|
t.Errorf("loads naming the binary was refused: %v", p)
|
||||||
|
}
|
||||||
|
said.Build.Artifacts[0].Loads = []string{"tools/index.js"}
|
||||||
|
if p := said.Build.problems("lamp"); len(p) == 0 {
|
||||||
|
t.Error("a Go bundle loading a file it does not contain was admitted")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user