mirror of
https://github.com/Cacti/cacti.git
synced 2026-10-29 16:17:14 +09:00
develop
24
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6254b2c17d |
fix(package): name template archives without export-form fields (#8431)
* fix(packaging): name archives from supplied metadata Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(packaging): make archive leaf-name confinement explicit Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(e2e): move the pointer off the Deepness multiselect button Deepness sets a zero body margin, so the unhovered #ms-button sits at the viewport origin and headless Chromium on Linux intermittently applies :hover to it. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: pull pinned integration database from authenticated mirror Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
2761fdc226 |
fix(rrd): [develop] retain source identity after CF fallback (#8339)
* fix(rrd): [develop] retain source identity after CF fallback Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: measure native consolidation fallback coverage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
1997691de0 |
Render RRDtool Tune Info as balanced div boxes and POST the Data Source repair actions (#8412)
* data_sources: render RRDtool Tune Info as balanced div boxes rrdtool_tune() emitted an unbalanced mix of html_header() and html_end_box() calls wrapped around raw table rows inside the single box opened by data_sources.php. The premature and extra closing tags corrupted the DOM, which (depending on theme) clipped the Save button at the bottom of the Data Source edit page while in Data Source Info mode. - Separate the execute, CLI and HTML code paths in rrdtool_tune() and, for HTML, render each section as a self contained, balanced div box. - Extract and rename the helper print_leaves() to the standalone rrdtool_tune_print_leaves(), matching the rrdtool_tune_* naming convention, and emit div rows instead of table rows. - Switch the data_sources.php wrapper box to div mode to match. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * data_debug: require POST for the Data Source repair actions Applying RRDfile repairs and rerunning the debugger are state changing operations, so they should not be reachable with a GET. Driving them through a GET also meant the follow up redirect was pulled into the content area as a full page, losing the theme and navigation on rerender. Register data_debug.php run_repair and run_debug in the cactiIsPostActionUrl() allowlist so loadUrl() upgrades them to a token-bearing POST, and add the matching csrf_require_post() guard so the browser transport and server side guard stay in sync. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * rrd: split rrdtool_tune into testable render and execute helpers Break rrdtool_tune() into small single-purpose helpers so each path can be exercised directly by unit tests (the web display path is otherwise unreachable under CACTI_CLI): - rrdtool_tune_print_leaves() takes an explicit $html flag instead of branching on CACTI_CLI, so both the div and plain-text branches are testable. - rrdtool_tune_execute() applies the tune/resize commands for a repair. - rrdtool_tune_print_cli() prints the source commands as plain text. - rrdtool_tune_print_html() renders the balanced div boxes. - rrdtool_tune() becomes a thin dispatcher over the three. Add tests/Unit/RrdTuneRenderTest.php covering the leaf printer, the HTML and CLI printers, the execute path and the dispatcher, asserting the output is balanced div markup with no table rows. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * review: post Data Source Troubleshooter actions via cactiPostAction Address PR review feedback: - Switch the Apply Suggested Fixes and Rerun Analysis links to the existing cactiPostAction/data-url idiom (as data_sources.php already does for ds_repair) instead of upgrading a loadUrl() GET through the cactiIsPostActionUrl allowlist. The allowlist path replayed the query-free mutation URL into browser history, so a refresh reopened the list instead of the selected Data Source; a full cactiPostAction submission follows the server redirect to the read-only view URL and records that in history. The run_repair / run_debug csrf_require_post guards are retained, and the data_debug.php allowlist entry (and its now redundant click handlers) are removed. - Add a callable $executor test seam to rrdtool_tune_execute() (matching rrdtool_dump_document) so the unit tests assert the tune and resize commands are actually executed, with resize.rrd produced only when the resize command runs, rather than passing on the rename alone. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * review: move RrdTuneRenderTest into the Unit/Core/Rrd category folder Per AGENTS.md, new unit tests belong in a category subfolder rather than directly under tests/Unit. Move RrdTuneRenderTest there and update the UnitStubs include depth accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: TheWitness <copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
32467ddcab |
perf: reuse graph option arrays and document validation results (#8361)
* perf: reuse bootstrapped graph option arrays and document validation Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: record the installed RRDtool version in profiles Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: record final validation scope and profiling runtime limits Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: clarify the scope of changed-code coverage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: repair relocated PHPUnit configs and the deletion-only coverage gate - Point the five relocated configs that still carried a contributor's local autoload path (#8376) at ../include/vendor/autoload.php. - Pass --configuration=tests/phpunit.xml to the CSV window workflow and the README example now that phpunit.xml no longer lives in the repository root. - Let the changed-lines gate pass deletion-only PHP changes. Without added lines the generated config has no source filter, PHPUnit writes no clover report, and the gate failed on the missing file instead of reporting zero executable changed lines. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: TheWitness <thewitness@cacti.net> * ci: keep the missing request-report check for deletion-only changes Only short-circuit the changed-lines gate when there are no added PHP lines and PHPUnit wrote no clover report, so an empty request-coverage directory is still rejected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: TheWitness <thewitness@cacti.net> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Signed-off-by: TheWitness <thewitness@cacti.net> Co-authored-by: TheWitness <thewitness@cacti.net> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
4d11070ced |
feat: expose RRDtool 1.11 graph axis controls (#8356)
* feat: expose RRDtool 1.11 graph axis controls Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix: constrain axis template inheritance checkboxes Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): exercise native aggregate validation and enforce coverage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: share changed-code coverage contracts and enforce shell policy Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(ci): run request coverage with portable path matching Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: retain bootstrap coverage and validate request dispatch Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: synchronize native coverage fixture dispatch Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: measure coverage at the exact PR revision Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
2b6e96b23a |
style(php): [develop] wrap CLI and poller calls without changing execution (#8303)
* style(php): wrap CLI and poller calls without changing execution Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(ci): review security inventories after poller wrapping Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(boost): compare handoff source contracts by PHP tokens Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * style(php): wrap poller constant strings without changing values Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * style(php): wrap poller concatenations with token-preserving source contracts Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(cli): assert CDEF repair queries after constant folding Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: verify PHP formatting preserves parsed behavior Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
08d0f94f24 |
Fix develop client behavior, popup isolation and PHP method visibility (#8292)
* fix(core): correct client state and declare public method contracts Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(security): isolate Midwinter external homepage popup Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(client): isolate menu state and simplify validated JavaScript guards Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(auth): use certificate expiry truth in rendering assertions Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * refactor(js): remove unused local storage while retaining initializer calls Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(js): encode inline translated values through the shared JSON boundary Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * style(js): wrap encoded translation literals without changing messages Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(client): remove unused checkbox reads from graph resizing Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * refactor(client): declare repeated function locals once Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(ui): run column width regression in browser CI Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
16f62713c5 |
paper-plane: dark-mode refinements (readable forms/rows, consistent button system) (#8207)
* paper-plane: dark-mode refinements (readable forms/rows, consistent button system) * tests: make CactiErrorHandler suppression test hermetic against leaked IN_CACTI_INSTALL The three suppression cases eval a sandboxed copy of CactiErrorHandler to exercise the error_reporting() mask and logging path. Pest runs the whole suite in one process, and tests/integration/BoostProcessTableUpgradeIntegrationTest defines the global IN_CACTI_INSTALL constant at collection time. A constant cannot be unset, so the handler short-circuited to true before reaching the branch under test, failing 'an enabled level is logged and reported to PHP as unhandled'. Strip the install-mode guard from the sandboxed copy so the case is independent of collection order. --------- Co-authored-by: TheWitness <larry@thewitness.org> |
||
|
|
b5a388094d |
Honor @ error suppression in CactiErrorHandler on PHP 8 (#8197)
* Honor @ error suppression in CactiErrorHandler on PHP 8 CactiErrorHandler() guarded against the @ operator with error_reporting() == 0, which was the PHP 7 semantics. On PHP 8 the @ operator sets error_reporting() to a non-zero bitmask that merely excludes the suppressed level, so the guard never matched and deliberately suppressed warnings still reached the log. This surfaced after the Symfony mailer swap: Symfony's SendmailTransport writes to the sendmail pipe with @fwrite(), and when sendmail is misconfigured the broken-pipe notice leaked into the Cacti log instead of being swallowed and reported as the handled TransportException. Mask error_reporting() against the incoming level so the @ operator is honored on every supported PHP version. * Add regression test for CactiErrorHandler @-suppression mask Exercises both paths of the error_reporting() mask check: a notice and a warning raised under PHP 8's @-operator bitmask return before logging, while an enabled level is logged and reported back to PHP as unhandled. The suppressed cases would have logged under the previous error_reporting() == 0 guard, so the test fails closed if that regression returns. |
||
|
|
f79dc15c08 |
Port #8166 SNMP credential cache + procedural SNMPv3 (with #8171/#8172 follow-ups) to develop (#8174)
* Port #8166 SNMP credential cache + procedural SNMPv3 to develop Ports the shared SNMPv3 credential cache and procedural SNMPv3 routing from the 1.2.x feature (merged as #8166) onto develop, adapted to develop's refactored SNMP layer. Parts of the 1.2.x change that do not apply to develop are omitted: the cacti_exec() idle-timeout rewrite (develop has no cacti_exec()), the PHP floor bump and composer/doc changes (develop is already 8.3+), and the cmd.php max_oids batching (develop's cmd.php already collects SNMP in-process through persistent sessions, so the per-item spawn the batching removed does not occur). - lib/cache.php: new cross-process \Cacti\Cache\SharedCache (file + POSIX shared-memory + process-local tiers, optional AES-256-GCM sealing). Loaded via lib/snmp.php (the Cacti\Cache\ namespace is not PSR-4 autoloaded). The crypto helpers it seals with already live in develop's lib/auth.php, loaded by global.php, so no duplicate was added. - lib/snmp.php: snmp_get_method() now routes SNMPv3 get/getnext to the procedural snmp3_*() calls when the running PHP supports the configured auth/privacy tokens and no context/engine id is set (SHA-224/384 and AES-192/256[C] stay on the binary before PHP 8.6); the three single-get functions gain the procedural v3 path with \Throwable handling; adds the credential-cache subsystem, protocol-option/MD5-DES helpers, snmp_native_protocol(), snmp_format_agent() and cacti_snmp_get_multi(); the binary v3 auth builder consults the cache when enabled. - poller.php / script_server.php: prime / load the shared cache. - poller_maintenance.php: daily out-of-band cache rebuild on every collector (per-poller lastrun marker). - lib/api_device.php / lib/utility.php: bump snmp_cred_version only on v3 credential add/change (and propagate the token to the affected remote poller). - include/global.php: resolve and create the private cache/ directory. - include/global_settings.php: add 'Enable Credential Cache' and 'Enable MD5 and DES for SNMPv3' settings (both off by default); default new-device v3 auth/privacy to SHA/AES instead of legacy MD5/DES. - host.php / automation_snmp.php: drop MD5/DES from the pickers when disabled and default new records to SHA/AES on upgraded installs. - include/config.php.dist: document $config['cache_dir']. - tests/Unit/Core/Cache/SharedCacheTest.php: SharedCache behaviour coverage. - tests/security/baselines: baseline the two new lib/cache.php sinks. * Incorporate #8171: binary fallback for unsupported SNMPv3 protocols Layers PR #8171 onto the develop port so an SNMPv3 device whose auth/privacy protocols the running PHP's ext-snmp cannot service natively (e.g. AES-256 before PHP 8.6) no longer fatals the poller or device-edit screen. - lib/snmp.php: add CactiSnmpBinarySession, a session stand-in exposing the get/getnext/walk/close interface the cacti_snmp_session_*() helpers use and delegating each call to cacti_snmp_*() -> the Net-SNMP binary. cacti_snmp_session() returns it when php-snmp is absent or the v3 protocol is not natively serviceable, so cmd.php/host.php collect these devices via the binary on pre-8.6 and switch to the in-process path on 8.6 with no caller change. v1/v2 snmpget/snmp2_get now go through snmp_format_agent(). The ERRNO_TIMEOUT check tolerates php-snmp being absent. Drop the vendored classSNMP.php compatibility shim and its include (and the Yandex attribution). - cmd.php: open_snmp_session() returns the down sentinel when a host is already marked down this run, instead of returning an unset (null) [] that cacti_snmp_session_get() then dereferenced (TypeError). - lib/ping.php: ping_snmp() runs the availability check through the procedural cacti_snmp_get()/getnext() path so an unsupported protocol falls back to the binary instead of raising a ValueError in SNMP::setSecurity(). * Incorporate #8172: retire include/vendor/phpsnmp, relocate into lib Follow-up to #8171 on the develop port. After classSNMP.php was removed, the include/vendor/phpsnmp/ directory held only Cacti-owned files; this retires it. - lib/snmp.php: the ext-snmp subclass that carried Cacti's bulk_walk_size / value_output_format (previously vendor/phpsnmp/extension.php) is now declared directly as CactiSnmpNativeSession, guarded by CACTI_PHP_SNMP; the include and the 'use phpsnmp\SNMP' alias are gone, and new SNMP(...) / SNMP::VERSION_* now reference the native \SNMP and the new subclass. - lib/mib_parser.php: moved from include/vendor/phpsnmp/mib_parser.php; lib/mib_cache.php includes it via __DIR__. - Remove include/vendor/phpsnmp/extension.php and index.php (directory retired). - tests: SnmpCoverageTest uses \SNMP::ERRNO_TIMEOUT now that phpsnmp\SNMP is gone; drop the stale include/vendor/phpsnmp/ entry from the vendor-policy allowlist. develop's sink baseline tracks constant-based includes differently than 1.2.x, so no baseline refresh was needed here. * Address PR #8174 review: snmp_get_method params, v3 walk, getnext agent, cache bump, CHANGELOG - lib/snmp.php: restore $php_snmp as the 6th snmp_get_method() parameter and move the new $auth_proto/$priv_proto after it (callers pass them by name), so the positional $php_snmp used by SnmpCoverageTest and others keeps working. - lib/snmp.php: keep every SNMPv3 operation except get/getnext on the Net-SNMP binary - the native walk branch implements only v1/v2, so a v3 walk reaching the procedural gate would have silently returned empty when path_snmpbulkwalk is missing. - lib/snmp.php: cacti_snmp_getnext() v1/v2 branches now use snmp_format_agent() like get/get_raw, so an IPv6 literal / non-default port is bracketed. - lib/api_device.php: bump snmp_cred_version only when the host's v3 membership or one of the cached credential fields actually changed, instead of on every save of a v3 device. - CHANGELOG: move the #8171 entry into the issue block and the #8166 entries into the feature block, matching the established section ordering. * Fix CI: unbracket IPv4/DNS SNMP targets, inline auth-cache SQL columns, apply phpcsfixer standard * Refresh sink inventory baseline after short-array normalization * Restore lib/snmp.php 100% coverage after aligning v3 routing to 1.2.x - update the three SnmpCoverageTest assertions that still encoded develop's pre-port behavior: v3 snmp_get_method now returns PHP, an unsupported- protocol v3 session returns the binary-delegating session object, and the v3 cacti_snmp_get path runs natively - add a v3 noAuthNoPriv user to the snmp-coverage snmpd fixture so native snmp3_get is exercised deterministically - add tests covering the ported subsystems to 100%: shared auth cache, binary-delegating session, protocol pickers, v3 credential args, cacti_snmp_get_multi, and the cacti_get_snmpv3_auth cache path - snmp_auth_cache_load uses a resettable process guard so its enabled and disabled branches are both coverable in a single process * Resolve phpstan errors in the relocated SNMP MIB parser and ported snmp.php - lib/mib_parser.php: type the MibParser properties, add parameter/return types, guard file_get_contents()/preg_split() against false, correct the parse_bracket_token delimiter params (string, not integer), and drop the unreachable return after trigger_error(E_USER_ERROR) - now phpstan clean - lib/mib_cache.php: drop the redundant isset($mp->oids) guard (the typed property is always initialized; $mp->mib is the real check) - lib/snmp.php: type the CactiSnmpBinarySession and CactiSnmpNativeSession properties/methods and pass bool to snmp_set_quick_print() - .phpstan.neon: ignore greaterOrEqual.alwaysFalse alongside the existing greater.alwaysFalse (the PHP_VERSION_ID >= 80600 forward-compat gate) - regenerate phpstan-baseline.neon for the irreducible ext-snmp stub strictness (snmp3_get literal-union protocols, int<-1,max> timeouts) in the ported procedural v3 path, the new lib/cache.php shmop stubs, and the $config array-shape offsets in include/global.php * Make the v3 getter catch coverage net-snmp-build-independent The DES-rejection trick that drove the procedural snmp3_get()/snmp3_getnext() try/catch blocks only works on net-snmp builds compiled without DES; CI's Debian net-snmp accepts DES, so those catches went uncovered (98.3%). - extend the existing native_get injection seam (already on cacti_snmp_get) to cacti_snmp_get_raw, cacti_snmp_getnext, and cacti_snmp_get_multi, and drive the catch blocks with a throwing native getter in the test - mark the seam-less cacti_snmp_session() setSecurity catch with @codeCoverageIgnore (it only throws for a protocol the running net-snmp rejects, which is not portably reproducible in the fixture) * Exclude ext-snmp/PHP-8.6-gated defensive branches from snmp coverage Two branches in lib/snmp.php are unreachable on the PHP 8.3 + ext-snmp coverage runner and were only "covered" locally via opcache dead-code elimination: - snmp_get_method()'s !function_exists('snmp3_get') fallback (ext-snmp always provides snmp3_get) - snmp_php_v3_protocols_supported()'s PHP_VERSION_ID >= 80600 block (SHA-224/384 and AES-192/256 tokens are only accepted on PHP 8.6+) Mark both with @codeCoverageIgnore so the 100% gate is deterministic across runners regardless of opcache settings. * Account for the #8166 SNMPv3 credential-cache gate query in the batching test poller_update_poller_cache_from_buffer() now runs one SELECT per flush to decide whether the flush touched SNMPv3 poller items before bumping the shared credential-cache version (matching 1.2.x). UpdateDataQueryCacheBatchingIntegrationTest counted 4 statements per flush; update it to 5 (and 3 per-row flushes to 15, 1 batched flush to 5). The guard's intent - batching issues fewer statements than per-row flushes - still holds. * Port #8175: group SNMP options under an SNMP Behavior section Mirror the 1.2.x settings reorganization (#8175) on develop. develop already keeps the SNMP options in a dedicated SNMP tab, so add an "SNMP Behavior" spacer there, order the behavior options as md5/des, credential cache, max get size, bulkwalk fetch size, and move "Disable increasing OID Check" out of the Poller tab to sit last in that group. Display-only; no settings added or removed and no behavior change. Adds the "SNMP Behavior" heading to cacti.pot. * fix: complete dependabot htmx 2.0.10 to 2.0.11 bump Dependabot bumped package.json and package-lock.json to htmx.org 2.0.11 (PR 8179) but left the vendored include/js/htmx.js, its version marker, and the pinned SRI constant at 2.0.10. The htmx-filters CI workflow runs npm ci, which regenerates include/js/htmx.js from the 2.0.11 package, so HtmxTest's runtime sha384 no longer matches the HTMX_2_0_10_SRI constant and the integrity assertion fails. Complete the bump: regenerate the vendored include/js/htmx.js to the 2.0.11 build, bump include/js/htmx.js.version to 2.0.11, rename HTMX_2_0_10_SRI to HTMX_2_0_11_SRI with the recomputed sha384 hash, and update the version/integrity assertions in tests/Unit/Ui/Html/HtmxTest.php and tests/HandOff/HtmxLoaderHandOffTest.php. package.json and package-lock.json match the values dependabot already landed on develop. * settings: move SNMP Agent Support under the SNMP Behavior spacer Relocate the enable_snmp_agent setting (SNMP Agent Support Enabled) so it is the first item under the SNMP Behavior spacer instead of sitting in the Poller General group, grouping it with the other SNMP behavior options. * Address PR #8174 review: keep SHA-224/384 on the binary, honor port on transport targets Resolves the two still-valid Copilot review findings on lib/snmp.php that were left unresolved (only marked outdated after later commits shifted their lines). - snmp_php_v3_protocols_supported(): drop SHA224/SHA384 from the native auth allowlist. ext-snmp's SNMP::setSecurity()/snmp3_*() only map MD5/SHA/SHA256/ SHA512 - there is no SHA-224/SHA-384 mapping on any build, including PHP 8.6 (verified against php-src ext/snmp/snmp.c), so routing those tokens to the procedural path raised a ValueError instead of using the binary. They now always fall back to the Net-SNMP binary. The AES-192/256 privacy tokens that ext-snmp does add on 8.6 stay gated behind PHP_VERSION_ID >= 80600. - snmp_format_agent(): a udp/tcp transport-qualified target that omits a port now has the configured non-default port appended (udp6:[2001:db8::1] + 1161 -> udp6:[2001:db8::1]:1161), matching the Net-SNMP binary path. Targets that already carry a port, and unix: sockets (no port), are left untouched. - SnmpCoverageTest: cover the new transport-target branches; lib/snmp.php stays at 100%. |
||
|
|
d57431371b |
perf(poller/boost): cached per-data-source field-name lookups, remove batched prefetch (#8078)
* perf(poller/boost): replace batched field-name prefetch with cached per-data-source lookups poller_prefetch_rrd_field_names() (issue#7534) batched the unused/nt field-name lookups into large IN() lists and rebuilt them on every process_poller_output()/boost_process_local_data_ids() call, so the completion-wait loop re-ran them each pass (DB thrash) and the IN() lists risk crashing some MariaDB/MySQL releases and do not scale to multi-million-data-source installs. Option B (full): remove poller_prefetch_rrd_field_names() and replace it with two small per-data-source helpers - poller_get_unused_data_source_names() and poller_get_nt_rrd_field_names() - each a single indexed WHERE local_data_id = ? query cached by local_data_id in a caller-held static, so every data source is queried at most once per poller process. Templated field names resolve from the static poller_data_template_field_mappings cache (the Data Template dictates); only non-templated (data_template_id == 0) manual sources hit the per-instance query - a rare exception. Both process_poller_output() (lib/poller.php) and boost_process_local_data_ids() (poller_boost.php) now use the helpers. Added a WARNING documentation block to both bulk hot-path functions spelling out the query-discipline rules for future maintainers/AI (minimal queries, no query in the per-row loop, avoid large IN() lists and full-table scans, single pass, static template-dictated caching). Updated BoostProcessBugsTest assertions to the new helpers and removed the now-obsolete BoostPrefetchRrdFieldNamesTest integration file. * fix(poller/boost): split GROUP_CONCAT'd field mappings; guard orphan-name query to templated sources; add coverage * boost: normalize orphan-name guard to ternary at third call site The reset_template branch in boost_process_local_data_ids() guarded the poller_get_unused_data_source_names() call with an if/else block rather than the ternary used at the other two call sites. Normalize it so all three sites read identically and the template-id guard is uniform. |
||
|
|
182b21dc53 |
fix(csv): align export and graph sample windows (#7987)
* fix(csv): align export and graph sample windows Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci(csv): satisfy release policy checks * test(csv): align legacy capacity contract * test(csv): add standard license headers * fix(rrd): infer step from trailing fetch row Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci(csv): trigger on resolution query coverage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): mirror fetch helper arguments Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): isolate percentile globals Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): annotate intentional eval Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): restore integration config Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): enable strict types Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): restore font config Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: align CSV coverage with supported PHP versions Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: TheWitness <thewitness@cacti.net> |
||
|
|
3c20f4ce7e |
Harden Boost data handoffs and graph cache writes (#7729)
* fix(boost): harden data handoffs and cache writes Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Define $updates_ok when there is nothing to flush PHPStan level 6 also flags the poller ownership check, which is the POLLER_ID constant case the file already annotates above. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Use a line comment to match the fixer Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Record the boost process columns in the audit schema Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: resolve includes through Cacti path constants Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Fix Boost handoff review concerns Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: seed settings in Boost database fixture Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: refresh SQL interpolation baseline Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: record Boost handoff hardening Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix: stop boost discarding a cycle and wedging a shard Three defects in the handoff hardening. A rejected ownership handoff returned false, which the poller reads as boost having consumed the data, so it skipped the RRD write. The poller_output rows were already deleted by then, so a stale poller_item copy on a remote poller silently lost the whole cycle. Return true instead and let the poller write directly, matching the database failure path. Any non-OK RRDtool response retained the shard, and the retry then replayed rows already written, which RRDtool rejects as an illegal update time. That failed again on every pass, so the archive tables accumulated and boost never drained. Treat an at-or-behind timestamp as applied, since the sample is in the RRD; genuine errors still retain the shard. The two new poller_output_boost_processes columns passed 'null' where db_install_update_table reads 'NULL', so NOT NULL was never emitted and upgraded installs diverged from cacti.sql. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix: spell the NULL column key so upgrades emit NOT NULL db_add_column() reads $column['NULL'] and PHP array keys are case sensitive, so the thirteen definitions in the 1.3.0 upgrade that passed a lowercase 'null' key had the flag discarded and created nullable columns. Fresh installs built from cacti.sql got NOT NULL, upgraded installs did not, and Cacti's own schema audit reports the difference. The same file already spells the key in upper case 144 times, and the wrapper's own docblock example uses the upper case form. Guard the class with a test over every upgrade file rather than only the one that was wrong. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: assert the NULL key plainly toContain() takes needles rather than a failure message. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(boost): close remaining handoff review gaps Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(boost): guard nullable graph output Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(boost): keep in-flight completion rows through the 1.3.0 upgrade The truncate only existed so the run_child UNIQUE key could build over rows that predate run_id; deleting just those rows leaves a running boost its completion records. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * refactor(boost): drop the poller ownership gate Its boost_poller_on_demand() call sits behind the boost_redirect early return that poller.php forces on for every multi-collector install, and its recovery call turns a device deletion on main into a recovery that never brings the collector back online. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(boost): bound atomic cache write allocations Guard upgrade source reads so failures report clearly, write graph cache data in fixed-size chunks, and exercise a multi-chunk payload. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(boost): support Windows cache replacement Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(boost): expand handoff failure coverage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(boost): support ANSI_QUOTES upgrade checks Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(boost): stop staging after chunk failure Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(recovery): use numeric poller status Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(sql): support ANSI_QUOTES in recovery paths Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(boost): preserve cache on replacement failure Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(boost): retain readable cache permissions Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(boost): repair completion schema at runtime Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(recovery): bound timestamp batch fetches Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(boost): satisfy runtime schema analysis Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(recovery): restore status after transfer failure Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(boost): rely on unit bootstrap helpers Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(boost): refresh generated cache secret Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(boost): normalize cache path separators Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(boost): fail clearly on unreadable fixtures * fix(boost): name ignored duplicate sample keys The staging warning only said rows were dropped, so a retry could not be told from a colliding writer. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Lack of pre-commit hook execution allowed lint failure --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: TheWitness <thewitness@cacti.net> |
||
|
|
1ae479d4f5 |
feat(cli): add unified command frontend and normalize legacy failures (#7903)
* feat(cli): add unified command frontend and normalize legacy failures Add the Symfony-backed bin/cacti entry point while preserving legacy argument, terminal, signal, and exit-status behavior. Fold in the focused legacy CLI correctness fixes from #7906 without adding its unused parser abstraction. Keep path containment and the PHP 8.3 floor out of this review; the latter remains in #7939. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(cli): enforce PHP floor and deny web dispatch --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
95060c49ba | Close test-suite discovery and coverage gaps (#7970) | ||
|
|
a155419ff3 |
Serialize process registry admission with portable locks (#7771)
* Serialize process registry admission with Symfony Lock Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Fix PDO process lock mode handling Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: run process lock coverage on PHP 8.2 Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix: confirm a pid is still ours before signalling it #7574 added the still-running guard to dsstats but left six byte-identical siblings signalling a pid straight out of the processes table. After a crash or a power loss the row survives, the pid is recycled by an unrelated daemon, and the next start SIGTERMs a stranger. That is issue #7425, still live in rrdcheck, boost, poller_commands, float_rrdfiles, poller_reindex_hosts and rebuild_poller_cache. Wrap each kill in cacti_process_still_running(), matching the dsstats shape, and leave unregister_process() outside the guard so a stale row is still cleaned up. Cover all seven with a test that walks every kill site, so a new variant cannot reintroduce it. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: assert the guard plainly toContain() takes needles rather than a failure message, so the file name was being asserted as a second required substring and the test always failed. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs(poller): describe required lock parameters --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
da7015e497 |
Break out of the --bulk_walk case in change_device.php (#7904)
* Break out of the --bulk_walk case in change_device.php * Add CHANGELOG entry for #7904 * Fix CHANGELOG entry ordering Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(cli): pin bulk walk option control flow Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: Sean Mancini <sean@seanmancini.com> |
||
|
|
66a2808cc9 |
Let one notification address several recipients (#7782)
* feat(notify): let one notification address several recipients Symfony calls a channel once per recipient, so a caller that needs a single message sent to several people could not express it. The email 'to' option folds the extra addresses into the same mailer() call and drops any that match the recipient. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(notify): compare the local part of an address exactly RFC 5321 leaves local part case to the receiving host, so folding the whole address deduplicated OPS@example.com and ops@example.com into one mailbox. Only the domain folds now. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
964c1fb1f4 |
Harden RRDtool execution and data handoff (#7615)
* fix(rrdtool): quote RRDfile paths passed to the command line __rrd_execute() hands the assembled line to shell_exec(), and its docblock already required callers to quote each variable argument. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(tests): widen bare RRD path sweep Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(rrdtool): quote binary path as one argument Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(rrd): preserve caller logging context Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Make RRD XML mutations transactional Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Harden RRDtool proxy transport handling Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(rrdproxy): reject invalid command argument lists Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(rrdproxy): preserve binary graph payloads Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Keep RRDtool proxy sessions encrypted Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Harden local RRDtool command and output handoff Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Eliminate graph rendering metadata lookups Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Batch DSStats metadata and last-value reads Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Batch interface speed metadata reads Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Update architectural hotspot baseline for RRD execution Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Batch RRD resolution profile lookups Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Batch DSStats summary aggregates Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Narrow phpseclib key types for the proxy encrypt and decrypt calls Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): bound the forked proxy peers so a stall cannot hang the suite The children accepted and read with no deadline while the parent used a 2s socket timeout, so any mismatch left the child blocked in read and the parent blocked in a bare pcntl_waitpid(). Note that accept() ignores SO_RCVTIMEO, so readiness has to be waited on with socket_select() rather than a socket option. Also corrects the array-command expectation, which still assumed develop's escape-everything behaviour rather than rrdtool_build_command() leaving the operation unquoted. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): seed proxy settings where the real read_config_option looks UnitStubs only declares its stub when lib/functions.php has not been loaded yet, so during a full run the real database-backed function is the one in effect and $unit_config_options was being ignored. The parent then dialled an address the child was not listening on, which is what stalled the handshake. Seeding the option cache keeps the settings visible to either implementation. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): assert the shell-free RRDtool launch instead of the old quoting __rrd_init now hands proc_open an argv array with bypass_shell, so escaping the binary path would put the quotes inside the filename. The assertion still expected the pre-argv line and had been failing unnoticed behind the suite hang. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(dsstats): derive the expected stamps instead of assuming UTC dsstats_poller_output() formats with date(), so the hardcoded UTC strings only matched on a UTC runner. The failure was masked by the suite hang. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(rrd): keep RRDtool control codes intact in stdin commands Escaping the backslash when converting a shell-quoted argument to an RRDtool token left legends such as " IO Wait\:" ending in a dangling control code, so RRDtool refused every graph carrying an escaped colon. Verified against RRDtool 1.7.2 in pipe mode; values with no unambiguous quoted form are now refused rather than mangled. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: use Cacti test bootstrap and config Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: resolve includes through Cacti path constants Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: match the escaping helpers by token, not by text lib/rrd.php documents its escaping behaviour in a comment, and the regex over raw source counted that as a call site. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: refresh sink inventory after develop rebase Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): prove argv isolation and concurrent pipe draining Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(security): refresh sink inventory baseline after rebase onto develop Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
fe5d824d13 | ci: restore coverage and workflow policy gates (#7791) | ||
|
|
619b33142e | feat(rendering): add HTML, URL, and inline-data output helpers (#7252) | ||
|
|
4d021a93e3 | Add plugin-extensible notification API (#7775) | ||
|
|
49f5212181 |
fix(tests): restore paths and isolate test doubles (#7764)
* fix(tests): correct path depths after the domain reorganisation The category move left nine files resolving paths relative to their old depth, so the bootstrap could not read tests/Helpers/UnitStubs.php and no test ran at all. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix tests without replacing production functions * remove unrelated failing integration tests * remove unrelated broken test workflows --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
96033267cb |
refactor(tests): reorganize unit tests into domain category folders (#7733)
* refactor(tests): reorganize unit tests into domain category folders - Consolidate per-advisory GHSA regression tests into Security/ subfolders by vuln class - Group all 186 test files into domain folders: DataCollection/, Ui/, Core/, Database/, Installer/, Scripts/, Security/, Plugin/ - Strip GitHub issue/GHSA numbers from filenames; keep IDs in test descriptions - Fix all __DIR__ relative paths to match new folder nesting depth - Update CI workflow path triggers and phpunit XML configs for new file locations - Update .github/copilot-instructions.md with unit test organization guidelines - Add tests/vendor/ to .gitignore * add gaurds * fix up guard for unit tests * fix redeclaration of cacti_log in tests * fix updates to unit tests * fix test patjhs * fix: update test __DIR__ paths for reorganized test structure * fix: conditionally define read_user_setting to prevent redeclaration in tests * fix: conditionally define functions to prevent redeclaration in tests - Wrap clean_up_lines, raise_message, cacti_debug_backtrace, and get_debug_prefix with function_exists() checks to prevent conflicts when test stubs are loaded before lib/functions.php in the same PHP process * fix: add unit test bootstrap to prevent function redeclaration errors - Create tests/bootstrap-unit.php to load core libraries before tests - Ensures lib/functions.php loads before test stubs define stub functions - Test stubs use function_exists() checks, so they detect pre-loaded functions - Update phpunit.xml to use bootstrap-unit.php for Unit testsuite - Fixes 'Cannot redeclare read_user_setting()' errors when tests run in same process * fix: load test stubs before global.php in unit test bootstrap - Reorder bootstrap to load CactiStubs.php and UnitStubs.php first - Ensures stub functions like __() are available when global.php loads - global.php calls get_cacti_version_text() which needs __() for translations - Fixes 'Call to undefined function __()' error during bootstrap * fix: remove function conflicts from test stubs - Remove stub definitions for functions already in lib/functions.php: cacti_sizeof, cacti_log, cacti_strtolower, read_config_option, read_user_setting, cacti_count - Keep translation function stubs (__(), __esc()) needed by global.php - Update bootstrap to load lib/functions.php after stubs - This prevents function redeclaration errors while maintaining test isolation * fix: prevent constant and variable redeclaration in bootstrap - Remove explicit PHP_TESTING and CACTI_TEST_BOOTSTRAP defines from bootstrap (CactiStubs.php now handles this with guards) - Add guards to CactiStubs.php to prevent redefinition of PHP_TESTING - Only set CACTI_TEST_BOOTSTRAP env vars if not already set - Fixes PHP warnings about 'Constant X already defined' * fix: remove redundant lib/functions.php load from bootstrap include/global.php already loads lib/functions.php at lines 287-288. The bootstrap was trying to load it again after global.php, but global.php needs format_cacti_version() to be available on lines 293-294 to define CACTI_VERSION and CACTI_VERSION_FULL constants. Solution: Let global.php handle loading lib/functions.php itself, and don't load it separately in the bootstrap. * fix: remove more conflicting function stubs from test helpers - Remove stubs for functions also defined in lib/functions.php: raise_message, clean_up_lines, cacti_debug_backtrace, get_debug_prefix - Remove POLLER_ID constant stub (defined unconditionally by global.php) - Keep only translation functions and test-specific helpers - This prevents function/constant redeclaration errors * fix: minimize test stubs to only translation functions Remove ALL helper functions and constants from UnitStubs.php that are: - Defined in lib/functions.php (raise_message, clean_up_lines, etc.) - Defined in lib/html_utility.php (srv, set_request_var) - Defined in global_constants.php (POLLER_VERBOSITY_*, MESSAGE_LEVEL_*) - Defined in global.php (POLLER_ID) Keep ONLY translation functions (__(), __esc()) that are: - Called by global.php during initialization - Not defined elsewhere - Required for proper bootstrap sequence This eliminates all constant and function redeclaration errors. * fix: remove __esc stub - already defined in global_languages.php Keep only __() translation function stub, which is needed by global.php and not defined elsewhere in Cacti core. * fix: handle no-arg case in __() translation stub The __() function may be called with just a string and no format arguments. Previously, vsprintf() would fail with 'arguments array must contain 2 items'. Now, if no args are provided, return the text as-is. |