-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: output license usage and issues
- Loading branch information
Showing
5 changed files
with
184 additions
and
2 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
const licenseGroups = require('./licenses.json'); | ||
const {getFindings} = require('./utils'); | ||
|
||
const LICENSE_TYPES = [ | ||
'Public Domain', | ||
'Permissive', | ||
'Weakly Protective', | ||
'Strongly Protective', | ||
'Network Protective', | ||
'Uncategorized', | ||
'Invalid', | ||
]; | ||
|
||
const DEFAULT_POLICY = { | ||
high: ['cat:Network Protective', 'cat:Strongly Protective'], | ||
moderate: ['cat:Weakly Protective'], | ||
}; | ||
|
||
const typeForLicense = (license) => { | ||
if (!license || license === 'N/A') { | ||
return 'N/A'; | ||
} | ||
if (license.includes(' ')) { | ||
// Parse simple AND/OR SPDX expressions | ||
if ((license.match(/\s/g) || []).length === 2) { | ||
let expressionLicenses; | ||
let condition; | ||
|
||
if (license.match(/ or /i)) { | ||
condition = 'or'; | ||
expressionLicenses = license.replace(/[()]/g, '').split(/ or /i); | ||
} else if (license.match(/ and /i)) { | ||
condition = 'and'; | ||
expressionLicenses = license.replace(/[()]/g, '').split(/ and /i); | ||
} | ||
|
||
if (expressionLicenses) { | ||
const expressionTypes = [ | ||
typeForLicense(expressionLicenses[0]), | ||
typeForLicense(expressionLicenses[1]), | ||
]; | ||
|
||
if ([expressionTypes[0], expressionTypes[1]].includes('Invalid')) { | ||
return 'Invalid'; | ||
} | ||
|
||
const aggregateExpressionType = | ||
LICENSE_TYPES[ | ||
condition === 'or' | ||
? Math.min( | ||
LICENSE_TYPES.indexOf(expressionTypes[0]), | ||
LICENSE_TYPES.indexOf(expressionTypes[1]), | ||
) | ||
: Math.max( | ||
LICENSE_TYPES.indexOf(expressionTypes[0]), | ||
LICENSE_TYPES.indexOf(expressionTypes[1]), | ||
) | ||
]; | ||
|
||
return aggregateExpressionType; | ||
} | ||
} | ||
return 'Expression'; | ||
} | ||
return licenseGroups.types.find(({licenses}) => licenses.includes(license))?.type || 'Invalid'; | ||
}; | ||
|
||
module.exports = { | ||
typeForLicense, | ||
getLicenseUsage: ({dependencies = []}) => { | ||
const licenseUsage = dependencies.reduce((agg, {name, version, license}) => { | ||
const licenseName = license || 'N/A'; | ||
|
||
return { | ||
...agg, | ||
[licenseName]: { | ||
meta: { | ||
type: typeForLicense(licenseName), | ||
}, | ||
dependencies: (agg[licenseName]?.dependencies || []).concat([{name, version}]), | ||
}, | ||
}; | ||
}, {}); | ||
|
||
return licenseUsage; | ||
}, | ||
|
||
getLicenseIssues: ({licenseUsage, packageGraph}) => { | ||
const issues = []; | ||
const allLicenses = Object.keys(licenseUsage); | ||
|
||
if (allLicenses.includes('N/A')) { | ||
issues.push({ | ||
severity: 'critical', | ||
title: 'Dependencies have no specified license', | ||
dependencies: licenseUsage['N/A'].dependencies, | ||
}); | ||
} | ||
|
||
Object.entries(licenseUsage).forEach(([licenseName, {meta, dependencies}]) => { | ||
const licenseType = meta?.type; | ||
|
||
if (!licenseName.includes(' ') && !['Expression', 'N/A'].includes(licenseType)) { | ||
if (!licenseGroups.osiApproved.includes(licenseName)) { | ||
issues.push({ | ||
severity: 'low', | ||
title: `Dependencies use a license that is not OSI approved: ${licenseName}`, | ||
dependencies, | ||
}); | ||
} | ||
} | ||
|
||
if (!licenseType || licenseType === 'Uncategorized') { | ||
issues.push({ | ||
severity: 'high', | ||
title: `Dependencies use an atypical license: ${licenseName}`, | ||
dependencies, | ||
}); | ||
} else if (licenseType === 'Invalid') { | ||
issues.push({ | ||
severity: 'high', | ||
title: `Dependencies use an invalid SPDX license: ${licenseName}`, | ||
dependencies, | ||
}); | ||
} else if (licenseType === 'Expression') { | ||
issues.push({ | ||
severity: 'high', | ||
title: `Dependencies use a custom license expression: ${licenseName}`, | ||
dependencies, | ||
}); | ||
} | ||
|
||
Object.entries(DEFAULT_POLICY).forEach(([severity, includes]) => { | ||
if (includes.includes(licenseName)) { | ||
issues.push({ | ||
severity, | ||
title: `Dependencies use potentially problematic license: ${licenseName}`, | ||
dependencies, | ||
}); | ||
} else if (includes.includes(`cat:${licenseType}`)) { | ||
issues.push({ | ||
severity, | ||
title: `Dependencies use ${licenseType} license: ${licenseName}`, | ||
dependencies, | ||
}); | ||
} | ||
}); | ||
}); | ||
|
||
return issues.reduce( | ||
(agg, {severity, title, dependencies}) => | ||
agg.concat( | ||
dependencies.map(({name, version}) => ({ | ||
severity, | ||
title, | ||
name, | ||
version, | ||
findings: getFindings(packageGraph, name, version), | ||
})), | ||
), | ||
[], | ||
); | ||
}, | ||
}; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"types": [{"type":"Network Protective","licenses":["AGPL-1.0","AGPL-1.0-only","AGPL-1.0-or-later","AGPL-3.0","AGPL-3.0-only","AGPL-3.0-or-later","CPAL-1.0","EUPL-1.0","EUPL-1.1","EUPL-1.2","RPL-1.1","RPL-1.5","SSPL-1.0"]},{"type":"Uncategorized","licenses":["AAL","Abstyles","Adobe-2006","Adobe-Glyph","ADSL","Afmparse","Aladdin","AMDPLPA","AML","AMPAS","ANTLR-PD","ANTLR-PD-fallback","APAFML","App-s2p","Arphic-1999","Baekmuk","Bahyph","Barr","Bitstream-Vera","blessing","BlueOak-1.0.0","Borceux","BSD-1-Clause","BSD-2-Clause-Patent","BSD-2-Clause-Views","BSL-1.0","BUSL-1.1","bzip2-1.0.5","bzip2-1.0.6","C-UDA-1.0","CAL-1.0","CAL-1.0-Combined-Work-Exception","Caldera","CC-BY-1.0","CC-BY-2.0","CC-BY-2.5","CC-BY-2.5-AU","CC-BY-3.0","CC-BY-3.0-AT","CC-BY-3.0-DE","CC-BY-3.0-IGO","CC-BY-3.0-NL","CC-BY-3.0-US","CC-BY-4.0","CC-BY-NC-1.0","CC-BY-NC-2.0","CC-BY-NC-2.5","CC-BY-NC-3.0","CC-BY-NC-3.0-DE","CC-BY-NC-4.0","CC-BY-NC-ND-1.0","CC-BY-NC-ND-2.0","CC-BY-NC-ND-2.5","CC-BY-NC-ND-3.0","CC-BY-NC-ND-3.0-DE","CC-BY-NC-ND-3.0-IGO","CC-BY-NC-ND-4.0","CC-BY-NC-SA-1.0","CC-BY-NC-SA-2.0","CC-BY-NC-SA-2.0-FR","CC-BY-NC-SA-2.0-UK","CC-BY-NC-SA-2.5","CC-BY-NC-SA-3.0","CC-BY-NC-SA-3.0-DE","CC-BY-NC-SA-3.0-IGO","CC-BY-NC-SA-4.0","CC-BY-ND-1.0","CC-BY-ND-2.0","CC-BY-ND-2.5","CC-BY-ND-3.0","CC-BY-ND-3.0-DE","CC-BY-ND-4.0","CC-BY-SA-1.0","CC-BY-SA-2.0","CC-BY-SA-2.0-UK","CC-BY-SA-2.1-JP","CC-BY-SA-2.5","CC-BY-SA-3.0","CC-BY-SA-3.0-AT","CC-BY-SA-3.0-DE","CC-BY-SA-4.0","CC-PDDC","CDL-1.0","CDLA-Permissive-1.0","CDLA-Permissive-2.0","CDLA-Sharing-1.0","CERN-OHL-1.1","CERN-OHL-1.2","CERN-OHL-P-2.0","CERN-OHL-S-2.0","CERN-OHL-W-2.0","checkmk","COIL-1.0","Community-Spec-1.0","copyleft-next-0.3.0","copyleft-next-0.3.1","CPOL-1.02","Crossword","CrystalStacker","Cube","curl","D-FSL-1.0","diffmark","DL-DE-BY-2.0","DOC","Dotseqn","DRL-1.0","dvipdfm","ECL-1.0","eCos-2.0","eGenix","Elastic-2.0","Entessa","EPICS","etalab-2.0","EUDatagrid","Eurosym","Fair","FDK-AAC","Frameworx-1.0","FreeBSD-DOC","FreeImage","FSFAP","FSFUL","FSFULLR","FSFULLRWD","GD","GFDL-1.1","GFDL-1.1-invariants-only","GFDL-1.1-invariants-or-later","GFDL-1.1-no-invariants-only","GFDL-1.1-no-invariants-or-later","GFDL-1.1-only","GFDL-1.1-or-later","GFDL-1.2","GFDL-1.2-invariants-only","GFDL-1.2-invariants-or-later","GFDL-1.2-no-invariants-only","GFDL-1.2-no-invariants-or-later","GFDL-1.2-only","GFDL-1.2-or-later","GFDL-1.3","GFDL-1.3-invariants-only","GFDL-1.3-invariants-or-later","GFDL-1.3-no-invariants-only","GFDL-1.3-no-invariants-or-later","GFDL-1.3-only","GFDL-1.3-or-later","Giftware","GL2PS","Glide","Glulxe","GLWTPL","gnuplot","HaskellReport","Hippocratic-2.1","HPND","HPND-sell-variant","HTMLTIDY","IBM-pibs","IJG","ImageMagick","Imlib2","Info-ZIP","Intel","Intel-ACPI","Jam","JPNIC","Knuth-CTAN","LAL-1.2","LAL-1.3","Latex2e","Leptonica","LGPLLR","Libpng","libpng-2.0","libselinux-1.0","libtiff","libutil-David-Nugent","LiLiQ-P-1.1","LiLiQ-R-1.1","LiLiQ-Rplus-1.1","Linux-man-pages-copyleft","Linux-OpenIB","LPL-1.0","LPL-1.02","LZMA-SDK-9.11-to-9.20","LZMA-SDK-9.22","MakeIndex","Minpack","MirOS","MIT-Modern-Variant","MIT-open-group","MITNFA","mpi-permissive","mpich2","mplus","MS-LPL","MTLL","MulanPSL-1.0","MulanPSL-2.0","Multics","Mup","NAIST-2003","NBPL-1.0","NCGL-UK-2.0","NCSA","Net-SNMP","NetCDF","Newsletr","NGPL","NICTA-1.0","NIST-PD","NIST-PD-fallback","NLOD-1.0","NLOD-2.0","Noweb","NPL-1.0","NPL-1.1","NPOSL-3.0","NRL","NTP","NTP-0","Nunit","O-UDA-1.0","OCCT-PL","OCLC-2.0","ODC-By-1.0","OFL-1.0","OFL-1.0-no-RFN","OFL-1.0-RFN","OFL-1.1","OFL-1.1-no-RFN","OFL-1.1-RFN","OGC-1.0","OGDL-Taiwan-1.0","OGL-Canada-2.0","OGL-UK-1.0","OGL-UK-2.0","OGL-UK-3.0","OGTSL","OML","OPL-1.0","OPUBL-1.0","OSET-PL-2.1","Parity-6.0.0","Parity-7.0.0","Plexus","PolyForm-Noncommercial-1.0.0","PolyForm-Small-Business-1.0.0","PostgreSQL","PSF-2.0","psfrag","psutils","Python-2.0.1","Qhull","Rdisc","RPSL-1.0","RSA-MD","Saxpath","SCEA","SchemeReport","Sendmail-8.23","SGI-B-1.0","SGI-B-1.1","SGI-B-2.0","SHL-0.5","SHL-0.51","SimPL-2.0","SMLNJ","SMPPL","SNIA","Spencer-86","Spencer-94","Spencer-99","SSH-OpenSSH","SSH-short","StandardML-NJ","SWL","TAPR-OHL-1.0","TCP-wrappers","TMate","TORQUE-1.1","TOSL","TU-Berlin-1.0","TU-Berlin-2.0","UCL-1.0","Unicode-DFS-2015","Unicode-DFS-2016","Unicode-TOU","UPL-1.0","VOSTROM","VSL-1.0","Wsuipa","wxWindows","X11-distribute-modifications-variant","Xerox","Xnet","xpp","XSkat","Zed","Zend-2.0"]},{"type":"Permissive","licenses":["0BSD","AFL-1.1","AFL-1.2","AFL-2.0","AFL-2.1","AFL-3.0","Apache-1.0","Apache-1.1","Apache-2.0","APSL-1.0","Artistic-2.0","Beerware","BSD-2-Clause","BSD-2-Clause-FreeBSD","BSD-2-Clause-NetBSD","BSD-3-Clause","BSD-3-Clause-Attribution","BSD-3-Clause-Clear","BSD-3-Clause-LBNL","BSD-3-Clause-Modification","BSD-3-Clause-No-Military-License","BSD-3-Clause-No-Nuclear-License","BSD-3-Clause-No-Nuclear-License-2014","BSD-3-Clause-No-Nuclear-Warranty","BSD-3-Clause-Open-MPI","BSD-4-Clause","BSD-4-Clause-Shortened","BSD-4-Clause-UC","BSD-Protection","BSD-Source-Code","CECILL-1.0","CECILL-1.1","CECILL-2.0","CECILL-2.1","CECILL-B","CNRI-Jython","CNRI-Python","CNRI-Python-GPL-Compatible","Condor-1.1","DSDP","ECL-2.0","EFL-1.0","EFL-2.0","FTL","ICU","iMatix","ISC","JasPer-2.0","JSON","MIT","MIT-0","MIT-advertising","MIT-CMU","MIT-enna","MIT-feh","Naumen","NLPL","OLDAP-1.1","OLDAP-1.2","OLDAP-1.3","OLDAP-1.4","OLDAP-2.0","OLDAP-2.0.1","OLDAP-2.1","OLDAP-2.2","OLDAP-2.2.1","OLDAP-2.2.2","OLDAP-2.3","OLDAP-2.4","OLDAP-2.5","OLDAP-2.6","OLDAP-2.7","OLDAP-2.8","OpenSSL","PHP-3.0","PHP-3.01","Python-2.0","Ruby","Sendmail","TCL","W3C","W3C-19980720","W3C-20150513","WTFPL","X11","XFree86-1.1","xinetd","Zlib","zlib-acknowledgement","ZPL-1.1","ZPL-2.0","ZPL-2.1"]},{"type":"Strongly Protective","licenses":["APL-1.0","CPL-1.0","EPL-1.0","EPL-2.0","GPL-1.0","GPL-1.0+","GPL-1.0-only","GPL-1.0-or-later","GPL-2.0","GPL-2.0+","GPL-2.0-only","GPL-2.0-or-later","GPL-2.0-with-autoconf-exception","GPL-2.0-with-bison-exception","GPL-2.0-with-classpath-exception","GPL-2.0-with-font-exception","GPL-2.0-with-GCC-exception","GPL-3.0","GPL-3.0+","GPL-3.0-only","GPL-3.0-or-later","GPL-3.0-with-autoconf-exception","GPL-3.0-with-GCC-exception","IPA","MS-RL","ODbL-1.0","OSL-1.0","OSL-1.1","OSL-2.0","OSL-2.1","OSL-3.0","QPL-1.0","Vim"]},{"type":"Public Domain","licenses":["CC0-1.0","PDDL-1.0","SAX-PD","Unlicense"]},{"type":"Weakly Protective","licenses":["APSL-1.1","APSL-1.2","APSL-2.0","Artistic-1.0","Artistic-1.0-cl8","Artistic-1.0-Perl","BitTorrent-1.0","BitTorrent-1.1","CATOSL-1.1","CDDL-1.0","CDDL-1.1","CECILL-C","ClArtistic","CUA-OPL-1.0","ErlPL-1.1","gSOAP-1.3b","Interbase-1.0","IPL-1.0","LGPL-2.0","LGPL-2.0+","LGPL-2.0-only","LGPL-2.0-or-later","LGPL-2.1","LGPL-2.1+","LGPL-2.1-only","LGPL-2.1-or-later","LGPL-3.0","LGPL-3.0+","LGPL-3.0-only","LGPL-3.0-or-later","LPPL-1.0","LPPL-1.1","LPPL-1.2","LPPL-1.3a","LPPL-1.3c","Motosoto","MPL-1.0","MPL-1.1","MPL-2.0","MPL-2.0-no-copyleft-exception","MS-PL","NASA-1.3","Nokia","NOSL","RHeCos-1.1","RSCPL","SISSL","SISSL-1.2","Sleepycat","SPL-1.0","SugarCRM-1.1.3","Watcom-1.0","YPL-1.0","YPL-1.1","Zimbra-1.3","Zimbra-1.4"]}], | ||
"osiApproved": ["0BSD","AAL","AFL-1.1","AFL-1.2","AFL-2.0","AFL-2.1","AFL-3.0","AGPL-3.0","AGPL-3.0-only","AGPL-3.0-or-later","Apache-1.1","Apache-2.0","APL-1.0","APSL-1.0","APSL-1.1","APSL-1.2","APSL-2.0","Artistic-1.0","Artistic-1.0-cl8","Artistic-1.0-Perl","Artistic-2.0","BSD-1-Clause","BSD-2-Clause","BSD-2-Clause-Patent","BSD-3-Clause","BSD-3-Clause-LBNL","BSL-1.0","CAL-1.0","CAL-1.0-Combined-Work-Exception","CATOSL-1.1","CDDL-1.0","CECILL-2.1","CERN-OHL-P-2.0","CERN-OHL-S-2.0","CERN-OHL-W-2.0","CNRI-Python","CPAL-1.0","CPL-1.0","CUA-OPL-1.0","ECL-1.0","ECL-2.0","EFL-1.0","EFL-2.0","Entessa","EPL-1.0","EPL-2.0","EUDatagrid","EUPL-1.1","EUPL-1.2","Fair","Frameworx-1.0","GPL-2.0","GPL-2.0+","GPL-2.0-only","GPL-2.0-or-later","GPL-3.0","GPL-3.0+","GPL-3.0-only","GPL-3.0-or-later","GPL-3.0-with-GCC-exception","HPND","Intel","IPA","IPL-1.0","ISC","Jam","LGPL-2.0","LGPL-2.0+","LGPL-2.0-only","LGPL-2.0-or-later","LGPL-2.1","LGPL-2.1+","LGPL-2.1-only","LGPL-2.1-or-later","LGPL-3.0","LGPL-3.0+","LGPL-3.0-only","LGPL-3.0-or-later","LiLiQ-P-1.1","LiLiQ-R-1.1","LiLiQ-Rplus-1.1","LPL-1.0","LPL-1.02","LPPL-1.3c","MirOS","MIT","MIT-0","MIT-Modern-Variant","Motosoto","MPL-1.0","MPL-1.1","MPL-2.0","MPL-2.0-no-copyleft-exception","MS-PL","MS-RL","MulanPSL-2.0","Multics","NASA-1.3","Naumen","NCSA","NGPL","Nokia","NPOSL-3.0","NTP","OCLC-2.0","OFL-1.1","OFL-1.1-no-RFN","OFL-1.1-RFN","OGTSL","OLDAP-2.8","OSET-PL-2.1","OSL-1.0","OSL-2.0","OSL-2.1","OSL-3.0","PHP-3.0","PHP-3.01","PostgreSQL","Python-2.0","QPL-1.0","RPL-1.1","RPL-1.5","RPSL-1.0","RSCPL","SimPL-2.0","SISSL","Sleepycat","SPL-1.0","UCL-1.0","Unicode-DFS-2016","Unlicense","UPL-1.0","VSL-1.0","W3C","Watcom-1.0","wxWindows","Xnet","Zlib","ZPL-2.0","ZPL-2.1"], | ||
"deprecated": ["AGPL-1.0","AGPL-3.0","BSD-2-Clause-FreeBSD","BSD-2-Clause-NetBSD","bzip2-1.0.5","eCos-2.0","GFDL-1.1","GFDL-1.2","GFDL-1.3","GPL-1.0","GPL-1.0+","GPL-2.0","GPL-2.0+","GPL-2.0-with-autoconf-exception","GPL-2.0-with-bison-exception","GPL-2.0-with-classpath-exception","GPL-2.0-with-font-exception","GPL-2.0-with-GCC-exception","GPL-3.0","GPL-3.0+","GPL-3.0-with-autoconf-exception","GPL-3.0-with-GCC-exception","LGPL-2.0","LGPL-2.0+","LGPL-2.1","LGPL-2.1+","LGPL-3.0","LGPL-3.0+","Nunit","StandardML-NJ","wxWindows"] | ||
} |
File renamed without changes.
File renamed without changes.