Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d0bb152
fix: json-encode pie and treemap chart labels
somethingwithproof Oct 24, 2026
d90f0a5
fix: check panel permission on add, reload and detail requests
somethingwithproof Oct 24, 2026
3353365
fix: require POST for dashboard actions that change data
somethingwithproof Oct 24, 2026
531ff28
fix: run poller rows without an owner as user 0
somethingwithproof Oct 24, 2026
ddbcb20
fix: delete user group auth by user_group_id
somethingwithproof Oct 24, 2026
67ca89f
fix: stop the 3.0.0 permission upgrade failing on a string row
somethingwithproof Oct 24, 2026
20f446d
fix: rename dashboards with UPDATE so sharing is kept
somethingwithproof Oct 24, 2026
e0bddd8
fix: apply the viewer realm check on remote pollers too
somethingwithproof Oct 24, 2026
1897e5d
fix: delete the user panel data row by id when a panel is withdrawn
somethingwithproof Oct 24, 2026
751cc8e
fix: restore hide_disabled when the device lookup fails
somethingwithproof Oct 24, 2026
aed4e23
fix: join threshold event permissions for the viewing user only
somethingwithproof Oct 24, 2026
cf71655
test: cover POST dispatch of dashboard actions
somethingwithproof Oct 24, 2026
5ca386f
chore: update the translation template
somethingwithproof Oct 24, 2026
1004eca
test: add end-to-end tests that run against a live Cacti
somethingwithproof Oct 24, 2026
2281ab5
docs: add changelog entries for the review fixes
somethingwithproof Oct 24, 2026
6d6d33b
test: restore cacti.log after the deliberate warning in the end-to-en…
somethingwithproof Oct 24, 2026
616639d
test: use random bytes for the generated template hash
somethingwithproof Oct 24, 2026
a51934f
fix: look up the panel row before get_panel in the details request
somethingwithproof Oct 24, 2026
1e0f3a2
test: drive the changed entry points end to end
somethingwithproof Oct 24, 2026
63a3747
test: add a report of which tests run the changed lines
somethingwithproof Oct 24, 2026
f085691
ci: serve Cacti and run the end-to-end tests
somethingwithproof Oct 24, 2026
8051e6a
test: fire the graph_buttons hook through Cacti in the end-to-end tests
somethingwithproof Oct 24, 2026
4f99075
docs: note the end-to-end tests and the coverage report in the changelog
somethingwithproof Oct 24, 2026
4e04cd4
test: name the coverage directories after the start of the test name
somethingwithproof Oct 24, 2026
4a69e77
Query NTP over IPv6 and tidy panel leftovers (stacked on #432) (#434)
somethingwithproof Oct 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/plugin-ci-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ permissions:

env:
CACTI: 1.2.x
# Where the end-to-end tests reach the Cacti web server and its database
INTROPAGE_E2E_SCHEME: http
INTROPAGE_E2E_HOST: 127.0.0.1:8080
INTROPAGE_E2E_DB_HOST: 127.0.0.1
INTROPAGE_E2E_DB_NAME: cacti
INTROPAGE_E2E_DB_USER: cactiuser
INTROPAGE_E2E_DB_PASS: cactiuser

concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
Expand Down Expand Up @@ -197,7 +204,41 @@ jobs:
- name: Set expected Cacti version for unit tests
run: echo -n "${{ env.CACTI }}" | sudo tee ${{ github.workspace }}/cacti/plugins/intropage/tests/.cacti-version > /dev/null

# The installer runs as root and leaves cacti.log owned by root; the tests
# restore the log after provoking warnings, so the runner needs write access.
- name: Make the Cacti log writable for the tests
run: |
sudo chown -R www-data:runner ${{ github.workspace }}/cacti/log
sudo find ${{ github.workspace }}/cacti/log -type d -exec chmod 775 {} \;
sudo find ${{ github.workspace }}/cacti/log -type f -exec chmod 664 {} \;

# The end-to-end tests send real requests to intropage.php, so serve the
# installed Cacti with PHP's built-in server as the web user.
- name: Serve Cacti for the end-to-end tests
run: |
p="${{ github.workspace }}"
while [ "$p" != "/" ]; do
sudo chmod o+x "$p" || true
p=$(dirname "$p")
done

cd ${{ github.workspace }}/cacti
sudo sed -i "s#^\$url_path = .*#\$url_path = '/';#" include/config.php
sudo -u www-data nohup php -S "$INTROPAGE_E2E_HOST" -t ${{ github.workspace }}/cacti > "${{ runner.temp }}/cacti-web.log" 2>&1 &

for i in $(seq 1 30); do
if curl -s -o /dev/null --max-time 2 "$INTROPAGE_E2E_SCHEME://$INTROPAGE_E2E_HOST/index.php"; then
exit 0
fi
sleep 1
done

cat "${{ runner.temp }}/cacti-web.log"
exit 1

- name: Run Pest Unit Tests
env:
INTROPAGE_E2E_CACTI: ${{ github.workspace }}/cacti
run: |
cd ${{ github.workspace }}/cacti
"$CACTI_PEST_BIN" --configuration=plugins/intropage/phpunit.xml \
Expand Down
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@

--- develop ---

* security: Encode pie and treemap chart columns as JSON so device template names can no longer end the string in the inline chart script
* security: Check the panel permission when a panel is added, reloaded or opened in the detail dialog, not only when the dashboard renders
* security: Accept dashboard actions that change data (add, remove, resize, settings, sharing, login option) only as POST so they carry Cacti's CSRF token; the favorite-graph button and the panel tools now post
* issue: Fix the poller stopping with a TypeError, and Cacti disabling the plugin, when a system panel definition has no data row yet; poller rows without an owner now run as user 0
* issue: Fix the upgrade from 3.0.0 or older failing on PHP 8 while converting per-panel permissions
* issue: Fix deleting a user group leaving its Intropage permission row behind
* issue: Keep a dashboard's shared flag when dashboards are renamed in the settings form
* issue: Apply the Intropage Viewer realm check on online remote pollers as well as on the main poller
* issue: Delete a user's own panel data row when the panel is withdrawn from them
* issue: Restore the hide_disabled user setting when the device lookup fails
* issue: Join threshold event permissions for the viewing user only, so events are no longer repeated once per user holding a permission
* issue: Look up the panel row before building the details view, so an unknown panel id no longer logs a warning or creates a row
* dev: Add end-to-end tests that log in to a running Cacti and drive intropage.php, the poller, the graph_buttons hook and the upgrade, and run them in CI against the installed Cacti served by PHP's built-in server
* dev: Add tests/bin/e2e-coverage-report.php, which lists the tests that execute each changed line from the end-to-end Xdebug dumps and the unit XML coverage
* issue: Query NTP servers over IPv6 as well as IPv4: an IPv6 address (also in brackets) is used as it is, a name is resolved to its first AAAA and A address and both are tried; the check no longer needs the PHP sockets extension
* issue: Fix the first favourite graph of a user without panels not being stored (the priority came out as NULL)
* issue: `intropage_add_panel()` and `intropage_remove_panel()` could not work against the current schema; they now log a deprecation warning and return false. Register panels with a register_<name>() function in a panellib file
* issue: Stop the poller running panel code, and Cacti logging an authentication error each cycle, for panel rows of users that no longer exist; the rows and their dashboard links are deleted in bounded steps
* issue: Fix the dashboard page not scrolling with the mouse wheel over chart panels: charts were sized from the whole card (header included) and overflowed the card body, turning it into a nested scroller that captured the wheel; charts now keep their server-sized height (which also stops pie/treemap charts growing on every window resize) and card bodies no longer scroll vertically
* issue: Keep long Panel Details content inside the dialog and scrollable, instead of spilling under the Close button pane, on themes (e.g. deepness) that force `.ui-dialog-content` to `overflow: visible`; the dialog height is also capped to the viewport
* issue: Render dashboard panels with a shared, self-contained card chrome (bundled `includes/cards/cards.css` + `cards.js`, no cross-plugin dependency): a left-hand drag handle and unified per-card tools (grow/shrink height, maximize, reload, remove), replacing jQuery UI Sortable with a keyboard-accessible drag; growing/shrinking a panel now resizes it immediately before the persist+reload round-trip
Expand Down
37 changes: 4 additions & 33 deletions display.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,40 +117,11 @@ function display_information(): bool {
$console_access = api_plugin_user_realm_auth('index.php');

// remove admin prohibited panels
$panels = db_fetch_assoc_prepared('SELECT pd.panel_id AS panel_name, pd.id AS id
FROM plugin_intropage_panel_data AS pd
INNER JOIN plugin_intropage_panel_dashboard AS pda
ON pd.id = pda.panel_id
WHERE pda.user_id = ?
AND pda.dashboard_id = ?',
[$_SESSION['sess_user_id'], $dashboard_id]);

if (cacti_sizeof($panels)) {
$removed = 0;

foreach ($panels as $one) {
$allowed = is_panel_allowed($one['panel_name']);
$removed = intropage_remove_prohibited_panels((int) $_SESSION['sess_user_id'], (int) $dashboard_id);

if (!$allowed) {
db_execute_prepared('DELETE FROM plugin_intropage_panel_dashboard
WHERE user_id = ?
AND dashboard_id = ?
AND panel_id = ?',
[$_SESSION['sess_user_id'], $dashboard_id, $one['id']]);

db_execute_prepared('DELETE FROM plugin_intropage_panel_data
WHERE user_id = ?
AND panel_id = ?',
[$_SESSION['sess_user_id'], $one['id']]);

$removed++;
}
}

if ($removed > 0) {
raise_message('intropage_permissions', __('One or more panels was removed due to insufficient permissions. Contact administrator.', 'intropage'), MESSAGE_LEVEL_ERROR);
cacti_log('INTROPAGE WARNING: One or more panels was removed to user ' . $_SESSION['sess_user_id'] . ' due to insufficient permissions');
}
if ($removed > 0) {
raise_message('intropage_permissions', __('One or more panels was removed due to insufficient permissions. Contact administrator.', 'intropage'), MESSAGE_LEVEL_ERROR);
cacti_log('INTROPAGE WARNING: One or more panels was removed to user ' . $_SESSION['sess_user_id'] . ' due to insufficient permissions');
}

if ($display_important_first == 'on') {
Expand Down
4 changes: 2 additions & 2 deletions includes/database.php
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,6 @@ function intropage_upgrade_database(): void {
$panels = initialize_panel_library();
$permissions = db_fetch_assoc('SELECT * FROM plugin_intropage_user_auth');

$permissions['favourite_graph'] = 'on';

if (cacti_sizeof($permissions)) {
foreach ($permissions as $p) {
$user = $p['user_id'];
Expand All @@ -274,6 +272,8 @@ function intropage_upgrade_database(): void {
}
}

$p['favourite_graph'] = 'on';

$perms = json_encode($p);

db_execute_prepared('UPDATE plugin_intropage_user_auth
Expand Down
Loading