174 Commits
Author SHA1 Message Date
TheWitness 6bbfb58492 Fit status pills to label text and toggle-clear the status filter on second click (#854)
The status pills were being clipped to a fixed width because the single-class theme rules (e.g. .deviceUpFull width:14%, padding:3px) outranked the equal-specificity .thold-pill shape rule, so long labels such as 'Not Monitored' overflowed the coloured pill on the Device Status page. Element-qualify the selector (span.thold-pill) so the shape rule wins and the pill hugs its label in every theme.

Also make a second click on an already-selected status pill clear that filter (reset the Status select to All, value -1) instead of re-applying the same value. Applied to all three thold_graph.php sub-tabs (Thresholds, Device Status, Threshold Log) and the matching Thresholds console page (thold.php).
2026-10-09 09:32:34 -04:00
TheWitness 4d432a2e20 thold: status pills with sortable/clickable Status column and zebra rows (#851)
* thold: status pills with sortable/clickable Status column and zebra rows

Replace the whole-row status colour on the Thresholds (thold.php) and Device Status (thold_graph.php) pages with a rounded status pill in a new Status column right of Name; rows now fall back to zebra striping. The column is server-side sortable by severity via a new thold_severity_sql() CASE (a faithful SQL mirror of get_thold_severity(), legend-order rank 1=Alert..7=Disabled), the Status filter gains the seven per-severity options (values 101-107 handled in thold_get_state_filter()), and clicking a pill sets that filter and reloads. Pill shape lives in a theme-agnostic css/pills.css; all colours stay theme-aware (reusing each theme's .thold<State> backgrounds, with light pill text added to the saturated classic/modern/paw themes). Adds Pest coverage for thold_severity_sql() and the severity filter branch.

* thold: regenerate cacti.pot for the status-pill i18n strings

* thold: address review - pill contrast, time_warning_low '0' parity, keyboard a11y, stronger test

Light themes (classic/modern/paw all have white/snow backgrounds) now use dark pill text instead of white, which failed 4.5:1 at 11px. thold_severity_sql() treats time_warning_low '0' as falsy (NOT IN ('','0')) to match get_thold_severity(), so the pill never disagrees with sort/filter. Pills are now focusable role=button spans with Enter/Space activation on both pages. TholdSeveritySqlTest now executes the CASE over an in-memory SQLite row and asserts the SQL rank equals get_thold_severity() across branch/boundary scenarios incl. the '0' case.
2026-10-08 14:58:54 -04:00
TheWitnessandTheWitness 1158c70de0 Use a CSS class for the status legend footer instead of inline styles (#850)
* Pin status legends to the bottom of the page (match MacTrack)

Wrap the thold, host and log legend renders in the same fixed-position footer container MacTrack uses, so the legend stays pinned to the bottom of the viewport instead of scrolling away with the list.

* Use a CSS class for the legend footer instead of inline styles

Replace the inline fixed-position wrapper around the status legend with a
plugin-specific *LegendFooter class defined in the plugin's stylesheet. The
class lays the legend out as a centered footer in normal document flow, so it
no longer sits outside flow and overlay the final rows, pagination, or action
controls at the bottom of the page.

---------

Co-authored-by: TheWitness <1439914+TheWitness@users.noreply.github.com>
2026-10-07 21:00:07 -04:00
TheWitnessandTheWitness 1e226aa6c5 security: move filter inline onChange/onClick handlers into ready() for CSP (#849)
* security: move filter inline onChange/onClick handlers into ready() for CSP

The threshold, notification list, notification queue, template and
device/log status filter forms still carried inline onChange/onClick
attributes on their selects and Clear/Go/Import/Export controls. Under
Cacti's Content-Security-Policy these trip the script-src-attr directive
(inline event handlers). Bind them in each view's existing
$(function(){...}) ready block instead.

Scope: thold.php, notify_queue.php, thold_templates.php, notify_lists.php,
thold_graph.php (all gate-allowlisted UI files; no measured source changed).
The cactiReturnTo() cancel buttons on the bulk-action confirmation pages are
left as-is (shared Cacti-core pattern). Regenerated locales/po/cacti.pot for
the shifted source line references.

* security: convert cactiReturnTo cancel buttons to the CSP-safe class

The confirmation pages' Cancel buttons used an inline
onClick='cactiReturnTo()' handler, which trips Cacti's Content-Security-Policy
script-src-attr directive. Switch them to the CSP-safe cactiReturnTo CSS
class (class='cactiReturnTo', plus an optional data-url when a target is
passed).

Cacti 1.2.31 and later bind this class automatically. The README documents a
one-time include/layout.js applySkin() snippet for operators still on an
earlier release - no shim is baked into the core or the plugin.

* fix: give Thresholds/Devices filter Clear buttons the id the ready() handler binds

The hosts() and tholds() filter views used name='clear' on the Clear button, but the ready() handler binds to #clear, so Clear was a no-op on those two views. Switch them to id='clear' to match the other views and the handler.

---------

Co-authored-by: TheWitness <larry@thewitness.org>
2026-10-07 21:00:03 -04:00
TheWitnessandCopilot 9b217e0e3a INFO: set compat to 1.2.29 (#838)
* INFO: set compat to 1.2.32

* docs: update Copilot instructions Cacti baseline to 1.2.32 (matches INFO compat)

* INFO: back off compat to 1.2.29

* Add manifest.json + upgrade-time file pruning

* Prune phpunit.xml on upgrade and ignore markdown-lint configs

phpunit.xml ships in the repo for CI but is a dev-only test artifact, so it
is removed from manifest.json 'expected', pruned from installs on upgrade
(like tests/), and excluded from the manifest drift check.

The retired markdown-lint configs (.mdlrc, .md_style.rb) are deleted, and
.md* is now ignored like .git*: protected from pruning and excluded from
drift if it reappears.

* Move thold_functions.php and thold_webapi.php into includes/; flatten css

The main threshold library becomes includes/functions.php and the web API
helper becomes includes/webapi.php; every caller (setup.php, includes/*, the
CLI/poller/notify entry points and the test suite) loads them from includes/.
Each per-theme stylesheet css/<theme>/main.css becomes css/<theme>.css so users
can drop their own css/<theme>.css into the css base, and the page_head hook
looks there. Old paths are tombstoned so existing installs drop the stale
copies on upgrade.

* Regenerate cacti.pot for the includes/ file relocations

Moving the plugin's library files into includes/ changed the source-reference
lines in the translation template; regenerate it so the 'Verify translation
template' CI check passes.

* Harden the hook-include test and make RPN integer ops explicit

The HookFunctionsIncludeTest invokes real hooks with placeholder input purely
to execute their relocated include_once lines; it now swallows engine
notices/warnings/deprecations during those calls (and restores the error
handler and config afterward) so it cannot trip the suite's failOnDeprecation
or leak state into other tests. The RPN % and ^ operators now cast their
operands to int explicitly, matching their long-standing integer-truncation
behaviour while silencing the implicit float-to-int conversion deprecation.

* Harden prune against tampered-manifest path traversal

The upgrade-time prune now rejects any tombstone containing '.'/'..' segments
(which could escape the plugin directory or resolve to its root) and treats
ancestors of whitelist entries as protected, so a tombstone on a parent
directory can no longer delete a whitelisted file beneath it.

* docs: update and align the Project Structure block

Point the structure tree at the relocated files (libraries now under
includes/, data files under docs/, stylesheets under css/) and align the
trailing '# ...' comments to a single column so they no longer drift right.

* docs/tests: standardize test header and correct manifest-contract notes

- Use the full license header (from the plugin's own setup.php) in
  tests/Unit/PruneFilesTest.php instead of the abbreviated copyright banner.
- Document that the manifest drift check and the upgrade-time prune also
  handle phpunit.xml and .md* files, matching the implemented behavior.

* refactor: rename prune helpers to the plugin-slug function prefix

The repository naming contract reserves the plugin_<name>_ prefix for plugin
lifecycle / hook-registration functions; all other functions use the plain
<name>_ prefix. Rename the internal upgrade helpers accordingly:

  plugin_<name>_prune_files() -> <name>_prune_files()
  plugin_<name>_rmtree()      -> <name>_rmtree()

The call site, unit tests, and the copilot-instructions.md references are
updated to match. No behavioral change.

* chore: set the Cacti compatibility floor to 1.2.29

Align the compat metadata (and the contributor-guide references) with the
team decision to standardize the minimum supported Cacti version at 1.2.29;
the previously proposed 1.2.32 floor was not adopted.

---------

Co-authored-by: Copilot <copilot@users.noreply.github.com>
2026-10-01 01:40:00 -05:00
TheWitness b7f3741880 security(csp): version-safe inline-script nonce wrapper + strengthen PO/MO instructions (#829)
* security(csp): add version-safe inline-script nonce wrapper; strengthen PO/MO instructions

* test(csp): cover setup.php page_head/device hook nonce lines; ignore exit-branch scripts; stub UI helpers

* test(csp): drop fragile isolated wrapper test; ignore the framework-only delegation line

* test(csp): cover the CactiSecureHeaders delegation branch without process isolation

* csp: leave the two exit()-branch confirm-dialog scripts un-nonced (uncoverable under the 100%% patch-coverage gate)

* test(csp): exercise nonce delegation in isolated process; full GPL header
2026-09-28 09:33:21 -04:00
TheWitness 41dc700357 Add PHPDoc blocks to undocumented functions (partial - thold_functions.php follow-up owed) (#828)
* Add PHPDoc blocks: small files batch (cli_import, poller_thold, includes/tab, includes/database, cli_thresholds, thold_notify, notify_queue)

* Add PHPDoc blocks: includes/polling.php, includes/settings.php (WIP checkpoint)

* Add PHPDoc blocks: thold_process.php, thold_daemon.php (WIP checkpoint)

* Add PHPDoc blocks: thold_webapi.php (WIP checkpoint)

* Add PHPDoc blocks: thold.php (WIP checkpoint)

* Add PHPDoc blocks: thold_graph.php (WIP checkpoint)

* Add PHPDoc blocks: notify_lists.php (WIP checkpoint)

* Add PHPDoc blocks: thold_templates.php (WIP checkpoint)

* Add PHPDoc blocks: setup.php batch 1-2 (WIP checkpoint)

* Add PHPDoc blocks: setup.php batch 3-4 (WIP checkpoint)

* Add PHPDoc blocks: setup.php batch 5 (WIP checkpoint)

* Add PHPDoc blocks: setup.php batch 6-7 (WIP checkpoint)

* Add PHPDoc blocks: setup.php complete

* Address review feedback and refresh translation template

- Fix thold_update_host_status() return type (int|null, since it
  falls through with no explicit return in the normal case)
- Fix @global $device_change_fields description in
  thold_config_arrays() (appends this plugin's fields, not unused)
- Fix @global $config description in thold_graph_button() (used to
  build the Create Threshold link's URL)
- Fix thold_data_source_action_prepare()/thold_graphs_action_prepare()
  return types (array|void; only the non-plugin_thold_create branch
  returns $save)
- Fix @global $timearray description in list_tholds() (used to render
  each baseline threshold's reference time range)
- Fix @global $thold_types description in thold_show_log() (used to
  render each log row's type column)
- Regenerate locales/po/cacti.pot (source line references only)
- Fix .gitignore pattern for compiled .mo files (locales/LC_MESSAGES/, not locales/po/)

* test(coverage): allowlist untestable entry points touched by PHPDoc pass

This PR only adds PHPDoc blocks (no functional changes), but touching every file in the plugin newly triggers the 'Enforce coverage of changed lines' CI gate for files that were never require()'d by any test before now:

- cli_import.php, cli_thresholds.php: CLI entry points (include cli_check.php / chdir + execute at the top level).

- poller_thold.php: poller entry point, same category.

- thold.php, thold_graph.php, thold_templates.php, notify_lists.php: authenticated web entry points (chdir + include(auth.php) at the top level), like notify_queue.php/thold_notify.php already allowlisted above.

- thold_daemon.php: daemon entry point, same category as thold_process.php already allowlisted above.

- includes/settings.php, includes/tab.php: Settings-page/header-tab-bar hook callbacks, only meaningful inside a live Cacti page render.

- thold_webapi.php: web-page action handlers that read \ and the database directly.

None of these can be require()'d into the isolated unit test process, matching the existing allowlist entries' precedent exactly. Verified locally: running patch-coverage.php against the PR's actual base ref confirms all 11 files are no longer reported as unexpected-unmeasured.

* docs: add PHPDoc blocks to remaining thold_functions.php functions

* chore: refresh translation template after PHPDoc line-number shifts
2026-09-25 12:30:04 -04:00
Sean ManciniandTheWitness 2288c7a1ee security: replace rand() with hrtime(true) for graph cache-buster (GHSA-vhwj-hfwg-gfg3) (#806)
* security: replace rand() with hrtime(true) for graph cache-buster (S2245)

Replaces the non-cryptographic PRNG rand() with hrtime(true), a
monotonic nanosecond clock that never throws. This URL parameter is
a cache-buster, not a security boundary, so a CSPRNG (random_int)
is the wrong reliability tradeoff — it can throw Random\RandomException
on CSPRNG failure, making threshold editing fatal.

hrtime(true) provides:
- Never throws (no CSPRNG dependency)
- Monotonic (never goes backwards on NTP step)
- Nanosecond resolution (no collisions on fast page renders)
- Returns int (clean URL query parameter)

Fixes GHSA-vhwj-hfwg-gfg3
Rule: php:S2245 (CWE-338)

* fix: restore SQL binding, trigger-command quoting, and RPN safety fixes

These security/robustness fixes were already documented in CHANGELOG.md and
covered by tests (GetAllowedThresholdsTest, TholdCommandExecutionTest,
TholdReplaceThresholdTagsTest, TholdExpressionMathRpnTest,
OptionalCoreFunctionTest), but the corresponding thold_functions.php changes
were missing, leaving the Pest suite failing on every PR built on develop.

- get_allowed_thresholds()/get_allowed_threshold_logs(): bind graph_id and
  caller-supplied params instead of interpolating them into the SQL text,
  and use the *_prepared fetchers.
- thold_replace_threshold_tags(): add a \ flag that quotes
  device/threshold free-text values with cacti_escapeshellarg() when the
  substituted text is a trigger command; email/notification callers are
  unaffected.
- thold_command_execution(): pass shell=true when building the three
  trigger commands, and fix a topic-string typo ('thold' vs 'thold_cmd')
  that silently suppressed exit-status logging for inline (non-queued)
  command runs.
- thold_expression_math_rpn(): remove a stray break that exited the
  operator switch before pushing the 0/0 result, flag modulo-by-zero
  instead of letting PHP throw DivisionByZeroError, reject non-numeric
  unary operands before eval(), and flag SQRT/LOG results that are NAN or
  INF instead of pushing them onto the stack.

* fix(tests): stop includes/arrays.php loading from silently no-op'ing

thold_functions.php includes includes/arrays.php with a plain include()
(not include_once()) from several of its own functions (e.g. thold_log()),
keyed off \['base_path']. Once any test in the shared Pest process
exercised one of those call sites, PHP's include-once registry considered
the file already included: a later thold_test_load() (require_once) on the
same resolved path silently no-op'd and never (re)published \
to \, depending on which order the test files happened to run in.

This intermittently broke every test that reads \
(TholdReplaceThresholdTagsTest's THOLDTYPE substitution) as well as tests
several call frames downstream of thold_log()/thold_check_threshold()
(NotificationEmailDeduplicationTest, ThresholdTimeBasedCharacterizationTest),
depending on file execution order.

Add thold_test_load_always()/loadPluginSourceAlways(), which use a plain
require() instead of require_once(), for plugin files that only assign
file-scope variables (no function/class declarations) and are therefore
safe to load more than once. Switch the four test classes that load
includes/arrays.php to the new helper.

* debug: temporary CI diagnostics for notification/restoral test failures

Adds stderr diagnostics behind THOLD_CI_DEBUG to see the real values
computed on the Linux Pest CI run for the two failures that do not
reproduce locally on Windows. Will be removed once the root cause is
identified.

* debug: make CI diagnostics fire unconditionally for this run

* Revert "debug: make CI diagnostics fire unconditionally for this run"

This reverts commit 71877471e7.

* Revert "debug: temporary CI diagnostics for notification/restoral test failures"

This reverts commit 76d05ad300.

* debug: temporary CI diagnostics (round 2)

* chore: retrigger CI

* Revert "debug: temporary CI diagnostics (round 2)"

This reverts commit 7ce80b2d1c.

* debug: temporary CI diagnostics (round 3)

* chore: retrigger CI for diagnostics

* Revert "debug: temporary CI diagnostics (round 3)"

This reverts commit 9aff7a428e.

* debug: temporary CI diagnostics (round 4)

* chore: retrigger CI (2)

* Revert "debug: temporary CI diagnostics (round 4)"

This reverts commit 4bb7f44ecf.

* debug: temporary CI diagnostics (round 5)

* chore: retrigger CI (3)

---------

Co-authored-by: TheWitness <thewitness@cacti.net>
2026-09-21 10:23:07 -04:00
Thomas Vincent 1c0d2a2fe3 security: harden SQL, output escaping, and unserialize paths (#773) 2026-08-30 13:35:57 -07:00
TheWitness 0f526404f7 Updating copyrights to 2026 (#740) 2026-02-14 14:16:33 -05:00
TheWitnessandCopilot 2d3b623d7a Updating workflow to include code validation PHP8.4 and MariaDB 10.6 (#739)
* Adding Worflows for code validation

* Apply php-cs-fixer rules

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-06 06:59:30 -05:00
ec9dfdbfbf Fix for 723 (#735)
* Agents for Github

* Ci workflow

* fix syntax

* Update plugin-ci-workflow.yml

* Update agent tools

* Initial plan

* Fix PHP 8+ type coercion error in pagination calculations

Co-authored-by: bmfmancini <13388748+bmfmancini@users.noreply.github.com>

* Update .github/workflows/plugin-ci-workflow.yml

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: bmfmancini <13388748+bmfmancini@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-04 11:57:28 -05:00
TheWitness a7991dc6cf QA: Update Copyrights to 2025 2025-06-16 09:26:09 -04:00
TheWitness eaec552e82 Fixing issue where all Threshols are checked by default 2024-11-29 21:00:01 -05:00
Petr Macek 974ca4e943 extend email replacement (#696)
* extend email replacement

* update
2024-09-23 10:13:26 -04:00
Jimmy Conner e8402a8db4 Fix a few more undefined variables / misspelled 2024-08-28 02:24:47 -05:00
TheWitness 59b964d545 QA: Fixing Inconsistencies with template_enabled flag 2024-04-15 10:06:48 -04:00
TheWitness dd1b9bde81 Two Validation Features
* feature: Better validation of Threshold values to reduce human error
* feature: Validate Threshold Template values identical to normal Threshold values
2024-04-14 11:37:19 -04:00
TheWitness 94905f3691 Fixing #664 - State Filter Issues Console and Top Tab
Inconsistent counts in thold tab and management -> thresholds
2024-04-06 14:35:24 -04:00
TheWitness 4b14a89172 Allow Templates and Thresholds to have an External ID
feature: Allow Templates and Thresholds to include an External ID
2024-01-30 20:22:37 -05:00
Linegod 1520ee1868 typos 2023-12-05 23:07:22 -06:00
TheWitness 9fc1f8f8b9 QA: Change default form action 2023-11-18 20:36:10 -05:00
Petr Macek 4158d38bfd better default values (#629) 2023-10-13 14:06:02 -04:00
TheWitness d2b687308d QA: More thold testing
* Hide the Baseline Type when the type is not baseline deviation
* More meaningful enable/disable visibility.
2023-10-08 12:09:11 -04:00
TheWitness 4524129b85 Fixing #627 - Form Ambiguity 2023-10-07 13:10:20 -04:00
TheWitness d5505511c1 Fixing Issue #627 - Thold Still Triggering when disabled
Threshold enabled setting issues, templated and non templated
2023-10-07 11:14:00 -04:00
TheWitness c1fb5742aa More QA on #625 2023-10-04 10:19:42 -04:00
TheWitness f6b211b88b Revert "More QA on #465"
This reverts commit 5631350150.
2023-10-04 10:19:07 -04:00
TheWitness 5631350150 More QA on #465 2023-10-04 10:18:20 -04:00
TheWitness 776e781252 QA: One more commit on #625 2023-10-04 09:23:30 -04:00
TheWitness 095b8f0fb5 QA: More issues around #625 2023-10-04 09:07:27 -04:00
TheWitness 81935cf1e6 QA: Fixing #624 - Creating thold from Data Sources Interface
Create thold from Management -> Data Sources produces a lot of php wanings
2023-10-04 08:17:17 -04:00
TheWitness f3c3189ce8 QA: Fixing #613 - Over Escaping 2023-09-07 22:37:14 -04:00
Jing Chen 01db8a818c More case for #585: save->return (#607) 2023-08-11 04:11:27 -04:00
Jing Chen 522dfd2d10 More fixing for #585 (#606) 2023-08-10 11:39:49 -04:00
TheWitness f4f30f80b3 Fixing #135 - Customized Email Subjects
- Ability to change the subject for the threshold alert message
- Rearranged a bit of the forms here as well for readability.
2023-08-05 13:14:49 -04:00
TheWitness c6ce9a9592 Correct some SQL Injection points 2023-08-04 16:00:40 -04:00
TheWitness 063bb35aa0 Fixing #601 and Adding 5 More Baseline Types 2023-08-04 11:20:13 -04:00
TheWitness c6501c1911 Starting #590 - Just the settings with some outstanding issues
Found that there is no good way to hook the settings page without a global JavaScript file.  Really need a hook at the bottom of the settings page.
2023-07-27 21:48:06 -04:00
TheWitness dc83bde317 Allow specification of units suffix and decimal digits
* feature: Allow the specification of the units suffix overriding automatic the number of significant digits to display
2023-07-27 09:10:00 -04:00
TheWitness 1336890179 Fixing Issue #79 - Allow unit suffixes on Threshold Values
Allow and correctly handle unit suffix in the context of values
2023-07-25 19:05:26 -04:00
TheWitness f360f0eb65 QA: Two bugs Timespan and Re-enable Template 2023-07-25 14:50:25 -04:00
TheWitness 72050a81e9 feature: Allow specification of timespan for threshold or template
* feature: Allow the specification of the Graph Timespan when editing/creating the Threshold or Template
2023-07-25 09:37:44 -04:00
TheWitness c31bd71f0a Feature: Support Format Files in Thold
Another long sought after feature request now addressed.
2023-07-24 23:45:31 -04:00
TheWitness 3e0f7a18a8 2 Features around Enabling and Disabling Tholds and Templates
* feature: Mass Enable/Disable at Template Level
* feature: Make Enabling and Disabling a Thold Different than Enabling or Disabling a Template
* QA: Cleanup some of the state calculation logic to make similar between pages.
2023-07-24 22:24:41 -04:00
TheWitness 2ac0f862c6 Fixing #140 - Floating Average Baseline
Baseline Deviation Moving Average
2023-07-22 19:19:46 -04:00
TheWitness a028fbc6e3 Feature #185, Issue #586 - Multiple issues and features
* feature: Allow quick links to the Threshold Template when editing a Thold
* feature#185: Baseline deviation with exact changes
* issue#586: Attempting to edit a non-existing thold template results in plugin being disabled
2023-07-22 18:18:00 -04:00
TheWitness 45c643d224 Additional minor QA: #486 - Skipscale
This changes the defaults and adds a rand() call to get the image to change upon changing the scipscale setting
2023-07-22 13:41:49 -04:00
TheWitness fe2053079f Fixing #486 - Add Skipscale to HRules
add ":skipscale" option to prevent diagram area from being scaled by threshold lines, thus losing granularity in the graphs
2023-07-22 13:25:22 -04:00
TheWitness 4f71ffafeb Fixing #585 - Returning to wrong location
The return Web page is wrong after clicking the "return" button in the "edit threshold"
2023-07-20 19:17:59 -04:00