check_licenses
1 #!/usr/bin/env bash 2 3 set -euo pipefail 4 5 : "${CARGO:=cargo}" 6 7 # A list of the licenses that we currently allow in our code. 8 # 9 # If a package supports multiple licenses (using OR), then we are okay 10 # if it supports _any_ of these licenses. 11 # 12 # We don't currently do a good job of understanding AND, so 13 # interesting license combinations that involve AND may need to be given 14 # in quotes. 15 RECOGNIZED_LICENSES=( 16 Apache-2.0 17 BSD-2-Clause 18 BSD-3-Clause 19 BSL-1.0 20 CC0-1.0 21 ISC 22 MIT 23 Unicode-DFS-2016 24 Unicode-3.0 25 Unlicense 26 Zlib 27 "MIT AND BSD-3-Clause" 28 "(MIT OR Apache-2.0) AND Unicode-DFS-2016" 29 "MIT AND (MIT OR Apache-2.0)" 30 # cargo-license appears to break on the OR inside () and then sort! 31 # https://github.com/onur/cargo-license/issues/78 32 "Apache-2.0) OR MIT AND (MIT" 33 # Used by unicode-ident 34 "(MIT OR Apache-2.0) AND Unicode-3.0" 35 ) 36 37 # List of packages that don't list a license. 38 NO_LICENSE=( 39 # The license for "ring" is something like "ISC AND openssl AND 40 # ssleay AND MIT"; the openssl license is not up-to-date with 41 # modern openssl. It includes an advertising clause. :P 42 # 43 # See https://gitlab.torproject.org/tpo/core/arti/-/issues/493 for 44 # our related ticket. 45 ring 46 # License appears to be ISC. 47 webpki 48 # The unicode folks have their own license now that is no longer 49 # "Unicode-DFS-2016" and which might not even have a SPDX 50 # entry. But it still seems to be a permissive DFSG-compliant 51 # license. 52 tinystr 53 ) 54 55 # List of packages which we allow to use the MPL-2.0 license. 56 # 57 # We need to check these individually because, if the party says 58 # "MPL-2.0" without actually including the text of exhibit A from the 59 # MPL, it is not unambiguous that they have applied MPL-2.0 to their 60 # code. 61 # 62 # (See https://gitlab.torproject.org/tpo/core/arti/-/issues/845) 63 MPL_20_OK=( 64 option-ext 65 dynasm 66 dynasmrt 67 ) 68 69 # List of packages allowed to use the LGPL-3.0-only license. 70 # 71 # We aren't including LGPL code in the general Arti dependency tree, this is 72 # just meant to be a limited whitelist which allows some of our own crates 73 # we are developing under the LGPL. 74 LGPL_30_ONLY_OK=( 75 equix 76 hashx 77 ) 78 79 containsElement () { 80 local e match="$1" 81 shift 82 for e; do 83 [[ "$e" == "$match" ]] && return 0; 84 done 85 return 1 86 } 87 88 if ! $CARGO license --help >/dev/null; then 89 echo "cargo-license is not installed!" 90 echo 91 echo "For reasonable results, run:" 92 echo " cargo install cargo-license" 93 exit 2 94 fi 95 96 cd "$(dirname "$0")/.." 97 98 # The caller might reasonably have set CARGO to something containing spaces. 99 # So collect the output before we set IFS. 100 output=$($CARGO license --all-features -t) 101 102 problems=0 103 IFS=$'\n' 104 for line in $output; do 105 package=$(echo "$line" | cut -f1) 106 licenses=$(echo "$line" | cut -f5) 107 108 # skip the first line. 109 if test "$package" = "name" && test "$licenses" = "license"; then 110 continue; 111 fi 112 if test -z "$licenses"; then 113 if ! containsElement "$package" "${NO_LICENSE[@]}"; then 114 echo "$package has no license" 115 problems=1 116 fi 117 continue 118 fi 119 120 if test "$licenses" = "MPL-2.0"; then 121 if ! containsElement "$package" "${MPL_20_OK[@]}"; then 122 echo "$package uses MPL-2.0 but has not been allow-listed." 123 problems=1 124 fi 125 continue 126 fi 127 128 if test "$licenses" = "LGPL-3.0-only"; then 129 if ! containsElement "$package" "${LGPL_30_ONLY_OK[@]}"; then 130 echo "$package uses LGPL-3.0-only but has not been allow-listed." 131 problems=1 132 fi 133 continue 134 fi 135 136 if test "$licenses" = "LGPL-3.0-or-later OR MPL-2.0"; then 137 # priority-queue has some paperwork trouble 138 # - MPL but missing Exhibit A 139 # We are using this in tor-rtmock, where it's IMO fine to have LGPL. 140 # Upstream conversation here 141 # https://github.com/garro95/priority-queue/pull/48 142 # (or maybe followup tickets) 143 if ! containsElement "$package" "priority-queue"; then 144 echo "$package uses wrong SPDX and isn't priority-queue." 145 problems=1 146 fi 147 continue 148 fi 149 150 found_ok=0 151 if containsElement "$licenses" "${RECOGNIZED_LICENSES[@]}"; then 152 found_ok=1 153 else 154 # TODO: By Splitting on "OR" without parsing, this can give bogus 155 # elements in the output if the license is something like "(A OR 156 # B) AND C". Fortunately the parenthesis will save us from false 157 # negatives here, but in the end we should probably switch to a 158 # real parser. 159 for lic in ${licenses// OR /$'\n'}; do 160 if containsElement "$lic" "${RECOGNIZED_LICENSES[@]}"; then 161 found_ok=1 162 break 163 fi 164 done 165 fi 166 if test $found_ok = "0"; then 167 echo "$package does not advertise any supported license!" 168 echo " ($package: $licenses)" 169 problems=1 170 fi 171 done 172 173 if test "$problems" = 1; then 174 echo "You can suppress the above warnings by editing $0..." 175 echo "but only do so if we are actually okay with all the licenses!" 176 fi 177 178 exit "$problems"