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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
#!/usr/bin/env bash
set -euo pipefail
: "${CARGO:=cargo}"
# A list of the licenses that we currently allow in our code.
#
# If a package supports multiple licenses (using OR), then we are okay
# if it supports _any_ of these licenses.
#
# We don't currently do a good job of understanding AND and OR, so
# interesting license combinations that involve AND may need to be given
# in quotes.
RECOGNIZED_LICENSES=(
Apache-2.0
BSD-2-Clause
BSD-3-Clause
BSL-1.0
CC0-1.0
CDLA-Permissive-2.0
ISC
MIT
Unicode-DFS-2016
Unicode-3.0
Unlicense
Zlib
"BSD-3-Clause AND MIT"
"MIT AND BSD-3-Clause"
"(MIT OR Apache-2.0) AND Unicode-DFS-2016"
"MIT AND (MIT OR Apache-2.0)"
# Used by unicode-ident
"(MIT OR Apache-2.0) AND Unicode-3.0"
"(Apache-2.0 OR MIT) AND Unicode-3.0"
# Used by ring >= v0.17.10
"Apache-2.0 AND ISC"
# Used by aws-lc-rs
"ISC AND (Apache-2.0 OR ISC)"
"(Apache-2.0 OR MIT) AND BSD-3-Clause"
)
# List of packages that don't list a license.
NO_LICENSE=(
)
# List of packages which we allow to use the MPL-2.0 license.
#
# We need to check these individually because, if the party says
# "MPL-2.0" without actually including the text of exhibit A from the
# MPL, it is not unambiguous that they have applied MPL-2.0 to their
# code.
#
# To deal with a new MPL dependency, take a look at its repository.
# Look for the Exhibit A text (grep for "Source Code Form").
# If it's present, fine, you can add it to this list.
# If not, here is an example of how to proceed
# https://github.com/soc/option-ext/pull/4
# After the crate upstream merges that MR, we can take that as a declaration
# about the licence status, so you can include the crate in this list,
# even if upstream haven't *released* the updated crate yet.
#
# For background, see
# https://gitlab.torproject.org/tpo/core/arti/-/issues/845#note_2900025
#
MPL_20_OK=(
option-ext
dynasm
dynasmrt
)
# List of packages allowed to use the LGPL-3.0-only or LGPL-3.0 license.
#
# We aren't including LGPL code in the general Arti dependency tree, this is
# just meant to be a limited whitelist which allows some of our own crates
# we are developing under the LGPL.
LGPL_30_OK=(
equix
hashx
)
######
# Exceptions for specific crates only.
#
# We use these when a license would otherwise not be allowed,
# but we want to allow it for just one crate.
#
# If you expect that a specific license will be allowed for _several_ crates,
# make a new thing like LGPL_30_OK above.
declare -A PERMIT_LICENSE
# awc-ls-sys hasn't updated their license from OpenSSL to Apache;
# their ticket is https://github.com/aws/aws-lc/issues/2203.
#
# The OpenSSL license is GPL-incompatible, but we tolerate it,
# since never use aws-lc-sys by default.
PERMIT_LICENSE["aws-lc-sys"]="ISC AND (Apache-2.0 OR ISC) AND OpenSSL"
# priority-queue is MPL-2.0 with exhibit A text
#
# See MPL_20_OK above.
PERMIT_LICENSE["priority-queue"]="LGPL-3.0-or-later OR MPL-2.0"
containsElement () {
local e match="$1"
shift
for e; do
[[ "$e" == "$match" ]] && return 0;
done
return 1
}
if ! $CARGO license --help >/dev/null; then
echo "cargo-license is not installed!"
echo
echo "For reasonable results, run:"
echo " cargo install cargo-license"
exit 2
fi
cd "$(dirname "$0")/.."
# The caller might reasonably have set CARGO to something containing spaces.
# So collect the output before we set IFS.
output=$($CARGO license --all-features -t)
problems=0
IFS=$'\n'
for line in $output; do
package=$(echo "$line" | cut -f1)
licenses=$(echo "$line" | cut -f5)
# skip the first line.
if test "$package" = "name" && test "$licenses" = "license"; then
continue;
fi
if test -z "$licenses"; then
if ! containsElement "$package" "${NO_LICENSE[@]}"; then
echo "$package has no license"
problems=1
fi
continue
fi
if test "$licenses" = "MPL-2.0"; then
if ! containsElement "$package" "${MPL_20_OK[@]}"; then
echo "$package uses MPL-2.0 but has not been allow-listed."
problems=1
fi
continue
fi
if test "$licenses" = "LGPL-3.0-only" || test "$licenses" = "LGPL-3.0"; then
if ! containsElement "$package" "${LGPL_30_OK[@]}"; then
echo "$package uses LGPL-3.0 but has not been allow-listed."
problems=1
fi
continue
fi
if [[ -v PERMIT_LICENSE[$package] ]]; then
if test "$licenses" = "${PERMIT_LICENSE[$package]}"; then
# We've made an exception for this package.
:
else
echo "$package has an exception listed, but its license does not match that exception."
problems=1
fi
continue
fi
found_ok=0
if containsElement "$licenses" "${RECOGNIZED_LICENSES[@]}"; then
found_ok=1
else
# TODO: By Splitting on "OR" without parsing, this can give bogus
# elements in the output if the license is something like "(A OR
# B) AND C". Fortunately the parenthesis will save us from false
# negatives here, but in the end we should probably switch to a
# real parser.
for lic in ${licenses// OR /$'\n'}; do
if containsElement "$lic" "${RECOGNIZED_LICENSES[@]}"; then
found_ok=1
break
fi
done
fi
if test $found_ok = "0"; then
echo "$package does not advertise any supported license!"
echo " ($package: $licenses)"
problems=1
fi
done
if test "$problems" = 1; then
echo "You can suppress the above warnings by editing $0..."
echo "but only do so if we are actually okay with all the licenses!"
fi
exit "$problems"
|