-
Notifications
You must be signed in to change notification settings - Fork 18
test: add Pest v1 security test infrastructure #305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| name: "CodeQL" | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main, master, develop, regression-audit] | ||
| paths-ignore: | ||
| - "**/*.php" | ||
| - "**/*.md" | ||
| pull_request: | ||
| branches: [main, master, develop, regression-audit] | ||
| paths-ignore: | ||
| - "**/*.php" | ||
| - "**/*.md" | ||
| schedule: | ||
| - cron: "30 1 * * 1" | ||
| workflow_dispatch: | ||
|
|
||
| concurrency: | ||
| group: codeql-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| analyze: | ||
| name: Analyze (${{ matrix.language }}) | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 20 | ||
| permissions: | ||
| actions: read | ||
| contents: read | ||
| security-events: write | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| language: ["javascript-typescript", "python", "ruby"] | ||
| steps: | ||
|
Comment on lines
+31
to
+35
|
||
| - name: Checkout repository | ||
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | ||
| - name: Initialize CodeQL | ||
| uses: github/codeql-action/init@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3 | ||
| with: | ||
| languages: ${{ matrix.language }} | ||
| - name: Autobuild | ||
| uses: github/codeql-action/autobuild@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3 | ||
| - name: Perform CodeQL Analysis | ||
| uses: github/codeql-action/analyze@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3 | ||
| with: | ||
| category: "/language:${{ matrix.language }}" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| { | ||
| "name": "cacti/plugin_syslog", | ||
| "description": "plugin_syslog plugin for Cacti", | ||
| "license": "GPL-2.0-or-later", | ||
| "require-dev": { | ||
| "pestphp/pest": "^1.23" | ||
| }, | ||
| "config": { | ||
| "allow-plugins": { | ||
| "pestphp/pest-plugin": true | ||
| } | ||
| }, | ||
| "autoload-dev": { | ||
| "files": [ | ||
| "tests/bootstrap.php" | ||
| ] | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| <?php | ||
| /* | ||
| +-------------------------------------------------------------------------+ | ||
| | Copyright (C) 2004-2026 The Cacti Group | | ||
| +-------------------------------------------------------------------------+ | ||
| | Cacti: The Complete RRDtool-based Graphing Solution | | ||
| +-------------------------------------------------------------------------+ | ||
| */ | ||
|
|
||
| /* | ||
| * Pest configuration file. | ||
| */ | ||
|
|
||
| require_once __DIR__ . '/bootstrap.php'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| <?php | ||
| /* | ||
| +-------------------------------------------------------------------------+ | ||
| | Copyright (C) 2004-2026 The Cacti Group | | ||
| +-------------------------------------------------------------------------+ | ||
| | Cacti: The Complete RRDtool-based Graphing Solution | | ||
| +-------------------------------------------------------------------------+ | ||
| */ | ||
|
|
||
| /* | ||
| * Verify plugin source files do not use PHP 8.0+ syntax. | ||
| * Cacti 1.2.x plugins must remain compatible with PHP 7.4. | ||
| */ | ||
|
|
||
| describe('PHP 7.4 compatibility in syslog', function () { | ||
| $files = array( | ||
| 'database.php', | ||
| 'functions.php', | ||
| 'setup.php', | ||
| 'syslog.php', | ||
| 'syslog_alerts.php', | ||
| 'syslog_process.php', | ||
| 'syslog_removal.php', | ||
| 'syslog_reports.php', | ||
| ); | ||
|
|
||
| it('does not use str_contains (PHP 8.0)', function () use ($files) { | ||
| foreach ($files as $relativeFile) { | ||
| $path = realpath(__DIR__ . '/../../' . $relativeFile); | ||
|
|
||
| if ($path === false) { | ||
| continue; | ||
| } | ||
|
|
||
| $contents = file_get_contents($path); | ||
|
|
||
| if ($contents === false) { | ||
| continue; | ||
| } | ||
|
|
||
|
Comment on lines
+28
to
+40
|
||
| expect(preg_match('/\bstr_contains\s*\(/', $contents))->toBe(0, | ||
| "{$relativeFile} uses str_contains() which requires PHP 8.0" | ||
| ); | ||
| } | ||
| }); | ||
|
|
||
| it('does not use str_starts_with (PHP 8.0)', function () use ($files) { | ||
| foreach ($files as $relativeFile) { | ||
| $path = realpath(__DIR__ . '/../../' . $relativeFile); | ||
|
|
||
| if ($path === false) { | ||
| continue; | ||
| } | ||
|
|
||
| $contents = file_get_contents($path); | ||
|
|
||
| if ($contents === false) { | ||
| continue; | ||
| } | ||
|
|
||
| expect(preg_match('/\bstr_starts_with\s*\(/', $contents))->toBe(0, | ||
| "{$relativeFile} uses str_starts_with() which requires PHP 8.0" | ||
| ); | ||
| } | ||
| }); | ||
|
|
||
| it('does not use str_ends_with (PHP 8.0)', function () use ($files) { | ||
| foreach ($files as $relativeFile) { | ||
| $path = realpath(__DIR__ . '/../../' . $relativeFile); | ||
|
|
||
| if ($path === false) { | ||
| continue; | ||
| } | ||
|
|
||
| $contents = file_get_contents($path); | ||
|
|
||
| if ($contents === false) { | ||
| continue; | ||
| } | ||
|
|
||
| expect(preg_match('/\bstr_ends_with\s*\(/', $contents))->toBe(0, | ||
| "{$relativeFile} uses str_ends_with() which requires PHP 8.0" | ||
| ); | ||
| } | ||
| }); | ||
|
|
||
| it('does not use nullsafe operator (PHP 8.0)', function () use ($files) { | ||
| foreach ($files as $relativeFile) { | ||
| $path = realpath(__DIR__ . '/../../' . $relativeFile); | ||
|
|
||
| if ($path === false) { | ||
| continue; | ||
| } | ||
|
|
||
| $contents = file_get_contents($path); | ||
|
|
||
| if ($contents === false) { | ||
| continue; | ||
| } | ||
|
|
||
| expect(preg_match('/\?->/', $contents))->toBe(0, | ||
| "{$relativeFile} uses nullsafe operator which requires PHP 8.0" | ||
| ); | ||
| } | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,64 @@ | ||||||||||||||||||||||||||||||
| <?php | ||||||||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||||||||
| +-------------------------------------------------------------------------+ | ||||||||||||||||||||||||||||||
| | Copyright (C) 2004-2026 The Cacti Group | | ||||||||||||||||||||||||||||||
| +-------------------------------------------------------------------------+ | ||||||||||||||||||||||||||||||
| | Cacti: The Complete RRDtool-based Graphing Solution | | ||||||||||||||||||||||||||||||
| +-------------------------------------------------------------------------+ | ||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||||||||
| * Verify migrated files use prepared DB helpers exclusively. | ||||||||||||||||||||||||||||||
| * Catches regressions where raw db_execute/db_fetch_* calls creep back in. | ||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| describe('prepared statement consistency in syslog', function () { | ||||||||||||||||||||||||||||||
| it('uses prepared DB helpers in all plugin files', function () { | ||||||||||||||||||||||||||||||
| $targetFiles = array( | ||||||||||||||||||||||||||||||
| 'database.php', | ||||||||||||||||||||||||||||||
| 'functions.php', | ||||||||||||||||||||||||||||||
| 'setup.php', | ||||||||||||||||||||||||||||||
| 'syslog.php', | ||||||||||||||||||||||||||||||
| 'syslog_alerts.php', | ||||||||||||||||||||||||||||||
| 'syslog_process.php', | ||||||||||||||||||||||||||||||
| 'syslog_removal.php', | ||||||||||||||||||||||||||||||
| 'syslog_reports.php', | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
Comment on lines
+16
to
+26
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| $rawPattern = '/\bdb_(?:execute|fetch_row|fetch_assoc|fetch_cell)\s*\(/'; | ||||||||||||||||||||||||||||||
| $preparedPattern = '/\bdb_(?:execute|fetch_row|fetch_assoc|fetch_cell)_prepared\s*\(/'; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| foreach ($targetFiles as $relativeFile) { | ||||||||||||||||||||||||||||||
| $path = realpath(__DIR__ . '/../../' . $relativeFile); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if ($path === false) { | ||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| $contents = file_get_contents($path); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if ($contents === false) { | ||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||
|
Comment on lines
+35
to
+41
|
||||||||||||||||||||||||||||||
| continue; | |
| } | |
| $contents = file_get_contents($path); | |
| if ($contents === false) { | |
| continue; | |
| throw new RuntimeException("Unable to resolve target file for prepared statement consistency test: {$relativeFile}"); | |
| } | |
| $contents = file_get_contents($path); | |
| if ($contents === false) { | |
| throw new RuntimeException("Unable to read target file for prepared statement consistency test: {$path}"); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,36 @@ | ||||||||||||||||||||||
| <?php | ||||||||||||||||||||||
| /* | ||||||||||||||||||||||
| +-------------------------------------------------------------------------+ | ||||||||||||||||||||||
| | Copyright (C) 2004-2026 The Cacti Group | | ||||||||||||||||||||||
| +-------------------------------------------------------------------------+ | ||||||||||||||||||||||
| | Cacti: The Complete RRDtool-based Graphing Solution | | ||||||||||||||||||||||
| +-------------------------------------------------------------------------+ | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /* | ||||||||||||||||||||||
| * Verify setup.php defines required plugin hooks and info function. | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| describe('syslog setup.php structure', function () { | ||||||||||||||||||||||
| $source = file_get_contents(realpath(__DIR__ . '/../../setup.php')); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
Comment on lines
+15
to
+16
|
||||||||||||||||||||||
| $source = file_get_contents(realpath(__DIR__ . '/../../setup.php')); | |
| $setupPath = realpath(__DIR__ . '/../../setup.php'); | |
| expect($setupPath) | |
| ->not->toBeFalse('Failed to resolve setup.php path from ' . __DIR__); | |
| $source = file_get_contents($setupPath); | |
| expect($source) | |
| ->not->toBeFalse('Failed to read setup.php at path: ' . $setupPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
paths-ignoreexcludes all**/*.php, so CodeQL won’t run on the vast majority of changes in this PHP plugin. If the intent is to security-scan the plugin, remove the PHP ignore (and consider ignoring only vendor/ or generated paths instead).