Skip to content

Commit 6dd4294

Browse files
authored
Update NOTICE file and add test to enforce completeness (#4943)
## Summary - Fix NOTICE file: add 13 missing BSD-3-Clause entries, remove 2 stale entries, move 3 wrongly attributed entries from MIT to BSD-3-Clause - Fix typos (`hashicopr` → `hashicorp`, `LIcense` → `License`, `—--` → `---`) - Fix broken license URLs (`palantir/pkg` branch `develop` → `master`, `tailscale/hujson` branch `main` → `master`) - Add `internal/build/notice_test.go` that cross-references go.mod against NOTICE, checking section order and exact entry sets per license ## Test plan - [x] `go test ./internal/build/` — all 5 tests pass - [x] All 38 license URLs verified with curl (HTTP 200, valid license text) This pull request was AI-assisted by Isaac.
1 parent 54e4b0b commit 6dd4294

2 files changed

Lines changed: 244 additions & 36 deletions

File tree

NOTICE

Lines changed: 67 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,21 @@ Copyright (c) 2011-2019 Canonical Ltd
1717
Copyright (c) 2006-2011 Kirill Simonov
1818
License - https://github.com/yaml/go-yaml/blob/v3/LICENSE
1919

20-
--
20+
---
2121

22-
This software contains code from the following open source projects, licensed under the MPL 2.0 license:
22+
This Software contains code from the following open source projects, licensed under the MPL 2.0 license:
2323

24-
hashicopr/go-version - https://github.com/hashicorp/go-version
24+
hashicorp/go-version - https://github.com/hashicorp/go-version
2525
Copyright 2014 HashiCorp, Inc.
2626
License - https://github.com/hashicorp/go-version/blob/main/LICENSE
2727

2828
hashicorp/hc-install - https://github.com/hashicorp/hc-install
2929
Copyright 2020 HashiCorp, Inc.
3030
License - https://github.com/hashicorp/hc-install/blob/main/LICENSE
3131

32-
hashicopr/terraform-exec - https://github.com/hashicorp/terraform-exec
32+
hashicorp/terraform-exec - https://github.com/hashicorp/terraform-exec
3333
Copyright 2020 HashiCorp, Inc.
34-
LIcense - https://github.com/hashicorp/terraform-exec/blob/main/LICENSE
34+
License - https://github.com/hashicorp/terraform-exec/blob/main/LICENSE
3535

3636
hashicorp/terraform-json - https://github.com/hashicorp/terraform-json
3737
Copyright 2019 HashiCorp, Inc.
@@ -43,24 +43,24 @@ License - https://github.com/hashicorp/terraform/blob/v1.5.5/LICENSE
4343

4444
---
4545

46-
This software contains code from the following open source projects, licensed under the BSD (2-clause) license:
46+
This Software contains code from the following open source projects, licensed under the BSD (2-clause) license:
4747

4848
pkg/browser - https://github.com/pkg/browser
4949
Copyright (c) 2014, Dave Cheney <dave@cheney.net>
5050
License - https://github.com/pkg/browser/blob/master/LICENSE
5151

52-
gorilla/websocket - github.com/gorilla/websocket
52+
gorilla/websocket - https://github.com/gorilla/websocket
5353
Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved.
5454
License - https://github.com/gorilla/websocket/blob/main/LICENSE
5555

5656
---
5757

58-
This software contains code from the following open source projects, licensed under the BSD (3-clause) license:
58+
This Software contains code from the following open source projects, licensed under the BSD (3-clause) license:
5959

6060
spf13/pflag - https://github.com/spf13/pflag
6161
Copyright (c) 2012 Alex Ogier. All rights reserved.
6262
Copyright (c) 2012 The Go Authors. All rights reserved.
63-
License - https://raw.githubusercontent.com/spf13/pflag/master/LICENSE
63+
License - https://github.com/spf13/pflag/blob/master/LICENSE
6464

6565
google/uuid - https://github.com/google/uuid
6666
Copyright (c) 2009,2014 Google Inc. All rights reserved.
@@ -70,7 +70,60 @@ manifoldco/promptui - https://github.com/manifoldco/promptui
7070
Copyright (c) 2017, Arigato Machine Inc. All rights reserved.
7171
License - https://github.com/manifoldco/promptui/blob/master/LICENSE.md
7272

73-
—--
73+
hexops/gotextdiff - https://github.com/hexops/gotextdiff
74+
Copyright (c) 2009 The Go Authors. All rights reserved.
75+
License - https://github.com/hexops/gotextdiff/blob/main/LICENSE
76+
77+
dario.cat/mergo - https://github.com/darccio/mergo
78+
Copyright (c) 2013 Dario Castañé. All rights reserved.
79+
Copyright (c) 2012 The Go Authors. All rights reserved.
80+
License - https://github.com/darccio/mergo/blob/master/LICENSE
81+
82+
gorilla/mux - https://github.com/gorilla/mux
83+
Copyright (c) 2023 The Gorilla Authors. All rights reserved.
84+
License - https://github.com/gorilla/mux/blob/main/LICENSE
85+
86+
palantir/pkg - https://github.com/palantir/pkg
87+
Copyright (c) 2016, Palantir Technologies, Inc.
88+
License - https://github.com/palantir/pkg/blob/master/LICENSE
89+
90+
quasilyte/go-ruleguard - https://github.com/quasilyte/go-ruleguard
91+
Copyright (c) 2022, Iskander (Alex) Sharipov / quasilyte
92+
License - https://github.com/quasilyte/go-ruleguard/blob/master/LICENSE
93+
94+
tailscale/hujson - https://github.com/tailscale/hujson
95+
Copyright (c) 2019 Tailscale Inc. All rights reserved.
96+
License - https://github.com/tailscale/hujson/blob/master/LICENSE
97+
98+
golang.org/x/crypto - https://github.com/golang/crypto
99+
Copyright 2009 The Go Authors.
100+
License - https://github.com/golang/crypto/blob/master/LICENSE
101+
102+
golang.org/x/exp - https://github.com/golang/exp
103+
Copyright 2009 The Go Authors.
104+
License - https://github.com/golang/exp/blob/master/LICENSE
105+
106+
golang.org/x/mod - https://github.com/golang/mod
107+
Copyright 2009 The Go Authors.
108+
License - https://github.com/golang/mod/blob/master/LICENSE
109+
110+
golang.org/x/oauth2 - https://github.com/golang/oauth2
111+
Copyright 2009 The Go Authors.
112+
License - https://github.com/golang/oauth2/blob/master/LICENSE
113+
114+
golang.org/x/sync - https://github.com/golang/sync
115+
Copyright 2009 The Go Authors.
116+
License - https://github.com/golang/sync/blob/master/LICENSE
117+
118+
golang.org/x/sys - https://github.com/golang/sys
119+
Copyright 2009 The Go Authors.
120+
License - https://github.com/golang/sys/blob/master/LICENSE
121+
122+
golang.org/x/text - https://github.com/golang/text
123+
Copyright 2009 The Go Authors.
124+
License - https://github.com/golang/text/blob/master/LICENSE
125+
126+
---
74127

75128
This Software contains code from the following open source projects, licensed under the MIT license:
76129

@@ -84,7 +137,7 @@ License - https://github.com/charmbracelet/bubbles/blob/master/LICENSE
84137

85138
charmbracelet/bubbletea - https://github.com/charmbracelet/bubbletea
86139
Copyright (c) 2020-2025 Charmbracelet, Inc
87-
License - https://github.com/charmbracelet/bubbletea/blob/master/LICENSE
140+
License - https://github.com/charmbracelet/bubbletea/blob/main/LICENSE
88141

89142
charmbracelet/huh - https://github.com/charmbracelet/huh
90143
Copyright (c) 2023 Charmbracelet, Inc.
@@ -104,7 +157,7 @@ License - https://github.com/Masterminds/semver/blob/master/LICENSE.txt
104157

105158
mattn/go-isatty - https://github.com/mattn/go-isatty
106159
Copyright (c) Yasuhiro MATSUMOTO <mattn.jp@gmail.com>
107-
https://github.com/mattn/go-isatty/blob/master/LICENSE
160+
License - https://github.com/mattn/go-isatty/blob/master/LICENSE
108161

109162
nwidger/jsoncolor - https://github.com/nwidger/jsoncolor
110163
Copyright (c) 2016 Niels Widger
@@ -114,35 +167,13 @@ sabhiram/go-gitignore - https://github.com/sabhiram/go-gitignore
114167
Copyright (c) 2015 Shaba Abhiram
115168
License - https://github.com/sabhiram/go-gitignore/blob/master/LICENSE
116169

117-
118170
stretchr/testify - https://github.com/stretchr/testify
119171
Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors.
120172
License - https://github.com/stretchr/testify/blob/master/LICENSE
121173

122-
whilp/git-urls - https://github.com/whilp/git-urls
123-
Copyright (c) 2020 Will Maier
124-
License - https://github.com/whilp/git-urls/blob/master/LICENSE
125-
126-
github.com/wI2L/jsondiff v0.6.1
127-
Copyright (c) 2020-2024 William Poussier <william.poussier@gmail.com>
128-
License - https://github.com/wI2L/jsondiff/blob/master/LICENSE
129-
130-
https://github.com/hexops/gotextdiff
131-
Copyright (c) 2009 The Go Authors. All rights reserved.
132-
License - https://github.com/hexops/gotextdiff/blob/main/LICENSE
133-
134-
https://github.com/BurntSushi/toml
174+
BurntSushi/toml - https://github.com/BurntSushi/toml
135175
Copyright (c) 2013 TOML authors
136-
https://github.com/BurntSushi/toml/blob/master/COPYING
137-
138-
dario.cat/mergo
139-
Copyright (c) 2013 Dario Castañé. All rights reserved.
140-
Copyright (c) 2012 The Go Authors. All rights reserved.
141-
https://github.com/darccio/mergo/blob/master/LICENSE
142-
143-
https://github.com/gorilla/mux
144-
Copyright (c) 2023 The Gorilla Authors. All rights reserved.
145-
https://github.com/gorilla/mux/blob/main/LICENSE
176+
License - https://github.com/BurntSushi/toml/blob/master/COPYING
146177

147178
go-yaml/yaml - https://github.com/yaml/go-yaml
148179
Copyright (c) 2011-2019 Canonical Ltd

internal/build/notice_test.go

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package build
2+
3+
import (
4+
"os"
5+
"regexp"
6+
"slices"
7+
"strings"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
"golang.org/x/mod/modfile"
13+
)
14+
15+
// moduleToGitHub maps non-GitHub go.mod paths to their GitHub org/repo slug.
16+
var moduleToGitHub = map[string]string{
17+
"gopkg.in/ini.v1": "go-ini/ini",
18+
"go.yaml.in/yaml/v3": "yaml/go-yaml",
19+
"dario.cat/mergo": "darccio/mergo",
20+
}
21+
22+
// Modules excluded from NOTICE requirements (Databricks-owned).
23+
var noticeExclude = map[string]bool{
24+
"github.com/databricks/databricks-sdk-go": true,
25+
}
26+
27+
// Additional entries required in the NOTICE file that are not direct go.mod
28+
// dependencies (e.g. bundled binaries).
29+
var noticeExtra = map[string][]string{
30+
"hashicorp/terraform": {"MPL-2.0"},
31+
}
32+
33+
// Expected order of license sections in the NOTICE file.
34+
var expectedSectionOrder = []string{
35+
"Apache-2.0",
36+
"MPL-2.0",
37+
"BSD-2-Clause",
38+
"BSD-3-Clause",
39+
"MIT",
40+
}
41+
42+
var headerToSPDX = map[string]string{
43+
"apache 2.0": "Apache-2.0",
44+
"mpl 2.0": "MPL-2.0",
45+
"bsd (2-clause)": "BSD-2-Clause",
46+
"bsd (3-clause)": "BSD-3-Clause",
47+
"mit": "MIT",
48+
}
49+
50+
var (
51+
githubSlugRe = regexp.MustCompile(`github\.com/([^/\s]+/[^/\s]+)`)
52+
sectionHeaderRe = regexp.MustCompile(`(?i)licensed under the (.+?) license`)
53+
)
54+
55+
func githubSlugFromModule(modPath string) string {
56+
if slug, ok := moduleToGitHub[modPath]; ok {
57+
return slug
58+
}
59+
if strings.HasPrefix(modPath, "github.com/") {
60+
parts := strings.SplitN(modPath, "/", 4)
61+
if len(parts) >= 3 {
62+
return parts[1] + "/" + parts[2]
63+
}
64+
}
65+
if strings.HasPrefix(modPath, "golang.org/x/") {
66+
return "golang/" + strings.TrimPrefix(modPath, "golang.org/x/")
67+
}
68+
return ""
69+
}
70+
71+
// parseNoticeSections parses the NOTICE file into a map from SPDX license
72+
// identifier to the list of GitHub org/repo slugs in that section.
73+
// It also returns the order in which sections appear.
74+
func parseNoticeSections(content string) (map[string][]string, []string) {
75+
sections := map[string][]string{}
76+
var order []string
77+
var currentSPDX string
78+
var block []string
79+
80+
flush := func() {
81+
if currentSPDX != "" && len(block) > 0 {
82+
text := strings.Join(block, "\n")
83+
if m := githubSlugRe.FindStringSubmatch(text); m != nil {
84+
sections[currentSPDX] = append(sections[currentSPDX], m[1])
85+
}
86+
}
87+
block = nil
88+
}
89+
90+
for _, line := range strings.Split(content, "\n") {
91+
if m := sectionHeaderRe.FindStringSubmatch(line); m != nil {
92+
flush()
93+
key := strings.ToLower(strings.TrimSpace(m[1]))
94+
if spdx, ok := headerToSPDX[key]; ok {
95+
currentSPDX = spdx
96+
order = append(order, spdx)
97+
}
98+
continue
99+
}
100+
101+
trimmed := strings.TrimSpace(line)
102+
if trimmed == "" || strings.Trim(trimmed, "-—") == "" {
103+
flush()
104+
continue
105+
}
106+
107+
if currentSPDX != "" {
108+
block = append(block, line)
109+
}
110+
}
111+
flush()
112+
113+
return sections, order
114+
}
115+
116+
func extractLicenseComment(r *modfile.Require) string {
117+
for _, c := range r.Syntax.Suffix {
118+
text := strings.TrimPrefix(c.Token, "//")
119+
text = strings.TrimSpace(text)
120+
if text != "indirect" {
121+
return text
122+
}
123+
}
124+
return ""
125+
}
126+
127+
func TestNoticeFileCompleteness(t *testing.T) {
128+
goModBytes, err := os.ReadFile("../../go.mod")
129+
require.NoError(t, err)
130+
modFile, err := modfile.Parse("../../go.mod", goModBytes, nil)
131+
require.NoError(t, err)
132+
133+
// Build expected: license → sorted list of slugs.
134+
expected := map[string][]string{}
135+
for _, r := range modFile.Require {
136+
if r.Indirect || noticeExclude[r.Mod.Path] {
137+
continue
138+
}
139+
slug := githubSlugFromModule(r.Mod.Path)
140+
if slug == "" {
141+
assert.Failf(t, r.Mod.Path, "cannot map to GitHub slug for NOTICE verification")
142+
continue
143+
}
144+
license := extractLicenseComment(r)
145+
if license == "" {
146+
continue // license_test.go catches missing comments
147+
}
148+
ids, _ := parseSPDXExpression(license)
149+
for _, id := range ids {
150+
expected[id] = append(expected[id], slug)
151+
}
152+
}
153+
for slug, licenses := range noticeExtra {
154+
for _, id := range licenses {
155+
expected[id] = append(expected[id], slug)
156+
}
157+
}
158+
for k := range expected {
159+
slices.Sort(expected[k])
160+
}
161+
162+
// Parse NOTICE file.
163+
noticeBytes, err := os.ReadFile("../../NOTICE")
164+
require.NoError(t, err)
165+
actual, sectionOrder := parseNoticeSections(string(noticeBytes))
166+
for k := range actual {
167+
slices.Sort(actual[k])
168+
}
169+
170+
// Check section order.
171+
assert.Equal(t, expectedSectionOrder, sectionOrder, "NOTICE section order")
172+
173+
// Check entries per section.
174+
for _, license := range expectedSectionOrder {
175+
assert.Equal(t, expected[license], actual[license], "NOTICE %s section", license)
176+
}
177+
}

0 commit comments

Comments
 (0)