summaryrefslogtreecommitdiff
path: root/maint/check_licenses
blob: f9be0ca52bccf26c8c77d27e77af9026d22a43d1 (plain)
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
#!/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, 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
    CC0-1.0
    ISC
    MIT
    Unicode-DFS-2016
    Unlicense
    Zlib
    "MIT AND BSD-3-Clause"
    "(MIT OR Apache-2.0) AND Unicode-DFS-2016"
)

# List of packages that don't list a license.
NO_LICENSE=(
    # The license for "ring" is something like "ISC AND openssl AND
    # ssleay AND MIT"; the openssl license is not up-to-date with
    # modern openssl.  It includes an advertising clause. :P
    #
    # See https://gitlab.torproject.org/tpo/core/arti/-/issues/493 for
    # our related ticket.
    ring
    # License appears to be ISC.
    webpki
    rustls-webpki
)

# 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.
#
# (See https://gitlab.torproject.org/tpo/core/arti/-/issues/845)
MPL_20_OK=(
    # This one is pending: See https://github.com/soc/option-ext/pull/4
    option-ext
    generational-arena
    dynasm
    dynasmrt
)

# List of packages allowed to use the LGPL-3.0-only 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_ONLY_OK=(
    equix
    hashx
)

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"; then
	if ! containsElement "$package" "${LGPL_30_ONLY_OK[@]}"; then
	    echo "$package uses LGPL-3.0-only but has not been allow-listed."
	    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"