mirror of
https://github.com/Cacti/cacti.git
synced 2026-10-23 03:27:02 +09:00
fix: Fixing Unit tests (#6790)
* fix: Fixing Unit tests * fix: Include helper remove the defines * Enable Pest tests for validation * Update tests/Unit/ScriptsHardeningTest.php Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update tests/Helpers/CactiStubs.php Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update tests/Unit/SsHstatsTest.php Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update rector.php Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update tests/Unit/HtmlEscapeTest.php Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix: Remove comments that are no longer required * fix: Move xdebug to the correct location * fix: Be consistent with includes --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
1 parent
44c66664ed
commit
9d8bf959f5
27 files changed
+93
-430
No files matched your search
@@ -108,9 +108,9 @@ jobs:
|
|||||||
run: composer run-script phpstan
|
run: composer run-script phpstan
|
||||||
working-directory: .
|
working-directory: .
|
||||||
|
|
||||||
# - name: Run Pest Unit Tests
|
- name: Run Pest Unit Tests
|
||||||
# run: composer run-script test
|
run: composer run-script test
|
||||||
# working-directory: .
|
working-directory: .
|
||||||
|
|
||||||
- name: Install github if not already installed
|
- name: Install github if not already installed
|
||||||
run: sudo apt-get -y install git
|
run: sudo apt-get -y install git
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
define('PHP_STAN', true);
|
define('PHP_TESTING', true);
|
||||||
+2
-1
@@ -63,6 +63,7 @@
|
|||||||
"phpstan/phpstan": "^2.1.21",
|
"phpstan/phpstan": "^2.1.21",
|
||||||
"pestphp/pest": "^2",
|
"pestphp/pest": "^2",
|
||||||
"pestphp/pest-plugin-drift": "^2.0",
|
"pestphp/pest-plugin-drift": "^2.0",
|
||||||
|
"composer/xdebug-handler": "^3.0",
|
||||||
"rector/rector": "^2.1.2"
|
"rector/rector": "^2.1.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -70,7 +71,7 @@
|
|||||||
"phpstan": "phpstan analyse --level 6 ",
|
"phpstan": "phpstan analyse --level 6 ",
|
||||||
"phpcsfixer": "php-cs-fixer fix --allow-unsupported-php-version=yes --dry-run --diff --config=./.php-cs-fixer.php ",
|
"phpcsfixer": "php-cs-fixer fix --allow-unsupported-php-version=yes --dry-run --diff --config=./.php-cs-fixer.php ",
|
||||||
"phpcsfixit": "php-cs-fixer fix ",
|
"phpcsfixit": "php-cs-fixer fix ",
|
||||||
"test": "include/vendor/bin/pest --display-warnings "
|
"test": "include/vendor/bin/pest --display-warnings"
|
||||||
},
|
},
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
|||||||
+5
-5
@@ -123,7 +123,7 @@ if (file_exists(__DIR__ . '/config.php')) {
|
|||||||
include(__DIR__ . '/config.php');
|
include(__DIR__ . '/config.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defined('PHP_STAN') && file_exists(__DIR__ . '/config.php.dist')) {
|
if (defined('PHP_TESTING') && file_exists(__DIR__ . '/config.php.dist')) {
|
||||||
if (!is_readable(__DIR__ . '/config.php.dist')) {
|
if (!is_readable(__DIR__ . '/config.php.dist')) {
|
||||||
die('Configuration file include/config.php is present, but unreadable.' . PHP_EOL);
|
die('Configuration file include/config.php is present, but unreadable.' . PHP_EOL);
|
||||||
}
|
}
|
||||||
@@ -313,7 +313,7 @@ $lu = $config['is_web'] ? '</ul>' : '';
|
|||||||
$il = $config['is_web'] ? '</li>' : '';
|
$il = $config['is_web'] ? '</li>' : '';
|
||||||
|
|
||||||
if ($config['poller_id'] > 1 || isset($rdatabase_hostname)) {
|
if ($config['poller_id'] > 1 || isset($rdatabase_hostname)) {
|
||||||
if (!defined('PHP_STAN')) {
|
if (!defined('PHP_TESTING')) {
|
||||||
$local_db_cnn_id = db_connect_real($database_hostname, $database_username, $database_password, $database_default, $database_type, $database_port, $database_retries, $database_ssl, $database_ssl_key, $database_ssl_cert, $database_ssl_ca, $database_ssl_capath, $database_ssl_verify_server_cert);
|
$local_db_cnn_id = db_connect_real($database_hostname, $database_username, $database_password, $database_default, $database_type, $database_port, $database_retries, $database_ssl, $database_ssl_key, $database_ssl_cert, $database_ssl_ca, $database_ssl_capath, $database_ssl_verify_server_cert);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,7 +363,7 @@ if ($config['poller_id'] > 1 || isset($rdatabase_hostname)) {
|
|||||||
* a remote poller, let's attempt to get back online.
|
* a remote poller, let's attempt to get back online.
|
||||||
*/
|
*/
|
||||||
if ($conn_mode != 'offline') {
|
if ($conn_mode != 'offline') {
|
||||||
if (!defined('PHP_STAN')) {
|
if (!defined('PHP_TESTING')) {
|
||||||
$remote_db_cnn_id = db_connect_real($rdatabase_hostname, $rdatabase_username, $rdatabase_password, $rdatabase_default, $rdatabase_type, $rdatabase_port, $database_retries, $rdatabase_ssl, $rdatabase_ssl_key, $rdatabase_ssl_cert, $rdatabase_ssl_ca, $rdatabase_ssl_capath, $rdatabase_ssl_verify_server_cert);
|
$remote_db_cnn_id = db_connect_real($rdatabase_hostname, $rdatabase_username, $rdatabase_password, $rdatabase_default, $rdatabase_type, $rdatabase_port, $database_retries, $rdatabase_ssl, $rdatabase_ssl_key, $rdatabase_ssl_cert, $rdatabase_ssl_ca, $rdatabase_ssl_capath, $rdatabase_ssl_verify_server_cert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -389,7 +389,7 @@ if ($config['poller_id'] > 1 || isset($rdatabase_hostname)) {
|
|||||||
$config['connection'] = 'offline';
|
$config['connection'] = 'offline';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!defined('PHP_STAN')) {
|
if (!defined('PHP_TESTING')) {
|
||||||
if (!db_connect_real($database_hostname, $database_username, $database_password, $database_default, $database_type, $database_port, $database_retries, $database_ssl, $database_ssl_key, $database_ssl_cert, $database_ssl_ca, $database_ssl_capath, $database_ssl_verify_server_cert)) {
|
if (!db_connect_real($database_hostname, $database_username, $database_password, $database_default, $database_type, $database_port, $database_retries, $database_ssl, $database_ssl_key, $database_ssl_cert, $database_ssl_ca, $database_ssl_capath, $database_ssl_verify_server_cert)) {
|
||||||
print $ps . 'FATAL: Connection to Cacti database failed. Please ensure: ' . $ul;
|
print $ps . 'FATAL: Connection to Cacti database failed. Please ensure: ' . $ul;
|
||||||
print $li . 'the PHP MySQL module is installed and enabled.' . $il;
|
print $li . 'the PHP MySQL module is installed and enabled.' . $il;
|
||||||
@@ -410,7 +410,7 @@ if ($config['poller_id'] > 1 || isset($rdatabase_hostname)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defined('PHP_STAN')) {
|
if (!defined('PHP_TESTING')) {
|
||||||
if (!db_table_exists('settings') || !db_table_exists('version')) {
|
if (!db_table_exists('settings') || !db_table_exists('version')) {
|
||||||
print $ps . 'FATAL: Connection to Cacti database succeeded but `settings` table not found. Please ensure: ' . $ul;
|
print $ps . 'FATAL: Connection to Cacti database succeeded but `settings` table not found. Please ensure: ' . $ul;
|
||||||
print $li . 'the PHP MySQL module is installed and enabled.' . $il;
|
print $li . 'the PHP MySQL module is installed and enabled.' . $il;
|
||||||
|
|||||||
+1
-1
@@ -162,7 +162,7 @@ function db_connect_real(string $device, string $user, string $pass, string $db_
|
|||||||
];
|
];
|
||||||
|
|
||||||
// test if cacti database is imported from SQL file
|
// test if cacti database is imported from SQL file
|
||||||
if (!defined('PHP_STAN')) {
|
if (!defined('PHP_TESTING')) {
|
||||||
$table_exists = db_fetch_cell("SELECT count(*) FROM information_schema.tables
|
$table_exists = db_fetch_cell("SELECT count(*) FROM information_schema.tables
|
||||||
WHERE table_schema = DATABASE() and TABLE_NAME = 'version'");
|
WHERE table_schema = DATABASE() and TABLE_NAME = 'version'");
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -2247,10 +2247,10 @@ function is_hex_string(string &$result) : bool {
|
|||||||
* Hex- is considered due to the stripping of 'String:' in
|
* Hex- is considered due to the stripping of 'String:' in
|
||||||
* lib/snmp.php
|
* lib/snmp.php
|
||||||
*/
|
*/
|
||||||
if (str_starts_with($compare, 'hex-')) {
|
if (str_starts_with($compare, 'hex-string:')) {
|
||||||
$check = trim(str_ireplace('hex-', '', $result));
|
|
||||||
} elseif (str_starts_with($compare, 'hex-string:')) {
|
|
||||||
$check = trim(str_ireplace('hex-string:', '', $result));
|
$check = trim(str_ireplace('hex-string:', '', $result));
|
||||||
|
} elseif (str_starts_with($compare, 'hex-')) {
|
||||||
|
$check = trim(str_ireplace('hex-', '', $result));
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -145,7 +145,7 @@ if (cacti_sizeof($parms)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for an invalid run location
|
// check for an invalid run location
|
||||||
if ($poller_id == 1 && !defined('PHP_STAN')) {
|
if ($poller_id == 1 && !defined('PHP_TESTING')) {
|
||||||
print "ERROR: This command is only to be run on remote Cacti Data Collectors\n";
|
print "ERROR: This command is only to be run on remote Cacti Data Collectors\n";
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
include(__DIR__ . '/include/vendor/autoload.php');
|
||||||
|
|
||||||
use Rector\Config\RectorConfig;
|
use Rector\Config\RectorConfig;
|
||||||
use Rector\Php54\Rector\Array_\LongArrayToShortArrayRector;
|
use Rector\Php54\Rector\Array_\LongArrayToShortArrayRector;
|
||||||
|
|
||||||
|
|||||||
@@ -65,11 +65,11 @@ function ss_cpoller(string $cmd = 'index', string $arg1 = '', string $arg2 = '')
|
|||||||
} elseif ($cmd == 'get') {
|
} elseif ($cmd == 'get') {
|
||||||
$arg = $arg1;
|
$arg = $arg1;
|
||||||
$index = $arg2;
|
$index = $arg2;
|
||||||
$value = '0';
|
$value = 'U';
|
||||||
|
|
||||||
switch($arg) {
|
switch($arg) {
|
||||||
case 'recacheTime':
|
case 'recacheTime':
|
||||||
$value = '0';
|
$value = 'U';
|
||||||
$stats = explode(' ', db_fetch_cell_prepared('SELECT value FROM settings WHERE name = ?', ['stats_recache_' . $index]));
|
$stats = explode(' ', db_fetch_cell_prepared('SELECT value FROM settings WHERE name = ?', ['stats_recache_' . $index]));
|
||||||
|
|
||||||
foreach ($stats as $_stat) {
|
foreach ($stats as $_stat) {
|
||||||
@@ -81,7 +81,7 @@ function ss_cpoller(string $cmd = 'index', string $arg1 = '', string $arg2 = '')
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case 'recacheDevices':
|
case 'recacheDevices':
|
||||||
$value = '0';
|
$value = 'U';
|
||||||
$stats = explode(' ', db_fetch_cell_prepared('SELECT value FROM settings WHERE name = ?', ['stats_recache_' . $index]));
|
$stats = explode(' ', db_fetch_cell_prepared('SELECT value FROM settings WHERE name = ?', ['stats_recache_' . $index]));
|
||||||
|
|
||||||
foreach ($stats as $_stat) {
|
foreach ($stats as $_stat) {
|
||||||
@@ -167,7 +167,7 @@ function ss_cpoller(string $cmd = 'index', string $arg1 = '', string $arg2 = '')
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ($value == '' ? '0' : $value);
|
return ($value == '' ? 'U' : $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'U';
|
return 'U';
|
||||||
|
|||||||
@@ -62,13 +62,13 @@ function ss_hstats(int $host_id = 0, string $stat = '') : string {
|
|||||||
$column = ss_hstats_map_stat_to_column($stat);
|
$column = ss_hstats_map_stat_to_column($stat);
|
||||||
|
|
||||||
if ($column === null) {
|
if ($column === null) {
|
||||||
return '0';
|
return 'U';
|
||||||
}
|
}
|
||||||
|
|
||||||
$allowed = ['polling_time', 'min_time', 'max_time', 'cur_time', 'avg_time', 'snmp_sysUpTimeInstance', 'failed_polls', 'availability', 'current_errors'];
|
$allowed = ['polling_time', 'min_time', 'max_time', 'cur_time', 'avg_time', 'snmp_sysUpTimeInstance', 'failed_polls', 'availability', 'current_errors'];
|
||||||
|
|
||||||
if (!in_array($column, $allowed, true)) {
|
if (!in_array($column, $allowed, true)) {
|
||||||
return '0';
|
return 'U';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($host_id > 0) {
|
if ($host_id > 0) {
|
||||||
@@ -82,5 +82,5 @@ function ss_hstats(int $host_id = 0, string $stat = '') : string {
|
|||||||
return ($value == '' ? 'U' : $value);
|
return ($value == '' ? 'U' : $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return '0';
|
return 'U';
|
||||||
}
|
}
|
||||||
@@ -31,11 +31,11 @@ if (!isset($called_by_script_server)) {
|
|||||||
print call_user_func_array('ss_mikrotik_health', $_SERVER['argv']);
|
print call_user_func_array('ss_mikrotik_health', $_SERVER['argv']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ss_mikrotik_health(int $host_id = 0, string $column = 'no') : string {
|
function ss_mikrotik_health(mixed $host_id = 0, string $column = 'no') : string {
|
||||||
$allowed_columns = ['voltage', 'temperature', 'processorTemperature', 'current', 'power', 'fanSpeed', 'cpuFrequency'];
|
$allowed_columns = ['voltage', 'temperature', 'processorTemperature', 'current', 'power', 'fanSpeed', 'cpuFrequency'];
|
||||||
|
|
||||||
if (!in_array($column, $allowed_columns, true)) {
|
if (!in_array($column, $allowed_columns, true)) {
|
||||||
return '0';
|
return 'U';
|
||||||
}
|
}
|
||||||
|
|
||||||
$value = db_fetch_cell_prepared("SELECT $column
|
$value = db_fetch_cell_prepared("SELECT $column
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ function ss_mikrotik_interfaces(int $host_id, string $cmd = 'index', string $arg
|
|||||||
|
|
||||||
function ss_mikrotik_interfaces_getvalue(int $host_id, string $index, string $column) : string {
|
function ss_mikrotik_interfaces_getvalue(int $host_id, string $index, string $column) : string {
|
||||||
if (!preg_match('/^[a-zA-Z0-9_]+$/', $column)) {
|
if (!preg_match('/^[a-zA-Z0-9_]+$/', $column)) {
|
||||||
return '0';
|
return 'U';
|
||||||
}
|
}
|
||||||
|
|
||||||
$column = 'cur' . $column;
|
$column = 'cur' . $column;
|
||||||
@@ -72,7 +72,7 @@ function ss_mikrotik_interfaces_getvalue(int $host_id, string $index, string $co
|
|||||||
];
|
];
|
||||||
|
|
||||||
if (!in_array($column, $allowed_columns, true)) {
|
if (!in_array($column, $allowed_columns, true)) {
|
||||||
return '0';
|
return 'U';
|
||||||
}
|
}
|
||||||
|
|
||||||
$index2 = str_replace('_', ' ', $index);
|
$index2 = str_replace('_', ' ', $index);
|
||||||
@@ -85,7 +85,7 @@ function ss_mikrotik_interfaces_getvalue(int $host_id, string $index, string $co
|
|||||||
[$index, $index2, $host_id]);
|
[$index, $index2, $host_id]);
|
||||||
|
|
||||||
if ($value === false) {
|
if ($value === false) {
|
||||||
return '0';
|
return 'U';
|
||||||
} else {
|
} else {
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,13 +92,13 @@ function ss_mikrotik_queues_getvalue(int $host_id, string $index, string $column
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return '0';
|
return 'U';
|
||||||
}
|
}
|
||||||
|
|
||||||
$allowed_columns = ['curBytesIn', 'curBytesOut', 'curPacketsIn', 'curPacketsOut', 'curQueuesIn', 'curQueuesOut', 'curDroppedIn', 'curDroppedOut'];
|
$allowed_columns = ['curBytesIn', 'curBytesOut', 'curPacketsIn', 'curPacketsOut', 'curQueuesIn', 'curQueuesOut', 'curDroppedIn', 'curDroppedOut'];
|
||||||
|
|
||||||
if (!in_array($column, $allowed_columns, true)) {
|
if (!in_array($column, $allowed_columns, true)) {
|
||||||
return '0';
|
return 'U';
|
||||||
}
|
}
|
||||||
|
|
||||||
$index2 = str_replace('_', ' ', $index);
|
$index2 = str_replace('_', ' ', $index);
|
||||||
@@ -111,7 +111,7 @@ function ss_mikrotik_queues_getvalue(int $host_id, string $index, string $column
|
|||||||
[$index, $index2, $host_id]);
|
[$index, $index2, $host_id]);
|
||||||
|
|
||||||
if ($value === false) {
|
if ($value === false) {
|
||||||
return '0';
|
return 'U';
|
||||||
} else {
|
} else {
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,35 +13,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shared stubs for Cacti helper functions used by production code.
|
* We set a testing variable such that Cacti will not attempt
|
||||||
* These replicate the production signatures so that test stubs
|
* to connect to a database when the tests are called, or to call
|
||||||
* can call them without loading the full Cacti environment.
|
* any function that will result in the failure due to the lack
|
||||||
|
* of a real database connection.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function cacti_sizeof($value): int {
|
define('PHP_TESTING', true);
|
||||||
if (is_array($value)) {
|
|
||||||
return sizeof($value);
|
|
||||||
} elseif ($value instanceof Countable) {
|
|
||||||
return count($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function cacti_count($value): int {
|
|
||||||
if (is_array($value)) {
|
|
||||||
return count($value);
|
|
||||||
} elseif ($value instanceof Countable) {
|
|
||||||
return count($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function __($text) {
|
|
||||||
return $text;
|
|
||||||
}
|
|
||||||
|
|
||||||
function __esc($text) {
|
|
||||||
return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
|
|
||||||
}
|
|
||||||
@@ -29,8 +29,8 @@
|
|||||||
* 3. HRULE item pparts[3] replacement (aggregate_graphs_insert_graph_items)
|
* 3. HRULE item pparts[3] replacement (aggregate_graphs_insert_graph_items)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
define('AGGREGATE_TOTAL_TYPE_SIMILAR', 1);
|
require_once dirname(__DIR__) . '/Helpers/CactiStubs.php';
|
||||||
define('AGGREGATE_TOTAL_TYPE_ALL', 2);
|
require_once dirname(__DIR__, 2) . '/include/global.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mimics the text_format :current: / :max: replacement logic from
|
* Mimics the text_format :current: / :max: replacement logic from
|
||||||
|
|||||||
@@ -16,15 +16,15 @@
|
|||||||
* Tests for XSS fix in auth_resetpassword.php.
|
* Tests for XSS fix in auth_resetpassword.php.
|
||||||
*
|
*
|
||||||
* The hash value in hidden form inputs was output without escaping. The fix
|
* The hash value in hidden form inputs was output without escaping. The fix
|
||||||
* wraps gnrv('hash') with htmle() to prevent XSS when the hash is reflected.
|
* wraps $_REQUEST['hash'] with htmlerv() to prevent XSS when the hash is reflected.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$authPath = __DIR__ . '/../../auth_resetpassword.php';
|
$authPath = __DIR__ . '/../../auth_resetpassword.php';
|
||||||
|
|
||||||
// --- auth_resetpassword.php: hash escaped in output ---
|
// --- auth_resetpassword.php: hash escaped in output ---
|
||||||
|
|
||||||
test('auth_resetpassword.php escapes hash with htmle', function () use ($authPath) {
|
test('auth_resetpassword.php escapes hash with htmlerv', function () use ($authPath) {
|
||||||
$contents = file_get_contents($authPath);
|
$contents = file_get_contents($authPath);
|
||||||
|
|
||||||
expect($contents)->toContain("htmle(gnrv('hash'))");
|
expect($contents)->toContain("htmlerv('hash')");
|
||||||
});
|
});
|
||||||
@@ -12,32 +12,8 @@
|
|||||||
+-------------------------------------------------------------------------+
|
+-------------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
require_once dirname(__DIR__) . '/Helpers/CactiStubs.php';
|
||||||
* Tests for exec_with_timeout() in lib/poller.php.
|
require_once dirname(__DIR__, 2) . '/include/global.php';
|
||||||
*
|
|
||||||
* Covers three bugs fixed in commit c58f8d940:
|
|
||||||
* 1. Operator precedence: (int) cast bound tighter than multiplication,
|
|
||||||
* truncating the elapsed-time float to 0 before scaling to microseconds.
|
|
||||||
* 2. stderr discard: any stderr output caused an early `return false`,
|
|
||||||
* throwing away valid stdout data.
|
|
||||||
* 3. Orphaned children: no process-group kill before proc_terminate.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Stub cacti_log so lib/poller.php can call it without the full framework.
|
|
||||||
if (!function_exists('cacti_log')) {
|
|
||||||
function cacti_log(string $msg, bool $output = false, string $facility = '', int $level = 0): void {
|
|
||||||
// no-op for tests
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!defined('POLLER_VERBOSITY_MEDIUM')) {
|
|
||||||
define('POLLER_VERBOSITY_MEDIUM', 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!defined('CACTI_SERVER_OS')) {
|
|
||||||
define('CACTI_SERVER_OS', PHP_OS === 'WINNT' ? 'win32' : 'unix');
|
|
||||||
}
|
|
||||||
|
|
||||||
require_once dirname(__DIR__, 2) . '/lib/poller.php';
|
require_once dirname(__DIR__, 2) . '/lib/poller.php';
|
||||||
|
|
||||||
// --- Bug 1: operator precedence in timeout microsecond conversion ---
|
// --- Bug 1: operator precedence in timeout microsecond conversion ---
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
+-------------------------------------------------------------------------+
|
+-------------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once __DIR__ . '/../../lib/functions.php';
|
require_once dirname(__DIR__) . '/Helpers/CactiStubs.php';
|
||||||
|
require_once dirname(__DIR__, 2) . '/include/global.php';
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
unset(
|
unset(
|
||||||
@@ -27,6 +28,7 @@ beforeEach(function () {
|
|||||||
|
|
||||||
test('returns REMOTE_ADDR when proxy_headers is false', function () {
|
test('returns REMOTE_ADDR when proxy_headers is false', function () {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
$config['proxy_headers'] = false;
|
$config['proxy_headers'] = false;
|
||||||
|
|
||||||
$_SERVER['REMOTE_ADDR'] = '192.168.1.100';
|
$_SERVER['REMOTE_ADDR'] = '192.168.1.100';
|
||||||
@@ -36,6 +38,7 @@ test('returns REMOTE_ADDR when proxy_headers is false', function () {
|
|||||||
|
|
||||||
test('returns false when no server variables are set', function () {
|
test('returns false when no server variables are set', function () {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
$config['proxy_headers'] = false;
|
$config['proxy_headers'] = false;
|
||||||
|
|
||||||
expect(get_client_addr())->toBeFalse();
|
expect(get_client_addr())->toBeFalse();
|
||||||
@@ -43,6 +46,9 @@ test('returns false when no server variables are set', function () {
|
|||||||
|
|
||||||
test('returns first valid IP from X-Forwarded-For when proxy_headers enabled', function () {
|
test('returns first valid IP from X-Forwarded-For when proxy_headers enabled', function () {
|
||||||
global $config, $allowed_proxy_headers;
|
global $config, $allowed_proxy_headers;
|
||||||
|
|
||||||
|
require __DIR__ . '/../../include/global_arrays.php';
|
||||||
|
|
||||||
$config['proxy_headers'] = true;
|
$config['proxy_headers'] = true;
|
||||||
|
|
||||||
$_SERVER['HTTP_X_FORWARDED_FOR'] = '10.0.0.1,10.0.0.2';
|
$_SERVER['HTTP_X_FORWARDED_FOR'] = '10.0.0.1,10.0.0.2';
|
||||||
@@ -53,6 +59,9 @@ test('returns first valid IP from X-Forwarded-For when proxy_headers enabled', f
|
|||||||
|
|
||||||
test('skips invalid IPs in forwarded header', function () {
|
test('skips invalid IPs in forwarded header', function () {
|
||||||
global $config, $allowed_proxy_headers;
|
global $config, $allowed_proxy_headers;
|
||||||
|
|
||||||
|
require __DIR__ . '/../../include/global_arrays.php';
|
||||||
|
|
||||||
$config['proxy_headers'] = true;
|
$config['proxy_headers'] = true;
|
||||||
|
|
||||||
$_SERVER['HTTP_X_FORWARDED_FOR'] = 'not-an-ip,203.0.113.50';
|
$_SERVER['HTTP_X_FORWARDED_FOR'] = 'not-an-ip,203.0.113.50';
|
||||||
@@ -63,6 +72,9 @@ test('skips invalid IPs in forwarded header', function () {
|
|||||||
|
|
||||||
test('falls back to REMOTE_ADDR when forwarded header has only invalid IPs', function () {
|
test('falls back to REMOTE_ADDR when forwarded header has only invalid IPs', function () {
|
||||||
global $config, $allowed_proxy_headers;
|
global $config, $allowed_proxy_headers;
|
||||||
|
|
||||||
|
require __DIR__ . '/../../include/global_arrays.php';
|
||||||
|
|
||||||
$config['proxy_headers'] = true;
|
$config['proxy_headers'] = true;
|
||||||
|
|
||||||
$_SERVER['HTTP_X_FORWARDED_FOR'] = 'garbage';
|
$_SERVER['HTTP_X_FORWARDED_FOR'] = 'garbage';
|
||||||
@@ -73,6 +85,7 @@ test('falls back to REMOTE_ADDR when forwarded header has only invalid IPs', fun
|
|||||||
|
|
||||||
test('ignores proxy headers when proxy_headers is false', function () {
|
test('ignores proxy headers when proxy_headers is false', function () {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
$config['proxy_headers'] = false;
|
$config['proxy_headers'] = false;
|
||||||
|
|
||||||
$_SERVER['HTTP_X_FORWARDED_FOR'] = '10.0.0.1';
|
$_SERVER['HTTP_X_FORWARDED_FOR'] = '10.0.0.1';
|
||||||
@@ -83,6 +96,7 @@ test('ignores proxy headers when proxy_headers is false', function () {
|
|||||||
|
|
||||||
test('supports IPv6 addresses', function () {
|
test('supports IPv6 addresses', function () {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
$config['proxy_headers'] = false;
|
$config['proxy_headers'] = false;
|
||||||
|
|
||||||
$_SERVER['REMOTE_ADDR'] = '::1';
|
$_SERVER['REMOTE_ADDR'] = '::1';
|
||||||
@@ -92,6 +106,7 @@ test('supports IPv6 addresses', function () {
|
|||||||
|
|
||||||
test('handles array proxy_headers config with specific headers allowed', function () {
|
test('handles array proxy_headers config with specific headers allowed', function () {
|
||||||
global $config, $allowed_proxy_headers;
|
global $config, $allowed_proxy_headers;
|
||||||
|
|
||||||
$config['proxy_headers'] = ['HTTP_CLIENT_IP'];
|
$config['proxy_headers'] = ['HTTP_CLIENT_IP'];
|
||||||
|
|
||||||
$_SERVER['HTTP_CLIENT_IP'] = '10.10.10.10';
|
$_SERVER['HTTP_CLIENT_IP'] = '10.10.10.10';
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
+-------------------------------------------------------------------------+
|
+-------------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
require_once dirname(__DIR__) . '/Helpers/CactiStubs.php';
|
||||||
|
require_once dirname(__DIR__, 2) . '/include/global.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for PR #6702: Verify CACTI_PATH_MIBS constant is defined
|
* Test for PR #6702: Verify CACTI_PATH_MIBS constant is defined
|
||||||
*/
|
*/
|
||||||
@@ -19,10 +22,6 @@
|
|||||||
test('CACTI_PATH_MIBS constant is defined in global_path.php', function () {
|
test('CACTI_PATH_MIBS constant is defined in global_path.php', function () {
|
||||||
// Simulate config array that would be set before including global_path.php
|
// Simulate config array that would be set before including global_path.php
|
||||||
global $config;
|
global $config;
|
||||||
$config['mibs_path'] = '/usr/share/snmp/mibs';
|
|
||||||
|
|
||||||
// Include the file that defines path constants
|
|
||||||
require_once __DIR__ . '/../../include/global_path.php';
|
|
||||||
|
|
||||||
expect(defined('CACTI_PATH_MIBS'))
|
expect(defined('CACTI_PATH_MIBS'))
|
||||||
->toBeTrue('CACTI_PATH_MIBS constant should be defined');
|
->toBeTrue('CACTI_PATH_MIBS constant should be defined');
|
||||||
@@ -30,10 +29,8 @@ test('CACTI_PATH_MIBS constant is defined in global_path.php', function () {
|
|||||||
|
|
||||||
test('CACTI_PATH_MIBS uses mibs_path from config', function () {
|
test('CACTI_PATH_MIBS uses mibs_path from config', function () {
|
||||||
global $config;
|
global $config;
|
||||||
$expectedPath = '/usr/share/snmp/mibs';
|
|
||||||
$config['mibs_path'] = $expectedPath;
|
|
||||||
|
|
||||||
require_once __DIR__ . '/../../include/global_path.php';
|
$expectedPath = CACTI_PATH_BASE . '/mibs';
|
||||||
|
|
||||||
expect(CACTI_PATH_MIBS)
|
expect(CACTI_PATH_MIBS)
|
||||||
->toBe($expectedPath, 'CACTI_PATH_MIBS should match config mibs_path');
|
->toBe($expectedPath, 'CACTI_PATH_MIBS should match config mibs_path');
|
||||||
@@ -41,9 +38,6 @@ test('CACTI_PATH_MIBS uses mibs_path from config', function () {
|
|||||||
|
|
||||||
test('CACTI_PATH_MIBS constant matches other CACTI_PATH_ patterns', function () {
|
test('CACTI_PATH_MIBS constant matches other CACTI_PATH_ patterns', function () {
|
||||||
global $config;
|
global $config;
|
||||||
$config['mibs_path'] = '/usr/share/snmp/mibs';
|
|
||||||
|
|
||||||
require_once __DIR__ . '/../../include/global_path.php';
|
|
||||||
|
|
||||||
// Verify it follows the same pattern as other path constants
|
// Verify it follows the same pattern as other path constants
|
||||||
expect(defined('CACTI_PATH_MIBS'))
|
expect(defined('CACTI_PATH_MIBS'))
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
require_once dirname(__DIR__) . '/Helpers/CactiStubs.php';
|
require_once dirname(__DIR__) . '/Helpers/CactiStubs.php';
|
||||||
require_once dirname(__DIR__, 2) . '/lib/functions.php';
|
require_once dirname(__DIR__, 2) . '/include/global.php';
|
||||||
require_once dirname(__DIR__, 2) . '/lib/xml.php';
|
require_once dirname(__DIR__, 2) . '/lib/xml.php';
|
||||||
|
|
||||||
// --- rrdxport2array: valid xport XML produces correct structure ---
|
// --- rrdxport2array: valid xport XML produces correct structure ---
|
||||||
|
|||||||
@@ -12,71 +12,8 @@
|
|||||||
+-------------------------------------------------------------------------+
|
+-------------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
require_once dirname(__DIR__) . '/Helpers/CactiStubs.php';
|
||||||
* Tests for XSS defense functions from lib/html.php.
|
require_once dirname(__DIR__, 2) . '/include/global.php';
|
||||||
*
|
|
||||||
* Each function under test is replicated as an inline stub that mirrors
|
|
||||||
* the production logic, allowing verification without loading the full
|
|
||||||
* Cacti environment. Functions tested:
|
|
||||||
*
|
|
||||||
* html_escape() - L1355 - core output encoding
|
|
||||||
* html_split_string() - L1386 - long string splitting for display
|
|
||||||
*/
|
|
||||||
|
|
||||||
// --- Stub: html_escape (lib/html.php L1355) ---
|
|
||||||
|
|
||||||
function html_escape(mixed $string = ''): string {
|
|
||||||
static $charset;
|
|
||||||
|
|
||||||
if ($charset == '') {
|
|
||||||
$charset = ini_get('default_charset');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($charset == '') {
|
|
||||||
$charset = 'UTF-8';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($string != '') {
|
|
||||||
$string = str_replace('`', '`', $string);
|
|
||||||
|
|
||||||
return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5, $charset, false);
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Stub: html_split_string (lib/html.php L1386) ---
|
|
||||||
|
|
||||||
function html_split_string(string $string, int $length = 90, int $forgiveness = 10): string {
|
|
||||||
$new_string = '';
|
|
||||||
$j = 0;
|
|
||||||
$done = false;
|
|
||||||
|
|
||||||
while (!$done) {
|
|
||||||
if (mb_strlen($string, 'UTF-8') > $length) {
|
|
||||||
for ($i = 0; $i < $forgiveness; $i++) {
|
|
||||||
if (substr($string, $length - $i, 1) == ' ') {
|
|
||||||
$new_string .= mb_substr($string, 0, $length - $i, 'UTF-8') . '<br>';
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$string = mb_substr($string, $length - $i, null, 'UTF-8');
|
|
||||||
} else {
|
|
||||||
$new_string .= $string;
|
|
||||||
$done = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$j++;
|
|
||||||
|
|
||||||
if ($j > 4) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $new_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// html_escape tests
|
// html_escape tests
|
||||||
|
|||||||
@@ -37,7 +37,8 @@
|
|||||||
* guard_foreach_iterable() - array|false before foreach
|
* guard_foreach_iterable() - array|false before foreach
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once __DIR__ . '/../Helpers/CactiStubs.php';
|
require_once dirname(__DIR__) . '/Helpers/CactiStubs.php';
|
||||||
|
require_once dirname(__DIR__, 2) . '/include/global.php';
|
||||||
|
|
||||||
// --- Stub: guard_db_result_access (pattern from multiple graph/data files) ---
|
// --- Stub: guard_db_result_access (pattern from multiple graph/data files) ---
|
||||||
// Mirrors: $row = db_fetch_row_prepared(...); returns array|bool.
|
// Mirrors: $row = db_fetch_row_prepared(...); returns array|bool.
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
+-------------------------------------------------------------------------+
|
+-------------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
require_once dirname(__DIR__) . '/Helpers/CactiStubs.php';
|
||||||
|
require_once __DIR__ . '/../../include/global.php';
|
||||||
require_once __DIR__ . '/../../lib/functions.php';
|
require_once __DIR__ . '/../../lib/functions.php';
|
||||||
|
|
||||||
// --- get_current_script_name ---
|
// --- get_current_script_name ---
|
||||||
|
|||||||
@@ -15,44 +15,47 @@
|
|||||||
/*
|
/*
|
||||||
* Tests for column allow-list and SNMP retry parameter hardening.
|
* Tests for column allow-list and SNMP retry parameter hardening.
|
||||||
* These scripts require DB + SNMP, so we test the allow-list guard
|
* These scripts require DB + SNMP, so we test the allow-list guard
|
||||||
* by calling with host_id=0 (returns '0' early) and verifying that
|
* by calling with host_id=0 (returns 'U' early) and verifying that
|
||||||
* invalid columns are rejected before reaching any SQL.
|
* invalid columns are rejected before reaching any SQL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once __DIR__ . '/../../lib/functions.php';
|
$called_by_script_server = true;
|
||||||
|
|
||||||
|
require_once dirname(__DIR__) . '/Helpers/CactiStubs.php';
|
||||||
|
require_once dirname(__DIR__, 2) . '/include/global.php';
|
||||||
|
|
||||||
// ss_mikrotik_health: column allow-list
|
// ss_mikrotik_health: column allow-list
|
||||||
require_once __DIR__ . '/../../scripts/ss_mikrotik_health.php';
|
require_once __DIR__ . '/../../scripts/ss_mikrotik_health.php';
|
||||||
|
|
||||||
test('ss_mikrotik_health rejects invalid column', function () {
|
test('ss_mikrotik_health rejects invalid column', function () {
|
||||||
expect(ss_mikrotik_health(0, '1; DROP TABLE hosts; --'))->toBe('0');
|
expect(ss_mikrotik_health(0, '1; DROP TABLE hosts; --'))->toBe('U');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ss_mikrotik_health rejects empty column', function () {
|
test('ss_mikrotik_health rejects empty column', function () {
|
||||||
expect(ss_mikrotik_health(0, ''))->toBe('0');
|
expect(ss_mikrotik_health(0, ''))->toBe('U');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ss_mikrotik_health rejects arbitrary column name', function () {
|
test('ss_mikrotik_health rejects arbitrary column name', function () {
|
||||||
expect(ss_mikrotik_health(0, 'password'))->toBe('0');
|
expect(ss_mikrotik_health(0, 'password'))->toBe('U');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ss_mikrotik_health accepts valid column voltage', function () {
|
test('ss_mikrotik_health accepts valid column voltage', function () {
|
||||||
expect(ss_mikrotik_health(0, 'voltage'))->toBe('0');
|
expect(ss_mikrotik_health(0, 'voltage'))->toBe('U');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ss_mikrotik_health accepts valid column temperature', function () {
|
test('ss_mikrotik_health accepts valid column temperature', function () {
|
||||||
expect(ss_mikrotik_health(0, 'temperature'))->toBe('0');
|
expect(ss_mikrotik_health(0, 'temperature'))->toBe('U');
|
||||||
});
|
});
|
||||||
|
|
||||||
// ss_hstats: column mapping via ss_hstats_map_stat_to_column
|
// ss_hstats: column mapping via ss_hstats_map_stat_to_column
|
||||||
require_once __DIR__ . '/../../scripts/ss_hstats.php';
|
require_once __DIR__ . '/../../scripts/ss_hstats.php';
|
||||||
|
|
||||||
test('ss_hstats rejects invalid stat with host_id 0', function () {
|
test('ss_hstats rejects invalid stat with host_id 0', function () {
|
||||||
expect(ss_hstats(0, 'invalid_stat'))->toBe('0');
|
expect(ss_hstats(0, 'invalid_stat'))->toBe('U');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ss_hstats returns 0 for valid stat with host_id 0', function () {
|
test('ss_hstats returns U for valid stat with host_id 0', function () {
|
||||||
expect(ss_hstats(0, 'polling_time'))->toBe('0');
|
expect(ss_hstats(0, 'polling_time'))->toBe('U');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify snmp_retries is referenced (not ping_retries)
|
// Verify snmp_retries is referenced (not ping_retries)
|
||||||
@@ -80,12 +83,6 @@ test('disk io scripts use snmp_retries not ping_retries', function () {
|
|||||||
expect($file)->not->toContain('ping_retries');
|
expect($file)->not->toContain('ping_retries');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('cpoller script uses snmp_retries not ping_retries', function () {
|
|
||||||
$file = file_get_contents(__DIR__ . '/../../scripts/ss_cpoller.php');
|
|
||||||
expect($file)->toContain('snmp_retries');
|
|
||||||
expect($file)->not->toContain('ping_retries');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('lmsensors script uses snmp_retries not ping_retries', function () {
|
test('lmsensors script uses snmp_retries not ping_retries', function () {
|
||||||
$file = file_get_contents(__DIR__ . '/../../scripts/ss_netsnmp_lmsensors.php');
|
$file = file_get_contents(__DIR__ . '/../../scripts/ss_netsnmp_lmsensors.php');
|
||||||
expect($file)->toContain('snmp_retries');
|
expect($file)->toContain('snmp_retries');
|
||||||
|
|||||||
@@ -12,132 +12,8 @@
|
|||||||
+-------------------------------------------------------------------------+
|
+-------------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
require_once dirname(__DIR__) . '/Helpers/CactiStubs.php';
|
||||||
* Tests for deserialization guards and input validation from lib/functions.php.
|
require_once dirname(__DIR__, 2) . '/include/global.php';
|
||||||
*
|
|
||||||
* These functions defend against PHP object injection, rrdtool command
|
|
||||||
* injection, and malformed network addresses. Each is replicated as an
|
|
||||||
* inline stub mirroring production logic.
|
|
||||||
*
|
|
||||||
* sanitize_unserialize_selected_items() - L5002 - PHP object injection defense
|
|
||||||
* sanitize_cdef() - L4988 - rrdtool CDEF/VDEF injection
|
|
||||||
* is_ipaddress() - L7256 - IP address validation
|
|
||||||
* is_mac_address() - L2217 - MAC address validation
|
|
||||||
* is_hex_string() - L2239 - hex string validation
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once __DIR__ . '/../Helpers/CactiStubs.php';
|
|
||||||
|
|
||||||
// --- Stub: sanitize_unserialize_selected_items (lib/functions.php L5002) ---
|
|
||||||
|
|
||||||
function sanitize_unserialize_selected_items(mixed $items): mixed {
|
|
||||||
$return_items = false;
|
|
||||||
|
|
||||||
if (!empty($items) && is_string($items)) {
|
|
||||||
$unstripped = stripslashes($items);
|
|
||||||
|
|
||||||
if (preg_match('/^a:[0-9]+:{/', $unstripped) && !preg_match('/(^|;|{|})O:\+?[0-9]+:"/', $unstripped)) {
|
|
||||||
$items = unserialize($unstripped, ['allowed_classes' => false]);
|
|
||||||
|
|
||||||
if (is_array($items)) {
|
|
||||||
$return_items = $items;
|
|
||||||
|
|
||||||
foreach ($items as $item) {
|
|
||||||
if (is_array($item)) {
|
|
||||||
$return_items = false;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_numeric($item) && ($item != '')) {
|
|
||||||
$return_items = false;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $return_items;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Stub: sanitize_cdef (lib/functions.php L4988) ---
|
|
||||||
|
|
||||||
function sanitize_cdef(string $cdef): string {
|
|
||||||
static $drop_char_match = ['^', '$', '<', '>', '`', '\'', '"', '|', '[', ']', '{', '}', ';', '!'];
|
|
||||||
static $drop_char_replace = ['', '', '', '', '', '', '', '', '', '', '', '', '', ''];
|
|
||||||
|
|
||||||
return str_replace($drop_char_match, $drop_char_replace, $cdef);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Stub: is_ipaddress (lib/functions.php L7256) ---
|
|
||||||
|
|
||||||
function is_ipaddress(string $ip_address = ''): bool {
|
|
||||||
if (function_exists('filter_var')) {
|
|
||||||
if (filter_var($ip_address, FILTER_VALIDATE_IP) !== false) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} elseif (inet_pton($ip_address) !== false) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Stub: is_mac_address (lib/functions.php L2217) ---
|
|
||||||
|
|
||||||
function is_mac_address(string $result): mixed {
|
|
||||||
if (!defined('FILTER_VALIDATE_MAC')) {
|
|
||||||
if (preg_match('/^([0-9a-f]{1,2}[\.:-]) {5}([0-9a-f]{1,2})$/i', $result)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return filter_var($result, FILTER_VALIDATE_MAC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Stub: is_hex_string (lib/functions.php L2239) ---
|
|
||||||
|
|
||||||
function is_hex_string(string &$result): bool {
|
|
||||||
if ($result == '') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$compare = strtolower($result);
|
|
||||||
|
|
||||||
if (str_starts_with($compare, 'hex-string:')) {
|
|
||||||
$check = trim(str_ireplace('hex-string:', '', $result));
|
|
||||||
} elseif (str_starts_with($compare, 'hex-')) {
|
|
||||||
$check = trim(str_ireplace('hex-', '', $result));
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$parts = explode(' ', $check);
|
|
||||||
|
|
||||||
if (cacti_sizeof($parts) == 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($parts as $part) {
|
|
||||||
if (strlen($part) != 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctype_xdigit($part) == false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = $check;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// sanitize_unserialize_selected_items tests
|
// sanitize_unserialize_selected_items tests
|
||||||
|
|||||||
@@ -102,8 +102,8 @@ test('all identity-mapped stats return the stat name as column', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Test ss_hstats() wrapper behavior with host_id=0
|
// Test ss_hstats() wrapper behavior with host_id=0
|
||||||
test('ss_hstats returns zero when host_id is zero', function () {
|
test('ss_hstats returns U when host_id is zero', function () {
|
||||||
expect(ss_hstats(0, 'polling_time'))->toBe('0')
|
expect(ss_hstats(0, 'polling_time'))->toBe('U')
|
||||||
->and(ss_hstats(0, 'uptime'))->toBe('0')
|
->and(ss_hstats(0, 'uptime'))->toBe('U')
|
||||||
->and(ss_hstats(0, 'invalid'))->toBe('0');
|
->and(ss_hstats(0, 'invalid'))->toBe('U');
|
||||||
});
|
});
|
||||||
@@ -12,121 +12,8 @@
|
|||||||
+-------------------------------------------------------------------------+
|
+-------------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
require_once dirname(__DIR__) . '/Helpers/CactiStubs.php';
|
||||||
* Tests for pure string functions from lib/functions.php.
|
require_once dirname(__DIR__, 2) . '/include/global.php';
|
||||||
*
|
|
||||||
* Each function under test is replicated as an inline stub that mirrors
|
|
||||||
* the production logic, allowing verification without loading the full
|
|
||||||
* Cacti environment. Functions tested:
|
|
||||||
*
|
|
||||||
* title_trim() - L37 - string truncation with ellipsis
|
|
||||||
* sanitize_search_string() - L4908 - XSS-relevant character stripping
|
|
||||||
* clean_up_lines() - L3105 - line ending normalization
|
|
||||||
* clean_up_name() - L3121 - name sanitization
|
|
||||||
* clean_up_file_name() - L3139 - filename sanitization
|
|
||||||
* is_valid_pathname() - L2372 - path traversal guard
|
|
||||||
* is_base64_encoded() - L4959 - encoding validation
|
|
||||||
* generate_hash() - L4779 - format validation (random output)
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once __DIR__ . '/../Helpers/CactiStubs.php';
|
|
||||||
|
|
||||||
// --- Stub: title_trim (lib/functions.php L37) ---
|
|
||||||
|
|
||||||
function title_trim(string $text, int $max_length): string {
|
|
||||||
if (strlen($text) > $max_length) {
|
|
||||||
return mb_substr($text, 0, $max_length) . '...';
|
|
||||||
} else {
|
|
||||||
return $text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Stub: sanitize_search_string (lib/functions.php L4908) ---
|
|
||||||
|
|
||||||
function sanitize_search_string(string $string): string {
|
|
||||||
static $drop_char_match = ['(', ')', '^', '$', '<', '>', '`', '\'', '"', '|', ',', '?', '+', '[', ']', '{', '}', '#', ';', '!', '=', '*'];
|
|
||||||
static $drop_char_replace = ['', '', ' ', ' ', ' ', ' ', '', '', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '];
|
|
||||||
|
|
||||||
$string = preg_replace('/[\n\r]/is', ' ', $string);
|
|
||||||
$string = preg_replace('/\b&[a-z]+;\b/', ' ', $string);
|
|
||||||
$string = preg_replace('/\b[a-z0-9]+:\/\/[a-z0-9\.\-]+(\/[a-z0-9\?\.%_\-\+=&\/]+)?/', ' ', $string);
|
|
||||||
|
|
||||||
for ($i = 0; $i < cacti_count($drop_char_match); $i++) {
|
|
||||||
$string = str_replace($drop_char_match[$i], $drop_char_replace[$i], $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Stub: clean_up_lines (lib/functions.php L3105) ---
|
|
||||||
|
|
||||||
function clean_up_lines(mixed $string): mixed {
|
|
||||||
if ($string !== null) {
|
|
||||||
$string = preg_replace('/\s*[\r\n]+\s*/', ' ', $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Stub: clean_up_name (lib/functions.php L3121) ---
|
|
||||||
|
|
||||||
function clean_up_name(mixed $string): mixed {
|
|
||||||
if ($string !== null) {
|
|
||||||
$string = preg_replace('/[\s\.]+/', '_', $string);
|
|
||||||
$string = preg_replace('/[^a-zA-Z0-9_]+/', '', $string);
|
|
||||||
$string = preg_replace('/_{2,}/', '_', $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Stub: clean_up_file_name (lib/functions.php L3139) ---
|
|
||||||
|
|
||||||
function clean_up_file_name(mixed $string): mixed {
|
|
||||||
if ($string !== null) {
|
|
||||||
$string = preg_replace('/[\s\.]+/', '_', $string);
|
|
||||||
$string = preg_replace('/[^a-zA-Z0-9_-]+/', '', $string);
|
|
||||||
$string = preg_replace('/_{2,}/', '_', $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Stub: is_valid_pathname (lib/functions.php L2372) ---
|
|
||||||
|
|
||||||
function is_valid_pathname($path) {
|
|
||||||
if (preg_match('/^([a-zA-Z0-9\_\.\-\\\:\/]+)$/', trim($path))) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Stub: is_base64_encoded (lib/functions.php L4959) ---
|
|
||||||
|
|
||||||
function is_base64_encoded($data) {
|
|
||||||
if (!preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $data)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$ndata = base64_decode($data, true);
|
|
||||||
|
|
||||||
if ($ndata === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (base64_encode($ndata) != $data) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Stub: generate_hash (lib/functions.php L4779) ---
|
|
||||||
|
|
||||||
function generate_hash(): string {
|
|
||||||
return bin2hex(random_bytes(16));
|
|
||||||
}
|
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// title_trim tests
|
// title_trim tests
|
||||||
|
|||||||
Reference in new issue
Block a user