Skip to content

fix: repoint include/ -> includes/ plugin_hooks on every upgrade check so broken installs self-heal - #410

Merged
TheWitness merged 2 commits into
developfrom
fix/repoint-include-hooks-unconditionally
Oct 1, 2026
Merged

TheWitness merged 2 commits into
developfrom
fix/repoint-include-hooks-unconditionally

Conversation

@TheWitness

Copy link
Copy Markdown
Member

Summary

Enabling intropage can fatal with a redeclaration, and after manually deleting the old include/ directory the data collector/UI then logs a flood of SECURITY ERROR: Attempted inclusion of invalid plugin file include/settings.php from intropage with the hook name config_settings.

ERROR PHP COMPILE_ERROR in Plugin 'intropage': Cannot redeclare intropage_get_allowed_devices()
  (previously declared in .../plugins/intropage/include/functions.php:47)
  in file: .../plugins/intropage/includes/functions.php on line: 47
SECURITY ERROR: Attempted inclusion of invalid plugin file include/settings.php from intropage with the hook name config_settings

Root cause

The plugin's library directory was renamed include/ -> includes/. intropage_upgrade_database() already contains the migration that repoints stale plugin_hooks rows from the old path to the new one:

db_execute("UPDATE plugin_hooks SET file = REPLACE(file, 'include/', 'includes/')
    WHERE name = 'intropage' AND file LIKE 'include/%'");

…but it lives inside the if (!cacti_version_compare($oldv, $current, '=')) version gate. On an install whose plugin_config.version was already bumped to the current version without its hooks having been repointed (e.g. the version write succeeded on an earlier load but the hooks were not, or the repoint shipped in a later commit of the same version number), the gate is permanently closed and the repoint never runs again.

With the old include/ directory still on disk, the stale include/functions.php and the new includes/functions.php both get loaded in one request -> Cannot redeclare .... Once the user removes include/ to escape that, the stale hook rows now point at a missing file and Cacti's plugin file-inclusion security check rejects every one -> the repeated SECURITY ERROR lines.

Fix

Run the idempotent hook repoint unconditionally, before the version comparison, so a broken install self-heals on the next upgrade check (which is reached via plugin_intropage_check_config() / plugin_intropage_upgrade(), both invoked by Cacti core directly rather than through the broken hook rows). The WHERE ... file LIKE 'include/%' filter makes it a no-op on healthy installs. The now-duplicate copy inside the version gate is removed.

Validation

  • Only includes/database.php changes; the repoint moves out of the version gate, no other logic is touched.
  • Healthy installs: zero rows match file LIKE 'include/%', so the extra UPDATE is a no-op.
  • Broken installs (version already current, hooks still on include/...): the repoint now runs, rewriting the rows to includes/..., which clears both the redeclaration fatal and the SECURITY ERROR floods on the next page load.

Note: I was unable to run php -l in this environment; the change is a straight hoist of an existing statement, reviewed by inspection.

The hook file repoint lived inside the version-change gate in
intropage_upgrade_database(), so installs whose plugin_config.version was
already bumped to the current version (but whose plugin_hooks rows were
never repointed from the old include/ path) never got healed. With the old
include/ directory still present this produced "Cannot redeclare ..."
fatals from loading both include/functions.php and includes/functions.php;
after deleting include/ it produced repeated "SECURITY ERROR: Attempted
inclusion of invalid plugin file include/settings.php" because the stale
hook rows point at a now-missing file.

Run the idempotent repoint UPDATE unconditionally (before the version
comparison) so broken installs self-heal on the next upgrade check. The
WHERE ... file LIKE 'include/%' filter makes it a no-op on healthy
installs. The duplicate copy inside the version gate is removed.
@TheWitness
TheWitness requested review from xmacan and a balanced review from Copilot October 1, 2026 18:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The existing current-version lifecycle test will fail until updated for the new database call.

Review effort: Balanced
Findings: 1 High severity

Open (1)
What changed in this PR

Moves stale hook-path repair outside the version gate so broken installations self-heal.

Changes:

  • Runs the include/ → includes/ hook migration on every upgrade check.
  • Removes the gated duplicate.
File Description
includes/​database.php Makes hook-path repair unconditional.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread includes/database.php
TheWitness added a commit to Cacti/plugin_evidence that referenced this pull request Oct 1, 2026
The hook file repoint lived inside the version-change gate in
plugin_evidence_upgrade_database(), so installs whose plugin_config.version
was already bumped to the current version (but whose plugin_hooks rows were
never repointed from the old include/ path) never got healed. With the old
include/ directory still present this risks "Cannot redeclare ..." fatals
from loading both include/<lib> and includes/<lib>; after deleting include/
it produces repeated "SECURITY ERROR: Attempted inclusion of invalid plugin
file include/<lib>" because the stale hook rows point at a now-missing file.

Run the idempotent repoint UPDATE unconditionally (before the version
comparison) so broken installs self-heal on the next upgrade check. The
WHERE ... file LIKE 'include/%' filter makes it a no-op on healthy installs.
Mirrors the intropage fix (Cacti/plugin_intropage#410).
…e installs

The repoint moved out of the version-change gate, so plugin_intropage_check_config()
now issues the idempotent plugin_hooks UPDATE even when the stored version already
matches. Update the lifecycle test to pin that contract (exactly one db call: the
repoint) instead of asserting no work is done.
@TheWitness
TheWitness merged commit 3496e4d into develop Oct 1, 2026
5 checks passed
@TheWitness
TheWitness deleted the fix/repoint-include-hooks-unconditionally branch October 1, 2026 21:22
TheWitness added a commit to Cacti/plugin_evidence that referenced this pull request Oct 7, 2026
…k so broken installs self-heal (#55)

* fix: repoint include/ -> includes/ plugin_hooks on every upgrade check

The hook file repoint lived inside the version-change gate in
plugin_evidence_upgrade_database(), so installs whose plugin_config.version
was already bumped to the current version (but whose plugin_hooks rows were
never repointed from the old include/ path) never got healed. With the old
include/ directory still present this risks "Cannot redeclare ..." fatals
from loading both include/<lib> and includes/<lib>; after deleting include/
it produces repeated "SECURITY ERROR: Attempted inclusion of invalid plugin
file include/<lib>" because the stale hook rows point at a now-missing file.

Run the idempotent repoint UPDATE unconditionally (before the version
comparison) so broken installs self-heal on the next upgrade check. The
WHERE ... file LIKE 'include/%' filter makes it a no-op on healthy installs.
Mirrors the intropage fix (Cacti/plugin_intropage#410).

* test: assert the include/ -> includes/ hook repoint runs on up-to-date installs

The repoint moved out of the version-change gate, so plugin_evidence_check_config()
now issues the idempotent plugin_hooks UPDATE even when the stored version already
matches. Update the lifecycle test to pin that contract (exactly one db call: the
repoint) instead of asserting no work is done.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants