Skip to content

Commit

Permalink
Risky invocation warnings and refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
mtolhuys committed Jul 23, 2019
1 parent 8658002 commit 71ce788
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 41 deletions.
16 changes: 11 additions & 5 deletions src/Commands/EnvScan.php
Expand Up @@ -55,22 +55,28 @@ public function handle()
}

private function showOutput() {
foreach ($this->scanner->warnings as $warning) {
$this->warn("Warning: <fg=red>{$warning->invocation}</fg=red> found in {$warning->filename}");
}

if ($this->option('undefined-only')) {
if ($this->scanner->results['undefined'] === 0) {
$this->info("Looking good!");
} else {
$this->output->write(
"<fg=red>{$this->scanner->results['undefined']} used environmental variables are undefined:</fg=red>\n"
$this->line(
"<fg=red>{$this->scanner->results['undefined']} used environmental variables are undefined:</fg=red>"
);
$this->output->write('<fg=red>'.implode(PHP_EOL, $this->scanner->undefined)."</fg=red>\n");
$this->line('<fg=red>'.implode(PHP_EOL, $this->scanner->undefined)."</fg=red>");
}
} else {
}

else {
$this->table([
"Files ({$this->scanner->results['files']})",
"Defined ({$this->scanner->results['defined']})",
"Depending on default ({$this->scanner->results['depending_on_default']})",
"Undefined ({$this->scanner->results['undefined']})",
], $this->scanner->results['data']);
], $this->scanner->results['columns']);
}
}
}
102 changes: 68 additions & 34 deletions src/LaravelEnvScanner.php
Expand Up @@ -18,15 +18,18 @@ class LaravelEnvScanner
'defined' => 0,
'undefined' => 0,
'depending_on_default' => 0,
'data' => [],
'columns' => [],
];

/**
* Stores processed var names
* Stores processed file and var names
*
* @var array
*/
private $processed = [];
private $processed = [
'files' => [],
'vars' => [],
];

/**
* Stores undefined var names
Expand All @@ -35,6 +38,13 @@ class LaravelEnvScanner
*/
public $undefined = [];

/**
* Stores warnings for vars not passing validation
*
* @var array
*/
public $warnings = [];

