Skip to content

perf(rrd): [1.2.x] reuse capability checks within calls - #8341

Merged
TheWitness merged 3 commits into
Cacti:1.2.xfrom
somethingwithproof:perf/1.2-rrd-version-checks
Oct 14, 2026
Merged

TheWitness merged 3 commits into
Cacti:1.2.xfrom
somethingwithproof:perf/1.2-rrd-version-checks

Conversation

@somethingwithproof

@somethingwithproof somethingwithproof commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

RRDtool update batches repeat the same 1.5 capability comparison for every timestamp; graph construction repeats the same 1.4 comparison for four options. Reuse the result within each call, including false, and recompute it on the next call. Public interfaces, command text and validation remain unchanged.

The regression executes the maintenance update body with instrumented process boundaries: two files, six timestamps, old/new RRDtool versions and a return to the old version. It fails before the change and passes afterward with 42 assertions. Native PHP 8.2.31 validates both production capability expressions and the update fixture; the focused existing Pest runner also passes. Full command/reference comparisons against the pre-change maintenance source remain identical. No dependency or CI changes.

This is the 1.2.x companion to the develop optimization, also carried in #8012. Release notes remain in the final changelog PR #8319.

Development companion: #8340.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
@github-actions
github-actions Bot force-pushed the perf/1.2-rrd-version-checks branch from 892201c to 00462f4 Compare October 13, 2026 20:49
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
bmfmancini
bmfmancini previously approved these changes Oct 14, 2026

@bmfmancini bmfmancini left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed the full diff. The memoization is call-scoped ($supports_skip_past_updates / $supports_graph_formatters are locals initialized to null per function invocation), and get_rrdtool_version() is fixed for the process lifetime, so caching within rrdtool_function_update() and rrd_function_process_graph_options() cannot go stale. Verified on the diff that the only runtime semantics change is one fewer cacti_version_compare() per iteration; behavior for rrdtool < 1.5 is unchanged. The tokenization/eval usage is confined to the test fixture (tests/fixtures/UpdateCapabilities.php), not production code. All required checks pass (PHP 8.2/8.3/8.4 unit + RRDtool integration, changed-coverage >= 80%, POST guard, docker probe). Approving.

