Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
98064bc
security: migrate uninstall drop statements to prepared
somethingwithproof Mar 15, 2026
0bded94
fix: complete uninstall drop coverage and harden tests
somethingwithproof Mar 16, 2026
419d77f
fix: harden evidence uninstall drop path with IF EXISTS
somethingwithproof Mar 16, 2026
c5258ce
test: expand security test coverage for hardening changes
somethingwithproof Apr 9, 2026
5d26462
fix: escape quotes in Pest regex patterns
somethingwithproof Apr 10, 2026
5b3b479
fix(security): escape evidence filter output
somethingwithproof Apr 11, 2026
56444ae
test: align Evidence test framework with Thold model
TheWitness Sep 11, 2026
a02f42a
fix(tests): correct pre-existing test bugs surfaced by new CI run
TheWitness Sep 11, 2026
c9f6dbc
chore: normalize line endings to LF and enforce via .gitattributes
TheWitness Sep 11, 2026
c8248e9
fix(tests): address Copilot review feedback on PR #30
TheWitness Sep 11, 2026
33cd9c9
chore: remove php-unit-tests.yml workflow from this PR
TheWitness Sep 12, 2026
7e40891
docs: merge copilot-instructions.md with main's structure
TheWitness Sep 12, 2026
863fbce
docs: bring in CHANGELOG.md and updated README.md from main
TheWitness Sep 12, 2026
002f4a7
fix(tests): align phpunit.xml schema path and cacti version check wit…
TheWitness Sep 12, 2026
ad218a0
docs: clarify renaming plugin_evidence directory to evidence on install
TheWitness Sep 12, 2026
b2ffd5c
ci: add plugin-ci-workflow.yml from main and run full test suite; doc…
TheWitness Sep 12, 2026
d649410
ci: run composer install without sudo to avoid root-owned vendor tree…
TheWitness Sep 12, 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
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
448 changes: 448 additions & 0 deletions .github/copilot-instructions.md

Large diffs are not rendered by default.

251 changes: 251 additions & 0 deletions .github/workflows/plugin-ci-workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
# +-------------------------------------------------------------------------+
# | Copyright (C) 2004-2026 The Cacti Group |
# | |
# | This program is free software; you can redistribute it and/or |
# | modify it under the terms of the GNU General Public License |
# | as published by the Free Software Foundation; either version 2 |
# | of the License, or (at your option) any later version. |
# | |
# | This program is distributed in the hope that it will be useful, |
# | but WITHOUT ANY WARRANTY; without even the implied warranty of |
# | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
# | GNU General Public License for more details. |
# +-------------------------------------------------------------------------+
# | Cacti: The Complete RRDtool-based Graphing Solution |
# +-------------------------------------------------------------------------+
# | This code is designed, written, and maintained by the Cacti Group. See |
# | about.php and/or the AUTHORS file for specific developer information. |
# +-------------------------------------------------------------------------+
# | http://www.cacti.net/ |
# +-------------------------------------------------------------------------+

name: Plugin Integration Tests

on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop

env:
CACTI: 1.2.x

jobs:
integration-test:
runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
php: ['8.2', '8.3', '8.4']
os: [ubuntu-latest]

services:
mariadb:
image: mariadb:10.6
env:
MYSQL_ROOT_PASSWORD: cactiroot
MYSQL_DATABASE: cacti
MYSQL_USER: cactiuser
MYSQL_PASSWORD: cactiuser
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3

name: PHP ${{ matrix.php }} Integration Test on ${{ matrix.os }}

steps:
- name: Checkout Cacti
uses: actions/checkout@v4
with:
repository: Cacti/cacti
ref: ${{ env.CACTI }}
path: cacti

- name: Checkout evidence Plugin
uses: actions/checkout@v4
with:
path: cacti/plugins/evidence

