Skip to content

Conversation

@Treggats
Copy link
Contributor

@Treggats Treggats commented Oct 4, 2024

issue HPB-4006

With this PR we make it impossible to use Request methods which don't validate the input data.

@Treggats Treggats self-assigned this Oct 4, 2024
@Treggats Treggats marked this pull request as draft October 4, 2024 12:56
@Treggats Treggats force-pushed the feature/HPB-4006-restrict-validation-methods branch from 71e1236 to d8211ff Compare October 11, 2024 08:11
@Treggats
Copy link
Contributor Author

Currently dealing with the following error

Line src/Rules/ScopeRequestValidateMethods.php

63 Calling PHPStan\Reflection\Php\PhpParameterFromParserNodeReflection::getType() is not covered by backward compatibility promise. The method
might change in a minor PHPStan version.
💡 If you think it should be covered by backward compatibility promise, open a discussion:
💡 https://github.com/phpstan/phpstan/discussions
💡
💡 See also:
💡 https://phpstan.org/developing-extensions/backward-compatibility-promise

@Treggats Treggats force-pushed the feature/HPB-4006-restrict-validation-methods branch from d8211ff to d6158cf Compare October 14, 2024 11:34
@Treggats Treggats force-pushed the feature/HPB-4006-restrict-validation-methods branch 3 times, most recently from 509a207 to 191c5d5 Compare October 14, 2024 12:24
@Treggats Treggats force-pushed the feature/HPB-4006-restrict-validation-methods branch from dc27990 to 97fed3e Compare October 15, 2024 09:55
@Treggats Treggats force-pushed the feature/HPB-4006-restrict-validation-methods branch from 97fed3e to b7c590d Compare October 15, 2024 11:10
composer.json Outdated
"require": {
"php": "^8.2",
"phpstan/phpstan": "^1.10.55",
"phpstan/phpstan": "^1.11.0",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first version where identifiers are used

composer.json Outdated
"psr-4": {
"Hihaho\\PhpstanRules\\": "src/"
"Hihaho\\PhpstanRules\\": "src/",
"Illuminate\\Foundation\\Http\\": "tests/stubs/Illuminate/Foundation/Http",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

map stubs to the stubbed namespace

return true;
}

return $varName === 'safe' && $this->isValidateMethod($methodName);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a validation method chained of the safe() method is allowed

{
/** @var Error[] $errors */
$errors = $this->gatherAnalyserErrors([__DIR__ . '/../../stubs/App/Http/Controllers/PeopleControllerStub.php']);
$validErrors = array_filter(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are more errors present, but we only want to assert the errors from the rules we are introducing into this PR

);
self::assertCount(6, $validErrors);

$unsafeRequestDataError = static fn (int $line) => [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because of the amount of the repeated error messages, I've extracted it to a simple closure

$unsafeRequestDataError(18),
$unsafeRequestDataError(21),
[
'No error with identifier method.notFound is reported on line 20.',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this extra error is present because a @phpstan-ignore is used in the stub

'children' => [
'name' => $request->only(['name']),
],
'email' => $request->safe()->email, // @phpstan-ignore method.notFound
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the safe() method does not exist on the Illuminate Request class, it is allowed. So ignoring the method.notFound error, in favour of being able to assert against it.

#[Test]
public function form_request_class_does_not_use_unvalidated_data_outside_its_namespace(): void
{
$this->analyse([__DIR__ . '/../../stubs/App/Http/Requests/UserRequest.php'], []);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usage of validation methods are allowed within the App\Http\Requests namespace

@Treggats Treggats marked this pull request as ready for review October 15, 2024 15:40
- name: Install dependencies
run: |
composer require "illuminate/support:${{ matrix.laravel }}" --no-interaction --no-update
composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replacing the illuminate packages with laravel/framework, as we need additional classes and it's easier to have one dependency

composer.json Outdated
"psr-4": {
"Hihaho\\PhpstanRules\\": "src/"
"Hihaho\\PhpstanRules\\": "src/",
"App\\Http\\Controllers\\": "tests/stubs/App/Http/Controllers",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mapping namespaces to the stub file location

"php": "^8.2",
"phpstan/phpstan": "^1.10.55",
"illuminate/support": "^10|^11",
"laravel/pint": "^1.13.9"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the PHPStan and Laravel Pint packages are used during development. So made more sense to have them in the require-dev

Copy link
Member

@RobertBoes RobertBoes Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"illuminate/support": "^10|^11", would need to stay, as without it you'd be able to install the package in Laravel < 10 (or even, not in a Laravel app)
Could also change it for illuminate/contracts, not sure what the best one would be

@Treggats
Copy link
Contributor Author

Putting in draft while I work on some internal errors 🙈

@Treggats Treggats marked this pull request as draft October 29, 2024 09:31
it is handled by the other rule

Signed-off-by: Tonko Mulder <[email protected]>
it not only covers the Illuminate Request

but also the FormRequest and NovaRequest

Signed-off-by: Tonko Mulder <[email protected]>
note; PHPStan throws the following error.
Ignoring because I do not have the time to properly figure this out.

Creating new PHPStan\Node\AnonymousClassNode is not covered by backward compatibility promise.
The class might change in a minor PHPStan version.

Signed-off-by: Tonko Mulder <[email protected]>
using concatenation because I had issues with formatting the test

Signed-off-by: Tonko Mulder <[email protected]>
@Treggats Treggats marked this pull request as ready for review October 31, 2024 14:41

parameters:
scoperequestvalidatemethods:
allowedRequestMethods:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default valid validation methods, this can be appended by the local PHPStan config.

diff --git a/phpstan.neon b/phpstan.neon
index f011012500..ee07b64d03 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -50,6 +50,11 @@ parameters:
     # ignore the following error: Called 'Model::make()' which performs unnecessary work, use 'new Model()'.
     noModelMake: false
 
+    scoperequestvalidatemethods:
+        allowedRequestMethods:
+            - 'safe'
+            - 'validated'
+
     # Optional for having a clickable link to PHPStorm
     editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%'
 
`

@@ -1,4 +1,31 @@
parametersSchema:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PHPStan requires a schema for the parameters used by the rule

{
public function __construct(array $allowedRequestMethods)
{
$this->allowedRequestMethods = array_unique($allowedRequestMethods);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

autowired by the PHPStan config. Currently there is no overriding, only appending to this list

try {
return (new ReflectionClass($className))->getMethods();
} catch (ReflectionException) {
// @phpstan-ignore phpstanApi.constructor
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ignoring because PHPStan complains that it is not backwards compatible, but otherwise we'd get a "not found" for anonymous classes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants