Repository navigation
security: move inline event handlers to CSP-safe bindings - #38
Conversation
Cacti's Content-Security-Policy script-src-attr directive blocks inline event-handler attributes. This converts the plugin's remaining inline handlers: - The graph "Add to QuickTree" icon (graph_buttons hook in setup.php) moves its onClick='addQuickTree(...)' to a delegated jQuery binding in js/quicktree.js, carrying the ids via a quicktreeAddLink class and data-local-graph-id / data-rra-id attributes. - The two confirmation-page Cancel buttons in quicktree.php switch from onClick='cactiReturnTo()' to the CSP-safe cactiReturnTo class. The graph_buttons unit test is updated to assert the new data-attribute markup. Cacti 1.2.31+ binds the cactiReturnTo class automatically; the README documents a one-time applySkin() snippet for earlier releases.
There was a problem hiding this comment.
🟡 Changes recommended
Cancel buttons break on supported Cacti 1.2.29–1.2.30 installations without manually patching core.
2 open findings
What changed in this PR
Moves QuickTree interactions to CSP-safe delegated bindings.
Changes:
- Replaces inline graph and Cancel handlers.
- Adds delegated QuickTree click handling.
- Updates tests and compatibility documentation.
| File | Description |
|---|---|
setup.php |
Emits data attributes for graph actions. |
js/quicktree.js |
Adds delegated graph-click handling. |
quicktree.php |
Uses cactiReturnTo classes. |
tests/Unit/QuicktreeGraphButtonsTest.php |
Updates graph-button assertions. |
README.md |
Documents legacy Cacti compatibility. |
CHANGELOG.md |
Records the CSP change. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The graph-buttons test only checked the data- payload, so it would still pass if the quicktreeAddLink class (which the delegated click in js/quicktree.js keys off) were dropped, or if an inline onClick regressed. Assert the binding class is present and that no on*= attribute is emitted.
TheWitness
left a comment
There was a problem hiding this comment.
Review
CSP cleanup looks correct and consistent with the fleet pattern: the graph + icon's inline onClick='addQuickTree(...)' moves to a delegated binding in js/quicktree.js keyed off the quicktreeAddLink class with data-local-graph-id / data-rra-id payloads, and the two confirmation-page Cancel buttons switch to the CSP-safe .cactiReturnTo class. quicktree.js is already injected on every page via the page_head hook, so the delegated handler is present on the graph view.
Open issue addressed (ec1e0cb)
The Copilot reviewer correctly noted that QuicktreeGraphButtonsTest only asserted the data- payload, so it would still pass if the quicktreeAddLink binding class were dropped (delegated click never runs) or if an inline handler regressed. Added two assertions: toContain('quicktreeAddLink') and not->toMatch('/on[a-z]+\s*=/i'). Thread resolved.
Verification
php -lclean on the test file.- Simulated the exact hook output and confirmed all assertions pass, the inline-handler guard catches a reintroduced
onClick, and it does not false-match the real markup.
Note: Pest isn't vendored in the plugin clone (CI runs it against a full Cacti tree), so I validated the assertion logic standalone rather than running the suite locally — worth a green CI check before merge.
The other thread (README < 1.2.31 compat note) was already resolved by the author.


Summary
Removes the plugin's remaining inline event-handler attributes so pages comply with Cacti's Content-Security-Policy
script-src-attrdirective. Part of the fleet-wide CSP inline-handler cleanup.Changes
quicktree_graph_buttonshook) — the graph "Add to QuickTree"+icon moves itsonClick='addQuickTree(...)'to a delegated jQuery binding, passing the ids via aquicktreeAddLinkclass anddata-local-graph-id/data-rra-idattributes.clickbinding (quicktree.jsis already injected on every page via thepage_headhook, so it is present on the graph view).onClick='cactiReturnTo()'to the CSP-safecactiReturnToclass.data-attribute markup, thequicktreeAddLinkbinding class (the hook into the delegated handler), and that no inlineon*=handler is emitted — so the test fails if either the binding class is dropped or an inline handler regresses. Keeps the measuredsetup.phphook at 100% patch coverage.No
__esc()/i18n calls changed, socacti.potis untouched;quicktree.phpis already in the patch-coverage allowlist.Compatibility
Cacti 1.2.31+ binds the
cactiReturnToclass automatically. The README documents a one-timeapplySkin()snippet for operators on earlier releases. No shim is baked into core or the plugin.