Skip to content

refactor: deduplicate selected-item bulk action dispatch#279

Open
somethingwithproof wants to merge 2 commits intoCacti:developfrom
somethingwithproof:refactor/bulk-action-dispatch
Open

refactor: deduplicate selected-item bulk action dispatch#279
somethingwithproof wants to merge 2 commits intoCacti:developfrom
somethingwithproof:refactor/bulk-action-dispatch

Conversation

@somethingwithproof
Copy link

Summary

Fixes #276

Validation

  • php -l functions.php
  • php -l syslog_alerts.php
  • php -l syslog_reports.php
  • php -l syslog_removal.php
  • php -l tests/regression/issue276_bulk_action_dispatch_helper_test.php
  • php tests/regression/issue276_bulk_action_dispatch_helper_test.php

Copilot AI review requested due to automatic review settings March 7, 2026 02:58
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the Syslog plugin’s rule pages (alerts/reports/removal) to remove duplicated “selected items” bulk-action dispatch logic by introducing a shared helper in functions.php, while keeping per-page action maps local to preserve behavior.

Changes:

  • Add syslog_apply_selected_items_action() helper to centralize selected-item action dispatch and export session storage.
  • Update form_actions() handlers in alerts/reports/removal pages to use the shared helper.
  • Add a small regression test to assert the helper exists and is referenced by all three pages; update changelog for issue #276.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
functions.php Introduces shared selected-item bulk-action dispatch helper (including export session handling).
syslog_alerts.php Refactors bulk action dispatch in form_actions() to call the shared helper.
syslog_reports.php Refactors bulk action dispatch in form_actions() to call the shared helper.
syslog_removal.php Refactors bulk action dispatch in form_actions() to call the shared helper.
tests/regression/issue276_bulk_action_dispatch_helper_test.php Adds regression coverage to detect removal/non-usage of the shared helper (string-based).
CHANGELOG.md Adds issue #276 entry under develop.

exit(1);
}

if (strpos($functions, 'function syslog_apply_selected_items_action(') === false) {
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

This check uses strpos() with an exact substring ('function syslog_apply_selected_items_action('), which is brittle to harmless formatting changes (whitespace/newlines) and can match inside comments. Consider using preg_match() (whitespace-tolerant) or token_get_all() to assert the helper function is actually defined.

Suggested change
if (strpos($functions, 'function syslog_apply_selected_items_action(') === false) {
$tokens = token_get_all($functions);
$helper_found = false;
for ($i = 0, $len = count($tokens); $i < $len; $i++) {
if (is_array($tokens[$i]) && $tokens[$i][0] === T_FUNCTION) {
// Skip any whitespace or comments after 'function'
$j = $i + 1;
while ($j < $len && is_array($tokens[$j]) && in_array($tokens[$j][0], [T_WHITESPACE, T_COMMENT, T_DOC_COMMENT], true)) {
$j++;
}
if ($j < $len && is_array($tokens[$j]) && $tokens[$j][0] === T_STRING && $tokens[$j][1] === 'syslog_apply_selected_items_action') {
$helper_found = true;
break;
}
}
}
if (!$helper_found) {

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

Fixed — using preg_match() now.

Comment on lines +30 to +33
if (strpos($content, 'syslog_apply_selected_items_action(') === false) {
fwrite(STDERR, "Shared selected-items action helper is not used in $target\n");
exit(1);
}
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

This usage assertion relies on strpos($content, 'syslog_apply_selected_items_action('), which will fail if the call is reformatted (e.g., syslog_apply_selected_items_action () and can be satisfied by a commented-out string. Consider switching this to a whitespace-tolerant regex or token-based search to make the regression test stable.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

Fixed — using preg_match() now.

functions.php Outdated
$action_function($selected_item);
}
} elseif ($export_action != '' && $drp_action == $export_action) {
$_SESSION['exporter'] = $export_items;
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

syslog_apply_selected_items_action stores the raw selected_items request parameter ($export_items from get_nfilter_request_var('selected_items')) directly in $_SESSION['exporter'], which is later embedded into a JavaScript document.location string in the alert/report/removal pages without any escaping. An attacker can tamper with the selected_items POST value to include characters that break out of the single-quoted JS string (for example by appending data after a valid serialized array), leading to arbitrary script execution in the context of an authenticated user when the auto-export redirect runs. To fix this, avoid propagating the raw request value into the session for use in HTML/JS; instead derive the export parameter from the sanitized $selected_items array and ensure it is properly URL-encoded or otherwise safely escaped before being inserted into HTML or JavaScript contexts.

Suggested change
$_SESSION['exporter'] = $export_items;
/* Derive exporter from sanitized selected items, not raw request data */
if (is_array($selected_items) && cacti_sizeof($selected_items)) {
$_SESSION['exporter'] = rawurlencode(serialize($selected_items));
} else {
unset($_SESSION['exporter']);
}

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

Fixed — rawurlencode(serialize($selected_items)) now.

somethingwithproof and others added 2 commits March 7, 2026 05:32
Fixes Cacti#276

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
rawurlencode(serialize($selected_items)) replaces storing the raw
request string directly in $_SESSION['exporter']. The raw value was
later embedded verbatim in a document.location JS string, which allowed
XSS if the serialized payload contained quote or bracket characters.

Use the already-sanitized $selected_items array, re-serialize it, then
URL-encode before session storage so the JS embed is always safe.

Also tighten the regression test to use preg_match instead of strpos so
whitespace variations in the function signature do not cause false
failures.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
@somethingwithproof somethingwithproof force-pushed the refactor/bulk-action-dispatch branch from 0fa3c47 to 620318c Compare March 7, 2026 13:37
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.

refactor: deduplicate bulk action item handling across alerts/reports/removal pages

2 participants