Licenses #19
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Licenses | |
# This workflow will check the licences of any installed composer and NPM dependencies against a list of | |
# allowed SPDX identifiers of open source licences. These are contained env variable $SPDX_ALLOWED_DELIMITED | |
# If any installed non-dev dependencies are found that are not in the allowed list then the job will fail. | |
# See https://spdx.org/licenses/ for a list of SPDX identifiers. | |
# Note that the `Unlicense` is an SPDX identifier for an actual license and not a placeholder for a missing license. | |
on: | |
# At 4 AM UTC, only on Saturday | |
workflow_dispatch: | |
schedule: | |
- cron: '0 4 * * 6' | |
permissions: {} | |
jobs: | |
checklicenses: | |
name: Check licenses | |
runs-on: ubuntu-latest | |
permissions: | |
contents: read | |
env: | |
SPDX_ALLOWED_DELIMITED: 'MIT;MIT-0;ISC;0BSD;BSD-2-Clause;BSD-3-Clause;Apache-2.0;Python-2.0;CC0-1.0;CC-BY-3.0;CC-BY-4.0;Public Domain;Unlicense' | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 | |
- name: Get PHP version | |
id: phpversion | |
run: | | |
# Get the PHP version to use from composer.json | |
PHP=$(jq -r '.require["php"]' composer.json) | |
# Remove the leading caret | |
PHP=${PHP//^/} | |
echo "::set-output name=version::$PHP" | |
- name: Install PHP | |
uses: shivammathur/setup-php@c541c155eee45413f5b09a52248675b1a2575231 # v2.31.1 | |
with: | |
php-version: ${{ steps.phpversion.outputs.version }} | |
extensions: curl, dom, gd, intl, json, ldap, mbstring, mysql, tidy, xdebug, zip | |
tools: composer:v2 | |
coverage: xdebug | |
- name: Composer install | |
run: composer install | |
- name: Composer licenses | |
run: | | |
# Validate licenses of all composer dependencies are allowed | |
echo "Checking licenses of all dependencies" | |
composer global require madewithlove/license-checker | |
COMPOSER_GLOBAL_HOME=$(composer -q -n config --global home) | |
# Update the licenses in installed.json file to be sorted so that allowed SPDX identifier | |
# are at the top of the list. This is done because the license-checker will only check the first SPDX. | |
SPDX_ALLOWED_DELIMITED=$SPDX_ALLOWED_DELIMITED php -r ' | |
$allowedSpdxDelimted = getenv("SPDX_ALLOWED_DELIMITED"); | |
$allowedSpdx = explode(";", $allowedSpdxDelimted); | |
$filename = "vendor/composer/installed.json"; | |
$contents = file_get_contents("vendor/composer/installed.json"); | |
$json = json_decode($contents, true); | |
foreach ($json["packages"] as &$package) { | |
if (!isset($package["license"])) { | |
throw new Exception("License field missing for package " . $package["name"]); | |
} | |
usort($package["license"], fn ($spdx) => in_array($spdx, $allowedSpdx) ? -1 : 1); | |
} | |
file_put_contents($filename, json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); | |
' | |
# Translate " " to "_" (and back again later) for any SPDX that has a space in it, such as "Public Domain" | |
# Otherwise the bash for loop will split on the space | |
SPDX_ALLOWED_LIST=$(echo $SPDX_ALLOWED_DELIMITED | tr " " "_" | tr ";" "\n") | |
SPDX_USED_LIST=$($COMPOSER_GLOBAL_HOME/vendor/bin/license-checker --no-dev used) | |
for SPDX_USED in $SPDX_USED_LIST; do | |
IS_ALLOWED=0 | |
for SPDX_ALLOWED in $SPDX_ALLOWED_LIST; do | |
SPDX_ALLOWED=$(echo $SPDX_ALLOWED | tr "_" " ") | |
if [[ $SPDX_USED == $SPDX_ALLOWED ]]; then | |
IS_ALLOWED=1 | |
break | |
fi | |
done | |
if [[ $IS_ALLOWED == 0 ]]; then | |
echo "License $SPDX_USED found in composer dependencies is not allowed. Check vendor/composer/installed.json" | |
exit 1 | |
fi | |
done | |
# Remove license-checker as its name will collide with the npm license checker | |
composer global remove madewithlove/license-checker | |
echo "All licenses are allowed" | |
- name: NPM licenses | |
run: | | |
# Set nvmdir explicitly before installation. Default dir doesn't work for some reason. | |
export NVM_DIR="${HOME}/.nvm" | |
# Installation fails if install dir is specified but doesn't exist | |
if ! [[ -d "$NVM_DIR" ]]; then | |
echo "NVM_DIR '$NVM_DIR' doesn't exist - creating it now" | |
mkdir $NVM_DIR | |
fi | |
# Get install nvm script from gha-run-tests | |
curl -s https://raw.githubusercontent.com/silverstripe/gha-run-tests/refs/heads/1/install-nvm.sh > install-nvm.sh | |
chmod +x install-nvm.sh | |
./install-nvm.sh | |
if [[ $? != 0 ]]; then | |
echo "Error while installing nvm" | |
exit 1 | |
fi | |
# This loads nvm | |
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" | |
EXCLUDE_PACKAGES='@silverstripe/[email protected];[email protected];[email protected];[email protected];[email protected]' | |
# Loop all package.json files that were previously installed by composer install | |
BASEDIR=$(pwd) | |
FILES=$(find . | grep package.json | grep -v node_modules) | |
for FILE in $FILES; do | |
# remove trailing "/package.json" | |
SUBDIR="${FILE/\/package.json/}" | |
DIR="$BASEDIR/$SUBDIR" | |
echo "Checking $DIR" | |
cd $DIR | |
if [[ ! -f .nvmrc ]]; then | |
echo "Missing .nvmrc" | |
exit 1 | |
fi | |
nvm install | |
nvm use | |
if [[ -z $(which yarn) ]]; then | |
npm install -g yarn; | |
fi | |
yarn install --network-concurrency 1 | |
if [[ -z $(which license-checker) ]]; then | |
echo "Installing license-checker" | |
npm install -g license-checker | |
fi | |
license-checker --production --unknown --out /dev/null --onlyAllow "$SPDX_ALLOWED_DELIMITED" --excludePackages "$EXCLUDE_PACKAGES" | |
done | |
echo "Passed" |