package main import ( "bytes" "os" "path/filepath" "strings" "testing" ) // novox/hq ADR 0225, issue 263: a consumer's identity is bounded by the provision it requires, an // overflow is refused before merge by `module check`, and a provider's machine is never refused for // one consumer's identity. // `module check` refuses the pull request that introduces an overflow, naming the module. func TestModuleCheckRefusesAnIdentityThatOverflowsWhatItRequires(t *testing.T) { dir := t.TempDir() write := func(name, body string) string { p := filepath.Join(dir, name+".json") if err := os.WriteFile(p, []byte(body), 0o600); err != nil { t.Fatal(err) } return p } objects := write("objects", `{"module":"objects","version":"1", "provides":[{"name":"s3-bucket","scope":"mesh","identity":{"max":20,"in":"an S3 access key"}}], "receives":{"s3-bucket":"/var/lib/mesh/objects/mesh.json"}}`) resolver := write("resolver", `{"module":"resolver","version":"1", "provides":[{"name":"wildcard-resolution","scope":"mesh","identity":false}]}`) album := write("photoalbum", `{"module":"photoalbum","version":"1","requires":["s3-bucket"]}`) nm := write("networkmanager", `{"module":"networkmanager","version":"1","requires":["wildcard-resolution"]}`) var out bytes.Buffer if err := moduleCheckFor([]string{resolver, nm}, 6, &out); err != nil { t.Fatalf("a long name requiring a keyless provision was refused (issue 263): %v\n%s", err, out.String()) } out.Reset() err := moduleCheckFor([]string{objects, album, resolver, nm}, 6, &out) if err == nil { t.Fatalf("an identity overflowing an S3 access key passed:\n%s", out.String()) } if !strings.Contains(out.String(), "photoalbum wants s3-bucket") || !strings.Contains(out.String(), "`slug` of at most 8 characters") || strings.Contains(out.String(), "networkmanager wants") { t.Fatalf("the refusal does not name the one overflowing module and its remedy:\n%s", out.String()) } } // Tonight's case, through the commands: networkmanager on a six-character machine requires the // resolver provision, and a second consumer there overflows an object store's access key. The // provider's machine still composes; the overflowing consumer is left out of its grants and named, // by push and by `status`, and the keyless consumer is granted with its long name.