/**
* Current file being processed
*
Expand All @@ -56,75 +66,93 @@ public function __construct(string $dir = null)
}

/**
* Execute the console command.
* Run the scan
*
* @return mixed
* @throws \Exception
*/
public function scan()
{
$files = $this->recursiveDirSearch($this->dir, '/.*?.php/');
$files = $this->recursiveDirSearch($this->dir, '/.*?.php/');

foreach ($files as $file) {
preg_match_all(
'# env\((.*?)\)| getenv\((.*?)\)#',
str_replace(["\n", "\r"], '', file_get_contents($file)),
$values
$matches
);

$values = array_filter(
array_merge($values[1], $values[2])
);
if (empty(array_filter($matches))) {
continue;
}

$this->currentFile = $file;
$invocations = $matches[0];

foreach ($invocations as $index => $invocation) {
$params = empty($matches[1][$index]) ? $matches[2][$index] : $matches[1][$index];

foreach ($values as $value) {
$result = $this->getResult(
explode(',', str_replace(["'", '"', ' '], '', $value))
$invocation,
explode(',', str_replace(["'", '"', ' '], '', $params))
);

if (! $result) {
if (!$result) {
continue;
}

$this->storeResult($file, $result);
$this->storeResult($result);
}
}

return $this;
}

/**
* Get result based on comma separated parsed env() parameters
* Get result based on comma separated parsed env() or getenv() parameters
* Validates by alphanumeric and underscore and skips already processed
*
* @param array $values
* @param string $invocation
* @param array $params
* @return object|bool
*/
private function getResult(array $values)
private function getResult(string $invocation, array $params)
{
$envVar = $values[0];
$envVar = $params[0];

if (in_array($envVar, $this->processed)) {
if (in_array($envVar, $this->processed['vars'])) {
return false;
}

$this->processed[] = $envVar;
$this->processed['vars'][] = $envVar;

if (!preg_match('/^[A-Za-z0-9_]+$/', $envVar)) {
$invocation = str_replace(' ', '', $invocation);

$this->warnings[] = (object)[
'filename' => $this->currentFile,
'invocation' => $invocation,
];

return false;
}

return (object)[
'envVar' => $envVar,
'hasValue' => env($values[0]) !== null,
'hasDefault' => isset($values[1]),
'hasValue' => env($envVar) !== null,
'hasDefault' => isset($params[1]),
];
}

/**
* Store result and optional runtime output
*
* @param string $file
* @param $result
*/
private function storeResult(string $file, $result)
private function storeResult($result)
{
$resultData = [
'filename' => $this->getFilename($file),
'filename' => $this->getColumnFilename(),
'defined' => '-',
'depending_on_default' => '-',
'undefined' => '-',
Expand All @@ -141,25 +169,31 @@ private function storeResult(string $file, $result)
$this->results['undefined']++;
}

$this->results['data'][] = $resultData;
$this->results['columns'][] = $resultData;

if (!in_array($this->currentFile, $this->processed['files'])) {
$this->results['files']++;
$this->processed['files'][] = $this->currentFile;
}
}

private function getFilename(string $file)
/**
* Return filename or '-' for table
*
* @return string
*/
private function getColumnFilename(): string
{
$basename = basename($file);

if ($this->currentFile === $basename) {
if (in_array($this->currentFile, $this->processed['files'])) {
return '-';
}

$this->results['files']++;

return $this->currentFile = $basename;
return basename($this->currentFile);
}

private function recursiveDirSearch(string $folder, string $pattern): array
{
if (! file_exists($folder)) {
if (!file_exists($folder)) {
return [];
}

Expand All @@ -172,7 +206,7 @@ private function recursiveDirSearch(string $folder, string $pattern): array

$list = [];

foreach($files as $file) {
foreach ($files as $file) {
$list = array_merge($list, $file);
}

Expand Down
11 changes: 9 additions & 2 deletions tests/EnvScanTest.php
Expand Up @@ -29,6 +29,7 @@ public function getPackageProviders($app)
private function scanning_for_env(string $dir = null)
{
$this->scanner = (new LaravelEnvScanner($dir))->scan();
$risky = 'USAGE';

// Defined
env('FILLED');
Expand All @@ -38,6 +39,8 @@ private function scanning_for_env(string $dir = null)
env('FILLED');
env('NOT_FILLED');
env('FILLED_WITH_FALSE');
env('POTENTIALLY_'.$risky);
getenv($risky);

env('DEPENDING_ON_DEFAULT', 'default');
getenv('GET_DEPENDING_ON_DEFAULT', 'default');
Expand All @@ -58,9 +61,9 @@ public function it_checks_if_example_env_scan_results_are_correct()
$this->assertTrue($this->scanner->results['defined'] === 4);
$this->assertTrue($this->scanner->results['depending_on_default'] === 3);
$this->assertTrue($this->scanner->results['undefined'] === 2);
$this->assertTrue($this->scanner->results['data'][0]['filename'] === basename(__FILE__));
$this->assertTrue($this->scanner->results['columns'][0]['filename'] === basename(__FILE__));

foreach ($this->scanner->results['data'] as $result) {
foreach ($this->scanner->results['columns'] as $result) {
if ($result['defined'] !== '-') {
$this->assertTrue($result['depending_on_default'] === '-');
$this->assertTrue($result['undefined'] === '-');
Expand Down Expand Up @@ -92,7 +95,11 @@ public function it_checks_if_example_env_scan_results_are_correct()
/** @test */
public function it_checks_if_command_output_is_correct_with_undefined_only_option()
{
$safeEnv = 'env';
$safeGetEnv = 'getenv';
$expectedOutput = 'Scanning: ' . __DIR__ . '...' . PHP_EOL
. "Warning: $safeEnv('POTENTIALLY_'.\$risky) found in ". __FILE__ . PHP_EOL
. "Warning: $safeGetEnv(\$risky) found in ". __FILE__ . PHP_EOL
. '2 used environmental variables are undefined:' . PHP_EOL
. 'UNDEFINED' . PHP_EOL
. 'GET_UNDEFINED' . PHP_EOL;
Expand Down

0 comments on commit 71ce788

Please sign in to comment.