A mail client's release is about 80 MB per version, too large to keep in a repository at every upgrade, and an add-on whose licence forbids copying it to third parties may not be in a repository at all. An archive artifact may now name url, sha256 and version (and file or within) instead of from: the build seat fetches it once, refuses it when its digest is not the pin's and names both, keeps it in its workspace under the digest (a vendor that serves only its newest version cannot break a later build of the same pin), and packs it like any archive, so a node gets the mesh's own archive by digest and never asks the vendor. The build seat's image carries xz, which Go's standard library does not read. The installation check takes the vendor's address and version of such a pin for the world's, as a registry is an image's.
83 lines
3.9 KiB
Go
83 lines
3.9 KiB
Go
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.invalid/release-1.tar.xz","sha256":"` + pinnedSum +
|
|
`","version":"1.0","within":"release"}`,
|
|
`{"name":"addon","kind":"archive","url":"https://vendor.invalid/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 TestAnUpstreamFilesVendorAndVersionNameNoInstallation(t *testing.T) {
|
|
// The vendor's address is the world's, as a public registry is an image's; a version of four dotted numbers
|
|
// is not an address. Anything else still is 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"}`)))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if problems := InstallationProblems(m); len(problems) != 0 {
|
|
t.Fatalf("the vendor and the version were taken for an installation: %v", problems)
|
|
}
|
|
m.Build.Artifacts[0].File = "mail.novox.be"
|
|
if problems := InstallationProblems(m); len(problems) != 1 || !strings.Contains(problems[0], "mail.novox.be") {
|
|
t.Fatalf("a name elsewhere in the artifact is still judged: %v", problems)
|
|
}
|
|
}
|