Skip to content

Commit ed6753c

Browse files
authored
Add allow option (#19)
* Add --allow option * Bump composer version to include bugfix GHSA-h5h8-pc6h-jvvx * Bump version to 2.2.0
1 parent d8dbec5 commit ed6753c

11 files changed

+164
-12
lines changed

.scrutinizer.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ build:
2424
override:
2525
- php-scrutinizer-run
2626
coverage:
27+
environment:
28+
variables:
29+
XDEBUG_MODE: coverage
2730
tests:
2831
override:
2932
- command: composer test-coverage

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
All notable changes to `composer-license-checker` will be documented in this file
44

5+
## 2.2.0 - 2021-06-02
6+
7+
### Added
8+
- __--allow__ option to always allow a specific package or author/vendor
9+
510
## 2.1.0 - 2020-12-31
611

712
### Added

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ Two separate commands are provided:
2828
Use `./composer-license-checker help` to get info about general usage or use the syntax `./composer-license-checker help COMMAND_NAME` to see more information about a specific command available.
2929

3030
``` bash
31-
vendor/bin/composer-license-checker check --allowlist MIT
31+
./vendor/bin/composer-license-checker check \
32+
--allowlist MIT \ # Fail if anything but MIT license is used
33+
--blocklist GPL \ # Fail if any dependency uses GPL
34+
--allow dominikb/composer-license-checker # Always allow this dependency regardless of its license
3235

3336
vendor/bin/composer-license-checker report -p /path/to/your/project -c /path/to/composer.phar
3437
```

composer-license-checker

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ $reportCommand = new ReportCommand;
4141
$reportCommand->setLicenseLookup($licenceLookUp);
4242
$reportCommand->setDependencyLoader(new DependencyLoader);
4343

44-
$application = new Application('composer-license-checker', '2.0.0');
44+
$application = new Application('composer-license-checker', '2.2.0');
4545

4646
$application->addCommands([$checkCommand, $reportCommand]);
4747

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "dominikb/composer-license-checker",
33
"description": "Utility to check for licenses of dependencies and block/allow them.",
4-
"version": "2.1.0",
4+
"version": "2.2.0",
55
"keywords": [
66
"dominikb",
77
"composer-license-checker"
@@ -18,7 +18,7 @@
1818
],
1919
"require": {
2020
"php": "^7.3|^8.0",
21-
"composer/composer": "^1.8|^2.0",
21+
"composer/composer": ">=1.10.22|>=2.0.13",
2222
"guzzlehttp/guzzle": "^6.3|^7.2",
2323
"psr/simple-cache": "^1.0",
2424
"symfony/cache": "^4.2.3|^5.2",

src/CheckCommand.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ protected function configure()
5959
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
6060
'Mark a specific license prohibited for usage'
6161
),
62+
new InputOption(
63+
'allow',
64+
'',
65+
InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL,
66+
'Determine a vendor or package to always be allowed and never trigger violations'
67+
),
6268
]));
6369
}
6470

@@ -82,7 +88,11 @@ public function execute(InputInterface $input, OutputInterface $output)
8288
$this->io->writeln(count($dependencies).' dependencies were found ...');
8389
$this->io->newLine();
8490

85-
$violations = $this->determineViolations($dependencies, $input->getOption('blocklist'), $input->getOption('allowlist'));
91+
$violations = $this->determineViolations($dependencies,
92+
$input->getOption('blocklist'),
93+
$input->getOption('allowlist'),
94+
$input->getOption('allow')
95+
);
8696

8797
try {
8898
$this->handleViolations($violations);
@@ -110,11 +120,15 @@ private function ensureCommandCanBeExecuted(): void
110120
}
111121
}
112122

113-
private function determineViolations(array $dependencies, array $blocklist, array $allowlist): array
123+
private function determineViolations(array $dependencies, array $blocklist, array $allowlist, array $allowed): array
114124
{
115125
$this->licenseConstraintHandler->setBlocklist($blocklist);
116126
$this->licenseConstraintHandler->setAllowlist($allowlist);
117127

128+
$this->licenseConstraintHandler->allow(array_map(function ($dependency) {
129+
return new Dependency($dependency);
130+
}, $allowed));
131+
118132
return $this->licenseConstraintHandler->detectViolations($dependencies);
119133
}
120134

src/ConstraintViolationDetector.php

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ class ConstraintViolationDetector implements LicenseConstraintHandler
1515
/** @var string[] */
1616
protected $allowlist = [];
1717

18+
/** @var Dependency[] */
19+
private $alwaysAllowed = [];
20+
1821
public function setBlocklist(array $licenses): void
1922
{
2023
$this->blocklist = $licenses;
@@ -25,6 +28,17 @@ public function setAllowlist(array $licenses): void
2528
$this->allowlist = $licenses;
2629
}
2730

