Skip to content

Commit

Permalink
Merge pull request #2 from spryker-sdk/feature/te-8136/master-impleme…
Browse files Browse the repository at this point in the history
…nt-sensiolab-static-security-check

TE-8136 Implement (Sensiolab) static security check
  • Loading branch information
Spryker Release Bot authored Jan 26, 2021
2 parents ccabeac + 8c3f1bd commit 8684493
Show file tree
Hide file tree
Showing 7 changed files with 301 additions and 14 deletions.
55 changes: 55 additions & 0 deletions .github/workflows/ci.yml
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
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,17 @@
[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%207.3-8892BF.svg)](https://php.net/)
[![PHPStan](https://img.shields.io/badge/PHPStan-level%208-brightgreen.svg?style=flat)](https://phpstan.org/)

Checks security issues in your project dependencies

## Installation

`composer require --dev spryker-sdk/security-checker`

## Configuration

After the installation you will need to enable it in the `ConsoleDependencyProvider`.

## Commands

Security shecker offer the following command:
- `console security:check` - check security issue in composer.lock file.
15 changes: 9 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
"description": "A security checker for your composer.lock",
"license": "proprietary",
"require": {
"php": ">=7.3"
"php": ">=7.3",
"symfony/console": "^4.0.0 || ^5.0.0",
"symfony/options-resolver": "^4.0.0 || ^5.0.0",
"symfony/process": "^4.0.0 || ^5.0.0"
},
"require-dev": {
"phpstan/phpstan": "^0.12.18",
Expand All @@ -27,9 +30,9 @@
"config": {
"sort-packages": true
},
"scripts": {
"cs-check": "phpcs --colors -p -s --extensions=php --standard=vendor/spryker/code-sniffer/Spryker/ruleset.xml --ignore=/tests/_data/,/_support/ src/ tests/",
"cs-fix": "phpcbf --colors -p --extensions=php --standard=vendor/spryker/code-sniffer/Spryker/ruleset.xml --ignore=/tests/_data/,/_support/ src/ tests/",
"stan": "phpstan analyze -l 8 src/"
}
"scripts": {
"cs-check": "phpcs --standard=vendor/spryker/code-sniffer/Spryker/ruleset.xml -v src/",
"cs-fix": "phpcbf --standard=vendor/spryker/code-sniffer/Spryker/ruleset.xml -v src/",
"stan": "phpstan analyze -l 8 src/"
}
}
2 changes: 1 addition & 1 deletion phpstan-bootstrap.php
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<?php

define('ROOT_DIR', __DIR__);
define('APPLICATION_ROOT_DIR', __DIR__);
4 changes: 1 addition & 3 deletions phpstan.neon
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
167 changes: 163 additions & 4 deletions src/SecurityChecker/Command/SecurityCheckerCommand.php
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;
}
}
58 changes: 58 additions & 0 deletions src/SecurityChecker/Result.php
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;
}
}

0 comments on commit 8684493

Please sign in to comment.