diff --git a/CHANGELOG.md b/CHANGELOG.md index c3c3172..9c9695b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ --- develop --- * bug: Pass a boolean (not the integer 1) to api_plugin_register_hook()'s $enable argument so the hook registration stays type-correct under Cacti 1.3's strict bool type-hint (the int only coerces while the file lacks declare(strict_types=1)) +* bug: Replace the audit_utilities_array() CACTI_VERSION gate with a 1.3 feature-detect (CactiTableFilter), so a develop build that reports a version comparing < 1.3.0 no longer adds the Audit Log Utilities-page entry a second time (nor runs array_merge() against an unset Technical Support section) when 1.3 already lists it via config_arrays * bug: Skip audit logging on CLI/poller requests until the `request_status` column exists, instead of emitting "Unknown column 'request_status'" errors when the audit_log schema migration (which only runs on plugins.php/audit.php page loads) has not yet applied; likewise make the shutdown-time request finalizer (`audit_finalize_request()`), which writes `request_status`, best-effort (its writes pass `$log = false`) so it fails quietly instead of logging "Table 'audit_log' doesn't exist" when the table was dropped (e.g. plugin uninstall) after `db_table_exists()`'s request-scoped cache was primed * dev: Enforce patch coverage of changed lines in CI and remove the inert COMPOSER_ROOT_VERSION env from the Pest step * dev: Relocate the schema/DB provisioning helpers (`audit_setup_table()`, `audit_setup_syslog_table()`, `audit_setup_user_log_state_table()`, `audit_upgrade_event_schema()`, and the user_log index helpers) from `setup.php` into `includes/database.php` to align with the fleet schema/includes convention, and add a root `manifest.json` with upgrade-time file pruning (`audit_prune_files()`) plus a CI manifest drift check (`tests/bin/validate-manifest.php`) diff --git a/setup.php b/setup.php index 334676d..4be257d 100644 --- a/setup.php +++ b/setup.php @@ -633,10 +633,14 @@ function audit_log_valid_event(): bool { function audit_utilities_array(): void { global $utilities; - if (version_compare(CACTI_VERSION, '1.3.0', '<')) { + // Cacti 1.3+ adds the Audit Log link through config_arrays instead of this + // legacy Utilities hook. Detect 1.3 via a class it introduced rather than a + // CACTI_VERSION string (a develop build can report < 1.3.0) so the entry is + // not added a second time. + if (!class_exists('CactiTableFilter')) { if (api_plugin_user_realm_auth('audit.php')) { $utilities[__('Technical Support', 'audit')] = array_merge( - $utilities[__('Technical Support', 'audit')], + $utilities[__('Technical Support', 'audit')] ?? [], [ __('View Audit Log', 'audit') => [ 'link' => 'plugins/audit/audit.php', diff --git a/tests/Unit/AuditUtilitiesArrayTest.php b/tests/Unit/AuditUtilitiesArrayTest.php new file mode 100644 index 0000000..1a82f36 --- /dev/null +++ b/tests/Unit/AuditUtilitiesArrayTest.php @@ -0,0 +1,73 @@ +toHaveKey($section); + expect($GLOBALS['utilities'][$section])->toHaveKey(__('View Audit Log', 'audit')); + expect($GLOBALS['utilities'][$section][__('View Audit Log', 'audit')]['link']) + ->toBe('plugins/audit/audit.php'); +}); + +it('preserves existing Technical Support entries when access is granted', function () { + $GLOBALS['__audit_test_realms']['audit.php'] = true; + + $section = __('Technical Support', 'audit'); + $existing = __('Existing Entry', 'audit'); + + $GLOBALS['utilities'][$section] = [ + $existing => ['link' => 'plugins/other/other.php'], + ]; + + audit_utilities_array(); + + expect($GLOBALS['utilities'][$section])->toHaveKey($existing); + expect($GLOBALS['utilities'][$section][$existing]['link'])->toBe('plugins/other/other.php'); + expect($GLOBALS['utilities'][$section])->toHaveKey(__('View Audit Log', 'audit')); +}); + +it('adds nothing when the user lacks audit.php realm access', function () { + $section = __('Technical Support', 'audit'); + + $GLOBALS['utilities'][$section] = []; + + audit_utilities_array(); + + expect($GLOBALS['utilities'][$section])->toBe([]); + expect($GLOBALS['utilities'][$section])->not->toHaveKey(__('View Audit Log', 'audit')); +});