-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlicensing_shipping_test.go
More file actions
136 lines (128 loc) · 5.92 KB
/
Copy pathlicensing_shipping_test.go
File metadata and controls
136 lines (128 loc) · 5.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package main
import (
"os"
"path/filepath"
"regexp"
"runtime"
"strings"
"testing"
)
// moduleRoot locates the repository root from this file's own path, so these
// tests do not depend on the working directory a runner happens to use.
func moduleRoot(t *testing.T) string {
t.Helper()
_, thisFile, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("runtime.Caller failed; cannot locate the module root")
}
return filepath.Dir(thisFile)
}
func readRoot(t *testing.T, name string) string {
t.Helper()
b, err := os.ReadFile(filepath.Join(moduleRoot(t), name))
if err != nil {
t.Fatalf("read %s: %v", name, err)
}
return string(b)
}
// licenceFiles are the two documents every distribution channel must carry: the
// project's own licence, and the third-party notices for everything linked into
// the binary.
var licenceFiles = []string{"LICENSE", "THIRD-PARTY-NOTICES.md"}
// TestImagesShipTheLicenceFiles holds the container images to the same
// attribution the other channels already provide. The archives ship these two
// files beside the binary (.goreleaser.yaml archives.files) and the deb/rpm
// install them under /usr/share/doc/pingularity (nfpms.contents), but the images
// shipped neither for their whole history: both Dockerfiles COPY'd only the
// binary, and org.opencontainers.image.licenses="MIT" is a label declaring
// Pingularity's own licence, not a reproduction of anyone else's.
//
// That matters because an image is a binary distribution like any other, and the
// binary inside it carries BSD-3 code (golang.org/x/crypto, golang.org/x/sys,
// speedtest-go, the modernc musl-derived libc) plus an OFL font, each of which
// asks for its notice to travel with the distribution.
//
// The two halves are checked together on purpose. goreleaser stages only the
// built binaries into the docker build context, so a COPY without a matching
// extra_files entry fails the build - loudly, which is fine - while an
// extra_files entry without a COPY silently ships an image with no notices,
// which is the failure worth a test.
func TestImagesShipTheLicenceFiles(t *testing.T) {
for _, dockerfile := range []string{"Dockerfile", "Dockerfile.iperf"} {
body := readRoot(t, dockerfile)
for _, want := range licenceFiles {
// The COPY must name the file and land it under the conventional
// package-documentation path, matching where the deb/rpm put it.
re := regexp.MustCompile(`(?m)^COPY\b[^\n]*\b` + regexp.QuoteMeta(want) + `\b[^\n]*/usr/share/doc/pingularity/`)
if !re.MatchString(body) {
t.Errorf("%s: no COPY placing %s into /usr/share/doc/pingularity/ - the image would ship the binary with that attribution missing",
dockerfile, want)
}
}
}
// Every dockers_v2 builder must stage both files into its build context.
cfg := readRoot(t, ".goreleaser.yaml")
dockersV2 := cfg[strings.Index(cfg, "\ndockers_v2:"):]
if !strings.HasPrefix(dockersV2, "\ndockers_v2:") {
t.Fatal(".goreleaser.yaml has no dockers_v2 block - this test's premise is gone")
}
builders := regexp.MustCompile(`(?m)^ - id: (\S+)`).FindAllStringSubmatch(dockersV2, -1)
if len(builders) == 0 {
t.Fatal("parsed no dockers_v2 builders - the test's matching has rotted")
}
for _, b := range builders {
id := b[1]
start := strings.Index(dockersV2, " - id: "+id)
end := len(dockersV2)
if next := strings.Index(dockersV2[start+1:], "\n - id: "); next >= 0 {
end = start + 1 + next
}
block := dockersV2[start:end]
for _, want := range licenceFiles {
if !regexp.MustCompile(`(?m)^\s*-\s*` + regexp.QuoteMeta(want) + `\s*$`).MatchString(block) {
t.Errorf("dockers_v2 builder %q does not list %s in extra_files - the Dockerfile's COPY of it will fail the build",
id, want)
}
}
}
}
// fontFace matches the dashboard's embedded @font-face: the family it declares,
// and the fact that the face is a data: URI rather than a fetched URL.
var fontFace = regexp.MustCompile(`@font-face\{font-family:'([^']+)'[^}]*src:url\(data:font/`)
// TestEmbeddedFontIsAttributed holds the notices to whatever font the dashboard
// actually embeds. internal/web/ui/index.html carries a base64 woff2 inside a
// data: URI, and web.go compiles that file into the binary with go:embed - so
// the font ships through every channel, in every image and package.
//
// Quicksand is under the SIL Open Font License, whose clause 2 requires that
// every copy of the Font Software carry the copyright notice and the licence.
// The font shipped for a long time with neither, because THIRD-PARTY-NOTICES.md
// was built from go.mod and a font is not a Go module - nothing in the toolchain
// could have noticed it.
//
// The family name is read out of the CSS rather than hard-coded here, so
// swapping the embedded face for a different one fails this test until its
// licence is reproduced too.
func TestEmbeddedFontIsAttributed(t *testing.T) {
ui := readRoot(t, filepath.Join("internal", "web", "ui", "index.html"))
m := fontFace.FindStringSubmatch(ui)
if m == nil {
// No embedded face is a legitimate state (a rewrite could drop it), but
// it invalidates this test's premise, so say so rather than pass quietly.
if strings.Contains(ui, "data:font/") {
t.Fatal("index.html embeds a data: font this test's @font-face pattern no longer recognises - recheck the pattern")
}
t.Skip("the dashboard embeds no font")
}
family := m[1]
notices := readRoot(t, "THIRD-PARTY-NOTICES.md")
if !strings.Contains(notices, family) {
t.Errorf("index.html embeds the %q font but THIRD-PARTY-NOTICES.md never names it - add a section reproducing its licence", family)
}
// The OFL is the licence Quicksand ships under; if the embedded face changes
// to something under a different licence, the family check above fires first
// and this line is updated with it.
if !strings.Contains(notices, "SIL OPEN FONT LICENSE Version 1.1") {
t.Errorf("THIRD-PARTY-NOTICES.md names %q but does not reproduce the SIL Open Font License, which that font requires to travel with every copy", family)
}
}