Skip to content
This repository has been archived by the owner on Jan 15, 2021. It is now read-only.

Commit

Permalink
added initial code
Browse files Browse the repository at this point in the history
  • Loading branch information
fabpot committed Feb 19, 2013
0 parents commit e9a1e92
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
composer.lock
/vendor/
19 changes: 19 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright (c) 2013 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
SensioLabs Security Checker
===========================

The SensioLabs Security Checker is a command line tool that checks if your
application use dependencies with known security vulnerabilities. It uses the
[SensioLabs Security Check Web service][1] and the [Security Advisories Database][2]
behind the scene:

$ php checker security:check /path/to/composer.lock

You can also integrate the checker in your own application/project

* by using the `SecurityCheckerCommand` class into your Symfony Console
application.

* by using the `SecurityChecker` class directly into your own code.

[1]: http://security.sensiolabs.org/
[2]: https://github.com/sensiolabs/security-advisories
65 changes: 65 additions & 0 deletions SensioLabs/Security/Command/SecurityCheckerCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace SensioLabs\Security\Command;

use SensioLabs\Security\SecurityChecker;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;

class SecurityCheckerCommand extends Command
{
private $checker;

public function __construct(SecurityChecker $checker)
{
$this->checker = $checker;

parent::__construct();
}

/**
* @see Command
*/
protected function configure()
{
$this
->setName('security:check')
->setDefinition(array(
new InputArgument('lock', InputArgument::REQUIRED, 'The path to the composer.lock file'),
new InputOption('format', '', InputOption::VALUE_REQUIRED, 'The output format', 'text'),
))
->setDescription('Checks security issues in your project dependencies')
->setHelp(<<<EOF
The <info>%command.name%</info> command checks a <info>composer.lock</info>
file for security issues in the project dependencies:
<info>php %command.full_name% security:check /path/to/composer.lock</info>
By default, the command displays the result in plain text, but you can also
configure it to output JSON instead by using the <info>--format</info> option:
<info>php %command.full_name% security:check /path/to/composer.lock --format=json</info>
EOF
);
}

/**
* @see Command
* @see SecurityChecker
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
try {
$data = $this->checker->check($input->getArgument('lock'), $input->getOption('format'));
} catch (\Exception $e) {
$output->writeln($this->getHelperSet()->get('formatter')->formatBlock($e->getMessage(), 'error', true));

return 1;
}

$output->write($data);
}
}
80 changes: 80 additions & 0 deletions SensioLabs/Security/SecurityChecker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

namespace SensioLabs\Security;

class SecurityChecker
{
/**
* Checks a composer.lock file.
*
* @param string $lock The path to the composer.lock file
* @param string $format The return format
*
* @return mixed The vulnerabilities
*
* @throws \InvalidArgumentException When the output format is unsupported
* @throws \RuntimeException When the lock file does not exist
* @throws \RuntimeException When curl does not work or is unavailable
*/
public function check($lock, $format = 'text')
{
if (!function_exists('curl_init')) {
throw new \RuntimeException('Curl is required to use this command.');
}

if (false === $curl = curl_init()) {
throw new \RuntimeException('Unable to create a new curl handle.');
}

if (is_dir($lock) && file_exists($lock.'/composer.lock')) {
$lock = $lock.'/composer.lock';
}

if (!is_file($lock)) {
throw new \RuntimeException('Lock file does not exist.');
}

switch ($format) {
case 'text':
$format = 'text/plain';
break;
case 'json':
$format = 'application/json';
break;
default:
throw new \InvalidArgumentException(sprintf('Unsupported format "%s".', $format));
}

curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_URL, 'https://security.sensiolabs.org/check_lock');
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: '.$format));
curl_setopt($curl, CURLOPT_POSTFIELDS, array('lock' => '@'.$lock));
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_MAXREDIRS, 3);
curl_setopt($curl, CURLOPT_FAILONERROR, false);

$data = curl_exec($curl);

if (false === $data) {
$error = curl_error($curl);
curl_close($curl);

throw new \RuntimeException(sprintf('An error occured: %s.', $error));
}

if (400 == curl_getinfo($curl, CURLINFO_HTTP_CODE)) {
throw new \InvalidArgumentException(sprintf('The web service failed with the following error: %s.', $data['error']));

This comment has been minimized.

Copy link
@schmittjoh

schmittjoh Feb 19, 2013

Contributor

There is something wrong here, $data is always a string at this point. I guess there is a json_decode missing although I don't know if the server always returns json for error responses even if text/plain was requested?

}

if (200 != curl_getinfo($curl, CURLINFO_HTTP_CODE)) {
throw new \RuntimeException('The web service failed for an unknown reason.');
}

curl_close($curl);

return $data;
}
}
12 changes: 12 additions & 0 deletions checker
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env php
<?php

require_once __DIR__.'/vendor/autoload.php';

use Symfony\Component\Console\Application;
use SensioLabs\Security\Command\SecurityCheckerCommand;
use SensioLabs\Security\SecurityChecker;

$console = new Application('SensioLabs Security Checker', '1.0');
$console->add(new SecurityCheckerCommand(new SecurityChecker()));
$console->run();
22 changes: 22 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "sensiolabs/security-checker",
"description": "A security checker for your composer.lock",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien.potencier@gmail.com"
}
],
"require": {
"symfony/console": "~2.0"
},
"bin": ["checker"],
"autoload": {
"psr-0": { "SensioLabs\\Security": "" }
},
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
}
}

0 comments on commit e9a1e92

Please sign in to comment.