31+
public function allow($dependencies): void
32+
{
33+
if (! is_array($dependencies)) {
34+
$dependencies = [$dependencies];
35+
}
36+
37+
foreach ($dependencies as $allowed) {
38+
$this->alwaysAllowed[] = $allowed;
39+
}
40+
}
41+
2842
/**
2943
* @param Dependency[] $dependencies
3044
*
@@ -35,9 +49,11 @@ public function detectViolations(array $dependencies): array
3549
{
3650
$this->ensureConfigurationIsValid();
3751

52+
$possibleViolators = $this->exceptAllowed($dependencies);
53+
3854
return [
39-
$this->detectBlocklistViolation($dependencies),
40-
$this->detectAllowlistViolation($dependencies),
55+
$this->detectBlocklistViolation($possibleViolators),
56+
$this->detectAllowlistViolation($possibleViolators),
4157
];
4258
}
4359

@@ -99,4 +115,56 @@ private function anyLicenseOnList(array $licenses, array $list): bool
99115
{
100116
return count(array_intersect($licenses, $list)) > 0;
101117
}
118+
119+
/**
120+
* @param Dependency[] $dependencies
121+
*
122+
* @return Dependency[]
123+
*/
124+
private function exceptAllowed(array $dependencies): array
125+
{
126+
$possiblyViolating = [];
127+
128+
if (empty($this->alwaysAllowed)) {
129+
return $dependencies;
130+
}
131+
132+
foreach ($dependencies as $dependency) {
133+
foreach ($this->alwaysAllowed as $allowedDependency) {
134+
if ($this->matches($allowedDependency, $dependency)) {
135+
continue 2; // Outer for: test next dependency
136+
}
137+
}
138+
139+
$possiblyViolating[] = $dependency;
140+
}
141+
142+
return $possiblyViolating;
143+
}
144+
145+
/**
146+
* Determine if the $original author and package name match for $tryMatch.
147+
* An empty string for either the author or package gets interpreted as a wilcard.
148+
*
149+
* @param Dependency $original
150+
* @param Dependency $tryMatch
151+
*
152+
* @return bool
153+
*/
154+
private function matches(Dependency $original, Dependency $tryMatch): bool
155+
{
156+
if ($original->getAuthorName()) {
157+
if (! ($original->getAuthorName() === $tryMatch->getAuthorName())) {
158+
return false;
159+
}
160+
}
161+
162+
if ($original->getPackageName()) {
163+
if (! ($original->getPackageName() === $tryMatch->getPackageName())) {
164+
return false;
165+
}
166+
}
167+
168+
return true;
169+
}
102170
}

src/Contracts/LicenseConstraintHandler.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ public function setBlocklist(array $licenses): void;
1313

1414
public function setAllowlist(array $licenses): void;
1515

16+
/**
17+
* @param Dependency[]|Dependency $dependencies
18+
*/
19+
public function allow($dependencies): void;
20+
1621
/**
1722
* @param Dependency[] $dependencies
1823
*

src/Dependency.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@ class Dependency
1515
/** @var string[] */
1616
private $licenses;
1717

18+
/**
19+
* Dependency constructor.
20+
*
21+
* @param string $name
22+
* @param string $version
23+
* @param string[] $licenses
24+
*/
25+
public function __construct(string $name = '', string $version = '', array $licenses = [])
26+
{
27+
$this->name = $name;
28+
$this->version = $version;
29+
$this->licenses = $licenses;
30+
}
31+
1832
/**
1933
* @return string
2034
*/
@@ -68,4 +82,20 @@ public function setLicenses(array $licenses): self
6882

6983
return $this;
7084
}
85+
86+
public function getAuthorName(): string
87+
{
88+
return explode('/', $this->name)[0];
89+
}
90+
91+
public function getPackageName(): string
92+
{
93+
$parts = explode('/', $this->name);
94+
95+
if (count($parts) != 2) {
96+
return '';
97+
}
98+
99+
return $parts[1];
100+
}
71101
}

src/ReportCommand.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use Dominikb\ComposerLicenseChecker\Contracts\LicenseLookupAware;
99
use Dominikb\ComposerLicenseChecker\Traits\DependencyLoaderAwareTrait;
1010
use Dominikb\ComposerLicenseChecker\Traits\LicenseLookupAwareTrait;
11-
use Symfony\Component\Cache\Simple\NullCache;
11+
use Symfony\Component\Cache\Adapter\NullAdapter;
1212
use Symfony\Component\Console\Command\Command;
1313
use Symfony\Component\Console\Helper\Table;
1414
use Symfony\Component\Console\Input\InputDefinition;
@@ -20,8 +20,6 @@ class ReportCommand extends Command implements LicenseLookupAware, DependencyLoa
2020
{
2121
use LicenseLookupAwareTrait, DependencyLoaderAwareTrait;
2222

23-
const LINES_BEFORE_DEPENDENCY_VERSIONS = 2;
24-
2523
protected static $defaultName = 'report';
2624

2725
protected function configure()
@@ -92,7 +90,7 @@ private function groupDependenciesByLicense(array $dependencies)
9290
private function lookUpLicenses(array $licenses, OutputInterface $output, $useCache = true)
9391
{
9492
if (! $useCache) {
95-
$this->licenseLookup->setCache(new NullCache);
93+
$this->licenseLookup->setCache(new NullAdapter);
9694
}
9795

9896
$lookedUp = [];

0 commit comments

Comments
 (0)