-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from spryker-sdk/feature/te-8136/master-impleme…
…nt-sensiolab-static-security-check TE-8136 Implement (Sensiolab) static security check
- Loading branch information
Showing
7 changed files
with
301 additions
and
14 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
name: CI | ||
|
||
on: | ||
pull_request: | ||
push: | ||
branches: | ||
- master | ||
schedule: | ||
- cron: "0 0 * * *" | ||
branches: | ||
- 'master' | ||
|
||
jobs: | ||
checks: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
php-version: ['7.3', '7.4'] | ||
|
||
steps: | ||
- name: Setup PHP | ||
uses: shivammathur/setup-php@v2 | ||
with: | ||
php-version: ${{ matrix.php-version }} | ||
extensions: mbstring, intl | ||
|
||
- name: Checkout | ||
uses: actions/checkout@v1 | ||
with: | ||
fetch-depth: 1 | ||
|
||
- name: Composer validate | ||
run: composer validate | ||
|
||
- name: Composer get cache directory | ||
id: composer-cache | ||
run: | | ||
echo "::set-output name=dir::$(composer config cache-files-dir)" | ||
- name: Composer cache | ||
uses: actions/cache@v2 | ||
with: | ||
path: ${{ steps.composer-cache.outputs.dir }} | ||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} | ||
restore-keys: | | ||
${{ runner.os }}-composer- | ||
- name: Composer install | ||
run: composer install --optimize-autoloader | ||
|
||
- name: CodeStyle checks | ||
run: composer cs-check | ||
|
||
- name: PHPStan checks | ||
run: composer stan |
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
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 |
---|---|---|
@@ -1,3 +1,3 @@ | ||
<?php | ||
|
||
define('ROOT_DIR', __DIR__); | ||
define('APPLICATION_ROOT_DIR', __DIR__); |
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 |
---|---|---|
@@ -1,5 +1,3 @@ | ||
parameters: | ||
bootstrap: %rootDir%/../../../phpstan-bootstrap.php | ||
checkMissingIterableValueType: false | ||
|
||
bootstrapFiles: | ||
- phpstan-bootstrap.php |
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 |
---|---|---|
@@ -1,12 +1,171 @@ | ||
<?php | ||
declare(strict_types=1); | ||
declare(strict_types = 1); | ||
|
||
/** | ||
* Copyright © 2019-present Spryker Systems GmbH. All rights reserved. | ||
* Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file. | ||
*/ | ||
namespace Brancho\SecurityChecker; | ||
|
||
class SecurityCheckerCommand | ||
namespace SecurityChecker\Command; | ||
|
||
use SecurityChecker\Result; | ||
use Symfony\Component\Console\Command\Command; | ||
use Symfony\Component\Console\Input\InputInterface; | ||
use Symfony\Component\Console\Output\OutputInterface; | ||
use Symfony\Component\Process\Exception\ProcessFailedException; | ||
use Symfony\Component\Process\Process; | ||
|
||
class SecurityCheckerCommand extends Command | ||
{ | ||
protected const CODE_SUCCESS = 0; | ||
protected const CODE_ERROR = 1; | ||
|
||
protected const COMMAND_NAME = 'security:check'; | ||
|
||
protected const BINARY_CHECKER = 'https://github.com/fabpot/local-php-security-checker/releases/download/v1.0.0/local-php-security-checker_1.0.0_linux_amd64'; | ||
protected const FILE_NAME = '/tmp/security-checker'; | ||
protected const FALSE_POSITIVE_ISSUE_NUMBER = 'CVE-NONE-0001'; | ||
|
||
/** | ||
* @return void | ||
*/ | ||
protected function configure(): void | ||
{ | ||
$this | ||
->setName(static::COMMAND_NAME) | ||
->setDescription('Checks security issues in your project dependencies'); | ||
} | ||
|
||
/** | ||
* @param \Symfony\Component\Console\Input\InputInterface $input | ||
* @param \Symfony\Component\Console\Output\OutputInterface $output | ||
* | ||
* @return int | ||
*/ | ||
public function execute(InputInterface $input, OutputInterface $output): int | ||
{ | ||
$this->loadFile(); | ||
$commandOutput = $this->runCommand(); | ||
$commandOutput = $this->markFalsePositiveResults($commandOutput); | ||
|
||
$result = $this->createResultFromCommandOutput($commandOutput); | ||
|
||
$output->writeln($result->getVulnerabilities()); | ||
|
||
return $this->convertResultToExitCode($result, $output); | ||
} | ||
|
||
/** | ||
* @throws \Symfony\Component\Process\Exception\ProcessFailedException | ||
* | ||
* @return void | ||
*/ | ||
protected function loadFile(): void | ||
{ | ||
if (file_exists(static::FILE_NAME)) { | ||
return; | ||
} | ||
|
||
$process = new Process(['wget', static::BINARY_CHECKER, '-O', static::FILE_NAME]); | ||
$process->run(); | ||
|
||
if ($process->getExitCode() === static::CODE_ERROR) { | ||
throw new ProcessFailedException($process); | ||
} | ||
|
||
$this->changeFileMode(); | ||
} | ||
|
||
/** | ||
* @return void | ||
*/ | ||
protected function changeFileMode(): void | ||
{ | ||
chmod(static::FILE_NAME, 0777); | ||
} | ||
|
||
/** | ||
* @throws \Symfony\Component\Process\Exception\ProcessFailedException | ||
* | ||
* @return string | ||
*/ | ||
protected function runCommand(): string | ||
{ | ||
$process = new Process([static::FILE_NAME, 'check:security']); | ||
$process->run(); | ||
|
||
if (!empty($process->getErrorOutput())) { | ||
throw new ProcessFailedException($process); | ||
} | ||
|
||
return $process->getOutput(); | ||
} | ||
|
||
/** | ||
* @param string $commandOutput | ||
* | ||
* @return \SecurityChecker\Result | ||
*/ | ||
protected function createResultFromCommandOutput(string $commandOutput): Result | ||
{ | ||
$count = 0; | ||
preg_match('/\d\spackage/m', $commandOutput, $matches); | ||
if (!empty($matches)) { | ||
$count = (int)$matches[0]; | ||
} | ||
|
||
return new Result($count, $commandOutput); | ||
} | ||
|
||
/** | ||
* @param string $commandOutput | ||
* | ||
* @return string | ||
*/ | ||
protected function markFalsePositiveResults(string $commandOutput): string | ||
{ | ||
if (strpos($commandOutput, static::FALSE_POSITIVE_ISSUE_NUMBER) !== false) { | ||
$commandOutput = str_replace( | ||
static::FALSE_POSITIVE_ISSUE_NUMBER, | ||
sprintf('<info>%s - is a false positive</info>', static::FALSE_POSITIVE_ISSUE_NUMBER), | ||
$commandOutput | ||
); | ||
} | ||
|
||
return $commandOutput; | ||
} | ||
|
||
/** | ||
* @param \SecurityChecker\Result $result | ||
* @param \Symfony\Component\Console\Output\OutputInterface $output | ||
* | ||
* @return int | ||
*/ | ||
protected function convertResultToExitCode(Result $result, OutputInterface $output): int | ||
{ | ||
if ($result->count() === 0) { | ||
return static::CODE_SUCCESS; | ||
} | ||
|
||
if (!$this->checkResultForFalsePositiveCase($result)) { | ||
return static::CODE_ERROR; | ||
} | ||
|
||
if ($output->isVerbose()) { | ||
$output->writeln(sprintf('<info>The issue about %s is a false positive result</info>', static::FALSE_POSITIVE_ISSUE_NUMBER)); | ||
$output->writeln('<info>Check https://github.com/FriendsOfPHP/security-advisories/issues/511 for details</info>'); | ||
} | ||
|
||
return static::CODE_SUCCESS; | ||
} | ||
|
||
} | ||
/** | ||
* @param \SecurityChecker\Result $result | ||
* | ||
* @return bool | ||
*/ | ||
protected function checkResultForFalsePositiveCase(Result $result): bool | ||
{ | ||
return $result->count() === 1 && strpos($result->getVulnerabilities(), static::FALSE_POSITIVE_ISSUE_NUMBER) !== false; | ||
} | ||
} |
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,58 @@ | ||
<?php | ||
declare(strict_types = 1); | ||
|
||
/** | ||
* Copyright © 2019-present Spryker Systems GmbH. All rights reserved. | ||
* Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file. | ||
*/ | ||
|
||
namespace SecurityChecker; | ||
|
||
use Countable; | ||
|
||
class Result implements Countable | ||
{ | ||
/** | ||
* @var int | ||
*/ | ||
protected $count; | ||
|
||
/** | ||
* @var string | ||
*/ | ||
protected $vulnerabilities; | ||
|
||
/** | ||
* @param int $count | ||
* @param string $vulnerabilities | ||
*/ | ||
public function __construct(int $count, string $vulnerabilities) | ||
{ | ||
$this->count = $count; | ||
$this->vulnerabilities = $vulnerabilities; | ||
} | ||
|
||
/** | ||
* @return string | ||
*/ | ||
public function getVulnerabilities(): string | ||
{ | ||
return $this->vulnerabilities; | ||
} | ||
|
||
/** | ||
* @return string | ||
*/ | ||
public function __toString(): string | ||
{ | ||
return $this->vulnerabilities; | ||
} | ||
|
||
/** | ||
* @return int | ||
*/ | ||
public function count(): int | ||
{ | ||
return $this->count; | ||
} | ||
} |