xmacan
xmacan previously approved these changes Oct 14, 2026
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
@somethingwithproof
somethingwithproof dismissed stale reviews from xmacan and bmfmancini via a6e8f1a October 14, 2026 06:52
@TheWitness
TheWitness merged commit c1ed40c into Cacti:1.2.x Oct 14, 2026
17 checks passed
somethingwithproof added a commit to somethingwithproof/cacti that referenced this pull request Oct 17, 2026
Records merged 1.2.x fixes that deferred their entries: Cacti#8275, Cacti#8285, Cacti#8318, Cacti#8338, Cacti#8341 and Cacti#8350.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
somethingwithproof added a commit to somethingwithproof/cacti that referenced this pull request Oct 17, 2026
Records merged 1.2.x fixes that deferred their entries: Cacti#8275, Cacti#8285, Cacti#8318, Cacti#8338, Cacti#8341 and Cacti#8350.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
somethingwithproof added a commit to somethingwithproof/cacti that referenced this pull request Oct 17, 2026
Records merged 1.2.x fixes that deferred their entries: Cacti#8275, Cacti#8285, Cacti#8318, Cacti#8338, Cacti#8341 and Cacti#8350. Moves the unnumbered zoom entry from Cacti#8417 into the issue group.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
somethingwithproof added a commit to somethingwithproof/cacti that referenced this pull request Oct 17, 2026
Records merged 1.2.x fixes that deferred their entries: Cacti#8275, Cacti#8285, Cacti#8318, Cacti#8338, Cacti#8341 and Cacti#8350. Moves the unnumbered zoom entry from Cacti#8417 into the issue group.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
somethingwithproof added a commit to somethingwithproof/cacti that referenced this pull request Oct 20, 2026
* fix(installer): [1.2.x] correct layout and test all shipped themes (Cacti#8325)

* test(theme): cover shipped maintenance themes

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(installer): restore headings and fit narrow viewports

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(rrd): [1.2.x] recognize RRDtool 1.9 through 1.11 (Cacti#8354)

* fix(rrd): recognize current RRDtool releases on 1.2.x

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(security): record consolidated RRDtool version probe

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(graphs): clear empty query fields in rendered text (Cacti#8350)

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(auth): escape the password-change username on 1.2.x (Cacti#8338)

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(graphs): [1.2.x] preserve drilldown focus and bound SpikeKill mutations (Cacti#8316)

* Graph drilldown: keep hamburger fixed, icons reachable, hide on graph leave

The action-icon strip now slides down below the hamburger (flex column) instead
of the hamburger dropping to the bottom of the icons. Closing is driven by
leaving the whole graph rather than the small icon strip, so the mouse can move
from the hamburger onto the icons without the strip closing. Leaving the graph
also blurs the hamburger so it no longer lingers after interacting with it.

* changelog: graph drilldown interaction fixes (Cacti#8316)

* Graph drilldown: tolerate tooltip-induced mouseleave, drop hamburger title

A native tooltip appearing over a drilldown icon fires a spurious mouseleave on
the graph (relatedTarget null), which closed the strip. Defer the close and
re-check the graph is genuinely not hovered first, so the icon tooltips no longer
destabilize it. Also drop the hamburger's redundant title (its aria-label stays).

* Graph drilldown: widen the close grace period to 500ms

* Graph drilldown: tie hamburger visibility to the graph image

Reveal the hamburger while the pointer is over the graph image (or the toggle
overlaid on it) rather than anywhere in the graph cell, so moving off the image
hides it after the grace period.  Entering a different graph now immediately
hides and closes any other graph's open strip.

* Graph drilldown: lift the open graph so its strip clears thumbnails below

With thumbnails a short graph's open icon strip overflows onto the graph below;
sibling graphs paint in DOM order, so that graph rendered on top of the strip,
making the icons unclickable and stealing the hover (which closed the strip).
Raise the open graph (.graphDrillActive, position:relative; z-index) so its
overflowing strip stays on top and the graph beneath is not hovered.

* Graph drilldown: reveal via :focus-visible and stop blurring to preserve keyboard focus

* fix(ui): preserve graph action focus during pointer navigation

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(ui): cover graph drilldown interactions and gate PR coverage

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: measure committed PR changes on a policy-compliant runner

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* feature#8316: label the graph drilldown strip as glyph+text rows

When a graph's drilldown strip opens, initGraphDrilldown() rewrites it into one row per action - the glyph followed by its title as visible text - and removes the markup's <br> separators; graph_drilldown.css lays the rows out as a left-aligned menu below the hamburger. The transform runs lazily on open (only the single open strip, never all graphs at load) and once per strip, and derives each label from the inner <i title>, so plugin-contributed icons that follow the same .iconLink/<i title> convention are labelled without any plugin change.

* test(e2e): cover drilldown label menu; simplify labelling; drop defensive br rule

Widen the drilldown E2E fixture so the open labelled panel no longer overlaps the graph image centre (restoring the pointer/grace-period assertions), give its icons real glyphs+titles, and add a test asserting each action is labelled from its tooltip once (idempotent re-open). Fold the icon-label guard into a single branch so every rewritten line is exercised, and drop the defensive iconWrapper br display:none rule (the JS already removes the separators).

* feature#8316: table-layout drilldown menu - text left, glyphs in a right column

Render the open drilldown strip as a display:table menu: each action is a table-row with the label in a left-aligned cell and the glyph in a fixed-width right-hand cell, so the glyphs stack directly above one another. A few pixels of vertical cell padding separate the rows, and the row hover uses a theme-appropriate color-mix wash of the panel's text colour. The label is now prepended (left cell).

* feature#8316: shorten core drilldown icon titles; cover full strip in markup probe

Shorten the graph drilldown action titles so they read well as menu labels: Details, CSV Export, Time View, Realtime, Kill Spikes. Render the GraphDrilldownMarkup coverage probe with the realtime and spikekill realms enabled (and a second realtime-mode pass) so the now-changed conditional title lines keep 100% changed-line coverage.

* feature#8316: label plugin glyphs lacking the drillDown class (fixes intropage eyeball)

Core labelling only recognised glyphs with the drillDown class, so a plugin-contributed icon such as intropage's Add-to-Dashboard eye (a bare fa fa-eye with a title) rendered an empty, unlabelled row. Fall back to the first titled <i> in the link and style any glyph <i> as the right-hand table cell, so plugin icons are labelled and column-aligned without each plugin changing.

* feature#8316: lower drilldown panel opacity, align glyph column, drop duplicate tooltip

Make the open strip panel a touch more translucent (0.82 -> 0.6 alpha) so the graph shows through; nudge the glyph column's right padding so the glyphs line up directly under the hamburger; and strip the row/glyph title once the visible label is shown so no native/jQuery-UI tooltip duplicates the label text on hover.

* feature#8316: make drilldown panel background more opaque (0.6 -> 0.85)

* feature#8316: centre-align drilldown glyph column

* feature#8316: nudge drilldown glyph column a few pixels left

* feature#8316: theme-aware drilldown palette (per-theme fg/bg/accent, fix light-theme hamburger)

Emit per-theme CSS custom properties (foreground, hamburger/panel backgrounds, hairline border and hover accent) as an inline style from graph_drilldown_icons(); graph_drilldown.css consumes them via var() with the prior dark values as fallback. Light themes now get a light pill with a dark glyph and a visible hairline border so the hamburger reads correctly, and the row highlight uses each theme's accent hue.

* feature#8316: e2e assertion that the drilldown strip adopts the theme palette

* feature#8316: move drilldown palette into theme CSS (:root vars); dos2unix theme main.css; add Time View/Realtime/Kill Spikes to pot

* fix(spikekill): bind menu requests and protect mutations on 1.2.x

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(spikekill): measure inline scripts and cover menu dismissal

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* perf(spikekill): skip disabled float debug formatting on 1.2.x

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(spikekill): repair CLI dry-run statistics on 1.2.x

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(spikekill): enforce RRA budgets and propagate failures on 1.2.x

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(spikekill): cover zero-valued window boundaries on 1.2.x

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test: remove unused SpikeKill preference binding

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <1439914+TheWitness@users.noreply.github.com>

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* security: batch 12 (1.2.x) - GHSA-5v3j data-input quoted-placeholder RCE + GHSA-vhh2 spikekill confirm (Cacti#8238)

* security: batch 12 (1.2.x) - data-input quoted-placeholder RCE (GHSA-5v3j) + spikekill confirm (GHSA-vhh2)

GHSA-5v3j-wcrr-jxjg: a Data Input template that wraps a <field>
placeholder in a matched pair of quotes ("<arg1>") neutralized the
value's own cacti_escapeshellarg() single-quoting, letting $(...) or
backticks in a realm-3 user's field value execute on the next poll
(bypassing the CVE-2026-39902 hardening). substitute_script_path() now
consumes one matched pair of surrounding quotes when a token resolves,
so the escaped value's quoting stays authoritative; unresolved tokens
keep their literal form and the single-pass GHSA-fq9x behaviour holds.

GHSA-vhh2-gghg-whjg: add a confirmation regression test that the
spikekill poller escapes the --rrdfile path (fixed in Cacti#7235).

Tests: tests/Unit/Security/DataInputQuotedPlaceholderTest.php (source +
behavioral) and tests/Unit/Security/SpikekillRrdfileEscapeTest.php.
Backport of the develop batch-12 fix (PR Cacti#8237).

* security(batch12): update batch-11 fq9x regression test for quote-aware substitute_script_path

The GHSA-5v3j quote-shedding changed substitute_script_path()'s regex
and capture group, which the batch-11 fq9x test pinned verbatim. Update
those two assertions to the quote-aware pattern marker and $matches[2];
the single-pass guarantee the test covers is unchanged.

* security(batch12): drop the executable bit on the new security test files

* security(batch12): make substitute_script_path fully quote-aware (GHSA-5v3j)

Backport of the develop fix (Cacti#8237). The matched-pair quote shed only
neutralised a token the template wrapped exactly ("<arg1>"). A token embedded in
a larger quoted word ("prefix<arg1>", "<arg1>suffix", "<a><b>") kept the outer
double quotes, so backticks/$(...) in the already-escaped value stayed live.

Replace the regex with a single-pass shell-quote-state scanner: it still sheds
an exact wrapping pair, but for any token inside a larger quoted word it briefly
closes the template's quoting around the escaped value so it cannot be
re-interpreted. Values are never re-scanned (single-pass, GHSA-fq9x retained).

Updates the source assertions in DataInputQuotedPlaceholderTest and
ShellInjection/ShellInjectionRegressionTest, and adds prefix/suffix/mixed
regression cases. The eval-extract fallback is kept here because the 1.2.x unit
bootstrap does not load lib/functions.php (unlike develop).

* security: preserve template quoting for raw path tokens; relocate tests under ShellInjection/

Address review feedback on PR Cacti#8238:
- substitute_script_path() now only sheds/closes template quotes for
  self-quoting (cacti_escapeshellarg) values. Trusted raw path_* tokens are
  substituted in place so a quoted "<path_php_binary>" keeps its quotes for
  shell_exec() and a bare <path_cacti>/scripts/x.php stays unquoted for the
  PHP script server, which realpath()s the first token.
- Move DataInputQuotedPlaceholderTest and SpikekillRrdfileEscapeTest into
  tests/Unit/Security/ShellInjection/ and fix the repo-root lookup to
  dirname(__DIR__, 4).
- Add a regression test asserting raw path tokens retain template quoting.

* security: reword docblock to avoid sink-scanner false positive

* security: keep substituting a token that follows a backslash in substitute_script_path

* fix(security): protect script field quote boundaries on 1.2.x

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(security): cover script substitution and gate PR coverage

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: measure committed PR changes on a policy-compliant runner

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* security: model nested command substitution in substitute_script_path (GHSA-5v3j)

Align the 1.2.x backport with the develop fix (Cacti#8237): replace the single
quote-state scanner with a stack of parsing frames so a command substitution
or backtick is scanned with its own fresh quoting context, exactly as /bin/sh
re-parses it. A field placed inside a command substitution is judged against
that nested (unquoted) context, so its own cacti_escapeshellarg() single
quotes genuinely protect it and an outer double quote can no longer re-enable
command substitution in the value.

Brings the 1.2.x placeholder test to parity with develop, including the
/bin/sh round-trip that proves each substituted word stays a safe literal and
never expands.

* test: cover nested command-substitution and backtick frames for changed-line coverage

* test: cover $(...) and backtick template frames in changed-coverage fixture

Mirror the develop ScriptSubstitutionMatrix nested-context cases so the
pr-changed-coverage gate exercises the command-substitution and backtick
frame handling in substitute_script_path(); revert the equivalent Pest
addition to keep DataInputQuotedPlaceholderTest at parity with develop.

* fix(security): reject unsupported nested shell syntax

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <copilot@users.noreply.github.com>
Co-authored-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <1439914+TheWitness@users.noreply.github.com>

* test(poller): [1.2.x] add scoped regressions and weekly performance checks (Cacti#8285)

* test(poller): add scoped regression gate and weekly performance backstop

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(poller): satisfy workflow policy and bound cold-cache queries

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(poller): retry failed template metadata reads

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* docs(changelog): defer release entries to final backlog PR

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(ci): include PHP 8.2 in polling release validation

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(poller): support acknowledged drains and stateful exclusions

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* Repair maintenance unit collection without database bootstrap

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test: cover empty poller mapping cache and failed read retries

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test: preserve shared source fixture exception boundaries

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>

* perf(rrd): [1.2.x] reuse capability checks within calls (Cacti#8341)

* perf(rrd): [1.2.x] reuse capability checks within calls

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test(rrd): cover maintenance capability checks with native commands

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test: preserve shared source fixture exception boundaries

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(plugins): load poller.php before replicate_out in api_plugin_replicate_config (Cacti#8364)

api_plugin_replicate_config() calls replicate_out(), which lives in lib/poller.php, but that library is not loaded during the early plugin config_arrays hook bootstrap. Commit aa1faf3 (Cacti#7235) removed the include_once that guarded this. With a remote poller present, enabling/replicating a plugin fatals with 'Call to undefined function replicate_out()'. Restore the include_once, matching api_plugin_drop_remote_table().

* security(1.2): pin Actions and isolate release signing (Cacti#8346)

* security: pin maintenance Actions and isolate release signing

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* docs(changelog): move release-signing entry to end of security section as -security#8346

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>

* Cross-filter Device and Graph Template on Preview and List views (Cacti#8362)

* Cross-filter Device and Graph Template on Preview and List views

On the Preview and List graph views, selecting a Device now narrows the Graph Template dropdown to the templates present on that device, and selecting a Graph Template narrows the Device list to the devices that have graphs of that template.

* Make Tree view Graph Template dropdown sensitive to selected device

On the Tree view, the Graph Template filter now lists only the templates present on the device selected in the tree, matching the Preview and List view behavior.

* fix(test): drive CSP getCspMode tests via config_options_array

bootstrap-unit.php (since Cacti#8285) loads lib/functions.php, which defines the real read_config_option and bypasses this test's function_exists-guarded stub, so getCspMode/isNonceMode read '' and failed. Inject the flag through config_options_array (the non-web cached-option seam read_config_option uses) so the tests pass under the shared bootstrap.

* Address review: fix Graph Template multiselect reload and gate 'Not Templated'

Remove the per-selection change handlers on #graph_template_id (Preview and List); the shared select2:close.graphTemplateSentinel handler already reloads once on close. Route that close-time reload to applyFilter() on the List view so site_id/location/rows are preserved and the in-flight request is not aborted. Only offer the 'Not Templated' sentinel when the current device filter has an allowed untemplated graph, so no empty device/template combination is presented.

* Revert Cacti#7863 on 1.2.x: package_public_keys table does not exist (Cacti#8369)

The backport introduced a package_public_keys trust store, but that table is not part of the 1.2.x schema (it is created by the 1.3.0 upgrade). Remove package_public_key_is_trusted() and its two call sites. The SHA-1 verification fallback is intentionally not restored; package_file_get_contents() now verifies with SHA-256 only.

Signed-off-by: TheWitness <thewitness@cacti.net>

* test: move maintenance PHPUnit configuration under tests (Cacti#8375)

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: pull 1.2.x service images from GHCR (Cacti#8378)

- Requires the develop change that adds ci-images.yml to merge and run first, so the GHCR copies exist.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test: normalize maintenance configuration paths for Pest discovery (Cacti#8380)

(cherry picked from commit 6fbf949)

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* Scope the tree Graph Templates filter to the drilled Device Template (Cacti#8371)

* Scope the tree Graph Templates filter to the drilled Device Template

When drilling a Site Branch into a Device Template (host_id=-1, host_template_id set), graph_view_template_host_where() applied no device restriction, so the tree Graph Templates filter listed every template. Scope it to the Graph Templates present on that Device Template's devices (within the Site when set). Only the tree view passes host_template_id, so the Preview/List callers are unaffected.

* docs(CHANGELOG): add issue#8371 entry

* Detect and repair RRDfile Data Source count mismatches via RRDtune (Cacti#8367)

* Detect and repair RRDfile Data Source count mismatches via RRDtune

Report when a Graph requires more or fewer Data Sources than its RRDfile
contains, generate the rrdtool tune DS:/DEL: command to correct it, and run
it when the RRDfile is writable.  Applies to data_debug (rrdtool_cacti_compare)
and the RRDchecker batch process (do_rrdcheck).  The decision logic lives in
pure helpers (rrdtool_cacti_compare_ds, rrdcheck_ds_findings) with unit tests.

Resolves Cacti#8366

* rrdcheck: only probe local writability for local storage

Under the storage proxy the RRDfile is remote, so is_resource_writable()
checks the wrong filesystem.  Skip the local probe when using the proxy and
let it enforce remote permissions and report failures via its response.

* rrdcheck: validate tune args, enforce RRA containment, fix failure detection

Validate every tune specification against RRDtool's documented DS grammar
(ds-name 1-19 [a-zA-Z0-9_], known DST, integer heartbeat, numeric-or-U min/max)
and escape it before use.  For local storage require the RRDfile to resolve
inside the RRA directory via data_source_path_within_rra().  Detect failures
from the real return value (false/null/empty or missing OK) instead of casting
to string, so a failed tune is no longer logged as success.

* rrd: normalize a 0/0 data source range to 0:U when building a tune add spec

rrdtool_function_info_from_ds() passes min/max through unchanged, so a source
stored as 0/0 produced DS:name:type:hb:0:0 which RRDtool rejects.  Mirror RRD
creation and emit 0:U so the repair paths can restore those sources.

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <1439914+TheWitness@users.noreply.github.com>

* fix: reject dangling symlinks in validate_relative_path_within (Cacti#8390)

* fix: reject dangling symlinks in validate_relative_path_within

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* docs: add changelog entry for dangling symlink fix

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci: pull the 1.2.x CDEF coverage MariaDB service from GHCR (Cacti#8385)

- The anonymous Docker Hub pull fails with toomanyrequests before any test step runs. Requires the ci-images.yml change already on develop.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* themes: make search-result highlight readable on deepness and dark (Cacti#8397)

Both themes set the .filteredValue search highlight to a neon yellow
(#F8D93D) background with no text color. On these dark themes the light
link/row text rendered on bright yellow was effectively unreadable.

- deepness: use a warm gold that complements the emerald palette with a
  near-black (--dp-page) text color.
- dark: match the develop branch (olive background with black text).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* test: allow configuration-only changes without a Clover report (Cacti#8384)

* test: normalize maintenance configuration paths for Pest discovery

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
(cherry picked from commit 6fbf949)

* test: keep maintenance bootstrap paths portable and allow XML-only coverage changes

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>

* fix(security): restore maintenance package imports and guard script contexts (Cacti#8372)

* fix(security): restore maintenance package trust checks and reject unsafe script contexts

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* test: preserve trusted configured paths inside backticks

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* ci(tests): keep 1.2.x-only coverage configs off unrelated PRs

Revert the incidental path normalization of tests/phpunit-poller-mapping.xml
and tests/phpunit-rrd-capabilities.xml. Editing these two files triggered the
poller-mapping and rrd-capability "Changed PHP lines >= 80%" coverage
workflows (which key on those config paths). Once triggered, those gates
require >=80% coverage of every changed production line, so the unrelated
lib/functions.php and package_import.php security changes reported 0% and the
gates failed. Both path forms resolve identically through prepare_config and
nothing else consumes these configs, so reverting them is a no-op for the
poller.php/rrd.php coverage checks while removing the spurious triggers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(security): reject ambiguous shell expansion contexts

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: TheWitness <thewitness@cacti.net>

* Add one-click RRDfile repair (Apply Suggested Fixes) to Data Source Info mode (Cacti#8400)

* 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. This adds the new header redirects in
  ds_repair and also absorbs pre-existing line-number drift (lib/functions.php
  and others) that already failed the sink guard on 1.2.x HEAD.

* Address review: drop undefined helper and detect proxy repair success

- Replace the undefined cacti_has_control_chars() check with an inline
  control-character test so a tune recommendation carrying control chars is
  skipped without a fatal undefined-function error.
- Accept both an empty local result and the RRDtool proxy's raw 'OK u:...'
  status as success so repairs over the proxy are not misreported as failed.
- Add the new translatable strings to locales/po/cacti.pot and reuse the
  existing failure msgid.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.cacti.net/projects/cacti/core-v1-2-x/
Translation: Cacti/core (v1.2.x)

* Fix console content area right/bottom margins hiding scrollbar column and Save button (Cacti#8402)

The console content area (.cactiConsoleContentArea / #navigation_right) is an
internal scroll region whose height is set to fill the viewport by
keepWindowSize() in layout.js. It had no right padding, so the vertical
scrollbar sat flush against the right-aligned cells (for example the Data
Source Info mode numbers on data_sources.php ds_edit), and no bottom padding,
so the last element - the Save button - was flush against the scroll edge and
could not be scrolled fully into view.

Add box-sizing: border-box so the JS-set height absorbs the padding, then give
the area a right scrollbar gutter and a bottom clearance in every bundled theme
(classic, dark, deepness, modern, paper-plane, paw, sunrise).

* ci(deps): bump actions/upload-artifact from 4.6.2 to 7.0.2 (Cacti#8407)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.2 to 7.0.2.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4.6.2...cf430e0)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.2
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* ci(deps): bump the github-actions-1-2-x group with 2 updates (Cacti#8406)

Bumps the github-actions-1-2-x group with 2 updates: [shivammathur/setup-php](https://github.com/shivammathur/setup-php) and [actions/setup-node](https://github.com/actions/setup-node).


Updates `shivammathur/setup-php` from 2.37.2 to 2.40.0
- [Release notes](https://github.com/shivammathur/setup-php/releases)
- [Commits](shivammathur/setup-php@f3e473d...eb7c497)

Updates `actions/setup-node` from 7.0.0 to 7.1.0
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](actions/setup-node@v7...949feb2)

---
updated-dependencies:
- dependency-name: shivammathur/setup-php
  dependency-version: 2.40.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions-1-2-x
- dependency-name: actions/setup-node
  dependency-version: 7.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions-1-2-x
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix return navigation from Time Graph View (Cacti#8414)

* Fix return navigation from Time Graph View

* Reference navigation fix in changelog

* Render RRDtool Tune Info as balanced div boxes and POST the Data Source repair actions (Cacti#8413)

* 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 the nested print_leaves() definition into a standalone
  rrdtool_tune_print_leaves() function, 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 loadPage() GET requests also meant the follow up redirect was
pulled into the content area, losing the theme and navigation on
rerender.

Convert the Apply Suggested Fixes and Rerun Analysis links to the
existing cactiPostAction/data-url idiom (as data_sources.php already
does for ds_repair) so they submit a token-bearing POST, add the
matching csrf_require_post() guards on the run_repair and run_debug
actions, and drop the now redundant click handlers.  The read-only
reloadquery refresh stays a GET.

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,
  keeping the control-character guards and storage_location handling.
- 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/Core/Rrd/RrdTuneRenderTest.php to the RRDtool capability
coverage suite, covering the leaf printer, the HTML and CLI printers,
the execute path (both storage_location branches) 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: add an executor test seam to rrdtool_tune_execute

Address PR review feedback carried over from the develop PR: give
rrdtool_tune_execute() an optional $executor parameter (matching
rrdtool_dump_document) so the unit tests assert the tune and resize
commands are actually executed, producing resize.rrd only when the
resize command runs, instead of passing on the unconditional rename
alone. The control-character guard retains dedicated coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* review: inject box renderers into rrdtool_tune_print_html

Address the PR review finding that the test's global html_start_box /
html_end_box stubs would redeclare the real helpers when the full Unit
suite loads lib/html.php.

Give rrdtool_tune_print_html() optional $open_box / $close_box seams
(defaulting to html_start_box / html_end_box) so the unit test injects
recording renderers instead of defining conflicting global functions.
The test now asserts each section opens and closes a balanced box with
the expected title, with no global helper declarations.

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>

* Refresh automatic graph end times after polling advances (Cacti#8415)

* Refresh last poll when choosing automatic graph end time

* Number the CHANGELOG entry and order the 1.2.x section

Add the PR reference (-issue#8415) and apply the section order: security
fixes first (sorted), then issues and features, each sorted by number
ascending. This moves the issue entries that had been added above the
security block (Cacti#8371, Cacti#8390, Cacti#8414) and puts out-of-order issue and feature
entries into place. No entry text changes; the stray trailing space on the
Cacti#8257 line is dropped.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Measure automatic graph timing coverage in the real renderer

---------

Co-authored-by: TheWitness <thewitness@cacti.net>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* tests: make the full unit suite runnable in one process (Cacti#8416)

The shared unit bootstrap (tests/bootstrap-unit.php) skips global.php, so a
couple of load-time prerequisites that library files expect were missing.
Running the whole tests/Unit tree in a single process therefore aborted with
fatals before completing:

- Including lib/snmp.php reads $config['php_snmp_support'] at load time. The
  bootstrap never set it, so the strict test error handler turned the
  "Undefined array key" warning into a fatal, taking down every test that
  loads lib/snmp.php (much of Security/ and all of Scripts/). Mirror global.php
  and set the flag from class_exists('SNMP').

- lib/html.php declares html_escape() (and other helpers) unguarded. A test
  that defines a function_exists()-guarded stub for one of these ran first and
  defined it, then a later test that included lib/html.php hit a redeclaration
  fatal. Load lib/html.php in the bootstrap (like lib/functions.php) so the
  real helpers exist first and the guarded stubs become no-ops.

With these two changes the full Unit suite runs to completion instead of
crashing. Remaining individual test failures are pre-existing and unrelated to
the harness. All targeted phpunit-*.xml configs that use this bootstrap still
pass unchanged.

Co-authored-by: TheWitness <copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix archive zoom targeting and graph refresh scroll jumps (Cacti#8417)

* Keep zoom overlays on graphs with archive ID zero

* Preserve graph dimensions during zoom refreshes

* fix: Update the deepness favicon (Cacti#8418)

* fix: Update the deepness favicon

* QA: If the SVG is present, it's all we need.

* Fix restrictive graph permission labels on 1.2.x (Cacti#8421)

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* feature: Add modern favicons svg images (Cacti#8423)

This change aligns the other themes with the latest favicon enhancement

* deps(deps): bump phpseclib/phpseclib (Cacti#8433)

Bumps the composer-1-2-x group with 1 update: [phpseclib/phpseclib](https://github.com/phpseclib/phpseclib).


Updates `phpseclib/phpseclib` from 4.0.1 to 4.0.2
- [Release notes](https://github.com/phpseclib/phpseclib/releases)
- [Changelog](https://github.com/phpseclib/phpseclib/blob/master/CHANGELOG.md)
- [Commits](phpseclib/phpseclib@4.0.1...4.0.2)

---
updated-dependencies:
- dependency-name: phpseclib/phpseclib
  dependency-version: 4.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: composer-1-2-x
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(layout): define spike removal URL locally

Co-authored-by: Thomas Vincent <341181+somethingwithproof@users.noreply.github.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Signed-off-by: TheWitness <thewitness@cacti.net>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
Co-authored-by: TheWitness <1439914+TheWitness@users.noreply.github.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: TheWitness <copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Muris <27321443+alcatron@users.noreply.github.com>
Co-authored-by: Gitar <noreply@gitar.ai>
Co-authored-by: Thomas Vincent <341181+somethingwithproof@users.noreply.github.com>
TheWitness added a commit that referenced this pull request Oct 22, 2026
* docs(changelog): [1.2.x] consolidate backlog release notes

Records merged 1.2.x fixes that deferred their entries: #8275, #8285, #8318, #8338, #8341 and #8350. Moves the unnumbered zoom entry from #8417 into the issue group.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* docs(changelog): use associated issues for maintenance fixes

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants