package catalogue import ( "strings" "testing" ) // An archive pinned by URL and sha256 (novox/hq ADR 0316 §2, §6): the vendor's file, mirrored by the build // seat, never a copy in the repository. const pinnedSum = "38dd24890a66b4cf9a45bc24e15192e00c26b929e1bb8df7974c16a4539129e2" func upstreamManifest(artifact string) string { return `{"module":"a","version":"1","build":{"artifacts":[` + artifact + `]}}` } func TestAnArchivePinnedByURLAndSha256IsAccepted(t *testing.T) { for _, a := range []string{ `{"name":"archive","kind":"archive","url":"https://vendor.example.org/release-1.tar.xz","sha256":"` + pinnedSum + `","version":"1.0","within":"release"}`, `{"name":"addon","kind":"archive","url":"https://vendor.example.org/addon.xpi","sha256":"` + pinnedSum + `","version":"1.5.6.1","file":"addon.xpi"}`, } { if _, err := ParseManifest([]byte(upstreamManifest(a))); err != nil { t.Errorf("%s was refused: %v", a, err) } } } func TestAnUpstreamFileThatIsNotPinnedIsRefused(t *testing.T) { cases := map[string]string{ // No digest: what the address serves changes under the mesh. `{"name":"x","kind":"archive","url":"https://vendor.invalid/r.tar.xz","version":"1"}`: "without a pinned sha256", `{"name":"x","kind":"archive","url":"https://vendor.invalid/r.tar.xz","sha256":"ABC","version":"1"}`: "without a pinned sha256", // No version: a person reading the pin cannot tell which release. `{"name":"x","kind":"archive","url":"https://vendor.invalid/r.tar.xz","sha256":"` + pinnedSum + `"}`: "says no version", // Not https. `{"name":"x","kind":"archive","url":"http://vendor.invalid/r.tar.xz","sha256":"` + pinnedSum + `","version":"1"}`: "over https", // Both a directory of the repository and a URL. `{"name":"x","kind":"archive","from":"files","url":"https://vendor.invalid/r.tar.xz","sha256":"` + pinnedSum + `","version":"1"}`: "one or the other", // A pin without a URL. `{"name":"x","kind":"archive","from":"files","sha256":"` + pinnedSum + `"}`: "no url", // Only an archive is mirrored from a file. `{"name":"x","kind":"image","from":"Dockerfile","url":"https://vendor.invalid/r.tar.xz","sha256":"` + pinnedSum + `","version":"1"}`: "only an archive", // A file name that is a path, a directory within that leaves the archive, and both at once. `{"name":"x","kind":"archive","url":"https://vendor.invalid/a.xpi","sha256":"` + pinnedSum + `","version":"1","file":"../a.xpi"}`: "not a plain relative file name", `{"name":"x","kind":"archive","url":"https://vendor.invalid/r.tar.xz","sha256":"` + pinnedSum + `","version":"1","within":"../up"}`: "not a plain relative directory", `{"name":"x","kind":"archive","url":"https://vendor.invalid/r.tar.xz","sha256":"` + pinnedSum + `","version":"1","within":"r","file":"r.tar.xz"}`: "a file is kept whole", } for artifact, want := range cases { _, err := ParseManifest([]byte(upstreamManifest(artifact))) if err == nil { t.Errorf("%s was accepted", artifact) continue } if !strings.Contains(err.Error(), want) { t.Errorf("%s was refused for another reason than %q: %v", artifact, want, err) } } } func TestAnUpstreamFilesVendorIsNamedOnPurposeAndAnInstallationsIsRefused(t *testing.T) { // The vendor's host is judged like any name, and passes through names-on-purpose; a version of four dotted // numbers is not an address, and a name in it is still judged. m, err := ParseManifest([]byte(upstreamManifest(`{"name":"owl","kind":"archive","url":"https://vendor.be/owl/owl.xpi","sha256":"` + pinnedSum + `","version":"1.5.6.1","file":"owl.xpi","names-on-purpose":{"vendor.be":"Owl's vendor publishes it there"}}`))) if err != nil { t.Fatal(err) } if problems := InstallationProblems(m); len(problems) != 0 { t.Fatalf("the declared vendor and the version were taken for an installation: %v", problems) } m.Build.Artifacts[0].NamesOnPurpose = nil if problems := InstallationProblems(m); len(problems) != 1 || !strings.Contains(problems[0], "vendor.be") { t.Fatalf("an undeclared vendor host is judged: %v", problems) } m.Build.Artifacts[0].Version = "git.novox.be 10.0.0.1" if problems := InstallationProblems(m); len(problems) != 2 { t.Fatalf("a name in the version is judged: %v", problems) } m.Build.Artifacts[0].URL, m.Build.Artifacts[0].Version = "https://mail.novox.be/owl.xpi", "1" if problems := InstallationProblems(m); len(problems) != 1 || !strings.Contains(problems[0], "mail.novox.be") { t.Fatalf("an installation's host in the url is judged: %v", problems) } } func TestAnUpstreamFileFromAnAddressOrAReservedNameIsRefused(t *testing.T) { for _, u := range []string{"https://git.novox.internal/r.tar.xz", "https://10.1.2.3/r.tar.xz", "https://203.0.113.9/r.tar.xz", "https://[2001:db8::1]/r.tar.xz", "https://nas.lan/r.tar.xz", "https://vendor/r.tar.xz"} { _, err := ParseManifest([]byte(upstreamManifest(`{"name":"x","kind":"archive","url":"` + u + `","sha256":"` + pinnedSum + `","version":"1"}`))) if err == nil || !strings.Contains(err.Error(), "published under a public name") { t.Errorf("%s: %v", u, err) } } }