Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ Here's a comprehensive list of all available rules:

21. **ForbidWeakCryptoKeyRule**: Prevents weak cryptographic key sizes in `openssl_pkey_new()` calls. RSA keys must be at least 2048 bits.

22. **ForbidHardcodedCredentialsRule**: Detects hardcoded credentials (passwords, API keys, secrets, tokens) in array definitions. Use environment variables instead.

## Configuration

You can customize the behavior of these rules by adding configuration to your `phpstan.neon` file. See the [configuration section](#configuration) for more details.
Expand Down
1 change: 1 addition & 0 deletions rules.neon
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ rules:
- Shopware\PhpStan\Rule\ForwardSalesChannelContextToSystemConfigServiceRule
- Shopware\PhpStan\Rule\ForbidPredictableSaltRule
- Shopware\PhpStan\Rule\ForbidWeakCryptoKeyRule
- Shopware\PhpStan\Rule\ForbidHardcodedCredentialsRule

services:
-
Expand Down
65 changes: 65 additions & 0 deletions src/Rule/ForbidHardcodedCredentialsRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

namespace Shopware\PhpStan\Rule;

use PhpParser\Node;
use PhpParser\Node\ArrayItem;
use PhpParser\Node\Scalar\String_;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\Rules\RuleErrorBuilder;

/**
* @implements Rule<ArrayItem>
*/
class ForbidHardcodedCredentialsRule implements Rule
{
private const SENSITIVE_KEYS = ['password', 'api_key', 'secret', 'token', 'apikey'];

public function getNodeType(): string
{
return ArrayItem::class;
}

/**
* @return list<RuleError>
*/
public function processNode(Node $node, Scope $scope): array
{
if (!$node->key instanceof String_) {
return [];
}

$keyName = strtolower($node->key->value);
$isSensitive = false;
foreach (self::SENSITIVE_KEYS as $sensitive) {
if (str_contains($keyName, $sensitive)) {
$isSensitive = true;
break;
}
}

if (!$isSensitive) {
return [];
}

if (!$node->value instanceof String_) {
return [];
}

$value = $node->value->value;
if ($value === '' || $value === '0' || str_starts_with($value, '%') || str_contains($value, 'env(')) {
return [];
}

return [
RuleErrorBuilder::message('Possible hardcoded credentials detected. Use environment variables.')
->identifier('shopware.forbidHardcodedCredentials')
->line($node->getLine())
->build(),
];
}
}
31 changes: 31 additions & 0 deletions tests/Rule/ForbidHardcodedCredentialsRuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Shopware\PhpStan\Tests\Rule;

use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use Shopware\PhpStan\Rule\ForbidHardcodedCredentialsRule;

/**
* @extends RuleTestCase<ForbidHardcodedCredentialsRule>
*/
class ForbidHardcodedCredentialsRuleTest extends RuleTestCase
{
protected function getRule(): Rule
{
return new ForbidHardcodedCredentialsRule();
}

public function testRule(): void
{
$this->analyse([__DIR__ . '/fixtures/ForbidHardcodedCredentialsRule/correct-usage.php'], []);
$this->analyse([__DIR__ . '/fixtures/ForbidHardcodedCredentialsRule/wrong-usage.php'], [
[
'Possible hardcoded credentials detected. Use environment variables.',
12,
],
]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace Shopware\PhpStan\Tests\Rule\fixtures\ForbidHardcodedCredentialsRule;

class CorrectUsage
{
public function envVariablePattern(): array
{
return [
'password' => '%env(DATABASE_PASSWORD)%',
];
}

public function envFunctionPattern(): array
{
return [
'secret' => 'env(APP_SECRET)',
];
}

public function emptyValue(): array
{
return [
'api_key' => '',
];
}

public function zeroValue(): array
{
return [
'apikey' => '0',
];
}

public function nullValue(): array
{
return [
'token' => null,
];
}

public function nonSensitiveKey(): array
{
return [
'username' => 'admin',
];
}
}
15 changes: 15 additions & 0 deletions tests/Rule/fixtures/ForbidHardcodedCredentialsRule/wrong-usage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Shopware\PhpStan\Tests\Rule\fixtures\ForbidHardcodedCredentialsRule;

class WrongUsage
{
public function getConfig(): array
{
return [
'password' => 'secret123',
];
}
}