- name: Install PHP ${{ matrix.php }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: intl, mysql, gd, ldap, gmp, xml, curl, json, mbstring, snmp
ini-values: "post_max_size=256M, max_execution_time=60, date.timezone=America/New_York"

- name: Check PHP version
run: php -v

- name: Run apt-get update
run: sudo apt-get update

- name: Install System Dependencies
run: sudo apt-get install -y snmp snmpd rrdtool fping

- name: Start SNMPD Agent and Test
run: |
sudo systemctl start snmpd
sudo snmpwalk -c public -v2c -On localhost .1.3.6.1.2.1.1

- name: Setup Permissions
run: |
sudo chown -R www-data:runner ${{ github.workspace }}/cacti
sudo find ${{ github.workspace }}/cacti -type d -exec chmod 775 {} \;
sudo find ${{ github.workspace }}/cacti -type f -exec chmod 664 {} \;
sudo chmod +x ${{ github.workspace }}/cacti/cmd.php
sudo chmod +x ${{ github.workspace }}/cacti/poller.php

- name: Create MySQL Config
run: |
echo -e "[client]\nuser = root\npassword = cactiroot\nhost = 127.0.0.1\n" > ~/.my.cnf
cat ~/.my.cnf

- name: Initialize Cacti Database
env:
MYSQL_AUTH_USR: '--defaults-file=~/.my.cnf'
run: |
mysql $MYSQL_AUTH_USR -e 'CREATE DATABASE IF NOT EXISTS cacti;'
mysql $MYSQL_AUTH_USR -e "CREATE USER IF NOT EXISTS 'cactiuser'@'localhost' IDENTIFIED BY 'cactiuser';"
mysql $MYSQL_AUTH_USR -e "GRANT ALL PRIVILEGES ON cacti.* TO 'cactiuser'@'localhost';"
mysql $MYSQL_AUTH_USR -e "GRANT SELECT ON mysql.time_zone_name TO 'cactiuser'@'localhost';"
mysql $MYSQL_AUTH_USR -e "FLUSH PRIVILEGES;"
mysql $MYSQL_AUTH_USR cacti < ${{ github.workspace }}/cacti/cacti.sql
mysql $MYSQL_AUTH_USR -e "INSERT INTO settings (name, value) VALUES ('path_php_binary', '/usr/bin/php')" cacti

- name: Validate composer files
run: |
cd ${{ github.workspace }}/cacti
if [ -f composer.json ]; then
composer validate --strict || true
fi

- name: Install Composer Dependencies
env:
COMPOSER_ROOT_VERSION: 1.3.0-dev
run: |
cd ${{ github.workspace }}/cacti
if [ -f composer.json ]; then
composer config --no-plugins allow-plugins.pestphp/pest-plugin true
composer require --dev --no-progress --no-interaction "pestphp/pest: ^3" "pestphp/pest-plugin-drift: ^3.0"
rm -f composer.lock
composer install --dev --no-progress
fi

- name: Create Cacti config.php
run: |
cat ${{ github.workspace }}/cacti/include/config.php.dist | \
sed -r "s/localhost/127.0.0.1/g" | \
sed -r "s/'cacti'/'cacti'/g" | \
sed -r "s/'cactiuser'/'cactiuser'/g" | \
sed -r "s/'cactiuser'/'cactiuser'/g" > ${{ github.workspace }}/cacti/include/config.php
sudo chmod 664 ${{ github.workspace }}/cacti/include/config.php

- name: Configure Apache
run: |
cat << 'EOF' | sed 's#GITHUB_WORKSPACE#${{ github.workspace }}#g' > /tmp/cacti.conf
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot GITHUB_WORKSPACE/cacti

<Directory GITHUB_WORKSPACE/cacti>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
EOF
sudo cp /tmp/cacti.conf /etc/apache2/sites-available/000-default.conf
sudo systemctl restart apache2

- name: Install Cacti via CLI
run: |
cd ${{ github.workspace }}/cacti
sudo php cli/install_cacti.php --accept-eula --install --force

- name: Install evidence Plugin
run: |
cd ${{ github.workspace }}/cacti
sudo php cli/plugin_manage.php --plugin=evidence --install --enable

- name: Check PHP Syntax for Plugin
run: |
cd ${{ github.workspace }}/cacti/plugins/evidence
if find . -name '*.php' -exec php -l {} 2>&1 \; | grep -iv 'no syntax errors detected'; then
echo "Syntax errors found!"
exit 1
fi

- name: Set expected Cacti version for unit tests
run: echo -n "${{ env.CACTI }}" | sudo tee ${{ github.workspace }}/cacti/plugins/evidence/tests/.cacti-version > /dev/null

- name: Run Pest Unit Tests
env:
COMPOSER_ROOT_VERSION: 1.3.0-dev
run: |
cd ${{ github.workspace }}/cacti
include/vendor/bin/pest --configuration=plugins/evidence/phpunit.xml \
--coverage-clover=plugins/evidence/coverage/clover.xml \
plugins/evidence/tests

- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-php${{ matrix.php }}
path: ${{ github.workspace }}/cacti/plugins/evidence/coverage/
if-no-files-found: warn

- name: Remove the plugins directory exclusion from the .phpstan.neon
if: ${{ env.CACTI != '1.2.x' }}
run: sed '/plugins/d' -i .phpstan.neon
working-directory: ${{ github.workspace }}/cacti

- name: Mark composer scripts executable
if: ${{ env.CACTI != '1.2.x' }}
run: sudo chmod +x ${{ github.workspace }}/cacti/include/vendor/bin/*

- name: Run Linter on base code
if: ${{ env.CACTI != '1.2.x' }}
run: composer run-script lint ${{ github.workspace }}/cacti/plugins/evidence
working-directory: ${{ github.workspace }}/cacti

- name: Checking coding standards on base code
if: ${{ env.CACTI != '1.2.x' }}
run: composer run-script phpcsfixer ${{ github.workspace }}/cacti/plugins/evidence
working-directory: ${{ github.workspace }}/cacti

- name: Run PHPStan at Level 6 on base code outside of Composer due to technical issues
if: ${{ env.CACTI != '1.2.x' }}
run: ./include/vendor/bin/phpstan analyze --level 6 ${{ github.workspace }}/cacti/plugins/evidence
working-directory: ${{ github.workspace }}/cacti

- name: Run Cacti Poller
run: |
cd ${{ github.workspace }}/cacti
sudo php poller.php --poller=1 --force --debug

if ! grep -q "SYSTEM STATS" log/cacti.log; then
echo "Cacti poller did not finish successfully"
cat log/cacti.log
exit 1
fi

- name: View Cacti Logs
if: always()
run: |
if [ -f ${{ github.workspace }}/cacti/log/cacti.log ]; then
echo "=== Cacti Log ==="
sudo cat ${{ github.workspace }}/cacti/log/cacti.log
fi
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Changelog

--- 0.3 ---
* Add generic snmp info

--- 0.2 ---
* Better data display

--- 0.1 ---
* Beginning
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
# plugin_evidence for Cacti

## Try find serial number, version and important information about devices
## Evidence plugin can be useful when you need to find serial number, firmware change,
or problematic firmware. Plugin can collect information about:
- Entity MIB - serial numbers, part numbers, version, firmware, ...
- MAC addresses
- IP addresses
- vendor specific information

A lot of vendors support SNMP Entity MIB (HPE, Synology, Cisco, Mikrotik, Fortinet, ...).
There are information about serial numbers, part numbers, versions, firmware, ..
For few vendors I added vendor specific OIDs (Aruba, Mikrotik, Synology, ..).
It can be useful when you need to find serial number, firmware change, problematic firmware, ...
The plugin also stores history and can notify you when a change occurs.

## Author
Petr Macek (petr.macek@kostax.cz)

Based on SNVer plugin 0.6

## Installation
Copy directory evidence to plugins directory (keep lowercase)
Copy directory plugin_evidence to the plugins directory and rename it to evidence (keep lowercase)
Check file permission (Linux/unix - readable for www server)
Enable plugin (Console -> Plugin management)
Configure plugin (Console -> Settings -> Evidence tab

## How to use?
You will see information about serial numbers and version on each supported device
You can use Evidence tab or link on edit device page
You can use the Evidence tab or link on edit device page

## Upgrade
Copy and rewrite files
Expand All @@ -31,9 +34,8 @@ Install and enable new version (Console -> Plugin management)
## Possible Bugs or any ideas?
If you find a problem, let me know via github or https://forums.cacti.net


## Changelog
--- 0.1
Beginning
See [CHANGELOG.md](CHANGELOG.md)

--- Based on SNVer plugin 0.6
-----------------------------------------------------------------------------
Copyright (c) 2004-2026 - The Cacti Group, Inc.
1 change: 1 addition & 0 deletions data/index.php
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<?php

header("Location:../index.php");
exit;
9 changes: 4 additions & 5 deletions evidence_tab.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ function evidence_display_form() {

if (cacti_sizeof($scan_dates)) {
foreach ($scan_dates as $scan_date) {
print '<option value="' . $scan_date . '" ' .
print '<option value="' . html_escape($scan_date) . '" ' .
(get_request_var('scan_date') == $scan_date ? ' selected="selected"' : '') .
'>' . $scan_date . '</option>';
'>' . html_escape($scan_date) . '</option>';
}
}

Expand All @@ -142,7 +142,7 @@ function evidence_display_form() {
print '</td>';
print '<td>';

print '<input type="text" name="find_text" id="find" value="' . get_request_var('find_text') . '">';
print '<input type="text" name="find_text" id="find" value="' . html_escape(get_request_var('find_text')) . '">';
print '</td>';
print '<td>';
print __('Specify data type');
Expand All @@ -157,7 +157,7 @@ function evidence_display_form() {
print '<option value="opt" ' . (get_request_var('datatype') == 'opt' ? 'selected="selected"' : '') . '>' . __('Vendor optional', 'evidence') . '</option>';

foreach ($entities as $key => $value) {
print '<option value="' . $key . '" ' . (get_request_var('datatype') == $key ? 'selected="selected"' : '') . '>Entity - ' . $value . '</option>';
print '<option value="' . html_escape($key) . '" ' . (get_request_var('datatype') == $key ? 'selected="selected"' : '') . '>Entity - ' . html_escape($value) . '</option>';
}

print '</select>';
Expand Down Expand Up @@ -260,4 +260,3 @@ function evidence_stats() {
print 'Oldest record: ' . $old . '<br/>';
}


1 change: 1 addition & 0 deletions images/index.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

header("Location:../index.php");
exit;

?>
1 change: 1 addition & 0 deletions index.php
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
<?php
header("Location:../index.php");
exit;
Loading
Loading