From 39fcb55904393dde39c901985b976eccf75cb944 Mon Sep 17 00:00:00 2001 From: Tim Basten Date: Thu, 5 Mar 2026 05:51:21 +0000 Subject: [PATCH] Add security workflow with composer audit, npm audit, and PHPStan Adds a new GitHub Actions workflow that runs dependency vulnerability checks for both PHP and Node packages, plus PHPStan static analysis with Larastan. Includes a baseline for existing errors. --- .github/workflows/security.yml | 67 ++++++++++++ composer.json | 2 + composer.lock | 188 ++++++++++++++++++++++++++++++++- phpstan-baseline.neon | 67 ++++++++++++ phpstan.neon | 9 ++ 5 files changed, 331 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/security.yml create mode 100644 phpstan-baseline.neon create mode 100644 phpstan.neon diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..0c86212 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,67 @@ +name: security + +on: + push: + branches: + - develop + - main + - master + pull_request: + branches: + - develop + - main + - master + +jobs: + audit: + name: Dependency Audit + runs-on: ubuntu-latest + environment: Testing + steps: + - uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Add Flux Credentials Loaded From ENV + run: composer config http-basic.composer.fluxui.dev "${{ secrets.FLUX_USERNAME }}" "${{ secrets.FLUX_LICENSE_KEY }}" + + - name: Install PHP Dependencies + run: composer install --no-interaction --prefer-dist --optimize-autoloader + + - name: Install Node Dependencies + run: npm install + + - name: Composer Audit + run: composer audit + + - name: NPM Audit + run: npm audit --omit=dev + + phpstan: + name: Static Analysis + runs-on: ubuntu-latest + environment: Testing + steps: + - uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + + - name: Add Flux Credentials Loaded From ENV + run: composer config http-basic.composer.fluxui.dev "${{ secrets.FLUX_USERNAME }}" "${{ secrets.FLUX_LICENSE_KEY }}" + + - name: Install Dependencies + run: composer install --no-interaction --prefer-dist --optimize-autoloader + + - name: Run PHPStan + run: vendor/bin/phpstan analyse --no-progress diff --git a/composer.json b/composer.json index 0845f76..e9d244f 100644 --- a/composer.json +++ b/composer.json @@ -17,12 +17,14 @@ }, "require-dev": { "fakerphp/faker": "^1.23", + "larastan/larastan": "^3.9", "laravel/boost": "^2.0", "laravel/pail": "^1.2.2", "laravel/pint": "^1.24", "laravel/sail": "^1.41", "mockery/mockery": "^1.6", "nunomaduro/collision": "^8.6", + "phpstan/phpstan": "^2.1", "phpunit/phpunit": "^11.5.3" }, "autoload": { diff --git a/composer.lock b/composer.lock index b5aaada..615a812 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "dee637c924fba6db2c11a4a299a491b6", + "content-hash": "5a44c97e5f49f06d06ce0246f320edf2", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -8592,6 +8592,137 @@ }, "time": "2025-04-30T06:54:44+00:00" }, + { + "name": "iamcal/sql-parser", + "version": "v0.7", + "source": { + "type": "git", + "url": "https://github.com/iamcal/SQLParser.git", + "reference": "610392f38de49a44dab08dc1659960a29874c4b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/iamcal/SQLParser/zipball/610392f38de49a44dab08dc1659960a29874c4b8", + "reference": "610392f38de49a44dab08dc1659960a29874c4b8", + "shasum": "" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^1.0", + "phpunit/phpunit": "^5|^6|^7|^8|^9" + }, + "type": "library", + "autoload": { + "psr-4": { + "iamcal\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Cal Henderson", + "email": "cal@iamcal.com" + } + ], + "description": "MySQL schema parser", + "support": { + "issues": "https://github.com/iamcal/SQLParser/issues", + "source": "https://github.com/iamcal/SQLParser/tree/v0.7" + }, + "time": "2026-01-28T22:20:33+00:00" + }, + { + "name": "larastan/larastan", + "version": "v3.9.3", + "source": { + "type": "git", + "url": "https://github.com/larastan/larastan.git", + "reference": "64a52bcc5347c89fdf131cb59f96ebfbc8d1ad65" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/larastan/larastan/zipball/64a52bcc5347c89fdf131cb59f96ebfbc8d1ad65", + "reference": "64a52bcc5347c89fdf131cb59f96ebfbc8d1ad65", + "shasum": "" + }, + "require": { + "ext-json": "*", + "iamcal/sql-parser": "^0.7.0", + "illuminate/console": "^11.44.2 || ^12.4.1 || ^13", + "illuminate/container": "^11.44.2 || ^12.4.1 || ^13", + "illuminate/contracts": "^11.44.2 || ^12.4.1 || ^13", + "illuminate/database": "^11.44.2 || ^12.4.1 || ^13", + "illuminate/http": "^11.44.2 || ^12.4.1 || ^13", + "illuminate/pipeline": "^11.44.2 || ^12.4.1 || ^13", + "illuminate/support": "^11.44.2 || ^12.4.1 || ^13", + "php": "^8.2", + "phpstan/phpstan": "^2.1.32" + }, + "require-dev": { + "doctrine/coding-standard": "^13", + "laravel/framework": "^11.44.2 || ^12.7.2 || ^13", + "mockery/mockery": "^1.6.12", + "nikic/php-parser": "^5.4", + "orchestra/canvas": "^v9.2.2 || ^10.0.1 || ^11", + "orchestra/testbench-core": "^9.12.0 || ^10.1 || ^11", + "phpstan/phpstan-deprecation-rules": "^2.0.1", + "phpunit/phpunit": "^10.5.35 || ^11.5.15 || ^12.5.8" + }, + "suggest": { + "orchestra/testbench": "Using Larastan for analysing a package needs Testbench", + "phpmyadmin/sql-parser": "Install to enable Larastan's optional phpMyAdmin-based SQL parser automatically" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Larastan\\Larastan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Can Vural", + "email": "can9119@gmail.com" + } + ], + "description": "Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel", + "keywords": [ + "PHPStan", + "code analyse", + "code analysis", + "larastan", + "laravel", + "package", + "php", + "static analysis" + ], + "support": { + "issues": "https://github.com/larastan/larastan/issues", + "source": "https://github.com/larastan/larastan/tree/v3.9.3" + }, + "funding": [ + { + "url": "https://github.com/canvural", + "type": "github" + } + ], + "time": "2026-02-20T12:07:12+00:00" + }, { "name": "laravel/boost", "version": "v2.2.2", @@ -9359,6 +9490,59 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpstan/phpstan", + "version": "2.1.40", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", + "reference": "9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2026-02-23T15:04:35+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "11.0.12", @@ -10989,5 +11173,5 @@ "php": "^8.2" }, "platform-dev": {}, - "plugin-api-version": "2.9.0" + "plugin-api-version": "2.6.0" } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..5819da2 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,67 @@ +parameters: + ignoreErrors: + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$email\.$#' + identifier: property.notFound + count: 1 + path: app/Jobs/SendApprovalDecisionEmail.php + + - + message: '#^Cannot access property \$value on string\.$#' + identifier: property.nonObject + count: 1 + path: app/Mail/ApprovalDecisionMail.php + + - + message: '#^Result of && is always false\.$#' + identifier: booleanAnd.alwaysFalse + count: 2 + path: app/Policies/TravelRequestPolicy.php + + - + message: '#^Strict comparison using \=\=\= between string and App\\Enums\\TravelStatus\:\:Draft will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: app/Policies/TravelRequestPolicy.php + + - + message: '#^Strict comparison using \=\=\= between string and App\\Enums\\TravelStatus\:\:Pending will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: app/Policies/TravelRequestPolicy.php + + - + message: '#^Parameter \#1 \$action of method Filament\\Panel\:\:login\(\) expects array\\|Closure\|string\|null, false given\.$#' + identifier: argument.type + count: 1 + path: app/Providers/Filament/AdminPanelProvider.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: app/Services/ApprovalService.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$role\.$#' + identifier: property.notFound + count: 1 + path: app/Services/ApprovalService.php + + - + message: '#^Call to an undefined method Illuminate\\Database\\Eloquent\\Model\:\:steps\(\)\.$#' + identifier: method.notFound + count: 1 + path: app/Services/ApprovalService.php + + - + message: '#^Parameter \#1 \$travelRequest of job class App\\Jobs\\SendApprovalDecisionEmail constructor expects App\\Models\\TravelRequest in App\\Jobs\\SendApprovalDecisionEmail\:\:dispatch\(\), Illuminate\\Database\\Eloquent\\Model\|null given\.$#' + identifier: argument.type + count: 2 + path: app/Services/ApprovalService.php + + - + message: '#^Parameter \#1 \$travelRequest of job class App\\Jobs\\SendApprovalRequestEmail constructor expects App\\Models\\TravelRequest in App\\Jobs\\SendApprovalRequestEmail\:\:dispatch\(\), Illuminate\\Database\\Eloquent\\Model\|null given\.$#' + identifier: argument.type + count: 1 + path: app/Services/ApprovalService.php diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..a2496a9 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,9 @@ +includes: + - vendor/larastan/larastan/extension.neon + - phpstan-baseline.neon + +parameters: + paths: + - app/ + + level: 5