Skip to content

Commit

Permalink
Add disallowedMethodCalls.allowCount to allow method calls N times
Browse files Browse the repository at this point in the history
See:
- #86
  • Loading branch information
ruudk committed Oct 21, 2021
1 parent 14138dc commit 862eaea
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 5 deletions.
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ parameters:
- src
level: max
typeAliases:
ForbiddenCallsConfig: 'array<array{function?:string, method?:string, message?:string, allowIn?:string[], allowInFunctions?:string[], allowInMethods?:string[], allowParamsInAllowed?:array<integer, integer|boolean|string>, allowParamsInAllowedAnyValue?:array<integer, integer>, allowParamsAnywhere?:array<integer, integer|boolean|string>, allowParamsAnywhereAnyValue?:array<integer, integer>, allowExceptParamsInAllowed?:array<integer, integer|boolean|string>, allowExceptParams?:array<integer, integer|boolean|string>, allowExceptCaseInsensitiveParams?:array<integer, integer|boolean|string>}>'
ForbiddenCallsConfig: 'array<array{function?:string, method?:string, message?:string, allowIn?:string[], allowInFunctions?:string[], allowInMethods?:string[], allowParamsInAllowed?:array<integer, integer|boolean|string>, allowParamsInAllowedAnyValue?:array<integer, integer>, allowParamsAnywhere?:array<integer, integer|boolean|string>, allowParamsAnywhereAnyValue?:array<integer, integer>, allowExceptParamsInAllowed?:array<integer, integer|boolean|string>, allowExceptParams?:array<integer, integer|boolean|string>, allowExceptCaseInsensitiveParams?:array<integer, integer|boolean|string>, allowCount?:int}>'
ForbiddenCalls: 'PhpParser\Node\Expr\FuncCall|PhpParser\Node\Expr\MethodCall|PhpParser\Node\Expr\StaticCall|PhpParser\Node\Expr\New_'

includes:
Expand Down
2 changes: 1 addition & 1 deletion src/Calls/ShellExecCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public function processNode(Node $node, Scope $scope): array
'shell_exec',
null,
$this->disallowedCalls,
'Using the backtick operator (`...`) is forbidden because shell_exec() is forbidden, %2$s%3$s'
'Using the backtick operator (`...`) is forbidden because shell_exec() is forbidden, %3$s%4$s'
);
}

Expand Down
28 changes: 27 additions & 1 deletion src/DisallowedCall.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ class DisallowedCall
/** @var array<int, DisallowedCallParam> */
private $allowExceptParams;

/** @var int */
private $allowCount;

/** @var int */
private $timesAllowed = 0;


/**
* DisallowedCall constructor.
Expand All @@ -44,8 +50,9 @@ class DisallowedCall
* @param array<int, DisallowedCallParam> $allowParamsAnywhere
* @param array<int, DisallowedCallParam> $allowExceptParamsInAllowed
* @param array<int, DisallowedCallParam> $allowExceptParams
* @param int $allowCount
*/
public function __construct(string $call, ?string $message, array $allowIn, array $allowInCalls, array $allowParamsInAllowed, array $allowParamsAnywhere, array $allowExceptParamsInAllowed, array $allowExceptParams)
public function __construct(string $call, ?string $message, array $allowIn, array $allowInCalls, array $allowParamsInAllowed, array $allowParamsAnywhere, array $allowExceptParamsInAllowed, array $allowExceptParams, int $allowCount)
{
$this->call = $call;
$this->message = $message;
Expand All @@ -55,6 +62,7 @@ public function __construct(string $call, ?string $message, array $allowIn, arra
$this->allowParamsAnywhere = $allowParamsAnywhere;
$this->allowExceptParamsInAllowed = $allowExceptParamsInAllowed;
$this->allowExceptParams = $allowExceptParams;
$this->allowCount = $allowCount;
}


Expand Down Expand Up @@ -124,6 +132,24 @@ public function getAllowExceptParams(): array
}


public function getAllowCount(): int
{
return $this->allowCount;
}


public function hasRemainingAllowCount(): bool
{
return $this->allowCount > $this->timesAllowed;
}


public function trackAllowedCall(): void
{
$this->timesAllowed++;
}


public function getKey(): string
{
// The key consists of "initial" config values that would be overwritten with more specific details in a custom config.
Expand Down
3 changes: 2 additions & 1 deletion src/DisallowedCallFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public function createFromConfig(array $config): array
$allowParamsInAllowed,
$allowParamsAnywhere,
$allowExceptParamsInAllowed,
$allowExceptParams
$allowExceptParams,
$disallowedCall['allowCount'] ?? 0
);
$calls[$disallowedCall->getKey()] = $disallowedCall;
}
Expand Down
8 changes: 7 additions & 1 deletion src/DisallowedHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,16 @@ public function getDisallowedMessage(?Node $node, Scope $scope, string $name, ?s
{
foreach ($disallowedCalls as $disallowedCall) {
if ($this->callMatches($disallowedCall, $name) && !$this->isAllowed($scope, $node, $disallowedCall)) {
if ($disallowedCall->hasRemainingAllowCount()) {
$disallowedCall->trackAllowedCall();
return[];
}

return [
sprintf(
$message ?? 'Calling %s is forbidden, %s%s',
$message ?? 'Calling %s%s is forbidden, %s%s',
($displayName && $displayName !== $name) ? "{$name}() (as {$displayName}())" : "{$name}()",
$disallowedCall->getAllowCount() > 0 ? sprintf(' more than %d times', $disallowedCall->getAllowCount()): '',
$disallowedCall->getMessage(),
$disallowedCall->getCall() !== $name ? " [{$name}() matches {$disallowedCall->getCall()}()]" : ''
),
Expand Down
17 changes: 17 additions & 0 deletions tests/Calls/MethodCallsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ protected function getRule(): Rule
1 => 'y',
],
],
[
'function' => 'Fiction\Pulp\GeneratedClass::execute*()',
'message' => 'use another generated class',
'allowCount' => 2,
'allowIn' => [
'../src/disallowed-allowed/*.php',
'../src/*-allow/*.*',
],
],
]
);
}
Expand Down Expand Up @@ -135,6 +144,14 @@ public function testRule(): void
'Calling DateTime::format() is forbidden, why too kay',
55,
],
[
'Calling Fiction\Pulp\GeneratedClass::execute() more than 2 times is forbidden, use another generated class [Fiction\Pulp\GeneratedClass::execute() matches Fiction\Pulp\GeneratedClass::execute*()]',
63,
],
[
'Calling Fiction\Pulp\GeneratedClass::executeOrThrow() more than 2 times is forbidden, use another generated class [Fiction\Pulp\GeneratedClass::executeOrThrow() matches Fiction\Pulp\GeneratedClass::execute*()]',
64,
],
]);
$this->analyse([__DIR__ . '/../src/disallowed-allow/methodCalls.php'], [
[
Expand Down
1 change: 1 addition & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/libs/Bar.php';
require_once __DIR__ . '/libs/Blade.php';
require_once __DIR__ . '/libs/GeneratedClass.php';
require_once __DIR__ . '/libs/Constructor.php';
require_once __DIR__ . '/libs/Inheritance.php';
require_once __DIR__ . '/libs/Royale.php';
Expand Down
10 changes: 10 additions & 0 deletions tests/libs/GeneratedClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
declare(strict_types = 1);

namespace Fiction\Pulp;

class GeneratedClass
{
public function execute() {}
public function executeOrThrow() {}
}
7 changes: 7 additions & 0 deletions tests/src/disallowed-allow/methodCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,10 @@
(new DateTime())->format('y');
(new DateTime())->format('Y');
new DateTime('tOmOrRoW');

use Fiction\Pulp\GeneratedClass;
$class = new GeneratedClass();
$class->execute();
$class->executeOrThrow();
$class->execute();
$class->executeOrThrow();
7 changes: 7 additions & 0 deletions tests/src/disallowed/methodCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,10 @@
(new DateTime())->format('y');
(new DateTime())->format('Y');
new DateTime('tOmOrRoW');

use Fiction\Pulp\GeneratedClass;
$class = new GeneratedClass();
$class->execute();
$class->executeOrThrow();
$class->execute();
$class->executeOrThrow();

0 comments on commit 862eaea

Please sign in to comment.