diff --git a/.editorconfig b/.editorconfig index 898c45c9..bad52845 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,3 +9,6 @@ max_line_length = 160 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true + +[*.{yml,yaml}] +indent_size = 2 diff --git a/.github/workflows/security.yaml b/.github/workflows/security.yaml new file mode 100644 index 00000000..329983e8 --- /dev/null +++ b/.github/workflows/security.yaml @@ -0,0 +1,23 @@ +on: + schedule: + - cron: '0 12 * * *' + workflow_dispatch: + +jobs: + job: + name: "Security" + runs-on: "ubuntu-latest" + + steps: + - name: "Checkout" + uses: "actions/checkout@v4" + with: + show-progress: false + + - name: "Setup PHP" + uses: "shivammathur/setup-php@v2" + with: + php-version: '7.4.1' + + - name: "Run composer audit" + run: "composer audit --no-dev --locked" diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 00000000..6a8043e5 --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,107 @@ +name: "Tests" + +concurrency: + group: "tests-${{ github.head_ref || github.run_id }}" + cancel-in-progress: true + +on: + pull_request: + push: + branches: [master] + +jobs: + tests: + name: "PHP ${{ matrix.php }} | PostgreSQL ${{ matrix.postgresql }}" + runs-on: "ubuntu-latest" + container: + image: "php:${{ matrix.php-version }}-cli-alpine" + env: + DATABASE_URL: "postgresql://main:main@postgresql:5432/main?serverVersion=${{ matrix.postgresql }}&charset=utf8" + services: + postgresql: + image: "postgres:${{ matrix.postgresql-version }}-alpine" + env: + POSTGRES_USER: main + POSTGRES_PASSWORD: main + POSTGRES_DB: main + + strategy: + fail-fast: false + matrix: + php: + - "7.4" + postgresql: + - "11" + include: + - php: "7.4" + php-version: "7.4.1" + - postgresql: "11" + postgresql-version: "11.7" + + steps: + - name: "Install OS dependencies" + run: "apk add --no-cache bash git icu-dev libzip-dev unzip zip" + + - name: "Adjust allowed PHP memory" + run: echo 'memory_limit = -1' > $PHP_INI_DIR/conf.d/memory-limit.ini; + + - name: "Install PHP extensions" + shell: bash + run: | + wget https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions --quiet -O /usr/local/bin/install-php-extensions + chmod +x /usr/local/bin/install-php-extensions + install-php-extensions intl pdo_pgsql zip + + - name: "Install composer" + run: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer --version=2.6.6 + + - name: "Checkout" + uses: "actions/checkout@v4" + with: + ref: ${{ github.event.pull_request.head.ref || '' }} + show-progress: false + + - name: "Install composer dependencies" + uses: "ramsey/composer-install@v2" + + - name: "Validate composer dependencies" + run: "composer validate" + + - name: "Run composer audit" + run: "composer audit --no-dev --locked" + + - name: "Check code style" + run: "composer check-cs" + + - name: "Run PHPStan" + run: "composer phpstan" + + - name: "Lint twig" + run: "bin/console lint:twig templates --show-deprecations" + + - name: "Run migrations" + run: "bin/console doctrine:migrations:migrate --no-interaction" + + - name: "Setup messenger transports" + run: "bin/console messenger:setup-transports" + + - name: "Validate database schema" + run: "bin/console doctrine:schema:validate" + + - name: "Set git committer info" + shell: bash + run: | + git config --global user.name "${GITHUB_ACTOR}" + git config --global user.email "${GITHUB_ACTOR_ID}+${GITHUB_ACTOR}@users.noreply.github.com" + + - name: "Run unit tests" + run: "composer phpunit:unit" + + - name: "Run integration tests" + run: "composer phpunit:integration" + + - name: "Run functional tests" + run: "composer phpunit:functional" + + - name: "Warmup prod cache" + run: "bin/console cache:warmup --env=prod" diff --git a/composer.json b/composer.json index 2cce648e..4e072d02 100644 --- a/composer.json +++ b/composer.json @@ -110,6 +110,9 @@ "symfony/web-profiler-bundle": "*" }, "config": { + "platform": { + "php": "7.4.1" + }, "preferred-install": { "*": "dist" }, @@ -118,6 +121,9 @@ "composer/package-versions-deprecated": true, "phpstan/extension-installer": true, "symfony/flex": true + }, + "audit": { + "abandoned": "report" } }, "extra": { @@ -164,10 +170,21 @@ ], "phpstan": [ "bin/console cache:clear --env=test", - "phpstan analyse --level=max" + "phpstan analyse --level=max --memory-limit=-1" ], "phpunit": [ - "phpunit --colors=always" + "@phpunit:unit", + "@phpunit:integration", + "@phpunit:functional" + ], + "phpunit:unit": [ + "phpunit --colors=always --testsuite=unit" + ], + "phpunit:integration": [ + "phpunit --colors=always --testsuite=integration" + ], + "phpunit:functional": [ + "phpunit --colors=always --testsuite=functional" ], "proxy-setup": [ "symfony proxy:start", diff --git a/composer.lock b/composer.lock index 177d9b4d..8e20235d 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": "0cde00da873c17994fc173205b392369", + "content-hash": "d9a3d0b434eb702ac25308fda9b37db1", "packages": [ { "name": "async-aws/core", @@ -259,12 +259,12 @@ } }, "autoload": { - "psr-4": { - "Aws\\": "src/" - }, "files": [ "src/functions.php" - ] + ], + "psr-4": { + "Aws\\": "src/" + } }, "notification-url": "https://repo.repman.io/downloads", "license": [ @@ -733,12 +733,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "Clue\\StreamFilter\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "Clue\\StreamFilter\\": "src/" + } }, "notification-url": "https://repo.repman.io/downloads", "license": [ @@ -3877,12 +3877,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "Laminas\\Code\\": "src/" - }, "files": [ "polyfill/ReflectionEnumPolyfill.php" - ] + ], + "psr-4": { + "Laminas\\Code\\": "src/" + } }, "notification-url": "https://repo.repman.io/downloads", "license": [ @@ -4749,12 +4749,12 @@ } }, "autoload": { - "psr-4": { - "JmesPath\\": "src/" - }, "files": [ "src/JmesPath.php" - ] + ], + "psr-4": { + "JmesPath\\": "src/" + } }, "notification-url": "https://repo.repman.io/downloads", "license": [ @@ -5426,12 +5426,12 @@ } }, "autoload": { - "psr-4": { - "Http\\Message\\": "src/" - }, "files": [ "src/filters.php" - ] + ], + "psr-4": { + "Http\\Message\\": "src/" + } }, "notification-url": "https://repo.repman.io/downloads", "license": [ @@ -10135,15 +10135,15 @@ }, "type": "library", "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { "Symfony\\Component\\Intl\\": "" }, "classmap": [ "Resources/stubs" ], - "files": [ - "Resources/functions.php" - ], "exclude-from-classmap": [ "/Tests/" ] @@ -11633,12 +11633,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Uuid\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + } }, "notification-url": "https://repo.repman.io/downloads", "license": [ @@ -14586,12 +14586,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, "files": [ "src/DeepCopy/deep_copy.php" - ] + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } }, "notification-url": "https://repo.repman.io/downloads", "license": [ @@ -14920,6 +14920,7 @@ "issues": "https://github.com/PHP-CS-Fixer/diff/issues", "source": "https://github.com/PHP-CS-Fixer/diff/tree/v1.3.1" }, + "abandoned": true, "time": "2020-10-14T08:39:05+00:00" }, { @@ -15915,11 +15916,11 @@ } }, "autoload": { - "classmap": [ - "src/" - ], "files": [ "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" ] }, "notification-url": "https://repo.repman.io/downloads", @@ -17497,5 +17498,8 @@ "ext-zip": "*" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "platform-overrides": { + "php": "7.4.1" + }, + "plugin-api-version": "2.6.0" } diff --git a/tests/Unit/Service/Downloader/ReactDownloaderTest.php b/tests/Unit/Service/Downloader/ReactDownloaderTest.php index f6d8b2a1..0e9b3f68 100644 --- a/tests/Unit/Service/Downloader/ReactDownloaderTest.php +++ b/tests/Unit/Service/Downloader/ReactDownloaderTest.php @@ -43,6 +43,9 @@ public function testLastModified(): void $downloader->run(); } + /** + * @doesNotPerformAssertions + */ public function testAsyncContent(): void { $downloader = new ReactDownloader(); diff --git a/tests/Unit/Service/PackageSynchronizer/ComposerPackageSynchronizerTest.php b/tests/Unit/Service/PackageSynchronizer/ComposerPackageSynchronizerTest.php index 79f6039a..0dae3124 100644 --- a/tests/Unit/Service/PackageSynchronizer/ComposerPackageSynchronizerTest.php +++ b/tests/Unit/Service/PackageSynchronizer/ComposerPackageSynchronizerTest.php @@ -136,8 +136,10 @@ public function testSynchronizePackageWithGitLabToken(): void $path = $this->baseDir.'/buddy/p/repman-io/repman.json'; @unlink($path); - $this->synchronizer->synchronize(PackageMother::withOrganizationAndToken('gitlab', $this->resourcesDir.'artifacts', 'buddy')); + $package = PackageMother::withOrganizationAndToken('gitlab', $this->resourcesDir.'artifacts', 'buddy'); + $this->synchronizer->synchronize($package); + self::assertTrue($package->isSynchronizedSuccessfully(), (string) $this->getProperty($package, 'lastSyncError')); self::assertFileExists($path); $json = unserialize((string) file_get_contents($path)); @@ -150,8 +152,10 @@ public function testSynchronizePackageWithGitHubToken(): void $path = $this->baseDir.'/buddy/p/repman-io/repman.json'; @unlink($path); - $this->synchronizer->synchronize(PackageMother::withOrganizationAndToken('github', $this->resourcesDir.'artifacts', 'buddy')); + $package = PackageMother::withOrganizationAndToken('github', $this->resourcesDir.'artifacts', 'buddy'); + $this->synchronizer->synchronize($package); + self::assertTrue($package->isSynchronizedSuccessfully(), (string) $this->getProperty($package, 'lastSyncError')); self::assertFileExists($path); $json = unserialize((string) file_get_contents($path)); @@ -164,8 +168,10 @@ public function testSynchronizePackageWithBitbucketToken(): void $path = $this->baseDir.'/buddy/p/repman-io/repman.json'; @unlink($path); - $this->synchronizer->synchronize(PackageMother::withOrganizationAndToken('bitbucket', $this->resourcesDir.'artifacts', 'buddy')); + $package = PackageMother::withOrganizationAndToken('bitbucket', $this->resourcesDir.'artifacts', 'buddy'); + $this->synchronizer->synchronize($package); + self::assertTrue($package->isSynchronizedSuccessfully(), (string) $this->getProperty($package, 'lastSyncError')); self::assertFileExists($path); $json = unserialize((string) file_get_contents($path)); diff --git a/tests/Unit/Service/Security/SensioLabsSecurityCheckerTest.php b/tests/Unit/Service/Security/SensioLabsSecurityCheckerTest.php index bac027b3..d08a39ee 100644 --- a/tests/Unit/Service/Security/SensioLabsSecurityCheckerTest.php +++ b/tests/Unit/Service/Security/SensioLabsSecurityCheckerTest.php @@ -141,20 +141,28 @@ public function testUpdateWhenRepoExist(): void private function updateAdvisoriesDatabaseRepo(): void { $this->filesystem->copy($this->repoDir.'/aws/aws-sdk-php/CVE-2015-5723.yaml', $this->repoDir.'/google/google-sdk-php/CVE-2015-5723.yaml'); - (new Process(['git', 'add', '.'], $this->repoDir))->run(); - (new Process(['git', '-c', 'commit.gpgsign=false', 'commit', '-a', '-m', 'New CVE discovered'], $this->repoDir))->run(); + $this->executeCommandInRepoDir(['git', 'add', '.']); + $this->executeCommandInRepoDir(['git', '-c', 'commit.gpgsign=false', 'commit', '-a', '-m', 'New CVE discovered']); } private function createAdvisoriesDatabaseRepo(): void { $this->filesystem->mkdir($this->repoDir); - (new Process(['git', 'init'], $this->repoDir))->run(); + $this->executeCommandInRepoDir(['git', 'init']); $this->filesystem->mirror( __DIR__.'/../../../Resources/fixtures/security/security-advisories', $this->repoDir ); - (new Process(['git', 'add', '.'], $this->repoDir))->run(); - (new Process(['git', '-c', 'commit.gpgsign=false', 'commit', '-a', '-m', 'AD repo'], $this->repoDir))->run(); + $this->executeCommandInRepoDir(['git', 'add', '-A']); + $this->executeCommandInRepoDir(['git', '-c', 'commit.gpgsign=false', 'commit', '-a', '-m', 'Add repo']); + } + + /** + * @param list $command + */ + private function executeCommandInRepoDir(array $command): void + { + (new Process($command, $this->repoDir))->mustRun(); } private function synchronizeAdvisoriesDatabase(): void