* data_sources: render RRDtool Tune Info as balanced div boxes
rrdtool_tune() emitted an unbalanced mix of html_header() and
html_end_box() calls wrapped around raw table rows inside the single
box opened by data_sources.php. The premature and extra closing tags
corrupted the DOM, which (depending on theme) clipped the Save button
at the bottom of the Data Source edit page while in Data Source Info
mode.
- Separate the execute, CLI and HTML code paths in rrdtool_tune() and,
for HTML, render each section as a self contained, balanced div box.
- Extract and rename the helper print_leaves() to the standalone
rrdtool_tune_print_leaves(), matching the rrdtool_tune_* naming
convention, and emit div rows instead of table rows.
- Switch the data_sources.php wrapper box to div mode to match.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* data_debug: require POST for the Data Source repair actions
Applying RRDfile repairs and rerunning the debugger are state changing
operations, so they should not be reachable with a GET. Driving them
through a GET also meant the follow up redirect was pulled into the
content area as a full page, losing the theme and navigation on
rerender.
Register data_debug.php run_repair and run_debug in the
cactiIsPostActionUrl() allowlist so loadUrl() upgrades them to a
token-bearing POST, and add the matching csrf_require_post() guard so
the browser transport and server side guard stay in sync.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* rrd: split rrdtool_tune into testable render and execute helpers
Break rrdtool_tune() into small single-purpose helpers so each path can
be exercised directly by unit tests (the web display path is otherwise
unreachable under CACTI_CLI):
- rrdtool_tune_print_leaves() takes an explicit $html flag instead of
branching on CACTI_CLI, so both the div and plain-text branches are
testable.
- rrdtool_tune_execute() applies the tune/resize commands for a repair.
- rrdtool_tune_print_cli() prints the source commands as plain text.
- rrdtool_tune_print_html() renders the balanced div boxes.
- rrdtool_tune() becomes a thin dispatcher over the three.
Add tests/Unit/RrdTuneRenderTest.php covering the leaf printer, the HTML
and CLI printers, the execute path and the dispatcher, asserting the
output is balanced div markup with no table rows.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* review: post Data Source Troubleshooter actions via cactiPostAction
Address PR review feedback:
- Switch the Apply Suggested Fixes and Rerun Analysis links to the
existing cactiPostAction/data-url idiom (as data_sources.php already
does for ds_repair) instead of upgrading a loadUrl() GET through the
cactiIsPostActionUrl allowlist. The allowlist path replayed the
query-free mutation URL into browser history, so a refresh reopened
the list instead of the selected Data Source; a full cactiPostAction
submission follows the server redirect to the read-only view URL and
records that in history. The run_repair / run_debug csrf_require_post
guards are retained, and the data_debug.php allowlist entry (and its
now redundant click handlers) are removed.
- Add a callable $executor test seam to rrdtool_tune_execute() (matching
rrdtool_dump_document) so the unit tests assert the tune and resize
commands are actually executed, with resize.rrd produced only when the
resize command runs, rather than passing on the rename alone.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* review: move RrdTuneRenderTest into the Unit/Core/Rrd category folder
Per AGENTS.md, new unit tests belong in a category subfolder rather than
directly under tests/Unit. Move RrdTuneRenderTest there and update the
UnitStubs include depth accordingly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: TheWitness <copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add one-click RRDfile repair to Data Source Info mode
The Data Source Info mode already compares the RRDfile against the Cacti
definition and prints the rrdtool tune recommendations (add a missing Data
Source with DS:name:type:heartbeat:min:max, remove an extra one with DEL:name,
and correct the type, heartbeat, minimum and maximum). It did not, however,
offer a way to apply them from the page the way data_debug.php does.
- Add an "Apply Suggested Fixes" link to the "RRDtool Tune Info" box header when
the web server can write the RRDfile; when it cannot, the header falls back to
"Run Fix from Command Line" and the commands remain listed for manual use.
- Add a ds_repair action that runs the same tune recommendations server-side
(gated on data_source_authorized() and on the RRDfile being writable, and
skipping any recommendation carrying control characters), logs each command to
DSDEBUG, then reloads the Data Source so the result is visible. This mirrors
data_debug.php's run_repair / "Apply Suggested Fixes".
- Harden the Info-mode guard so a missing/unreadable RRDfile (rrdtool info
returning false) no longer triggers an array-offset warning.
* Address review: POST-guard ds_repair and harden repair result check
- Route the "Apply Suggested Fixes" action through a CSRF-protected POST: the
link now uses the cactiPostAction handler (href="#", data-url) instead of a
GET navigation, and ds_repair is added to the $bad_actions guard in
include/global.php so a tokenless request fails closed with 405. ds_repair is
added to the curated CSRF action test for regression coverage.
- Use a strict comparison on the rrdtool_execute() result: it can return null
on a failed exec/proxy connection, and null == '' would have reported a failed
repair as "All RRDfile repairs succeeded."
- Refresh the sink inventory baseline for the new header redirects in ds_repair.
* Add request-coverage probe for the ds_repair RRDfile repair handler
The Data Source Info mode repair handler ds_repair() is a POST action that the
page-level e2e suites do not drive (it needs a Data Source whose RRDfile
mismatches its Cacti definition). Add a request-coverage fixture that loads the
handler in isolation via cacti_fixture_source_function(), stubs its I/O
boundaries, and drives every branch (unauthorized, unreadable RRDfile, no RRA,
nothing to tune, not writable, a control-character recommendation that is
skipped, and both tune success and failure). Register it in
run_request_coverage.sh for data_sources.php changes so the changed-line
coverage gate sees the handler exercised.
* Address review: use defined helpers and boolean repair result
- Replace the undefined cacti_has_control_chars() check with a comparison
against rrd_strip_control_chars() (loaded from lib/rrd.php) to skip any
tune recommendation that carries control characters.
- Execute each tune with RRDTOOL_OUTPUT_BOOLEAN and treat a strict true as
success so proxy storage (which returns the raw 'OK u:...' status under
RRDTOOL_OUTPUT_RETURN_STDERR) is not misreported as a failure.
- Add the new translatable strings to locales/po/cacti.pot and reuse the
existing failure msgid.
- Update the request-coverage fixture to the new boundary contract.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(win32): harden the cmd.exe shell sinks on develop (GHSA-rjvj-r52f-8v5q)
Forward-port of the 1.2.x win32 command-injection remediation. On Windows the
SNMP/ping/data-query/trap commands run through cmd.exe, which ignores the \"
escape and toggles quoting on every ", so cacti_escapeshellarg cannot stop
& | ^ < > ( ).
- add cacti_escapeshellarg_cmd(), stripping those operators on win32 before
quoting (a Unix pass-through)
- snmp_escape_string(): strip the operators in the win32 branch
- route the SNMP binary hostname, the data-query device values
(get_script_query_path), the data-input arg builders, the Windows ping
hostname, and the SNMP trap notification arguments through the strip
get_script_query_path is device-reachable (a rogue monitored device supplies an
SNMP index/system field that executes on the Windows poller); the rest are
post-auth.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(win32): strip %VAR% from the hostname on Windows (GHSA-rjvj-r52f-8v5q)
cmd.exe expands %VAR% even inside quotes, so a device hostname of %USERNAME%
would expand into the SNMP/ping command line. Add an opt-in $strip_env flag to
cacti_escapeshellarg_cmd() and set it for the SNMP binary and ping hostnames,
which never legitimately contain a percent. Community and credential values are
left untouched because they can legitimately contain %.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* docs(changelog): note win32 cmd.exe hardening for develop
* security: require Package Management permission to trust new package signers
package_accept_key() (reachable via the repository-based package import flow)
inserted new keys into package_public_keys, the global trust store consulted
by import_validate_signature() for every future import by every user,
without checking for the Package Management (realm 29) permission that
gates package_keys.php/package.php/package_repos.php for the same table.
An Import Templates (realm 17) user could therefore add themselves as a
trusted signer for the whole install. Also add the 'accept' action to the
CSRF-protected bad_actions list so the acceptance step requires POST plus a
valid token like every other state-changing action.
GHSA-gxgm-8rhv-r7jv
* docs(changelog): note package-signer trust authorization fix
* security: close tab-based open redirect bypass in CSRF timeout handler
sanitize_uri()'s guard (20298c6cd) models the WHATWG rule that browsers
strip leading C0 controls/whitespace before resolving a redirect, but
Chromium separately strips an embedded tab from anywhere in the target.
A request target of /%09/evil.example passes the guard (no leading control
char, not two leading slashes) but Chromium reduces the resulting
'Location: /<TAB>/evil.example' header to a network-path reference and
navigates off-site. 1.2.x already uses validate_redirect_url() for this
same sink (3338a63e1), which resolves the URL via parse_url() and checks
host/port against the server-configured values, so it isn't bypassable this
way. Switch develop's CSRF timeout handler to match.
GHSA-c725-4jm5-9fx5
* security: authorize single-item Report actions against ownership
reports.php sets \ = true, so include/auth.php grants an
implicit guest session (when the Guest User feature is enabled) without
ever evaluating the realm 22 gate declared for this page. The single-item
action handlers reports_item_remove()/_moveup()/_movedown() relied solely
on that page-level gate and performed no independent ownership check, so an
unauthenticated guest-bound request could delete or reorder reports_items
rows belonging to any report, including ones owned by an administrator.
reports_form_actions() already gained an equivalent \
check; add the same authorization (Reports admin realm 21, or the
requesting user owns the item's report) to the three single-item handlers.
Same underlying chain as the 1.2.31 fix for reports_user.php (guest bind
removed + cacti_authorize_resource() added to reports_item_remove()); the
rewritten develop reports.php/lib/html_reports.php did not carry either
half of that fix forward.
GHSA-j5jh-fhwg-r56x
* security: authorize tree node CRUD actions against per-tree access
tree.php dispatches create_node/delete_node/move_node/rename_node/copy_node
directly to api_tree_*() with no is_tree_allowed() check, even though the
normal tree-view path already enforces that boundary. A non-admin user with
the Trees realm but no explicit grant on a given tree_id could still create,
delete, move, rename or copy nodes on that tree by calling these actions
directly, bypassing the authorization boundary enforced elsewhere.
GHSA-prxj-84qq-v5jq
* security: remove shell from Realtime RRD create and validate DS bounds
poller_realtime.php built the Realtime-graph RRD 'create' command line
(including the SNMP-sourced ifSpeed/ifHighSpeed interface speed, substituted
in verbatim as the DS maximum) and ran it through shell_exec(). A hostile or
spoofed monitored device could return an ifSpeed value such as
'1000000000\uid=197608(ladams) gid=197121 groups=197121' and get arbitrary OS command execution as the web/poller
user the next time any user with the Realtime Graphs permission (or an
unauthenticated guest, where configured) viewed a realtime graph for an
affected data source.
- lib/rrd.php: rrdtool_function_interface_speed() now casts ifHighSpeed/
ifSpeed to int before they become the DS maximum.
- lib/rrd.php: rrdtool_function_create() now rejects any non-numeric
rrd_minimum/rrd_maximum right before they are concatenated onto the
rrdtool command line, forcing them to 'U' and logging instead.
- poller_realtime.php: the RRD create is now routed through the same
shell-free rrdtool_execute()/proc_open(bypass_shell) path every other
RRDtool invocation already uses, matching the pattern 1.2.x already uses
for this exact call site, instead of shell_exec().
GHSA-f88m-q789-g22j
* security: authorize Report save/edit against report ownership
reports_form_save()'s update path fetched the existing report's owner from
the database but never compared it to the session user before calling
sql_save(), so any user holding only the Reports realm could overwrite
another user's report by POSTing its id. reports_edit() had the same gap on
the read side: it fetched a report by id with no ownership check, so the
same user could view any other user's report configuration (recipients,
schedule, etc.). 1.2.x already guards both call sites with
cacti_authorize_resource(..., 'reports'); develop had lost that check.
GHSA-8f5c-3h59-q7gc
* security: reject ORDER BY sort_column subquery bypass
sanitize_sql_column()'s allowlist regex kept parentheses to support the
INET_ATON(col)/NATURAL_SORT_KEY(col) sort wrappers, but that also let
MySQL subquery syntax through unchanged, since a subquery like
(SELECT(0)FROM(SELECT(SLEEP(5)))a) needs only alphanumerics and
parentheses. get_order_string() then detects the '(' and disables its
backtick quoting, so the payload reaches ORDER BY verbatim, giving any
user with realm 2-5 a blind, time-based SQL injection via sort_column.
sanitize_sql_column() now only allows '(' through when the whole value is
exactly one of the two known safe wrapper forms around a plain identifier;
anything else containing '(' -- including subquery syntax -- now falls
back to the default. Added regression tests covering the reported
subquery and REGEXP-exfiltration payloads.
GHSA-8j73-cvf6-jrvx
* security: confine Reports format_file to a bare filename
reports_form_save() wrote the POST-supplied format_file value verbatim
into reports.format_file, and reports_load_format_file() concatenated it
onto CACTI_PATH_FORMATS with no directory-component check, so a value
such as ../../../../etc/passwd escaped the formats directory and any
Reports-realm user could read arbitrary files readable by the web
server. 1.2.x already fixed the same sink (GHSA-g37j-39f4-6r4j /
CVE-2026-41884, GHSA-mjvw-mhj5-9jcj / CVE-2026-40084); develop had lost
the guard. format_file is now confined to basename() at both the save
site and the load site, with the load site additionally rejecting a
bare '.'/'..'/empty result before any file IO. Added regression tests.
GHSA-5x27-wqpm-m24v
* security: authorize Data Source enable/disable against owning device
ds_enable()/ds_disable() and the bulk drp_action enable/disable loops in
form_actions() passed a user-controlled local_data_id straight into
api_data_source_enable()/api_data_source_disable() with no object-level
authorization check, so any user holding the Sites/Devices/Data realm
could toggle the enabled state of a data source belonging to a device
outside their assigned Device Permissions.
Added data_source_authorized(\), which allows
host-independent data sources (data_local.host_id = 0) and otherwise
defers to is_device_allowed(\), and applied it to both the
single-item and bulk action paths.
GHSA-2fhv-c794-v433
* security: authorize bulk Change Data Source Profile against owning device
The bulk 'Change Data Source Profile' action (drp_action == '6') iterated
selected_items and updated data_template_data/data_template_rrd/poller_item
for each supplied local_data_id with no object-level authorization check,
so any Sites/Devices/Data realm user could retarget the RRD step/heartbeat
of a data source belonging to a device outside their assigned Device
Permissions -- the same class of gap as GHSA-2fhv, in a different bulk
action. Guarded with the data_source_authorized() helper added for that
fix. This action does not exist on 1.2.x (develop-only feature).
GHSA-fc82-w6xq-4jg7
* security: grant AllowOverride All in docker/apache.conf
The packaged docker/apache.conf granted only 'AllowOverride FileInfo
Options=FollowSymLinks' for the Cacti document root. Cacti's shipped
.htaccess deny rules (log/, cache/*, scripts/, cli/, bin/, mibs/, rra/,
contrib/, tests/) rely on 'Require all denied' (Apache 2.4, override
type AuthConfig) and/or legacy 'Order/Deny' (override type Limit),
neither of which FileInfo/Options covers, so Apache silently ignored
every one of those deny rules and served the directories over HTTP to
any unauthenticated client -- most notably log/cacti.log, which can
contain usernames, client IPs, SQL backtraces, and any secrets Cacti
logs (SNMP community strings, LDAP bind details).
AllowOverride All lets every shipped .htaccess apply as intended. Added
a regression test. docker/ does not exist on 1.2.x (develop-only).
GHSA-fxfg-j995-j69j
* docs: add security advisory / CVE policy to Copilot instructions
Documents the policy established for this remediation effort: develop is
unreleased, so a develop-only vulnerability does not get a CVE requested;
1.2.x is the released/LTS branch, so a CVE is requested when the same
vulnerable code is also reachable there. Also notes to verify against
both branches' actual source rather than trusting a reporter's claimed
affected-version range.
* fix(security): update stale test harnesses and address review findings
CI fixes:
- CsrfCheckContractProbe.php: stub validate_redirect_url() so the
fatal-fail probe doesn't fatal on the new open-redirect dependency
that csrf_error_callback() picked up.
- InstallerCsrfRecoveryTest.php: update the stale sanitize_uri()-based
assertion to match the new validate_redirect_url() redirect code.
- psalm-baseline.xml: drop the TaintedHeader suppression for
include/csrf.php now that validate_redirect_url() resolves it.
Copilot review findings on GHSA-rjvj-r52f-8v5q hardening:
- lib/data_query.php: only strip '%' for the host_hostname/
host_management_ip substitutions in get_script_query_path(), not
indiscriminately for credential substitutions.
- lib/functions.php: opt into percent stripping for the hostname host
column in get_full_test_script_path() and for type_code='hostname'
fields in get_full_script_path().
- lib/snmpagent.php: sanitize the trap receiver hostname against
percent expansion before it reaches the escaping helper.
- tests/security/baselines/*.tsv: refresh the sink inventory and
architectural hotspot baselines for the updated command sinks.
- tests/Unit/DataCollection/Snmp/SnmpCoverageTest.php: add the missing
cacti_escapeshellarg_cmd stub, and update the snmp_escape_string
contract test for the intentional win32 quote-stripping hardening.
- tests/Unit/Security/Shell/CmdMetacharHelperTest.php +
tests/fixtures/CmdMetacharHelperWin32Probe.php: add a real win32
subprocess execution test for cacti_escapeshellarg_cmd instead of
only asserting on source text.
- CHANGELOG: add the pull-request reference to the new entry.
* fix(snmp): remove now-unreachable quote-escaping branch in snmp_escape_string
The metachar strip on the line above already removes the double quote
on win32, so the substr_count(SNMP_ESCAPE_CHARACTER) branch below it
could never execute; drop it so lib/snmp.php reaches 100% coverage
again.
* style: fix pre-existing php-cs-fixer blank-line drift blocking CI
data_sources.php and lib/html_reports.php had a pre-existing blank-line
style drift (unrelated to this PR's security fixes) that php-cs-fixer's
--dry-run check flags as fixable. Since "PHP 8.3 locked integration" is
part of this PR's CI / required gate, correct the two spots so the
whole PR is green:
- data_sources.php: collapse a double blank line before form_actions().
- lib/html_reports.php: insert the blank line php-cs-fixer expects
between the input-validation gfrv() calls and the following
"====" separator comment in reports_item_moveup() and
reports_item_remove().
No behavior change; purely CI/style formatting.
* style: refresh phpstan baseline for pre-existing, unrelated findings
Three PHPStan findings were masked behind the earlier php-cs-fixer
failure and only surfaced once that step passed:
- lib/html_reports.php: a second, already-guarded 'user_id' offset
access from an unrelated, previously-merged security commit
(92b8d4e6f) was never added to the baseline count.
- cli/splice_rrd.php, poller_realtime.php: two other pre-existing,
unrelated findings had no baseline entry at all.
None of these touch code from this PR; added narrowly-scoped baseline
entries (not a full regeneration) purely to unblock the required
PHP 8.3 locked integration check.
* fix(security): address follow-up review findings on consolidated PR
Closes the four remaining review findings from the follow-up review round:
- package_import.php: trustSigner() now POSTs with a CSRF token instead of
$.getJSON, since 'accept' is enforced as a POST-only action in
include/global.php's bad_actions list (GHSA-gxgm-8rhv-r7jv).
- lib/html_reports.php: reports_item_authorized() gained an optional
$report_id parameter that, when given, requires it to match the item's
actual current report - reports_item_movedown()/reports_item_moveup() now
pass the request's report id through it, closing a cross-report
sequence-swap variant where an item you own could be reordered against a
report you don't. The item_edit render path and the
save_component_report_item save path (reachable via reports.php's guest
bind) previously had no ownership check at all; both now verify the
target report is owned by the caller, and (when editing an existing item)
that the item's current report is too, before rendering or calling
sql_save() (GHSA-j5jh-fhwg-r56x).
- tree.php + include/global.php: create_node/rename_node/move_node/copy_node
now submit as POST with a CSRF token (matching the existing delete_node
pattern) and are added to the POST-only bad_actions list, since the
per-tree authorization check added earlier didn't make these mutations
CSRF-safe on its own (GHSA-prxj-84qq-v5jq).
Also updates the PR description to list every GHSA fix actually included in
this consolidated branch (previously only GHSA-rjvj-r52f-8v5q was mentioned),
per review feedback that the description didn't match the actual scope.
* fix: resolve CI failures on PR #8056 (docblock alignment, sink baseline)
- lib/html_reports.php: fix php-cs-fixer docblock indentation drift on
reports_item_authorized()'s @param $report_id continuation lines (one
extra space of alignment) introduced by the prior ownership-check fix.
- tests/security/baselines/sink_inventory.baseline.tsv: refresh to track
the 4 new header('Location: ' . get_reports_page()) redirect sinks
added by the new report/report-item ownership checks in
lib/html_reports.php. Verified via
tests/security/verify_sink_inventory.sh and confirmed
tests/security/verify_architectural_hotspots.sh still reports no new
hotspots.
* fix: track new PHPStan offset findings from extended reports_item_authorized()
phpstan-baseline.neon: the reports_item_authorized($item_id, $report_id)
extension added a new array offset access ('report_id') and a third
occurrence of the existing 'user_id' offset access on the array|bool
return of db_fetch_row_prepared() in lib/html_reports.php. Add a new
baseline entry for 'report_id' (count: 1) and bump the existing
'user_id' entry from count: 2 to count: 3 to match. Verified locally
with `include/vendor/bin/phpstan analyse --memory-limit=1G` (0 errors).
---------
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <copilot@users.noreply.github.com>
* fix(csrf): require POST tokens for item actions
* test(csrf): cover every guarded action path
* test(csrf): keep legacy guard contract extensible
* fix(csrf): hide POST-only targets from crawlers
* test(csrf): reject every crawlable state-action link
* fix(csrf): fail closed without logging crawler probes
* fix(csrf): post data-query item actions safely
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(csrf): normalize stripped token separators
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(csrf): distinguish method and token failures
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(csrf): escape POST action URL attributes
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(csrf): delegate POST action events
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(csrf): post data template add action
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* style(html): align POST button class
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
---------
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* feat(validator): add settings constraint validation pilot
Routes saved settings through Symfony Validator so include/global_settings.php
can declare per-setting constraints inline. The save handler runs one
validator pass and surfaces violations via the existing raise_message()
pattern, replacing scattered ad-hoc checks. Pilot covers 12 high-value
settings; the rest stay on the existing implicit form-render checks.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* ci(infection): allow infection/extension-installer composer plugin
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* docs(validator): document must-be-posted-to-validate contract
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(bootstrap): guard Symfony autoload in global_settings before use declarations
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(test): remove redundant autoload require in CactiSettingsTest
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(test): restore require_once for CactiSettings (not in Composer autoload)
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* feat(validator): fold helper into settings pilot
* fix(validator): translate default Symfony constraint messages
Default Symfony NotBlank/Length/Range/Choice/Positive messages render
in English regardless of Cacti locale because the validator runs
without a Symfony Translator. Pass explicit __()-wrapped message,
minMessage, maxMessage, and notInRangeMessage options on each bare
constraint in include/global_settings.php so violations participate
in Cacti's gettext pipeline. Documents the no-Translator decision in
CactiValidator so future contributors know to translate at the call
site.
Addresses Copilot PR #7077 review feedback.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(graph): improve remote agent parsing and RRD path validation
* feat(validator): migrate automation_graph_rules.php to symfony validator
* refactor(validator): move automation validator helper to shared library and enhance tests
* feat(validator): migrate automation_networks.php to symfony validator
* feat(validator): migrate automation_snmp.php to symfony validator
* feat(validator): migrate automation_templates.php to symfony validator
* feat(validator): migrate automation_tree_rules.php to symfony validator
* refactor(automation): move api_networks_save to shared library for testability
* feat(validator): add validateInput helper and migrate color_templates.php
* feat(validator): migrate host_templates.php to symfony validator
* feat(validator): migrate graph_templates.php to symfony validator
* feat(validator): migrate data_templates.php to symfony validator
* feat(validator): migrate data_input.php to symfony validator
* feat(validator): migrate data_queries.php to symfony validator
* feat(validator): migrate graphs_new.php to symfony validator
* feat(validator): migrate graphs.php to symfony validator
* feat(validator): migrate data_sources.php to symfony validator
* feat(validator): migrate user_group_admin.php to symfony validator
* feat(validator): migrate managers.php to symfony validator
* feat(validator): migrate package_repos.php to symfony validator
* Refactor pollers.php to use CactiValidator
* fix(security): close validator migration regressions
* test(snmp): add spine docker harness
* fix(review): address validator migration feedback
* fix(deps): include validator runtime packages
* chore(deps): normalize composer.json require-block indentation
The validator migration introduced tab-indented entries in an otherwise
space-indented require block. Re-indent the stevenmaguire/* and symfony/*
lines to 8 spaces so the block is consistent.
Co-Authored-By: Oz <oz-agent@warp.dev>
* fix(graphs): repair graph json response branch
* fix(validation): apply php cs fixer
* ci(codeql): skip autobuild for interpreted scans
* fix(link): satisfy phpstan path guard
* chore(pr): remove branch pollution
* ci(codeql): align autobuild pin with init and analyze
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* refactor(automation): use CactiValidator::validateInput, drop wrapper
automation_validate_input() in lib/api_automation.php was a byte-for-byte
duplicate of CactiValidator::validateInput() (identical session handling and
raise_message() semantics, and it already delegated to CactiValidator::validate
internally). Per review feedback, use the shared class directly everywhere
instead of a parallel automation-only wrapper.
- Remove automation_validate_input() from lib/api_automation.php
- Replace all call sites with CactiValidator::validateInput()
(automation_templates/graph_rules/tree_rules/snmp and api_networks_save)
- Update the automation validator unit tests to match
- Add @param/@return PHPDoc to CactiValidator specific-validator methods
Co-Authored-By: Oz <oz-agent@warp.dev>
---------
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: Thomas Vincent <thomas@vincent.dev>
Co-authored-by: Oz <oz-agent@warp.dev>
Co-authored-by: TheWitness <thewitness@cacti.net>
Escape data_source_path/rrd_path with cacti_escapeshellarg at the
create/update/fetch/info/file_exists/mkdir sinks, matching the existing
DEF and tune call sites, and whitelist the fetch consolidation function.
Fully anchor the rrd_minimum/maximum and upper/lower_limit validators
with \z so a crafted numeric prefix or trailing newline can no longer
reach rrdtool.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
* Update data_sources.php
feat: Add bulk change data source profile functionality with automatic RRD rebuild
- Add new action option "Change Profile" in data source bulk actions menu
- Implement profile change with automatic RRD file handling:
- Update data_template_data, data_template_rrd, and poller_item tables
- Automatically backup and remove RRD files when step value changes
- RRD files will be recreated with new parameters at next polling cycle
- Add form configuration for profile selection in bulk action dialog
- Add logging for RRD file backup operations
This feature allows administrators to bulk change data source profiles,
automatically handling the RRD file recreation when polling intervals change.
Old RRD files are backed up with timestamp before removal for safety.
Affects: data_sources.php
* Update data_sources.php
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update CHANGELOG.md for PR #6495
* Fix code style issues
* Apply suggestion from @Copilot
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Refactor loop to use foreach for selected_items
The foreach loop is much easier to read.
* Refactor data source profile updates and checks
Refactor data source profile handling to use cacti_sizeof for checking profile existence and update multiple database tables for remote connections.
* Refactor SQL query for fetching current step value
Also correct for a syntax error.
* Remove unnecessary blank lines in data_sources.php
* Change comment style from block to single line
Copilot does not know how to generate correct comments.
---------
Co-authored-by: TheWitness <thewitness@cacti.net>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Fix#6539 - Allow Standard Cacti Log Files to be Rotated on Demand from the Cacti UI
* QA: php-cs-fixer updates and documentation for lib/database.php
* QA: Update .gitignore for composer files
* QA: Update .gitignore for composer files
* QA: Back off .gitignore change its duplicated
* QA: Fix typing of db_has_permissions
* QA: Fixing typing issue in db_format_index_create
* Update lib/clog_webapi.php
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* QA: Fix additional code issues
* QA: Applying more defaults to add device
* QA: Fix at the database layer
* QA: Fixes based upon automated testing
* QA: Fix at the database layer
* QA: After new SQL checking
* QA: Skip MacTrack oui database download warnings
* QA: Fixing type issue
* QA: Recommendation from Copilot
* QA: Recommendation from Copilot
* QA: Recommendation from Copilot
* QA: Recommendation from Copilot
* QA: Some minor changes to avoid errors in testing
* QA: Unused variable
* QA: Recommendation from Copilot
* QA: Recommendation from Copilot
* QA: Recommendation from Copilot
* QA: Minor introduced code defect
* QA: Adding some unifying space around concatination
* QA: Consistent comments and new function alias'
* QA: Multi-line comment corrections
* QA: Fix SQL Style
* QA: Missed one function alias
* QA: PHPStan Level 2 and PHPDoc fixes
* QA: PHPStan Level 2 and PHPDoc Fixes
* QA: PHPStan Level 6 Fixes
* QA: Fix lib/xml.php to PHPStan Level 6
* QA: Wrong grep -v
* PHPStan Level 6 for lib/vdef.php
* PHPStan Level 8 for lib/time.php
* QA: Raise PHPStan to Level 6 for lib/database.php
* QA: Remove @deprecated tag from grv()
* QA: Switch to htmle() alias over html_escape()
* QA: More addressing PHPStan issues at Level 6
* QA: Change recommended by Copilot for Readability
* QA: More PHPStan fixes
* QA: More PHPStan fixes
* QA: More PHPStan fixes for lib/utility.php
* QA: More PHPStan fixes at Level 6
* QA: Raise PHPStan to Level 6 More Functions
* QA: Raise PHPStan to Level 6 More Functions
* QA: Raise PHPStan to Level 6 More Functions
* QA: Raise PHPStan to Level 6 More Functions
* QA: Raise PHPStan to Level 6 More Functions
* QA: More PHPStan fixes at Level 6
* QA: Raise PHPStan to Level 6 More Functions
* QA: Raise PHPStan to Level 6 More Functions
* QA: More PHPStan fixes at Level 6
* QA: More PHPStan fixes at Level 6
* QA: Raise PHPStan to Level 6 More Functions
* QA: Raise PHPStan to Level 6 More Functions
* QA: More PHPStan fixes at Level 6
* QA: Raise PHPStan to Level 6 More Functions
* QA: Raise PHPStan to Level 6 More Functions
* QA: More PHPStan fixes at Level 6
* QA: Raise PHPStan to Level 6 More Functions
* QA: Raise PHPStan to Level 6 More Functions
* QA: More PHPStan fixes at Level 6
* QA: More PHPStan fixes at Level 6
* QA: More PHPStan fixes at Level 6
* QA: Raise PHPStan to Level 6 More Functions
* QA: More PHPStan fixes at Level 6
* QA: Some phpseclib3 fixups to update to latest
* QA: More fixups for graphing for magic strings
* QA: More PHPStan fixes at Level 6
* QA: Fixing order string type on get_allowed_graphs()
* QA: Fixing improper use of print
* QA: Optimization of color_templates
* QA: Copilot recommendation
* QA: Copilot recommendation
* QA: Copilot recommendation
* QA: Copilot recommendation
* QA: Copilot recommendation
* QA: Copilot recommendation
* QA: Copilot recommendation
* QA: Copilot recommendation
* QA: Raise PHPStan to Level 6 More Functions
* QA: Issues insalling Cacti
* QA: Issues insalling Cacti
* QA: Issues insalling Cacti
* QA: Issues insalling Cacti
* QA: Issues insalling Cacti
* QA: Issues testing Cacti
* QA: Copilot recommendation
* QA: More PHPStan fixes at Level 6
* QA: More PHPStan fixes at Level 6
* QA: More PHPStan fixes at Level 6
* QA: More PHPStan fixes at Level 6
* QA: More PHPStan fixes at Level 6
* QA: Installer failing
* Undo ownership changes to remove tar errors
* QA: Updates after php-cs-fixer
* QA: Adding code checks to syntax checking
* QA Change syntax flow language
* QA: Reduce the number of cures
* QA: Use sequentional option
* Change runner to self-hosted for check job
* Fix typo in OS version in workflow file
* Add Git installation step in workflow
Added step to install Git if not already installed.
* Add '-y' flag to apt-get install and update commands
Updated apt-get commands to include '-y' for automatic confirmation.
* Change workflow OS version to 'ubuntu-latest'
Updated the workflow to use 'ubuntu-latest' instead of 'ubuntu:latest' and modified the 'runs-on' configuration.
* Remove sequential option from phpcsfixer script
* Remove PHPCS fixer step from workflow
Removed PHP coding standards check from workflow.
* Move code checks to before plugins
Moving these core checks to before the plugins are installed as we really want to check only the base Cacti here.
* Add Composer validation and caching to start of workflow
* QA: Addressing PHPStan additional
* QA: Restore composer lock file
* QA: Addressing PHPStan additional
* QA: Addressing PHPStan additional
* QA: Complete LDAP Project
* QA: php-cs-fixer doing it's thing
* QA: Syntax is already happening in PHPStan
* QA: The md5 function no longer exists
* QA: Update after ldap changes
* QA: Undo that last password hack
* QA: Attempting to switch to MariaDB 11.8
* QA: Attempting to switch to MariaDB 11.8
* QA: Resolving some issues with PHP8.4
* QA: Resolving some issues with PHP8.4
* QA: Add PHP8.5 to the matrix
* QA: Removing PHP8.5 due to dependency issues
* QA: Add the DB version to the testing output
* QA: Switch back to MySQL for the moment
* QA: More fidelity in reporting
* QA: The pipe must be mixed
* QA: Moving audit_schema.php changes from 1.2.x
* QA: Moving audit_schema.php changes from 1.2.x
* QA: Restore mysql monitoring
* QA: php-cs-fixer issues
* QA: Attempt to roll back to MariaDB 10.6
* QA: Attempt to fix check_all_pages.sh
* QA: Make installer functional again
* QA: Fix installer php-cs-fixer issues
* QA: Type to a string
* QA: Get the database version correctly
* QA: Fix issue with reports in check_all_pages.sh
* QA: Check the server version in the right place
* Feature: Support SHA256 as a new hash for passwords
* QA: Function definition and return typing audit
* QA: Refinement of form types
* QA: Refinement of form types
* QA: Consistency of comments
* QA: Issues with php-cs-fixer and more comments
* QA: More typing issues
* QA: php-cs-fixer on merge conflict resolution
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Introduce a new wrapper function for showing the show/hide column indicator
* Migrate all Core packages to use that new wrapper function
* Migrate pages to have JavaScript show immediately below the form object.
* Correct some indentation issues
* Finalizing the confirmation API adding special additional tags: return, rmessage for a return even though the object list is non-zero
* Fixing issues with adding objects to reports
* Adding new hook for confirmation API
* Properly supporting legacy hooks that provide their own confirmation HTML.
- When a developer uses backtracing, HTML output can be seen from command line bug confirmed
- When using `input_validate_xxx`, calls to `die_html_input_error()` do not pass variable name bug confirmed
Closes#3559Closes#3560
Update loadPage calls to be loadUrl
Update loadPageNoHeader calls to be loadUrl calls
Also includes changes to make logout adhere to new html_auth_xxx functions