Deprecate the deny-licenses option
I'll start with an opinion: a license deny list is a bad idea. A company using one would put copyleft licenses like GPL-2.0 in there, potentially missing other copyleft licenses like CC-BY-SA-4.0 or maybe they would forget to also add GPL-3.0. Additionally, it's easy to miss commercial licenses like Elastic which could be a problem for some users. This is even more an issue now that ClearlyDefined includes more license identifiers than ever before. A deny list provides very limited risk reduction.
Up until recently, DRA did not provide the tools necessary to remediate failures. The most important remediation is the ability to say "I've reviewed this package and it's fine", and DRA could do that, but only if the license was a valid license expression. Recent DRA releases check if a package is on the allow-dependencies-licenses list first, so it can pass even if there's an invalid license.
We should deprecate the deny list option in a 4.x release in preparation for an eventual 5.x release that removes it. It would be interesting to see if we have feedback that comes out in favor of deny lists and provides some justification as to why our product should support it.
Acceptance Criteria
- [ ] The README lists deny-licenses as deprecated
- [ ] The summary output from the action includes a very visible warning that deny-licenses is deprecated
- [ ] 4.x release is made with this behavior
I use the deny-licenses option (at least right now as part of a POC - subject to change! 😁) and would be impacted if it was removed
While an "allow list" is theoretically superior, there's a few real world challenges at play:
- Some legal departments have a deny list, rather than an allow list.
- Likelihood is a component of risk (impact * likelihood). A rare license used by a few components with low usage is inherently lower risk. The cost of a strict allow list (and inherent developer productivity loss) might outweigh the low risk of a rare license.
- Some component ecosystems are massive - NPM in particular. It's not uncommon to have hundreds of thousands or even millions of dependencies. Ensuring a 'flawlessly accurate' allow list is a massive undertaking that could be a barrier to entry. Deny lists would help them get something in place, even if it's not perfect.
The documentation should describe the pros/cons of each approach so that users are fully aware of the tradeoffs and risk inherent in either approach.
Something that I'd find personally helpful is for both lists to allow wildcards, or at least "starts with" matches. For example, adding something like AGPL-* would be far more efficient (and lower risk) than listing each one individually and then being caught off guard when a new version or variant is added.
Another helpful feature would be to allow specific packages - for example, a custom license for a commercial package isn't a problem if it's been reviewed by a corporate procurement team.
@ebickle Thanks for the feedback!
Another helpful feature would be to allow specific packages
I'd say that this is not just helpful, but required. My view is this:
- Start with an allow list
- If a package has a license that isn't on that list, review it and then take one of the three actions below:
- Allow the package
- Allow the license
- Don't use the package (switch to an alternative)
A license allow list absolutely doesn't work without the ability to allow a package. DRA does support that with the allow-dependencies-licenses option.
DRA is only checking changes to dependencies, so it's not too big a barrier to take one of the 3 actions above if a package fails the test.
I do acknowledge that a deny list does give some risk reduction, but it is likely to give a false sense of security around license compliance.
Hello!
I just wanted to voice my own opinion that I'm personally in favor of keeping a deny-licenses list. I've been trying to migrate a mid sized monorepo from using snyk.io for dependency scanning to using this dependency-review-action, including license scanning. The repo has over 3,000 transitive NPM packages with various licenses.
It's just been using Snyk's default license policy, which would block PRs if a dependency with any of a handful of 6 copyleft licenses got added, which I was planning to configure in a deny list on this action.
If I had to configure it using allow-licenses instead, I'd try copying the entire list of allowed licenses from the Snyk policy, which is nearly 500, and seems much tougher to manage.
This is what the CI job would look like with deny-licenses:
test-dependencies:
runs-on: ubuntu-24.04
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v4
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4
with:
fail-on-severity: high
deny-licenses: AGPL-3.0, AGPL-1.0, CPOL-1.02, GPL-2.0, GPL-3.0, SimPL-2.0
comment-summary-in-pr: on-failure
And this is what it'd look like with allow-licenses copied from the Snyk configuration:
test-dependencies:
runs-on: ubuntu-24.04
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v4
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4
with:
fail-on-severity: high
allow-licenses: 0BSD, AAL, Abstyles, AdaCore-doc, Adobe-2006, Adobe-Glyph, ADSL, AFL-1.1, AFL-1.2, AFL-2.0, AFL-2.1, AFL-3.0, Afmparse, AGPL-3.0-only, Aladdin, AMDPLPA, AML, AMPAS, ANTLR-PD, ANTLR-PD-fallback, Apache-1.0, Apache-1.1, Apache-2.0, APAFML, APL-1.0, App-s2p, APSL-1.0, APSL-1.1, APSL-1.2, APSL-2.0, Arphic-1999, Artistic-1.0-cl8, Artistic-1.0-Perl, Baekmuk, Bahyph, Barr, Beerware, Bitstream-Charter, Bitstream-Vera, BitTorrent-1.0, BitTorrent-1.1, blessing, BlueOak-1.0.0, Borceux, Brian-Gladman-3-Clause, BSD-1-Clause, BSD-2-Clause, BSD-2-Clause-FreeBSD, BSD-2-Clause-NetBSD, BSD-2-Clause-Patent, BSD-2-Clause-Views, 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-4.3RENO, BSD-4.3TAHOE, BSD-Advertising-Acknowledgement, BSD-Attribution-HPND-disclaimer, BSD-Protection, BSD-Source-Code, 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, CATOSL-1.1, 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-DE, 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, CC0-1.0, CDDL-1.1, CDL-1.0, CDLA-Permissive-1.0, CDLA-Permissive-2.0, CDLA-Sharing-1.0, CECILL-1.0, CECILL-1.1, CECILL-2.0, CECILL-2.1, CECILL-B, CECILL-C, CERN-OHL-1.1, CERN-OHL-1.2, CERN-OHL-P-2.0, CERN-OHL-S-2.0, CERN-OHL-W-2.0, CFITSIO, checkmk, ClArtistic, Clips, CMU-Mach, CNRI-Jython, CNRI-Python, CNRI-Python-GPL-Compatible, COIL-1.0, Community-Spec-1.0, Condor-1.1, copyleft-next-0.3.0, copyleft-next-0.3.1, Cornell-Lossless-JPEG, CPAL-1.0, CPL-1.0, Crossword, CrystalStacker, CUA-OPL-1.0, Cube, curl, D-FSL-1.0, diffmark, DL-DE-BY-2.0, DOC, Dotseqn, DRL-1.0, DSDP, dvipdfm, ECL-1.0, ECL-2.0, eCos-2.0, EFL-1.0, EFL-2.0, eGenix, Elastic-2.0, Entessa, EPICS, EPL-2.0, ErlPL-1.1, etalab-2.0, EUDatagrid, EUPL-1.0, EUPL-1.1, EUPL-1.2, Eurosym, Fair, FDK-AAC, Frameworx-1.0, FreeBSD-DOC, FreeImage, FSFAP, FSFUL, FSFULLR, FSFULLRWD, FTL, GD, GFDL-1.1, GFDL-1.2, GFDL-1.3, Giftware, GL2PS, Glide, Glulxe, GLWTPL, gnuplot, GPL-1.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-with-autoconf-exception, GPL-3.0-with-GCC-exception, Graphics-Gems, gSOAP-1.3b, HaskellReport, Hippocratic-2.1, HP-1986, HPND, HPND-export-US, HPND-Markus-Kuhn, HPND-sell-variant, HPND-sell-variant-MIT-disclaimer, HTMLTIDY, IBM-pibs, ICU, IEC-Code-Components-EULA, IJG, IJG-short, ImageMagick, iMatix, Imlib2, Info-ZIP, Intel, Intel-ACPI, Interbase-1.0, IPA, IPL-1.0, ISC, Jam, JasPer-2.0, JPL-image, JPNIC, JSON, Kazlib, 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, LOOP, LPL-1.0, LPL-1.02, LPPL-1.0, LPPL-1.1, LPPL-1.2, LPPL-1.3a, LPPL-1.3c, LZMA-SDK-9.11-to-9.20, LZMA-SDK-9.22, MakeIndex, Martin-Birgmeier, Minpack, MirOS, MIT, MIT-0, MIT-advertising, MIT-CMU, MIT-enna, MIT-feh, MIT-Modern-Variant, MIT-open-group, MIT-Wu, MITNFA, Motosoto, mpi-permissive, mpich2, MPL-1.0, MPL-2.0-no-copyleft-exception, mplus, MS-LPL, MS-PL, MTLL, MulanPSL-1.0, MulanPSL-2.0, Multics, Mup, NAIST-2003, NASA-1.3, Naumen, 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, NLPL, Nokia, NOSL, Noweb, NPL-1.0, NPL-1.1, NPOSL-3.0, NRL, NTP, NTP-0, Nunit, O-UDA-1.0, OCCT-PL, OCLC-2.0, ODbL-1.0, ODC-By-1.0, OFFIS, 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, 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, OML, OpenPBS-2.3, OpenSSL, OPL-1.0, OPUBL-1.0, OSET-PL-2.1, OSL-1.0, OSL-1.1, OSL-2.0, OSL-2.1, OSL-3.0, Parity-6.0.0, Parity-7.0.0, PDDL-1.0, PHP-3.0, PHP-3.01, Plexus, PolyForm-Noncommercial-1.0.0, PolyForm-Small-Business-1.0.0, PostgreSQL, PSF-2.0, psfrag, psutils, Python-2.0, Python-2.0.1, Qhull, QPL-1.0, QPL-1.0-INRIA-2004, Rdisc, RHeCos-1.1, RPL-1.1, RPL-1.5, RPSL-1.0, RSA-MD, RSCPL, Ruby, SAX-PD, Saxpath, SCEA, SchemeReport, Sendmail, Sendmail-8.23, SGI-B-1.0, SGI-B-1.1, SGI-B-2.0, SHL-0.5, SHL-0.51, SISSL, SISSL-1.2, Sleepycat, SMLNJ, SMPPL, SNIA, snprintf, Spencer-86, Spencer-94, Spencer-99, SPL-1.0, SSH-OpenSSH, SSH-short, SSPL-1.0, SugarCRM-1.1.3, SunPro, SWL, Symlinks, TAPR-OHL-1.0, TCL, TCP-wrappers, TMate, TORQUE-1.1, TOSL, TPDL, TPL-1.0, TTWL, TU-Berlin-1.0, TU-Berlin-2.0, UCAR, UCL-1.0, Unicode-DFS-2015, Unicode-DFS-2016, Unicode-TOU, Unlicense, UPL-1.0, Vim, VOSTROM, VSL-1.0, W3C, W3C-19980720, W3C-20150513, w3m, Watcom-1.0, Wsuipa, WTFPL, wxWindows, X11, X11-distribute-modifications-variant, Xerox, XFree86-1.1, xinetd, xlock, Xnet, xpp, XSkat, YPL-1.0, YPL-1.1, Zed, Zend-2.0, Zimbra-1.3, Zimbra-1.4, Zlib, zlib-acknowledgement, ZPL-1.1, ZPL-2.0, ZPL-2.1
comment-summary-in-pr: on-failure
It seems much easier to manage a smaller list of denied licenses, rather than trying to maintain a list of all allowed licenses.
But in either case, I seem to be running into a bug where the action is treating NPM package licenses as Null, and not able to determine whether they should be allowed or blocked. It seems related to https://github.com/actions/dependency-review-action/issues/923 and https://github.com/actions/dependency-review-action/issues/939
I hope the bug will get fixed soon, but I'm currently trying non-latest versions of the action in the meantime, to see if I have any better luck with them.
Cheers!
@dylanlan thanks for that feedback, it's super helpful. i completely agree that enumerating that allow list is pretty onerous. It's maybe not quite as bad as having them all as a comma-separated list inline, because you can use with: config-file to pull in a list of the identifiers from a separate file (docs).
Q: Of the 3k dependencies in the monorepo you're checking, how many different licenses are there?
thinking out loud here: would you find it useful to have pre-made lists to include that follow the scancode licensedb categories, so you don't have to enumerate all the permissive licenses, you could just say
allow-licenses:
- include:
- Permissive
- Free Restricted
- GFDL-1.1-only
(syntax very much TBD, obviously)
@ahpook Interesting idea. I really like the idea of using categories. Sadly, it wouldn't work out of the box in our case.
Our partners and clients have extremely strict requirements around specific licenses - they supply them as a list to us and state "never use these, for any reason, at any time". In that situation, an allow list is never going to work as a sole solution - it violates our clients' contractual requirements. We're dealing with real world contracts, lawyers, and fun stuff like that. There's no flexibility and its non-negotiable for us.
I'm not sure whether its on our list, but I'll use the example of agpl-3.0 and gpl-3.0. Both have copyleft as their scancode license categories. For web-hosted software, they are significantly different. There's a large list of compile-time tools that are gpl-1.0 licensed that are npm installed and act as part of a package.json but only get 'used', never act as part of a deployed application. That makes blocking all copyleft difficult for modern applications, given the lack of context. The situations where there is an obligation to open source an entire web application are the super scary ones for legal teams, but they're not well categorized today.
We use a deny-license list for a bulk list of licenses that will never be approved. Everything else is handled on a case by case basis. It saves us work. My company would be affected.
I am also adding a feedback in favor of deny lists, at least until a better solution is implemented.
We started with the "allow list" because it is indeed what makes the most sense "good-practice" wise; however in reality other factors come at play.
We switched to "deny list" at first because even Microsoft packages do not always correctly set up their license type and we encounter unknown types of licenses starting with "LicenseRef" and joined licenses (eg. Apache-2.0 AND MIT AND BSD-2-Clause AND CC-BY-4.0 AND BSD-3-Clause) which need to be specified for every combination or the review fails. It is very very cumbersome.
Furthermore, hen handling several ecosystems across several repositories it is very hard to incrementally grow the allow list. There is too many stakeholders and not enough bandwidth to track every blocking packages.
We switched to "deny list" at first because even Microsoft packages do not always correctly set up their license type and we encounter unknown types of licenses starting with "LicenseRef" and joined licenses (eg. Apache-2.0 AND MIT AND BSD-2-Clause AND CC-BY-4.0 AND BSD-3-Clause) which need to be specified for every combination or the review fails. It is very very cumbersome.
Fair point, thank you for the feedback @lucas-morel-shift! Note that this specific issue is fixed as of DRA 4.7.1. Now you can just list the licenses you want to permit, and it will correctly AND them together for compound license expressions (or permit if any of an OR expression's licenses are listed). See #927 for details.
I'd also be in favor of keeping support for a deny-licenses with this GitHub action. There are a lot of OSS licenses, and many companies and organizations do not make the time and bandwidth to review them and maintain an explicit allow list. For this reason, I think it makes sense for the action to continue to support a deny list.
Scancode Categories would work for us. We have the same problem, the npm license world is so dumb and there are so many licenses, a deny list was the only way we were able to make sense of it all.
Just my two cents on this… but an allow list is great when you only want specific licenses used. A deny list is great when you don’t want specific licenses used. Both have their pros and cons, removing one hinders the overall usefulness. But like any setting or feature in any program it’s up to the end user to use it and use it properly.
I came across this randomly searching and right off the bat saw the deny list setting and in my head said “yea that’s what I want to use”. Now is it perfect? No. But it’s better than looking through thousands of different licenses.
It’s my opinion both should remain. Just document them better. But they should also both support wildcards.
In theory only a allow-list is better. In practice there are so many packages with missing or incorrect license information that you want to tackle the process from both sides. For my organizations we use all features (allow and deny licenses and allow and deny packages) to correct for missing and incorrect licenses information and to correct for incorrect handling of SPDX identifier by this Action. The path forward I see is to amend dependency information before running this Action. GitHub does not provide such a feature.
I think GitHub Advanced Security will even less appealing when the deny-licenses is removed because it pushes users to a compliance process outside of GitHub, removing the need for this Action.