4 Commits
Author SHA1 Message Date
TheWitnessandCopilot 66358e0998 Adopt plugin table API and relocate schema to includes/database.php (#254)
* Relocate schema to includes/database.php via plugin table API + db_update_table upgrade

* CI: allowlist unmeasured schema bootstrap and web entry points

* CI: keep include_once for the settings-page-only lib/reports.php load (uncoverable)

* Add manifest.json + upgrade-time file pruning; consolidate themes/ into css/

* database: keep user-owned dashboards table across uninstall

api_plugin_db_table_create() records plugin_monitor_dashboards in
plugin_db_changes, so api_plugin_db_changes_remove() (run by
api_plugin_uninstall() after plugin_monitor_uninstall()) would drop it
even though monitor_drop_tables() intentionally leaves it in place. Remove
the 'create' ownership record after provisioning (install and upgrade
paths) so user dashboards survive an uninstall. Adds a regression test.

* 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 libraries into includes/, flatten css, drop sonar config

db_functions.php, monitor_render.php and monitor_controller.php move into
includes/ (the latter two lose the monitor_ prefix, becoming render.php and
controller.php); monitor.php and the tests load them from there. Each per-theme
stylesheet css/<theme>/monitor.css becomes css/<theme>.css so users can drop
their own css/<theme>.css into the css base, and plugin_monitor_page_head()
looks there, falling back to css/monitor.css. The unreferenced
sonar-project.properties is removed. Old paths are tombstoned so existing
installs drop the stale copies on upgrade.

* Rename includes/db_functions.php to includes/functions.php

Follows the fleet convention for the plugin's shared library filename; monitor.php,
the measured-source list and the unit test load it from the new name.

* 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 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.

* Bump plugin version to 3.0 so the upgrade-time cleanup migration runs

Add a 3.0 CHANGELOG section for this cycle's schema/manifest work and set
INFO version = 3.0 so existing 2.9 installs detect the version change and
run the schema refresh and manifest-based file prune.

---------

Co-authored-by: Copilot <copilot@users.noreply.github.com>
2026-10-01 01:39:53 -05:00
TheWitness 2e5f294c1f test: add Security baseline and expand Unit/Integration coverage for lifecycle (#246)
This plugin had no tests/Security category at all, and setup.php's
lifecycle/device-hook functions had zero test coverage (only db_functions.php
and the request-output escaping/wiring were tested). Closed both gaps:

- Security: added the standard PHP compatibility scan (8.0-8.4
  removed/added syntax) and a static structure check (required
  functions, INFO keys), matching the baseline used across the rest of
  the plugin fleet.
- Unit: plugin_monitor_version(), the lifecycle contract functions
  (plugin_monitor_uninstall - verifies it drops every table it owns,
  plugin_monitor_check_config - both the out-of-range and valid
  monitor_refresh branches, plugin_monitor_upgrade,
  monitor_check_upgrade()'s page-guard and version-drift branches),
  the device-list hooks (monitor_device_filters, monitor_device_sql_where,
  monitor_device_action_array, monitor_device_remove), monitor_draw_navigation_text(),
  monitor_get_default(), monitor_setup_table() (verifies every table it
  provisions), and monitor_poller_bottom() (primary-poller and
  non-primary-poller branches).
- Integration: plugin_monitor_install() (verifies every hook, the
  realm, the tables it provisions, and the config defaults it sets,
  together, in one pass) - this plugin had no tests/Integration
  coverage of setup.php before (the existing Integration tests cover
  request-output wiring, not the plugin lifecycle).

No new unserialize() hardening was needed: setup.php's one
unserialize() call already goes through
sanitize_unserialize_selected_items().

Also fixed tests/.cacti-version, which was pinned to a stale "1.2.31"
and failed the bootstrap's version check against any other real Cacti
checkout (e.g. a local 1.2.32 checkout); "1.2.x" matches the
moving-branch convention used elsewhere in this fleet.

Intentionally left uncovered: monitor_device_table_bottom()/monitor_show_tab()/
monitor_top_graph_refresh()/plugin_monitor_page_head() (print-heavy UI
rendering), monitor_config_settings()/monitor_config_arrays()/monitor_config_form()
(very large), monitor_device_action_execute()/monitor_device_action_prepare()
(large, print/DB-heavy confirmation dialogs), and monitor_api_device_save()
(moderate complexity, comparatively low value relative to the effort of
safely mocking its dependencies) - consistent with similarly-scoped
functions skipped elsewhere in this coverage-expansion pass.

tests/bootstrap-unit.php gained a fixture-mock DB API
(monitor_test_mock_db/monitor_test_reset_db_mocks/monitor_test_db_result,
matching the convention used elsewhere in the plugin fleet),
api_plugin_register_hook/api_plugin_register_realm call-logging stubs,
db_table_exists, and exec_background (call-logging, safe here since
setup.php's poller include always goes through $config['library_path'],
which points at a throwaway test stub, never Cacti core's real
lib/poller.php); read_config_option/set_config_option were rewired from
hardcoded no-ops to a real backing store - all needed by the new tests.

Verified via a real WSL Cacti install (composer-managed Pest, not a
plugin-local vendor tree): 63 passed (303 assertions), up from 31.
2026-09-23 10:04:23 -04:00
TheWitness 4b999d66b9 chore: harmonize CI workflow, templates, and test structure (#244)
* chore: harmonize CI workflow, templates, and test structure

Part of the fleet-wide plugin_* harmonization effort.

- Pin actions/checkout, shivammathur/setup-php, actions/upload-artifact to
  current release commit SHAs (was floating @v4/@v2).
- Stop logging the MySQL root password in CI output (cat ~/.my.cnf ->
  chmod 600).
- Harden MySQL bootstrap: quoted --defaults-file, grants added for both
  'cactiuser'@'localhost' and 'cactiuser'@'127.0.0.1'.
- Add "Restore vendor ownership for Pest" step after Composer install.
- Switch the PHP syntax-check step to the vendor-excluding, null-delimited
  find/xargs pattern used in plugin_audit.
- Remove the unused "Configure Apache" step (apache2/libapache2-mod-php are
  not installed and not needed).
- Simplify the Pest invocation to rely solely on phpunit.xml's <testsuites>.
- No CodeQL workflow added: this repo has no JavaScript/Python/Ruby content
  (PHP only), so there is nothing for CodeQL to scan.
- Consolidate tests/Security/Php74CompatibilityTest.php into
  tests/Security/PhpCompatibilityTest.php, now checking for PHP 8.3/8.4-only
  syntax (this plugin's floor is PHP 8.2 per the CI matrix).
- Remove tests/TestCase.php and its require in tests/bootstrap-unit.php: not
  referenced by any uses(TestCase::class) call in this plugin's tests.
- Add .github/ISSUE_TEMPLATE/{bug_report,feature_request}.md and
  .github/PULL_REQUEST_TEMPLATE.md, styled after Cacti/cacti's own templates.
- Document CI/dependency baselines in copilot-instructions.md.

* chore: add i18n build/verify workflow and bump MariaDB floor to 11.8

- Document the locales/build_gettext.sh + cacti.pot workflow in
  copilot-instructions.md (Weblate owns per-language .po/.mo sync).
- Add a CI step that regenerates cacti.pot and fails if it is stale,
  ignoring the POT-Creation-Date timestamp.
- Mark locales/build_gettext.sh executable.
- Bump the CI MariaDB service image floor to 11.8 (from mariadb:10.6 /
  mysql:8.0).

* fix: mariadb:11.8 healthcheck and i18n step permissions

- mariadb:11.8 no longer ships mysqladmin; use mariadb-admin for the
  service container healthcheck.
- Run chmod/build_gettext.sh with sudo in the i18n verification step,
  since locales/ is owned by www-data by the time it runs.

* chore: regenerate locales/po/cacti.pot with current source strings

Ran the real locales/build_gettext.sh (xgettext/msgmerge/msgfmt) to
refresh the translation template against current source. Per the i18n
workflow documented in copilot-instructions.md, only the regenerated
cacti.pot is committed here; Weblate owns syncing the per-language
.po/.mo files from it.

* fix: make locales/build_gettext.sh string extraction order deterministic

`find` without `sort` returns filesystem/readdir-order results, which
can differ between machines (e.g. a local regen vs. a GitHub Actions
runner), producing a spurious reordering diff in cacti.pot even when
no strings actually changed. Pipe through `sort` and regenerate
cacti.pot with the now-deterministic order.

* fix: Address Copilot review findings on the harmonization PR

- tests/Security/PhpCompatibilityTest.php: fixed the #[Override]/#[Deprecated]
  attribute regexes to also match the fully qualified (`#[\Override]`,
  `#[\Deprecated]`) form, added a realpath() false-guard for the plugin root,
  included the relative file path in both RuntimeException messages, added
  typed-class-constant and dynamic-class-constant-fetch checks (PHP 8.3), and
  restored each()/create_function() removed-in-PHP-8.0 guards that the
  consolidation had dropped. Also excludes include/vendor/ (not just vendor/)
  from the recursive source scan.
- .github/workflows/plugin-ci-workflow.yml: the "Create MySQL Config" step's
  root password is now masked via `::add-mask::` before it's echoed into
  ~/.my.cnf, so it no longer appears in plaintext in the Actions log (chmod
  600 alone only protected the file after creation, not the command's own
  echoed source in the log).
2026-09-21 12:44:08 -07:00
e2fc5aed5f ci: rebuild Monitor CI workflow from plugin_evidence template with Pest tests (#236)
* ci: modernize Monitor workflow

* ci: pin integration tests to Cacti 1.2.31

* ci(security): pin GitHub Actions to commit SHAs

Pin actions/checkout (v5), shivammathur/setup-php (v2) and actions/upload-artifact (v4) to full commit SHAs with a trailing # vX comment. Mutable tags let a compromised or force-pushed tag run arbitrary code in CI; pinning to an immutable SHA is the supply-chain-hardening best practice and matches the SHA-pinned checkout used in the core security workflow.

* Allow Cacti dependency validation warnings

* Align Monitor matrix with Cacti dependencies

* Fix Monitor PHPStan working directory

* Fix duplicate Monitor workflow key

* Guard optional PHPStan configuration

* Guard optional Composer vendor binaries

* Skip unavailable Composer quality scripts

* ci: restore full PHP 8.1-8.4 integration matrix

Keep 1.2.31 pin while covering mid-stream PHP releases.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: grant the Cacti database user the host pattern the service uses

The service container publishes a port, so Cacti reaches MariaDB from the
Docker gateway address and matches cactiuser@'%', not cactiuser@localhost.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: rebuild plugin CI workflow from plugin_evidence template

Replace the Monitor CI workflow wholesale with the plugin_evidence CI workflow, renamed for plugin_monitor, adding Pest test support (phpunit.xml, tests/Pest.php, tests/TestCase.php, tests/bootstrap-unit.php, tests/.cacti-version). Convert the existing raw-script sanity checks in tests/unit, tests/e2e, and tests/Integration into Pest tests, renaming tests/unit to tests/Unit and using PascalCase *Test.php file names.

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: Thomas Vincent <thomas@vincent.dev>
2026-09-15 15:24:17 -04:00