* PHPStan Level 8 - Phase 1 Conversion
Reduces the real (no-baseline) PHPStan level 8 error count from ~2,724 to 425
and regenerates phpstan-baseline.neon accordingly (8,941 -> 1,921 lines).
Core type-safety changes
- lib/database.php: narrow db_fetch_row()/db_fetch_row_prepared() to return
array (was bool|array) and db_fetch_assoc()/db_fetch_assoc_prepared() to
return array (was mixed); the _prepared workers coerce the connection-failure
path to an empty array so the declared type is honest. empty()/cacti_sizeof()
checks are unaffected.
- lib/database.php: narrow $db_conn guards from is_object() to instanceof PDO in
the transaction/quote/insert-id helpers so the PDO calls resolve.
- lib/mib_cache.php: the fluent MibCache methods mib()/object()/table()/row()
now return self instead of a bare object so chained calls type-check.
Type-safety casts and guards (mechanical, behaviour-preserving)
- Cast string|false/|null builtin results feeding string parameters
(json_decode, base64_encode, trim, htmle, preg_replace, explode, etc.).
- Cast int|string / int|false values feeding int id/pid parameters.
- Guard resource|false fopen()/popen() handles before fwrite/fclose/fread, and
wrap foreach over array|false/list|false results with `?: []`.
Genuine bugs found and fixed
- cli/add_tree.php / lib/api_tree.php: site tree nodes could not be created via
the CLI - the --site-id option was never parsed, $nodeTypes had no 'site'
entry (passing null to api_tree_item_save(int $type) -> TypeError), and
api_tree_item_save() never persisted site_id. All three fixed.
- tree.php: leaves_exist() is typed : int but returned db_fetch_assoc_prepared()
(an array of rows) for a SELECT COUNT(*); now uses db_fetch_cell_prepared()
and returns the scalar count.
- lib/mib_cache.php: $entries_per_object was a float (division / ceil) used as
an array key (PHP 8.1 implicit float-to-int key deprecation); now cast to int.
Config
- .phpstan.neon: add notIdentical.alwaysTrue and booleanAnd.alwaysFalse to the
existing always-true/false ignore family (same "PHPStan gets confused"
dynamic-constant cause already covered by identical.alwaysTrue,
notEqual.alwaysTrue, booleanAnd.leftAlwaysTrue, etc.).
- phpstan-baseline.neon: regenerated; the remaining 425 entries are the
untouched long tail for Phase 2.
* Remove redundant @phpstan-ignore comments
Follow-up cleanup for the level 8 Phase 1 work. Removes 14 inline
@phpstan-ignore comments that no longer suppress any reported error:
- cli/repair_database.php: `@phpstan-ignore booleanAnd.alwaysFalse` is now
covered by the global booleanAnd.alwaysFalse ignore added to .phpstan.neon.
- 13 others (host.php, include/global.php, include/session.php,
lib/api_automation.php x2, lib/functions.php x2, lib/html_utility.php x2,
lib/installer.php, lib/package.php, lib/reports.php, lib/rrd.php) no longer
match any reported error after the type-safety fixes (e.g. the
db_fetch_row_prepared() return-type narrowing removed the offset-assign
errors the api_automation ignores were suppressing).
Verified with reportUnmatchedIgnoredErrors enabled: 0 unmatched ignores
remain and the full level 8 run still reports 0 errors.
* ci: satisfy validator ratchet and refresh security sink baselines
- lib/api_tree.php: give the new tree-item site_id a real numeric
constraint ('^[-0-9]+$', matching html_reports.php) instead of an
empty regex, so the validator constraint ratchet passes without
bumping its baseline.
- tests/security/baselines: refresh the three sink/hotspot signatures
whose code text changed from the (string) casts added in this branch
(lib/poller.php setsid, cli/rrdresize.php json_encode, lib/import.php
simplexml_load_string).
* ci(js): allow DOMPurify 3.4.16 and update sync_js pin test
The dependabot bump (#8134) moved package.json/package-lock.json to
DOMPurify 3.4.16 on develop but left tests/js/sync_js.test.mjs pinned to
3.4.15, so the PR merge commit fails the 'DOMPurify is pinned' contract.
Bring package.json/package-lock.json to 3.4.16 (matching develop) and
update the pin test to expect 3.4.16.
* test: update sql.php null-handling assertion for the (string) cast
This branch changed scripts/sql.php from trim(\ ?? '') to
trim((string) \) (the phpstan-safe form that coerces both null and
false from shell_exec()). Update SqlScriptsTest's null-return assertion
to match the new cast instead of the removed '?? ''.
* fix: address Copilot review - ownership IDs, fopen guards, mib_cache bound
- chown()/chgrp(): pass integer UID/GID from fileowner()/filegroup()
(guarding the false lookup) instead of string-casting them, which made
them resolve account/group names like '1001' and fail. Covers
lib/api_device.php, lib/boost.php and poller_maintenance.php (x2).
- fopen() failure now short-circuits instead of reporting success:
lib/package.php returns false, lib/clog_webapi.php and utilities.php
render an error, and snmpagent_mibcachechild.php skips the cache write
and sentinel unlink so a concurrent writer's lock is preserved.
- lib/mib_cache.php: keep the float quotient as the loop bound and cast
only the array offset, so a non-even entries/columns split no longer
truncates the loop and drops a cached row.
* revert: keep db_fetch_* returning false on error; baseline Level 8 instead
Per review, restoring the intentional fail-safe: db_fetch_row[_prepared]()
return bool|array and db_fetch_assoc[_prepared]() return mixed again, so a
genuine SQL error (not just a missing connection) is signalled as false and
the === false checks in cdef_is_in_use(), boost_process_* and aggregate.php
work as before. Dropped the is_array() ? : [] coercion.
Level 8 stays green by regenerating phpstan-baseline.neon to capture the
re-introduced bool|array/mixed call-site errors (the ~1,850 the narrowing
had eliminated). Tightening those callers to drop them from the baseline is
Phase 2 work.
---------
Co-authored-by: TheWitness <copilot@users.noreply.github.com>
* form_multi_dropdown: default drop_multi to select2, keep legacy opt-in
The drop_multi form method now renders a select2 'N Selected' multi dropdown by default instead of the legacy jquery-multiselect widget, closing a gap left from the earlier select2-multi-count work (html_graph/html_tree already opted in explicitly). A caller keeps the legacy jquery-multiselect widget by including 'multiselect' in its field class; the Scheduler fields used by Automation Networks (lib/api_scheduler.php), Data Source Profiles consolidation functions (global_form.php) and the Settings selective-debug/spikekill pickers (global_settings.php) are marked accordingly so their existing per-page .multiselect() initializers keep working unchanged. Also drops the duplicate class concatenation the old code emitted.
* settings: convert selective debug and spikekill template pickers to select2
Mirror of the 1.2.x conversion. Drop the inline .multiselect() initializers for the Logging-tab Selective File/Plugin Debug pickers and the Spikes-tab 'Graph Templates to Spike Kill' picker, and remove their 'multiselect' opt-in class, so applySkin() renders them as the select2 'N Selected' multi dropdown. Each keeps its wording via per-field select_all_text/select_count_text (the select2-multi-count data-attribute mechanism used for graph_template_id): 'Select File(s)'/'Files Selected', 'Select Plugin(s)'/'Plugins Selected', and 'Select Template(s)'/'Templates Selected'. Empty stays the placeholder text (poller_spikekill.php treats no selection as none).
* settings: align array operators in debug/spikekill defs (php-cs-fixer)
* html_form: legacy opt-in strips select2-multi-count; add drop_multi tests; fix stale docblock
When a drop_multi field carries both 'multiselect' and 'select2-multi-count', the legacy opt-in now wins: the select2-multi-count token is stripped so applySkin() does not also decorate the field and collide with the page's own .multiselect() init. Adds tests/Unit/Ui/Html/FormMultiDropdownSelect2Test.php covering the default injection, legacy opt-in, preserved plugin class, no duplication, and the both-token precedence (either order collapses to the legacy widget). Also drops the stale 'Settings selective debug' example from the helper comment since this PR converts those fields to select2.
* feat: convert generic <select> elements to select2, with new class helpers
Replaces the jQuery UI selectmenu() catch-all in setSelectMenus() with select2,
applied uniformly to single and multi selects. Fewer than 10 options disables
the search box (minimumResultsForSearch: Infinity); 10 or more enables it -
same threshold now applied to the existing select2/select2-multi classes.
New layout.js class helper: select2-multi-count, a multi-select whose
selection summary reads "N Selected"/"All Selected" instead of one chip per
option (generic multiSelectAllText/multiSelectCountText strings in html.php,
overridable per-field via data-select-all-text/data-select-count-text/
data-select-all-value). graph_template_id (html_graph.php x2, html_tree.php)
now uses it in place of the jquery.multiselect-based .graph-multiselect,
preserving the existing "All Graph Templates"/"N Templates Selected" wording
and the -1 "all" sentinel behavior (reimplemented via select2:select/unselect
events in setSelectMenus()). The old .graph-multiselect jquery.multiselect
init block is left in place (now unreachable for core's own markup) in case
a plugin/theme still emits that class itself.
select2-callback is reworked from its previously-unused static-URL contract
into an ajax-backed replacement for the legacy .drop-callback/makeCallbacks()
autocomplete widget: data-action + data-variables build the query the same
way makeCallbacks() already did (pageName + action + live values of other
named fields + search term), and data-callback still names a JS function to
invoke on selection, matching form_callback()'s existing $on_change/$class
contract. form_callback() only renders the new <select> markup when its
$class parameter contains select2-callback (opt-in); every existing caller
that doesn't request it keeps the exact legacy output. html_graph.php's
host_id filter (both places) opts in. form_multi_dropdown() gained optional
$select_all_text/$select_count_text/$select_all_value parameters (all
additive/backward compatible) to plumb the graph_template_id wording through.
Compatibility: an org-wide code search found no plugin depending on the
.select2-callback/.graph-multiselect/.drop-callback/makeCallbacks() internals
being changed here (form_callback()'s default output is unchanged; the
.graph-multiselect jquery.multiselect init stays available). Everywhere else
in core that assumed the old jQuery UI selectmenu widget on elements now
covered by the broadened catch-all (disableField()/enableField(), the SNMP
security-level/protocol refresh logic, realtime.js's ds_step/graph_start/size
refresh, api_aggregate.php's field enable/disable, and html_reports.php's
branch_id/site_id/host_template_id handling) now branches on
.select2-hidden-accessible and uses select2's own refresh mechanism
(.trigger('change.select2')) instead, alongside the untouched legacy
selectmenu branch. #user_language and #i18n_default_language (which get
their own bespoke flag-icon languageselect widget) are excluded from the
catch-all, same as before.
The install wizard (install/install.js) has its own independent selectmenu
initialization and is intentionally left untouched.
* fix: use json_encode for select2 multi-select JS translation strings
* fix: make select2 initializers idempotent to stop duplicate widgets
applySkin() (which calls setSelectMenus(), where every select2/select2-multi/
select2-multi-count/select2-callback/catch-all initializer lives) runs more
than once per page view - once from cactiReady() on initial load, and again
from the generic AJAX-completion handler after any loadUrl()/postUrl() call,
which most list/filter pages already trigger during their own initial load.
Since calling .select2() a second time on an element that already has it
initialized creates a second, independent .select2-container next to the
first (select2 does not no-op or tear down the previous instance), every
affected <select> ended up rendering twice. Guard every initializer (plus
the graph_template_id -1 sentinel's event bindings, now namespaced and
unbound first) so a second setSelectMenus() pass skips elements already
marked .select2-hidden-accessible.
* fix: match select2 dropdown styling to the dark theme's real button look
border-radius was 4px (should be 6px, matching .ui-corner-all used
everywhere else); the selection box and dropdown panel were flat black
instead of this theme's actual .ui-button/.ui-widget-content backgrounds
(a subtle gradient-highlight image and a repeating texture image,
respectively). Also add a min-width and force the selected text/dropdown
option list to a single line instead of wrapping.
* fix: match select2 dropdown styling to each theme's real button look
Same fix as the earlier dark theme commit, applied to the remaining themes.
Every theme's select2 override previously used generic placeholder colors
(border-radius: 4px, background: #ffffff/#222222) that did not match that
theme's actual .ui-state-default/.ui-button/.ui-widget-content styling:
- cacti, carrot, hollyberry, raspberry, modern, paw: selection box now uses
the real button gradient-image background instead of flat white; dropdown
panel background already matched and is unchanged.
- sunrise: selection box background corrected to transparent (matching its
real button style) and the dropdown panel to its real black background,
instead of flat white for both.
- paper-plane: selection box background corrected to this theme's real
near-black button color instead of flat white.
- midwinter: switched from hardcoded generic colors to this theme's own
CSS custom properties (var(--border-color), var(--background-content),
var(--text-color-lighter), etc.), matching jquery-ui.midwinter.css.
border-radius is now 6px everywhere, matching .ui-corner-all. All themes
also gained a min-width and forced the selected text/dropdown option list
onto a single line instead of wrapping.
* fix: default select2's dropdownAutoWidth to true
The legacy jQuery UI selectmenu widget always sized its open dropdown to fit
the widest option, regardless of how narrow the closed control itself was.
Select2 defaults to matching the dropdown's width to the control's, so wide
option text was wrapping/truncating inside a narrow panel. Set this as a
global default once instead of touching every individual select2() call.
fix: destroy any existing select2 widget before re-initializing
applySkin() runs more than once per page view. The existing
:not(.select2-hidden-accessible) guards were meant to make re-running the
select2 initializers a no-op, but duplicate widgets were still being
reported. Explicitly tear down any select2 instance still attached right
before the initializers run again, so a widget can never end up duplicated
regardless of why applySkin() re-ran.
fix: don't select2-ify a select a plugin already widget-ified with selectmenu
Symmetric to the above: if a plugin's own script already deliberately
applied jQuery UI selectmenu to one of its selects (a few do, for their own
dynamically-created fields), skip converting it to select2 too.
* fix: convert the Device filter's legacy drop-callback widget to select2-callback
html_host_filter()'s autocomplete-enabled branch never got the select2
treatment applied to every other filter field - it still built its own
<input class='drop-callback'> wired up by the older makeCallbacks()/jQuery UI
autocomplete widget (styled with the legacy ui-selectmenu-button markup),
instead of opting into form_callback()'s newer select2-callback rendering like
everything else. Left side-by-side with now-modernized neighboring filters,
this old widget stood out as a leftover "old select". Switch it to the same
select2-callback select markup (data-action='ajax_hosts',
data-variables='site_id') the 1.2.x branch already uses, reusing the existing
ajax_hosts handlers and get_allowed_ajax_hosts()'s id/label response shape.
* fix: restore select2's gradient after closing without selecting, shrink its height, and drop the now-unneeded min-width
Every theme's active/open select2 style also matched .select2-container--focus,
but select2 leaves that class on the container after the dropdown closes (it
only drops --open), so the flat "active" background stuck around until the
next selection instead of the gradient returning right away. Scope the active
look to --open only.
Also shrink the single-select control from select2's stock 28px down to 24px
(and its arrow/rendered text to match) so it sits closer to the jQuery UI
button height it's replacing, and drop the min-width: 160px placeholder added
earlier to keep wide option text from being clipped - dropdownAutoWidth now
sizes the open dropdown to its content regardless of the closed control's
width, so the constraint is no longer needed.
* feat: add configurable select2 search threshold; drop autocomplete_enabled on develop
Add the same Select Search Minimum Rows setting added on 1.2.x, wiring it
through as the select2SearchRows JS global (include/global_session.php) and
replacing the hardcoded 10-option cutoff in every select2 initializer in
layout.js.
Remove Autocomplete Enabled entirely on develop: it only ever existed to let
the Classic theme opt out of the ajax-backed callback widgets, and Classic
doesn't exist as a develop theme. html_host_filter() and the Graph Items data
source field now always use the ajax-backed rendering (select2-callback /
drop_callback) unconditionally instead of branching on the removed setting.
* fix: keep the first 20 select2 results visible before scrolling
Select2's stock results list only guaranteed ~7-8 rows (200px) before
scrolling. Pin each result row to a consistent 24px (matching the shrunk
control height) and size the list's max-height to fit 20 of them before the
scrollbar kicks in.
* fix: repair layout.js corruption from the select2SearchRows commit, and exclude .multiselect from the catch-all
A faulty automated edit in 3cbc5a75 (feat: add configurable select2 search
threshold) matched the wrong text in 4 places and clobbered unrelated code
instead of the intended minimumResultsForSearch lines:
- deleted the fa-remove icon-class swap and mangled the `if (!theme)` check
- deleted setupPageTimeout()/CsrfMagic.end()
- left a stray bare `select2SearchRows` statement before the themeReady() call
- deleted the #password/#password_confirm delayKeyup wiring and broke the
showPage deferred's closing brace
Restored all four to their pre-corruption behavior and applied the intended
select2SearchRows threshold to the actual 4 select2 init blocks this time
(select2, select2-multi, select2-multi-count, and the generic catch-all).
While in there: the catch-all's '.multi-select'/'.graph-multiselect'
exclusions never matched anything real - form_multi_dropdown() always tags
its <select multiple> with plain 'multiselect', so every field using the
older jquery.multiselect plugin (Automation's day/month pickers, Consolidation
Functions, Selective Debug, etc.) was getting select2-ified on top of its own
dedicated multiselect() init. Exclude '.multiselect' instead.
* feat: checkbox-styled option rows for select2-multi-count dropdowns
Gets closer to the old jquery-multiselect look the count-style multi-selects
(Graph Templates, etc.) replaced: each option row in the open dropdown now
shows a checkbox-style indicator instead of plain text, driven by
[aria-selected] via CSS so it stays in sync with select2's own selection
state without any extra JS bookkeeping. closeOnSelect stays off so multiple
options can still be picked without the dropdown closing between clicks; the
closed control still shows the "N Selected"/"All Selected" summary text.
* fix: match multi-select control height to single-selects and add its missing dropdown arrow
select2's stock multi-select box only had a min-height with no matching
override, so it stayed taller than every single-select control next to it;
select2-multi-count fields never actually show real per-option chips (the
rendered area always gets replaced with "N Selected"/"All Selected" text),
so it's safe to tighten this to match.
select2 also only renders a .select2-selection__arrow element for
single-selects - multi-selects (Templates, Days of Week, etc.) got none by
default, so they looked handle-less next to every single-select control. Add
a matching CSS-only arrow via ::after (flips on select2-container--open,
same as the single-select's).
* fix: stop select2's multi-select inline search box from collapsing to near-zero width
Select2 sizes the inline search input it embeds in .select2-selection__rendered
by measuring the box's natural layout; my earlier height-matching CSS
(zeroed padding, a fixed line-height, and extending the single-select's
overflow:hidden/text-overflow:ellipsis truncation to multi-selects too) broke
that measurement, so the search field rendered as a barely-visible sliver
sitting inline next to the "N Selected" text instead of expanding to a usable
width.
Back off to a lighter touch: only nudge min-height down a little (no padding/
line-height overrides), and keep the overflow/ellipsis truncation scoped to
single-selects, which is where it was actually needed (short "N Selected"/
"All Selected" labels on multi-selects don't need it and it wasn't there
before this session's changes).
* fix: hide the inline search box on select2-multi-count controls
Reducing padding/line-height (previous attempt) didn't stop the box from
showing - select2's inline search-while-typing input for multi-selects still
rendered as a tiny stray rectangle next to the "N Selected" text and kept
inflating the control's height, since that input's own margin/height are
part of the rendered area's natural content flow regardless of the parent's
box model.
select2-multi-count fields always replace the rendered area with summary
text and rely on checkboxes in the open dropdown for picking options, so the
inline search box serves no purpose here - hide it outright via the adjacent-
sibling selector (select.select2-multi-count + .select2-container), which
also lets the control's height settle back down to match single-selects
without needing to fight select2's own sizing math.
* fix: let select2-multi-count's search box work again once opened; fix vertical alignment
Hiding the inline search box outright also removed the only way to search a
multi-select's open dropdown (multi-select mode has no separate dropdown-only
search box - the inline one filters the open list too). Scope the hide to
:not(.select2-container--open) instead, so it stays out of the way while
closed but reappears once the dropdown is open.
Also wrap the "N Selected"/"All Selected" label in its own span
(select2-count-label) instead of writing bare text into
.select2-selection__rendered, so its line-height/truncation can be
controlled independently of whatever else (the search box) shares that
container - this was causing the text to sit off-center vertically.
* fix: keep the multi-select control's height fixed when its search box opens
Even scoped to select2-container--open, the inline search <li> was still
sitting inside .select2-selection__rendered as a normal block-level sibling
of the "N Selected" label span, so it pushed the label onto its own line and
grew/shifted the whole control upward whenever the dropdown opened - visible
proof the search box was structurally part of the "selection" element, not
just visually overlapping it.
Take it fully out of flow with position: absolute (sized to the control via
top/left/right/height: 100%, overriding select2's own inline width/height on
the actual <input>), so it can never affect the parent's layout regardless of
when it's shown. Also switch the control to flexbox with align-items: center
for reliable vertical centering of the label instead of a guessed
line-height, and give it the same 8px left inset the single-select's text
already has.
* fix: stop the multi-select's overlaid search field from painting over the label
The generic .select2-search--inline .select2-search__field rule gives search
boxes a solid background (matching the dropdown panel's search box, where
that's correct) - but once resized to fill the whole control via absolute
positioning, that same solid background completely hid the "N Selected"
label behind it while the dropdown was open. Make it transparent/borderless
instead, and hide the label (visibility, not display, so layout doesn't
shift) while open so there's no overlapping text underneath the cursor.
* fix: put the multi-select's search box on its own row instead of overlapping the selection
Overlaying it via position: absolute solved the layout-corruption bug but
traded it for a worse one - it now hid the "N Selected" label completely.
Let it flow normally below the label instead (its own full-width block, small
top margin for separation), matching how a search box should actually behave
- visible on its own line, not fighting the label for the same space. The
container only grows taller while the dropdown is actually open, since the
search row is hidden entirely while closed.
Also reset the stray margin select2 puts on #select2-<id>-container (the
same element as .select2-selection__rendered) - it was inflating the closed
control's height too.
* fix: multi-select search box wraps below label; vertically center label text
The row-direction flex box for select2-selection--multiple had no
flex-wrap, so once the search field was added as a second full-width flex
item its own line-item competed with the label item in the same row -
squeezing/overlapping both instead of the intended label-then-search
stacked layout. flex-wrap: wrap lets the label take row 1 and the
full-width search field naturally wrap to row 2, only while open.
Also give the label an explicit line-height matching the control's height
(same technique already used for the single-select boxes) - flex centering
alone left the text sitting a few pixels high due to the font's default
line-height metrics.
* fix: search select2-multi-count from the dropdown, not an inline box in the control
Root cause of the open-state height jump: select2 gives every multiple-select
a type-to-filter <input> INSIDE the selection control (its SelectionSearch
adapter). When the dropdown opens that input appears, growing the control and
pushing the surrounding filter rows down. No amount of CSS on an in-flow child
of the control avoids that - the search genuinely lives inside the control's
box.
Single-selects don't have this problem because their search lives in the
floating dropdown panel (DropdownSearch adapter), which is body-attached and
never affects page layout. So give the multi-count controls the same wiring:
a custom dropdownAdapter (Dropdown + DropdownSearch + MinimumResultsForSearch
+ AttachBody) that searches from the panel, and a selectionAdapter of just
MultipleSelection + EventRelay with no inline search box at all.
The control now keeps a fixed height whether open or closed, and the surrounding
form no longer shifts. Guarded so it falls back to default behavior if the
select2 AMD modules aren't reachable.
* fix: show 15 select2 dropdown rows before scrolling instead of 20
* fix: actually apply the multi-count dropdown-search adapters + trim control padding
Two bugs behind the "search still looks attached to the (green) control and the
control grows when open" report:
1. The adapters were required with the ARRAY form of select2's amd.require(),
which almond defers via setTimeout - so multiCountDropdownAdapter/
multiCountSelectionAdapter were still undefined when the init loop ran, and
select2 silently fell back to its default inline search box inside the
control. Fetch each module with the synchronous string form instead so the
adapters are actually in place at init time. The search now lives in the
floating dropdown (black), not inline in the green open-state control.
2. Vendor select2.css's .select2-container--default .select2-selection--multiple
adds padding-bottom:5px (equal specificity, so it wasn't being reset), which
left the count label sitting against the top of the control with a gap below.
Set explicit padding: 0 20px 0 0 so the flex-centered label is truly centered
and the closed control matches the single-select height.
* fix: size select2-multi-count control/dropdown to content, not the native listbox width
* fix: reload graphs after the Template select2 fully closes, not mid-teardown
* docs: track pending select2 upstream dropdown-search PR for future cleanup
* docs: link the actual select2 upstream PR (#6462)
* fix: sync checkbox visuals for graph_template_id's -1/others exclusivity; skip reload if nothing changed
Two bugs in the "All Templates" (-1) mutual-exclusivity sentinel:
1. Selecting -1 didn't visually uncheck the other checkboxes, and vice versa.
The old code flipped the underlying <option>.selected directly and fired a
plain 'change' event - but select2's own 'change' listener only refreshes
the "N Selected" summary label, not the open dropdown's rendered results
list. The checkbox marks are drawn from aria-selected on those already-
rendered <li> elements, which never got touched. Fixed by routing through
select2's own internal event bus (available via $el.data('select2')) with
'select'/'unselect' triggers instead - the exact same path a real click
takes, which also runs Results.setClasses() to redraw the checkboxes.
2. Opening the dropdown and closing it again without changing anything used
to still reload the graphs. Now the selected value is snapshotted on open
and compared on close; the reload only fires if it actually changed.
* fix: force checkbox refresh in graph_template_id sentinel to fix off-by-one visual lag
Reported symptom: click template T1 while "All Graphs & Templates" is
checked - the "All" box unchecks correctly, but T1 does not visually check.
Click T2 next - T1 (not T2) now shows checked. Click T3 - T2 shows checked.
The checkbox visual was always exactly one click behind the actual selection.
Rather than keep chasing the precise internal event-ordering that causes
this (select2's DataAdapter/Results adapters both listen to the same
internal 'select'/'unselect' events our sentinel re-triggers), force a
direct, unconditional call to the Results adapter's own setClasses() method
(exposed publicly as $el.data('select2').results) immediately after our
selection changes. This guarantees the open dropdown's checkboxes reflect
the current underlying <option> selected state before the handler returns,
independent of dispatch ordering.
* debug: temporary console diagnostics for graphTemplateSentinel checkbox lag
* fix: checkbox checkmark keys off --selected class, not aria-selected (hover was stealing it)
Root cause of the "checkbox always one click behind" bug, finally confirmed
via console diagnostics: our checkbox checkmark CSS keyed off the
aria-selected attribute, but select2's own results.js reuses that exact same
attribute for a second, unrelated purpose - tracking which row is currently
mouse-hovered/keyboard-highlighted (a legitimate ARIA listbox pattern). Every
time the mouse moves onto a new row, select2 clears aria-selected on whatever
row was previously "highlighted" and sets it on the newly-hovered row,
completely independent of actual selection state.
Since a user naturally moves the mouse toward the next item immediately after
clicking the current one, this hover-tracking code was stealing
aria-selected="true" away from the just-selected row and handing it to
whatever's now under the cursor - producing exactly the observed "previous
box shows checked, current one doesn't" pattern. Confirmed via console
logging: aria-selected was momentarily correct right after each click (when
our own forced setClasses() call ran), then immediately got reassigned by the
very next mouseenter as the user moved toward their next target.
Fix: key the checkmark off the select2-results__option--selected CSS class
instead. That class is exclusively added/removed by setClasses() based on the
real underlying <option>.selected state, and is never touched by the
mouseenter/highlight-tracking code - so it can't be hijacked by hovering.
Also removes the temporary console.log diagnostics added while tracking this
down; the forced setClasses() calls in the sentinel are kept as harmless extra
insurance.
* chore: apply php-cs-fixer alignment fixes
CI's php-cs-fixer dry-run flagged 4 files for pure whitespace/alignment
drift introduced by the select2 conversion: array `=>` operators and a
docblock's @param columns need to align to the widest key/name in their
respective blocks, and two inline PHP print tags were missing the space
before `?>`. No behavioral change.
* fix: address Copilot review findings on select2 conversion (develop)
- lib/html_form.php: form_callback()'s select2-callback opt-in path used
htmle() (double_encode=false) for the select's id/name/class, its
data-action/data-variables/data-callback attributes, and the
pre-selected option's value attribute. A pre-encoded entity in any of
these caller-supplied values would survive into the attribute and be
decoded back into markup/quotes by the browser. Use html_escape_attr()
(double_encode=true) for all of these attribute contexts; the option's
text content stays on htmle() since that's body text, not an
attribute. Same fix for form_multi_dropdown()'s three
data-select-all-text/data-select-count-text/data-select-all-value
attributes.
- lib/html_reports.php: changeTree()'s replaceWith(data) on #branch_id
only swaps the <select> element itself, leaving a live Select2
instance's sibling .select2-container orphaned in the DOM. Destroy the
existing Select2 instance first so the re-initialization a few lines
down doesn't produce a duplicate branch control.
include/layout.js's select2-callback CSRF finding: verified this is not
an actual bug. select2 4.0.13's AjaxAdapter.query() calls
options.data.call(...) and hands the result straight to $.ajax() via the
default transport; for type: 'post' with a plain-object `data` and no
processData:false/contentType override, jQuery serializes it as the POST
body via $.param(), and Cacti's csrf_check() reads the token via
filter_input(INPUT_POST, ...). The __csrf_magic data() callback already
present here (since the PR's first commit) does get sent correctly. No
global $.fn.select2.defaults override clobbers it. Replied with this
analysis rather than changing working code.
Verified: php -l on both changed PHP files; brace-balance check on
lib/html_reports.php (295 open / 295 close).
* fix: address remaining Copilot review findings on select2 conversion (develop)
- include/layout.js: move the select2-hidden-accessible teardown in
applySkin() to run before setSelectMenus() instead of after it, so the
catch-all initializer still re-enhances plain <select> elements that the
teardown just destroyed (previously they stayed native after any
post-initial-load applySkin() re-run).
- include/layout.js: namespace the select2-callback widget's
select2:select listener and unbind it before rebinding, since destroying
and recreating the Select2 instance on every AJAX filter reload does not
remove a plain jQuery listener bound to the underlying <select>, which
was accumulating duplicate invocations of the configured callback.
- include/layout.js, lib/auth.php, lib/html.php: thread $noany/$nonone
from html_host_filter() through to its ajax-backed select2-callback
widget (as data-noany/data-nonone attributes forwarded as request vars),
and have get_allowed_ajax_hosts() honor them. $sql_where is intentionally
left unapplied over the ajax path and documented as such: passing
caller-supplied raw SQL across the client/server boundary would be a new
SQL injection vector, unlike the boolean any/none toggles.
- lib/html.php: use html_escape_attr() instead of htmle() for the two
attribute contexts in html_host_filter()'s markup (data-callback and the
option value), since htmle()/html_escape() disables double_encode and so
a pre-encoded quote entity in the input could survive and be decoded
back into a live quote by the browser, breaking out of the attribute.
htmle() is kept for the visible option text.
- lib/html.php: use cacti_js_encode() instead of plain json_encode() for
the two new multi-select translation strings emitted into the inline
<script> block, since json_encode() alone does not hex-escape </script>
sequences.
- lib/html_reports.php: use the global select2SearchRows setting instead
of a hard-coded 10-row threshold when reinitializing the branch_id
Select2 control after an AJAX tree change, so the configured
"Select Search Minimum Rows" setting (including "Always") is respected.
- include/themes/paper-plane/main.css, include/themes/sunrise/main.css:
fix unreadable dark-on-dark Select2 control text (both the base control
and its rendered value) by using each theme's existing light foreground
convention instead of the near-black color left over from the plain
jQuery UI selectmenu styling.
Verified: tests/Unit/InlineScriptDataEncodingTest,
tests/Unit/Security/Xss/HtmlEscapeTest, and reports/host/graph-filter
related Unit tests all pass; php -l and node --check clean on touched
files; empirically reproduced (jsdom + real select2 4.1.0 + jQuery 4.0)
that the select2-multi-count adapter combination does not create a
duplicate inline search box, contrary to one review comment - no code
change made for that finding, replied with the reproduction instead.
* security: add nonce CSP mode for inline JavaScript protection
Reworks the content_security_policy_script setting into a three-mode Inline JavaScript Protection dropdown (HTMLX default, Nonce, None) and ports the per-request nonce, strict-dynamic policy, and CSP violation report endpoint from 1.2.x. The stored option key and its default are unchanged, so existing installs keep their current policy byte-for-byte; nonce mode is opt-in.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* security: stage nonce CSP enforcement safely
Add report-only migration, gated enforcement, nonce-aware shared emitters, Linux Docker validation, and operator documentation.\n\nRefs #7703
* security: validate CSP header sources
Reject malformed alternate-source configurations at the CSP boundary, validate fallback report URIs, and remove the obsolete Psalm header-taint baseline entry.\n\nRefs #7705
* chore: drop the composer.json change from this PR
Dependency and manifest changes are a maintainer call and do not belong in
this one.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
---------
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* Harden remote graph transport boundaries
* Tighten remote graph SVG validation
* fix: PHPStan Issues with emerging code
* Refresh security baselines after develop rebase
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* Match transport test to the explicit response-header default
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
---------
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
* feat(rendering): add view renderer abstraction
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* isolate renderer traversal test file
* Standardize renderer headers and endpoint guard
* style(renderer): use standard unit-test header in CactiRendererTest
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(renderer): reject null-byte paths before realpath
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* ci: refresh sink and hotspot baselines for line shifts
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(renderer): guard root base path and template-dir redirect
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(renderer): canonicalize both paths in index.php direct-access guard
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* hardening: normalize renderer base path to one separator
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(renderer): reject filesystem root as template path
A /-rooted renderer collapsed the containment prefix to /, which
str_starts_with() matches for every absolute path, so any file was
includable. Fail closed by refusing a root template path.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* hardening: reject windows drive-root template path
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* refactor: adopt PHP 8.4 idioms in view renderer
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* test: cover renderer abstraction to full coverage
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* hardening(renderer): reject UNC template names and fix sink baselines
Refuse a leading-backslash (UNC) template name the same way absolute
POSIX paths are refused, skip the direct-request redirect when
SCRIPT_FILENAME carries a null byte, and correct the renderer include
and views redirect line numbers in the security baselines.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* style: apply php-cs-fixer
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(renderer): use PHP 8.1-compatible readonly property in CactiRenderer
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* hardening(rendering): drop template context array before include
Unset the internal context array after extract so an included template
only sees the extracted variables, not the full context.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* ci: refresh security baselines for renderer line shift
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(renderer): simplify containment check and drain nested output buffers
The redundant real_path !== template_path comparison in
validateTemplateFile() can never be false once is_file()/is_dir() have
run, so drop it and keep the str_starts_with() prefix check as the
actual containment guard. renderFile() also only unwound a single
output buffer, so a template that opens (and leaves) its own buffer
could leak an ob level or drop its content; unwind every buffer opened
during rendering and reassemble them in the order they were written.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* ci: refresh security baselines for renderer buffer/containment fix
The dynamic_include line for lib/renderer.php's include shifted again
after adding drainOutputBuffers().
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* feat(htmx): vendor htmx 2.0.6 and add opt-in filter loader
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* test: cover htmx filter loader
Add missing-vendored-file case for htmx_script_tag and mark the pre-bootstrap read_config_option guard as uncoverable.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* test: harden htmx loader harness and tighten enable check
Skip anything but an exact 'on' for htmx_enabled, reject 4xx/5xx fixture
responses, fail fast when the fixture base path is unresolved, pin
setup-php to a commit SHA, and reindent the e2e specs to tabs.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* style: apply php-cs-fixer to htmx test files
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* test(htmx): drop duplicate script-tag src assertion
The subdir-install test repeated the preceding assertion; CACTI_PATH_URL is
fixed at bootstrap so it could not exercise a distinct scenario.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(e2e): drop sqlite3 from docker-php-ext-install
php:8.2-apache already ships sqlite3 built in, and its ext/sqlite3
source only carries config0.m4 (not config.m4), so building it
standalone always fails with "Cannot find config.m4", breaking the
e2e image build before Playwright ever runs.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* test(htmx): clear stat cache around version-file rename
Earlier tests already stat the version file via file_exists()/
file_get_contents(), so PHP's stat cache can report it present right
after these tests rename it away, making the assertions flaky.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(htmx): recompute script-tag cache-buster per call
The md5 cache-buster was cached in a static, so FPM/script_server
processes kept serving a stale ?v=... hash after an htmx.min.js
upgrade. Recompute it per call, matching get_md5_include_js() and
get_theme_paths() in lib/functions.php, and drop the 'v=' parameter
name to match their path + '?' + hash shape.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* test(e2e): drop obsolete MariaDB options
* ci(htmx): run the htmx integration test by path instead of a testsuite filter
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* build: vendor htmx unminified
Debian rejects minified sources. The file is the htmx 2.0.6 dist source; its
minified sibling hashes identically to what was committed, and the pinned SRI
is recomputed over the unminified file.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix: address htmx review feedback
* test(e2e): resolve Cacti version through PHP
* test(htmx): harden portable server cleanup
* ci(actions): update checkout action pins
---------
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
* 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>
* Add Composer binary path setting with installer detection
First half of #6456: the path setting, auto-detection, and a
runnability probe on the Binary Locations step. Ref #6456
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* Normalize Windows path in composer probe
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* Use line comment per cs-fixer
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* Re-ordering issue per spec
ChangeLog is order as follows:
1. Issue first, in numeric order
2. Features next in numeric order
3. For issues and features that do not have a number, they should be at the bottom of each section.
---------
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
* fix(spikekill): escape RRD path in shell exec; fix default method to match dropdown
Bug: '--rrdfile=' . $f concatenated the RRD path without escaping, breaking
any path containing spaces (which is common). Wraps $f in cacti_escapeshellarg().
Bug: spikekill_method default was '2' (Float Range) but the dropdown array
only defined option 1 (Standard Deviation). Fresh installs got Float Range
behavior with Standard Deviation UI, and saving had no effect. Changed
default to '1' to match the visible option.
Fixes: the two remaining open bugs from issue #6652.
Related: #5112, #6647
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* test(spikekill): add regression suite for all 7 bugs from issue #6652
11 tests covering:
- Bug 2: SQL closing paren present in REPLACE INTO
- Bug 3: RRD path wrapped with cacti_escapeshellarg()
- Bug 4: no double-negation in numspike validation
- Bug 5: range validation guard direction correct
- Bug 6: bakfile guards own unlink (not xmlfile)
- Bug 7: spikekill_method default is '1' not '2'
- Integration: user/default assignment chain
Bug 1 (inverted branches) is covered by SpikekillInitTest.php.
Related: #6652#5112#6647
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* test(spikekill): remove tautological inline-closure tests
The two integration tests re-implemented production logic as an inline
closure in the test body, so they could not fail on a regression in
lib/spikekill.php. Removed. The 9 remaining source-scan tests still
guard against the original 7 bugs being re-introduced via grep-level
invariants.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(style): align match arms in ping.php (matches PR #7057)
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix(phpstan): generate baseline for pre-existing Level 6 errors
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
---------
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
* fix: correct codespell-detected spelling errors in PHP source files
Fix 63 spelling errors identified by automated codespell scan across 23
files. All changes are in comments, docblocks, string literals, and one
dead variable assignment ($flage → $flags in lib/database.php). No logic
changes.
Corrected words include: accommodate, authentication, complete, dependent,
draggable, filtering, formatting, heartbeat, immediately, information,
initialize, language, logging, parameter, please, resource, resetting,
similarly, specified, SQLite, statistics, support, timeout, whether.
Exclusions: parms/PARMS (Cacti CLI variable convention), tht/ot (SQL
aliases), CurrOS/hasTables (PHP variables), pring (internal function).
Fixes#6803
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix: address Copilot review suggestions on PR #6804
Remove dead variable assignment activated by $postion -> $position typo
fix in install/upgrades/1_0_0.php. The misspelled variable was never
read, so fixing the name caused it to silently overwrite the correctly
computed $position before the UPDATE. Removing the line restores the
original (intended) behavior.
Fix docblock possessive: "it's formatting" -> "its formatting" in
lib/reports.php.
Refs #6803
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* i18n: regenerate cacti.pot after msgid changes in global_settings.php
"pre-selected" -> "preselected" and "re-using" -> "reusing" changed two
msgid strings. Regenerate cacti.pot so translation tooling picks up the
corrected English source strings.
Refs #6803
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
---------
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
* fix: extend remote_agent_timeout dropdown to 30 and 60 seconds
Large environments with slow remote pollers or heavy reindex
operations can exceed the current 20-second maximum. The default
remains 5 seconds; this only adds options for sites that need them.
Ref #6545
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
* fix: add changelog entry for #6545 and fix array bracket indentation
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
---------
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
* QA: Add database session clear out to change password
* QA: Can not determine average fully loaded
* QA: Synchornize Spikekill with 1.2.x
* Removing Variance as it's not mathmatically correct
* Removing Variance as it's not mathmatically correct
* Properly re-draw graph
* 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>
This removes most entries to $config in the base code. A few new constants were defined to achieve this:
* CACTI_CONNECTION - The status of the current connection
* CACTI_CSRF_SECRET - The path to the csrf secret file
* CACTI_PHP_SNMP - True if php-snmp is installed
* CACTI_WHITELIST - The path to the Cacti Whitelist file if defined
I also moved several $config['poller_id'] to the existing POLLER_ID and move a number of $config['is_web'] to the existing CACTI_WEB constants.
There remain a few artifacts in the code. They will be handled in a separate commit.
* This merges @xmacan's changes and performs additional functions.
* Adds composer.json and composer.lock to include folder
* Places the flag-icons and phpmailer into that file
* Updates flag-icons and phpmailer to latest
* Adds the autoloader.php to global.php
* We only log in English by policy.
* Friendly Names use Title Case.
* Convert the poller_warning_1h_count to a drop_array.
* Add 'Disabled' for the 0 setting in the array.
* Change the global default for preview rows per page
* Change the gathering function for the -1 value
* Change the save function for a -1 value
* Change the way button callbacks work
* Restore the 'Save' function for Tree View after Filter Class light re-design.
* Fixing the display of unknown data as a global setting
* Re-arrange some RRDtool options such as business hours to be more prominent in both global and user settings.
* Convert colors to drop-color objects
* Add Business Hours as a Checkbox on Graphs Pages
* Make a filter function for both Thumbnails and Business Hours
* Defaults for replace_svalues, remove_orphans, and package_location
* Make trust signature work between repo and local files
* Move some functions into core import functions
* Accept trusted tokens from different sources
* In support of the packaging plugin, we need to add some columns to the host_template table including:
- version
- author
- email
- copyright
- tags
- installation
We also create new General Settings for Default Author information.
* Boost log file visibility and rotation not as expected
* New Requirement is that the boost log must also be in the Cacti log file, error will be displayed otherwise.
* Also, the Boost Log path moved to the "Paths" section and what remains in the Boost section is a new toggle to Enable Boost Debug logging.