Merge branch 'feat/mail-hardening' into mh-785
This commit is contained in:
@@ -247,6 +247,8 @@ func CatalogueProblems(shelf Shelf) []string {
|
||||
var problems []string
|
||||
// A stream name has one owner (novox/hq ADR 0363).
|
||||
problems = append(problems, StreamNameProblems(shelf)...)
|
||||
// A module that hears a restricted stream runs as an account of its own (novox/hq ADR 0376 §2).
|
||||
problems = append(problems, RestrictedHearingProblems(shelf)...)
|
||||
|
||||
// Who declares what, and who declared it first.
|
||||
declaredBy := map[string]string{}
|
||||
|
||||
@@ -311,6 +311,41 @@ func StreamNameProblems(shelf Shelf) []string {
|
||||
return problems
|
||||
}
|
||||
|
||||
// RestrictedHearingProblems refuses a module that would hear a restricted stream without an account of its own
|
||||
// (novox/hq ADR 0376 §2): a `consumes` naming a module literally and asking for events a restricted stream of
|
||||
// that module carries, by a manifest that declares no `runs-as`. A module the machine's tool runner carries
|
||||
// reaches the bus as the tool runner's account, which every agent session there shares, so the controller would
|
||||
// compose nothing for it. Judged only where the provider is on the shelf, as a consumer may be installed before
|
||||
// its emitter; a wildcard emitter never reaches a module's stream (ADR 0363 §5) and is not judged.
|
||||
func RestrictedHearingProblems(shelf Shelf) []string {
|
||||
var problems []string
|
||||
for _, module := range shelfOrder(shelf) {
|
||||
m := shelf[module]
|
||||
if m.RunsAs != "" {
|
||||
continue
|
||||
}
|
||||
for _, c := range m.Consumes {
|
||||
emitter, rest, named := strings.Cut(c, ".")
|
||||
provider, known := shelf[emitter]
|
||||
if !named || emitter == OneName || emitter == TheRest || !known {
|
||||
continue
|
||||
}
|
||||
hearing, _ := provider.StreamsHearing(rest)
|
||||
for _, s := range hearing {
|
||||
if s.Grant == nil {
|
||||
continue
|
||||
}
|
||||
problems = append(problems, fmt.Sprintf(
|
||||
"%s consumes %s, which %s's restricted stream %s carries, so %s must run as an account of its "+
|
||||
"own (runs-as): the machine's runtime runs as the operator's account, which every agent "+
|
||||
"runs as, and never hears a restricted stream (novox/hq ADR 0376)",
|
||||
module, c, emitter, s.BusName(), module))
|
||||
}
|
||||
}
|
||||
}
|
||||
return problems
|
||||
}
|
||||
|
||||
// GrantedKeys reads a restricting config value (novox/hq ADR 0363 §4): each key whose list names the
|
||||
// module wherever it runs, or the module on this machine as `<machine>.<module>`. A value of another shape
|
||||
// grants nothing; a key that is not one usable name grants nothing.
|
||||
|
||||
@@ -204,3 +204,41 @@ func TestNarrowingTwoPatterns(t *testing.T) {
|
||||
t.Fatalf("uncovered: %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// **A module that hears a restricted stream runs as an account of its own** (ADR 0376 §2): registration refuses a
|
||||
// `consumes` naming a module and asking for events its restricted stream carries, unless the manifest declares
|
||||
// `runs-as`; a stream without a grant, an event the provider says on EVENTS, and a wildcard emitter stay as they
|
||||
// were, and a consumer whose provider is not on the shelf is judged once it is.
|
||||
func TestHearingARestrictedStreamNeedsAnAccountOfItsOwn(t *testing.T) {
|
||||
provider, err := ParseManifest([]byte(mailManifest(t, mailStream, `"emits":["account.added"],`)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
feed := Manifest{Module: "feed", Streams: []StreamDeclaration{{Name: "items", Events: []string{"item.**"}}}}
|
||||
carried := Manifest{Module: "reader", Consumes: []string{"mesh-mail.mail.*.message.added"}}
|
||||
got := RestrictedHearingProblems(Shelf{"mesh-mail": provider, "reader": carried})
|
||||
if len(got) != 1 || !strings.Contains(got[0], "reader consumes mesh-mail.mail.*.message.added") ||
|
||||
!strings.Contains(got[0], "MAIL") || !strings.Contains(got[0], "runs-as") || !strings.Contains(got[0], "ADR 0376") {
|
||||
t.Fatalf("a carried module hearing MAIL was not refused as it should be: %v", got)
|
||||
}
|
||||
if all := strings.Join(CatalogueProblems(Shelf{"mesh-mail": provider, "reader": carried}), "; "); !strings.Contains(all, got[0]) {
|
||||
t.Fatalf("the catalogue's check does not refuse it: %s", all)
|
||||
}
|
||||
own := carried
|
||||
own.RunsAs = "reader"
|
||||
if got := RestrictedHearingProblems(Shelf{"mesh-mail": provider, "reader": own}); len(got) != 0 {
|
||||
t.Fatalf("a module of its own account was refused: %v", got)
|
||||
}
|
||||
for _, m := range []Manifest{
|
||||
{Module: "events", Consumes: []string{"mesh-mail.account.added"}},
|
||||
{Module: "items", Consumes: []string{"feed.item.**"}},
|
||||
{Module: "audit", Consumes: []string{"**", "*.mail.**"}},
|
||||
} {
|
||||
if got := RestrictedHearingProblems(Shelf{"mesh-mail": provider, "feed": feed, m.Module: m}); len(got) != 0 {
|
||||
t.Errorf("%s was refused: %v", m.Module, got)
|
||||
}
|
||||
}
|
||||
if got := RestrictedHearingProblems(Shelf{"reader": carried}); len(got) != 0 {
|
||||
t.Fatalf("judged without its provider: %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user