mirror of
https://github.com/Cacti/cacti.git
synced 2026-10-23 03:27:02 +09:00
develop
1878
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ffd7a81109 |
Scope the tree Graph Templates filter to the drilled Device Template (#8370)
* 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), create_tree_filter() fell through to listing every Graph Template. Scope the dropdown to the Graph Templates present on that Device Template's devices (within the drilled Site when set), matching the graphs the branch actually shows. * docs(CHANGELOG): add issue#8370 entry * test: cover the tree Device Template graph-template scope; fix CHANGELOG ordering Add an isolated source-slice probe that drives create_tree_filter()'s new host_template_id branch so the changed lines meet the >=80% changed-line coverage gate, wired into run_request_coverage.sh. Move the issue#8370 CHANGELOG entry into the issue block so it no longer precedes the security entries. * docs(CHANGELOG): append issue#8370 at the end of the issue block |
||
|
|
930b085703 |
feat(auth): log administrative account actions after confirmed writes (#8360)
* log user action (create, delete, locked, ..) * change log * update changelog * style(auth): apply coding standards to user action logging Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Audit password changes only after successful account saves Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(auth): sanitize audit fields and confirm account removals Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: cover native account audit state transitions Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: synchronize native coverage fixture dispatch Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(auth): audit only confirmed account persistence Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: measure coverage at the exact PR revision Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: Petr Macek <petr.macek@kostax.cz> |
||
|
|
f3ff777992 |
ci: install locked shared plugin test dependencies (#8345)
* ci: install locked shared plugin test dependencies Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: explain pinned tooling checkout for plugin CI Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
bcb4aaf4ae |
fix(auth): render password reset links outside login error text (#8289)
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
30db858d3f |
deepness: deep-dark login page with a bordered login box (#8224)
* deepness: deep-dark login background with a bordered, slightly-greyer login box Drop the emerald loginBody gradient for a flat deep-dark page (var(--dp-page)), give the login box a flat slightly-greyer tint (var(--dp-panel-alt)) with a thin var(--dp-border) border, and override -webkit-autofill so the username/password fields no longer show the olive autofill tint. * docs: add CHANGELOG entry for #8224 (Deepness login restyle) * deepness: use input surface for login autofill override The -webkit-autofill inset box-shadow used var(--dp-panel-alt) (the login card surface) instead of var(--dp-panel) used by the standard text/password inputs. Autofilled credentials therefore took on the card color rather than the normal input appearance. Use var(--dp-panel) so the override only removes Chrome's autofill tint. |
||
|
|
2e8afef8f7 |
issue: align Deepness console icon sizing/alignment with Modern (#8221)
* deepness: match modern console icon sizing/alignment and drop sub-menu indent Port modern's .menu_glyph size/alignment (18px, 22px width, padding-right:0, inline-block), add line-height:20px to .menuitem span, bump legacy i.fa to 15px with text-align:left, and remove the 32px sub-menu indent (#nav li ul li a now flush at 5px like the top-level items). * docs: add CHANGELOG entry for #8221 (Deepness console icon alignment) |
||
|
|
35e7181ded |
issue: skin the modern filter Edit dialog for the Deepness theme (#8220)
* issue: skin the modern filter Edit dialog for the Deepness theme The Deepness theme received the modern filter *bar* rules (#8219) but not the .ui-dialog.cactiFilterDialog skin the other themes carry, so the filter Edit dialog fell back to the default jQuery UI themeroller look (mismatched titlebar gradient, unstyled buttonpane). Port the scoped dialog block used by the other themes, using Deepness's emerald palette variables (--dp-accent-deep titlebar/primary button, --dp-border buttonpane divider). * issue#8220: reference PR number in CHANGELOG entry to satisfy the format gate |
||
|
|
4430210a85 |
issue: fix Deepness theme modern filter bar stacking vertically (#8219)
* issue: fix Deepness theme modern filter bar stacking vertically The Deepness theme (added in #8206) shipped include/themes/deepness/main.css without the modern filter-bar display rules the other themes carry, so .filterColumn/.filterColumnButton divs fell back to display:block and the Layouts/Search/Rows controls and action buttons stacked vertically. Port the .filterRow/.filterColumn/.filterColumnButton table-display rules and the .cactiFilterModernBar rules from the modern theme. * docs: add CHANGELOG entry for #8219 (Deepness filter bar fix) * issue#8219: port icon-rotate and barSep modern-bar rules to Deepness html_filter.php adds icon-rotate to the Refresh glyph and emits empty barSep separator spans. Deepness lacked both rules, so the refresh action had no spin feedback and the separators were invisible. Add .icon-rotate and .cactiFilterModernBar .barSep (using the dark-theme rgba(128,128,128,0.45) separator colour, matching the dark/carrot/paper-plane themes). |
||
|
|
59c13952e5 |
docs: phpseclib 4 fix and sync develop 1.2.32 CHANGELOG with 1.2.x (#8184)
* docs: correct CHANGELOG to reference phpseclib 4 not 3 (#7804) The RRDproxy encryption restoration (#7804) uses the Composer-managed phpseclib 4 line (see #8032/#7884), not phpseclib 3. Follow-up to #8182, which merged before this correction could be included. * docs: sync develop 1.2.32 CHANGELOG section with the 1.2.x branch Bring develop's 1.2.32 section in line with 1.2.x: add the issue#8173 graph-list date-range entry (positioned after the issue block) and the five feature#8166 SNMP auth-cache entries. The phpseclib 4 correction is already in this branch. |
||
|
|
f79dc15c08 |
Port #8166 SNMP credential cache + procedural SNMPv3 (with #8171/#8172 follow-ups) to develop (#8174)
* Port #8166 SNMP credential cache + procedural SNMPv3 to develop Ports the shared SNMPv3 credential cache and procedural SNMPv3 routing from the 1.2.x feature (merged as #8166) onto develop, adapted to develop's refactored SNMP layer. Parts of the 1.2.x change that do not apply to develop are omitted: the cacti_exec() idle-timeout rewrite (develop has no cacti_exec()), the PHP floor bump and composer/doc changes (develop is already 8.3+), and the cmd.php max_oids batching (develop's cmd.php already collects SNMP in-process through persistent sessions, so the per-item spawn the batching removed does not occur). - lib/cache.php: new cross-process \Cacti\Cache\SharedCache (file + POSIX shared-memory + process-local tiers, optional AES-256-GCM sealing). Loaded via lib/snmp.php (the Cacti\Cache\ namespace is not PSR-4 autoloaded). The crypto helpers it seals with already live in develop's lib/auth.php, loaded by global.php, so no duplicate was added. - lib/snmp.php: snmp_get_method() now routes SNMPv3 get/getnext to the procedural snmp3_*() calls when the running PHP supports the configured auth/privacy tokens and no context/engine id is set (SHA-224/384 and AES-192/256[C] stay on the binary before PHP 8.6); the three single-get functions gain the procedural v3 path with \Throwable handling; adds the credential-cache subsystem, protocol-option/MD5-DES helpers, snmp_native_protocol(), snmp_format_agent() and cacti_snmp_get_multi(); the binary v3 auth builder consults the cache when enabled. - poller.php / script_server.php: prime / load the shared cache. - poller_maintenance.php: daily out-of-band cache rebuild on every collector (per-poller lastrun marker). - lib/api_device.php / lib/utility.php: bump snmp_cred_version only on v3 credential add/change (and propagate the token to the affected remote poller). - include/global.php: resolve and create the private cache/ directory. - include/global_settings.php: add 'Enable Credential Cache' and 'Enable MD5 and DES for SNMPv3' settings (both off by default); default new-device v3 auth/privacy to SHA/AES instead of legacy MD5/DES. - host.php / automation_snmp.php: drop MD5/DES from the pickers when disabled and default new records to SHA/AES on upgraded installs. - include/config.php.dist: document $config['cache_dir']. - tests/Unit/Core/Cache/SharedCacheTest.php: SharedCache behaviour coverage. - tests/security/baselines: baseline the two new lib/cache.php sinks. * Incorporate #8171: binary fallback for unsupported SNMPv3 protocols Layers PR #8171 onto the develop port so an SNMPv3 device whose auth/privacy protocols the running PHP's ext-snmp cannot service natively (e.g. AES-256 before PHP 8.6) no longer fatals the poller or device-edit screen. - lib/snmp.php: add CactiSnmpBinarySession, a session stand-in exposing the get/getnext/walk/close interface the cacti_snmp_session_*() helpers use and delegating each call to cacti_snmp_*() -> the Net-SNMP binary. cacti_snmp_session() returns it when php-snmp is absent or the v3 protocol is not natively serviceable, so cmd.php/host.php collect these devices via the binary on pre-8.6 and switch to the in-process path on 8.6 with no caller change. v1/v2 snmpget/snmp2_get now go through snmp_format_agent(). The ERRNO_TIMEOUT check tolerates php-snmp being absent. Drop the vendored classSNMP.php compatibility shim and its include (and the Yandex attribution). - cmd.php: open_snmp_session() returns the down sentinel when a host is already marked down this run, instead of returning an unset (null) [] that cacti_snmp_session_get() then dereferenced (TypeError). - lib/ping.php: ping_snmp() runs the availability check through the procedural cacti_snmp_get()/getnext() path so an unsupported protocol falls back to the binary instead of raising a ValueError in SNMP::setSecurity(). * Incorporate #8172: retire include/vendor/phpsnmp, relocate into lib Follow-up to #8171 on the develop port. After classSNMP.php was removed, the include/vendor/phpsnmp/ directory held only Cacti-owned files; this retires it. - lib/snmp.php: the ext-snmp subclass that carried Cacti's bulk_walk_size / value_output_format (previously vendor/phpsnmp/extension.php) is now declared directly as CactiSnmpNativeSession, guarded by CACTI_PHP_SNMP; the include and the 'use phpsnmp\SNMP' alias are gone, and new SNMP(...) / SNMP::VERSION_* now reference the native \SNMP and the new subclass. - lib/mib_parser.php: moved from include/vendor/phpsnmp/mib_parser.php; lib/mib_cache.php includes it via __DIR__. - Remove include/vendor/phpsnmp/extension.php and index.php (directory retired). - tests: SnmpCoverageTest uses \SNMP::ERRNO_TIMEOUT now that phpsnmp\SNMP is gone; drop the stale include/vendor/phpsnmp/ entry from the vendor-policy allowlist. develop's sink baseline tracks constant-based includes differently than 1.2.x, so no baseline refresh was needed here. * Address PR #8174 review: snmp_get_method params, v3 walk, getnext agent, cache bump, CHANGELOG - lib/snmp.php: restore $php_snmp as the 6th snmp_get_method() parameter and move the new $auth_proto/$priv_proto after it (callers pass them by name), so the positional $php_snmp used by SnmpCoverageTest and others keeps working. - lib/snmp.php: keep every SNMPv3 operation except get/getnext on the Net-SNMP binary - the native walk branch implements only v1/v2, so a v3 walk reaching the procedural gate would have silently returned empty when path_snmpbulkwalk is missing. - lib/snmp.php: cacti_snmp_getnext() v1/v2 branches now use snmp_format_agent() like get/get_raw, so an IPv6 literal / non-default port is bracketed. - lib/api_device.php: bump snmp_cred_version only when the host's v3 membership or one of the cached credential fields actually changed, instead of on every save of a v3 device. - CHANGELOG: move the #8171 entry into the issue block and the #8166 entries into the feature block, matching the established section ordering. * Fix CI: unbracket IPv4/DNS SNMP targets, inline auth-cache SQL columns, apply phpcsfixer standard * Refresh sink inventory baseline after short-array normalization * Restore lib/snmp.php 100% coverage after aligning v3 routing to 1.2.x - update the three SnmpCoverageTest assertions that still encoded develop's pre-port behavior: v3 snmp_get_method now returns PHP, an unsupported- protocol v3 session returns the binary-delegating session object, and the v3 cacti_snmp_get path runs natively - add a v3 noAuthNoPriv user to the snmp-coverage snmpd fixture so native snmp3_get is exercised deterministically - add tests covering the ported subsystems to 100%: shared auth cache, binary-delegating session, protocol pickers, v3 credential args, cacti_snmp_get_multi, and the cacti_get_snmpv3_auth cache path - snmp_auth_cache_load uses a resettable process guard so its enabled and disabled branches are both coverable in a single process * Resolve phpstan errors in the relocated SNMP MIB parser and ported snmp.php - lib/mib_parser.php: type the MibParser properties, add parameter/return types, guard file_get_contents()/preg_split() against false, correct the parse_bracket_token delimiter params (string, not integer), and drop the unreachable return after trigger_error(E_USER_ERROR) - now phpstan clean - lib/mib_cache.php: drop the redundant isset($mp->oids) guard (the typed property is always initialized; $mp->mib is the real check) - lib/snmp.php: type the CactiSnmpBinarySession and CactiSnmpNativeSession properties/methods and pass bool to snmp_set_quick_print() - .phpstan.neon: ignore greaterOrEqual.alwaysFalse alongside the existing greater.alwaysFalse (the PHP_VERSION_ID >= 80600 forward-compat gate) - regenerate phpstan-baseline.neon for the irreducible ext-snmp stub strictness (snmp3_get literal-union protocols, int<-1,max> timeouts) in the ported procedural v3 path, the new lib/cache.php shmop stubs, and the $config array-shape offsets in include/global.php * Make the v3 getter catch coverage net-snmp-build-independent The DES-rejection trick that drove the procedural snmp3_get()/snmp3_getnext() try/catch blocks only works on net-snmp builds compiled without DES; CI's Debian net-snmp accepts DES, so those catches went uncovered (98.3%). - extend the existing native_get injection seam (already on cacti_snmp_get) to cacti_snmp_get_raw, cacti_snmp_getnext, and cacti_snmp_get_multi, and drive the catch blocks with a throwing native getter in the test - mark the seam-less cacti_snmp_session() setSecurity catch with @codeCoverageIgnore (it only throws for a protocol the running net-snmp rejects, which is not portably reproducible in the fixture) * Exclude ext-snmp/PHP-8.6-gated defensive branches from snmp coverage Two branches in lib/snmp.php are unreachable on the PHP 8.3 + ext-snmp coverage runner and were only "covered" locally via opcache dead-code elimination: - snmp_get_method()'s !function_exists('snmp3_get') fallback (ext-snmp always provides snmp3_get) - snmp_php_v3_protocols_supported()'s PHP_VERSION_ID >= 80600 block (SHA-224/384 and AES-192/256 tokens are only accepted on PHP 8.6+) Mark both with @codeCoverageIgnore so the 100% gate is deterministic across runners regardless of opcache settings. * Account for the #8166 SNMPv3 credential-cache gate query in the batching test poller_update_poller_cache_from_buffer() now runs one SELECT per flush to decide whether the flush touched SNMPv3 poller items before bumping the shared credential-cache version (matching 1.2.x). UpdateDataQueryCacheBatchingIntegrationTest counted 4 statements per flush; update it to 5 (and 3 per-row flushes to 15, 1 batched flush to 5). The guard's intent - batching issues fewer statements than per-row flushes - still holds. * Port #8175: group SNMP options under an SNMP Behavior section Mirror the 1.2.x settings reorganization (#8175) on develop. develop already keeps the SNMP options in a dedicated SNMP tab, so add an "SNMP Behavior" spacer there, order the behavior options as md5/des, credential cache, max get size, bulkwalk fetch size, and move "Disable increasing OID Check" out of the Poller tab to sit last in that group. Display-only; no settings added or removed and no behavior change. Adds the "SNMP Behavior" heading to cacti.pot. * fix: complete dependabot htmx 2.0.10 to 2.0.11 bump Dependabot bumped package.json and package-lock.json to htmx.org 2.0.11 (PR 8179) but left the vendored include/js/htmx.js, its version marker, and the pinned SRI constant at 2.0.10. The htmx-filters CI workflow runs npm ci, which regenerates include/js/htmx.js from the 2.0.11 package, so HtmxTest's runtime sha384 no longer matches the HTMX_2_0_10_SRI constant and the integrity assertion fails. Complete the bump: regenerate the vendored include/js/htmx.js to the 2.0.11 build, bump include/js/htmx.js.version to 2.0.11, rename HTMX_2_0_10_SRI to HTMX_2_0_11_SRI with the recomputed sha384 hash, and update the version/integrity assertions in tests/Unit/Ui/Html/HtmxTest.php and tests/HandOff/HtmxLoaderHandOffTest.php. package.json and package-lock.json match the values dependabot already landed on develop. * settings: move SNMP Agent Support under the SNMP Behavior spacer Relocate the enable_snmp_agent setting (SNMP Agent Support Enabled) so it is the first item under the SNMP Behavior spacer instead of sitting in the Poller General group, grouping it with the other SNMP behavior options. * Address PR #8174 review: keep SHA-224/384 on the binary, honor port on transport targets Resolves the two still-valid Copilot review findings on lib/snmp.php that were left unresolved (only marked outdated after later commits shifted their lines). - snmp_php_v3_protocols_supported(): drop SHA224/SHA384 from the native auth allowlist. ext-snmp's SNMP::setSecurity()/snmp3_*() only map MD5/SHA/SHA256/ SHA512 - there is no SHA-224/SHA-384 mapping on any build, including PHP 8.6 (verified against php-src ext/snmp/snmp.c), so routing those tokens to the procedural path raised a ValueError instead of using the binary. They now always fall back to the Net-SNMP binary. The AES-192/256 privacy tokens that ext-snmp does add on 8.6 stay gated behind PHP_VERSION_ID >= 80600. - snmp_format_agent(): a udp/tcp transport-qualified target that omits a port now has the configured non-default port appended (udp6:[2001:db8::1] + 1161 -> udp6:[2001:db8::1]:1161), matching the Net-SNMP binary path. Targets that already carry a port, and unix: sockets (no port), are left untouched. - SnmpCoverageTest: cover the new transport-target branches; lib/snmp.php stays at 100%. |
||
|
|
d15f09ef7c |
security: reconcile develop CHANGELOG - full 1.2.32 release mirror, CVEs, de-dup (#8170)
* security: reconcile develop CHANGELOG with the 1.2.32 release and assigned CVEs
- Mirror the pending 1.2.32 security changelog from the 1.2.x branch into the
develop 1.2.32 section (16 GHSA entries that were missing), so the section
matches the 1.2.x release one-for-one.
- Append the CVE identifiers GitHub has issued:
* 1.2.32 section: GHSA-jpf3-w6p4-pjrf -> CVE-2026-44480,
GHSA-v2mq-mxpw-55pf -> CVE-2026-46530
(GHSA-vp35-4h28-r883 -> CVE-2026-39939 carried in with its line)
* 1.3.0-dev section: GHSA-977w-79m7-xjc4 -> CVE-2026-40307,
GHSA-cfhh-pwvx-gp5g -> CVE-2026-40940, GHSA-5p79-q5q3-84vw -> CVE-2024-34705
- Move GHSA-2fhv-c794-v433 (affects 1.3.x only) out of the 1.2.32 release
section into 1.3.0-dev where it belongs.
* security: mirror the full 1.2.32 release into develop and de-duplicate 1.3.0-dev
- Populate the develop 1.2.32 section with the complete 1.2.32 release changelog
from the 1.2.x branch (security, issue and feature entries), so develop's
1.2.32 section matches the release one-for-one (67 GHSA entries, with the
assigned CVEs carried in: vp35/jpf3/v2mq).
- Remove the nine bare -security: hardening entries from 1.3.0-dev that now
appear as the 'Harden - ...' entries in the 1.2.32 section (path_dsstats_log,
guest revoke, id casts, Secure cookie proxy, query-data substitution,
forced-HTTPS, and three LDAP hardening items). The three bare -security:
entries with no 1.2.32 counterpart (SHA-1 package signatures, automation
sort/pagination, password-reset link rework) are kept.
- Drop the stray develop 1.2.x section (its entries are part of 1.2.32).
* security: number the CHANGELOG entries so the format check passes
- 1.3.0-dev: give the three bare -security: hardening entries their adding PR
(#8158) and the Harden - prefix for traceability.
- 1.2.32: number the six bundled-JS -feature entries with their feature PR
(#8159, DOMPurify 3.4.16 and npm/Dependabot bundling) so new -feature entries
carry a pull-request number.
---------
Co-authored-by: Larry Adams <TheWitness@users.noreply.github.com>
|
||
|
|
75d816a335 |
security: consolidate GHSA batch 11 fixes for develop (fq9x, hh7r, v99q, f5f5) (#8165)
* security: consolidate GHSA batch 11 fixes for develop (fq9x, hh7r, v99q, f5f5) Mirrors the 1.2.x batch-11 security consolidation. Items already fixed on the develop tip are credited on their advisories and omitted here: - GHSA-54hx-hxc4-jq7j: TICK/SHIFT values already pass through strip_alpha(). - GHSA-hh7r CSV portion: already guarded via cacti_csv_cell(); only the Content-Disposition filename needed sanitizing (included below). - GHSA-mx5c: REST scaffold already deny-by-default (404 unless api_enabled), enforced by tests/Unit/ApiDenyByDefaultTest.php. - GHSA-rjvj/pjq5/fmhq/mfw8: already addressed on develop. Fixes applied here: - GHSA-fq9x-x3vf-3vf2 (High): add substitute_script_path() single-pass token substitution and refactor get_full_script_path()/get_full_test_script_path() to use a pre-escaped value map, closing the second-order re-substitution OS command injection. - GHSA-hh7r-464j-rf39: sanitize the Content-Disposition filename in graph_xport.php. - GHSA-v99q-57w7-mpmg: escape the page title rendered in the HTML <title>. - GHSA-f5f5-h85v-6m3h: render user admin tooltip content as escaped text. * security: add batch-11 consolidation regression tests for develop Addresses PR #8165 review feedback by adding regression coverage for all four fixed sinks: - GHSA-fq9x: behavioral single-pass proof that substitute_script_path() does not re-substitute a field value containing another field token, plus source guards that both path builders use the helper. - GHSA-hh7r: Content-Disposition filename strips CR/LF/quote/backslash. - GHSA-v99q: the HTML <title> is html_escape()'d. - GHSA-f5f5: both the user_admin.php and user_group_admin.php tooltips render data-tooltip as escaped text. * style: apply php-cs-fixer formatting to substitute_script_path (CI coding standards) * docs: require composer run-script php-cs-fixit before creating any pull request * docs: require PHPStan (level 8, satisfies Level 6 floor) to pass before creating any pull request --------- Co-authored-by: Larry Adams <TheWitness@users.noreply.github.com> |
||
|
|
8411c2a1c1 |
security: batch 10 (develop) - batch-10 GHSAs under 1.2.32 CHANGELOG (#8158)
* security: batch 10 (develop) - list batch-10 1.2.x GHSAs under the 1.2.32 CHANGELOG release * security: batch 10 (develop) - credit GHSA-p5xj under 1.2.32 (90-day remember-me cap via login predicate + authcache_purge) * security(GHSA-p3rg-7pc3-2h86): gate unknown-user dummy verify on non-empty password The known-user path in LocalAuthLoginProvider::verifyCredential() skips compat_password_verify() when the submitted password is empty, but the unknown-user branch always ran the bcrypt dummy verify. An empty-password request therefore exposed a reversed timing distinction (known user fast, unknown user slow) that still leaked username validity. Gate the dummy verify on the same non-empty condition as the real path so timing matches for both empty and non-empty passwords, fully closing the enumeration side channel claimed in the 1.2.32 CHANGELOG entry. --------- Co-authored-by: Larry Adams <TheWitness@users.noreply.github.com> |
||
|
|
e6b663f220 |
security: batch 9 (develop) - list batch-9 1.2.x GHSAs under the 1.2.32 CHANGELOG release (No-Auth removal and 4p7f already present on develop) (#8154)
Co-authored-by: Larry Adams <TheWitness@users.noreply.github.com> |
||
|
|
cff89ca9d6 |
security: batch 8 (develop) - data-query XML oracle (GHSA-2x86) + batch-8 GHSAs under 1.2.32 CHANGELOG (#8151)
* security: batch 8 develop - confine data-query XML existence check (GHSA-2x86); list batch-8 GHSAs under the 1.2.32 CHANGELOG release * security: batch 8 (develop) - address review: use cacti_path_is_within() for XML existence-oracle containment with a NUL-byte guard (no realpath ValueError); add data_query_edit() UI hardening regression test --------- Co-authored-by: Larry Adams <TheWitness@users.noreply.github.com> |
||
|
|
9facd9b500 |
security: batch 7 develop - consolidate remaining develop-only GHSA advisories (12 fixes + 8 confirmations) (#8149)
* security: batch 7 develop - consolidate remaining develop-only GHSA advisories (12 fixes + 8 regression confirmations) Fixes: f7jw (automation preview XSS), rp5g (db_column_exists LIKE), vx2m (automation pivot CASE WHEN), h5wg (plugin DDL identifiers), 929h (aggregate LIKE filter), mfw8 (add_graphs REGEXP), m49v (user_admin sort_column allowlist), mpfm (rrd error-image theme allowlist), m3fh (SNMPv3 control chars), cg45 (remember-me row revoke), xq26 (remember-me retention window), m67r (import xml_path containment). Confirmed already fixed on develop, pinned with regression tests: 4gph, 977w, mgcq, 5p79, cfhh, wfcf, pjq5, wp33. Excluded: 227p (1.2.x-only), mx5c (maintainer private branch). * security: address batch-7 review feedback (lexical-first xml_path containment, session-wide sort allowlist, connection-aware db_column_exists quoting, reject-not-normalize plugin DDL identifiers, behavior-based test names) * style: apply php-cs-fixer single-quote fix to api_automation pivot builders; add WSL dev-environment note to copilot instructions * fix phpstan string typing * test: refresh SQL interpolation baseline for db_column_exists db_qstr change (database.php 9->8) --------- Co-authored-by: ci <ci@local> |
||
|
|
5e870a91df |
security: batch 6 develop - path_php_binary escape (GHSA-4p7f), boost-log .log guard (GHSA-m6wx), tree lock/unlock/get_node authz (GHSA-73qf), rrd create strip (GHSA-967c) (#8148)
* security: batch 6 develop - escape path_php_binary (GHSA-4p7f), boost-log .log guard (GHSA-m6wx), tree lock/unlock/get_node authz (GHSA-73qf), confirm rrd create control-char strip (GHSA-967c) * security: cast path_php_binary before escaping in resource_cache_out (GHSA-4p7f) |
||
|
|
9d628b4959 |
security: batch 5 develop - fail closed on No-Auth admin bypass (GHSA-69vw), tag GHSA-3jj2, add 1.2.32 CHANGELOG section (#8146)
* security(GHSA-69vw): fail closed on auth_method None instead of auto-granting an admin session - check_reset_no_authentication() no longer wipes the admin password, flips auth_method, or hands an unauthenticated request an admin session; it fails closed and requires a manual auth_method reset (GHSA-69vw-qxxv-p8w2). - Tag GHSA-3jj2-v5ch-wmq5 in the CHANGELOG: the domains_login_process() realm bypass is already closed by the Login Providers rewrite (realm < 1000 fails closed). - CHANGELOG: add a 1.2.32 section below 1.3.0-dev with the GHSAs also fixed in 1.2.x, and de-duplicate the security entries the #8145 merge doubled. * docs(CHANGELOG): file host_id SQLi fix under 1.2.31 as GHSA-r7hc-hrpv-52gf; drop plain issue#7693 entry |
||
|
|
41e6d9e033 |
security: consolidate verified GHSA fixes for develop (batch 4) (#8145)
* security: consolidate verified GHSA fixes for develop (batch 4) Develop counterparts of the 1.2.x batch-4 fixes in #8144, re-verified against current develop HEAD. - GHSA-4rmr-wvjq-qxc2: include/auth.php Basic Auth and guest branches fall through to the per-page realm check instead of returning early. - GHSA-j67j-wpm4-9g3x: the pre-dispatch update_policy branch in user_admin.php and user_group_admin.php requires a CSRF-token POST. The denylist -> allowlist redesign is tracked for 1.3 in #8143. - GHSA-2p3x-f5jm-rg6p: the View-Graphs -> poller RCE chain is broken by the realm check (4rmr), the update_policy guard (j67j) and shell-free webhits (x5pw). - GHSA-x5pw-cg7j-mj4r: scripts/webhits.pl runs wc through a shell-free list-form open. - GHSA-9737-rqh3-h7fh: names interpolated into raise_message() now use __esc() across the UI; URL- and HTML-bearing messages are excluded. - GHSA-9x9h-2577-9w86: the colordropdown input is built as a node and the label is no longer round-tripped through parseHTML (the list item already used createTextNode on develop). - GHSA-h96j-8xhc-2p3w: remote_agent.php authorizes on $_SERVER['REMOTE_ADDR'], not get_client_addr(), which honours client-settable proxy headers. Regression guards under tests/Unit/Security/{Auth,Csrf,Xss,ShellInjection}. php -l, check-changelog.py and the sink/architectural baselines all pass. * chore: reference PR #8145 on the batch-4 1.3.0-dev CHANGELOG entries * security: resolve develop merge - keep id-only xmlerror unescaped (matches #8141 h745 test) * security(GHSA-j67j): use REQUEST_METHOD POST guard instead of raw \ (hardening-pattern-guard) * security(GHSA-9737): fix review findings - drop double-encoding in __esc, escape missed name sinks, correct plugins format-arg count |
||
|
|
0055dd00cc |
security: consolidate verified GHSA fixes for develop (batch 3) + CHANGELOG CVE reconciliation (#8141)
* security: consolidate verified GHSA fixes for develop (batch 3) Develop counterparts of the 1.2.x fixes in #8138, each re-verified against develop HEAD. - GHSA-77pr-g949-4v5f: spikekill.php also requires is_graph_allowed() on the target graph, not just the Spike Kill realm. - GHSA-w3qw-762w-6g9v: the include/global.php GET action guard fails closed on an array-form action[] before the scalar denylist comparison. - GHSA-xhpr-w454-cc9w: update_poller_cache() casts the stored output_type to int before interpolation. - GHSA-j3px-vw6r-g25x: graphs_new.php escapes stored snmp_index via db_qstr() in the data-query IN() pivot. - GHSA-h745-3r76-g253: graphs_new.php escapes the data-query and field names in the XML parse error messages (__ -> __esc). GHSA-297h-95ff-r767 does not apply on develop: the clog log-file selector renders through the drop_array filter framework, which escapes. tests/Unit/Security/ConsolidatedBatch3Test.php adds source-scanning regression guards. CHANGELOG (1.3.0-dev) updated; php -l, the security baselines, and check-changelog.py all pass. * chore: lead 1.3.0-dev security CHANGELOG entries with the GHSA id Normalize the 1.3.0-dev -security entries to the approved "-security: GHSA-xxxx [CVE-xxxx] Description" form, moving the advisory id to the front. CVE tokens are omitted because none of these advisories have a CVE issued yet (verified via the repository security-advisories API). Covers the five batch-3 entries plus the pre-existing entries that still used the trailing (GHSA-xxxx) form. * chore: use the -security#GHSA-xxxx: form for the 1.3.0-dev CHANGELOG entries Correct the batch-3 and reconciled 1.3.0-dev -security entries to the approved "-security#GHSA-xxxx: CVE-yyyy Description" form (GHSA id in the prefix). No CVE tokens are added because none of these advisories have a CVE issued yet (verified via the repository security-advisories API). * test: split batch-3 security guards into vulnerability-class files; reconcile CHANGELOG - Move the ConsolidatedBatch3Test.php guards into the matching Auth, Csrf, SqlInjection and Xss folders with behavior-based filenames, and strengthen them per review: the GET-guard test asserts the array branch actually returns 405 and exits; the snmp_index test rejects both raw concatenation branches; the parse-error test asserts every name-bearing message uses __esc(). - Append this pull request number to the five new 1.3.0-dev security entries. - Add issued CVE identifiers to the older -security#GHSA CHANGELOG entries (verified via the repository security-advisories API). Entries with no CVE yet, entries that already carried a CVE, and non-GHSA lines are unchanged. |
||
|
|
1f9445bb03 |
Exclude repo/tooling metadata files from remote data collector replication (#8120)
* Exclude repo/tooling metadata files from remote replication Add .gitignore, .htaccess.dist, .mdl_style.rb and .mdlrc to should_ignore_from_replication() so these development-only files are never cached into poller_resource_cache nor written to remote data collectors' base and other directories during file replication. * CHANGELOG: use numbered -issue entry in correct order |
||
|
|
d4f2bd1f3b |
Restore legacy unique_keys[] support in the schema API (#8116)
* Restore legacy unique_keys[] support in the schema API develop expresses a unique index as a `keys[]` entry with `'unique' => true`, and both db_table_create() and db_update_table() were rewritten to only read that form. Plugins that still use the legacy `unique_keys[]` definition style (supported on 1.2.x) therefore get no UNIQUE index created, and any existing one dropped on the next schema refresh. Fold a legacy `unique_keys[]` definition into `keys[]` with the unique flag at the top of both functions, so the existing unique-aware key handling applies to it. New-style `keys[]` with `'unique' => true` continues to work unchanged. * CHANGELOG: reference PR #8116 * Fix CHANGELOG format and add unique_keys[] regression coverage CHANGELOG: use the -issue#8116 entry form (the -bug prefix and trailing (#NNNN) failed the CHANGELOG format check) and place it in the issue block so the security-issue-feature ordering holds. Adds DbUpdateTableUniqueKeysTest covering db_table_create() emitting the UNIQUE index and db_update_table() adding a missing one and preserving an existing one for a legacy unique_keys[] definition. FakeMySQLPDO now projects Seq_in_index/Column_name/Non_unique for named secondary indexes so the reconciliation path can be exercised. |
||
|
|
599c76b369 |
Add Force Uninstall for orphaned plugins whose directory is missing (develop) (#8107)
* Add Force Uninstall for orphaned plugins with a missing directory (#8105) The Plugin Management page showed a directory-missing plugin (status -5) with only an inert info icon, so its stale plugin_config/hooks/realms/db_changes entries could not be cleaned up from the UI. Make that icon a Force Uninstall action guarded by the existing displayDialog() modal confirmation; on confirm it POSTs action=remove, which calls api_plugin_uninstall(plugin, true) - that skips the unavailable uninstall hook and removes the plugin's hooks, realms, plugin_config row, and the tables/columns it created (via plugin_db_changes). * Force Uninstall: POST via dialog form to satisfy CSRF action guard; add cacti.pot strings * Force Uninstall: restrict to truly-orphaned plugins, block if required by others, replicate config to remote pollers * Refresh sink inventory baseline for Force Uninstall header redirects in plugins.php * Force Uninstall: post action=remove via dialog form fields (not a URL) and JSON-inject dialog strings to satisfy CsrfGetDeleteTest and the inline-JS hardening guard --------- Co-authored-by: Copilot <copilot@users.noreply.github.com> |
||
|
|
54f1dbabdd |
security: validate host_id before the graph_view filter WHERE clauses (GHSA-r7hc-hrpv-52gf) (#8100)
* security: validate host_id before the graph_view filter WHERE clauses (GHSA-r7hc-hrpv-52gf) * security: cover graph_view host_id WHERE sinks with regression tests and add PR ref (GHSA-r7hc-hrpv-52gf) --------- Co-authored-by: Copilot <copilot@example.com> |
||
|
|
e66a324d1a |
security: validate local_graph_id before the aggregate graph item sequence query (GHSA-6mjm-5vwr-3fr2) (#8099)
* security: validate local_graph_id before the aggregate graph item sequence query (GHSA-6mjm-5vwr-3fr2) * security: bind local_graph_id via array filter and add regression test (GHSA-6mjm-5vwr-3fr2) |
||
|
|
28aba6667e |
Resolving issue #8063: Support searching by graph ID on Graphs and Aggregate Graphs pages (#8067)
* Resolving issue #8063: Support searching by graph ID on Graphs and Aggregate Graphs pages * Restrict graph-ID matching to all-digit search values to avoid MySQL leading-digit coercion * Fix PHP CS Fixer coding-standards violations flagged by CI |
||
|
|
d3d99bb08a |
test(cdef): enforce resolver coverage (#7974)
* test(cdef): enforce resolver coverage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci(cdef): pin cache action correctly Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: isolate CDEF coverage bootstrap * fix(cdef): fail closed on invalid recursive definitions Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(cdef): log corrupt resolver records Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(cdef): bound and isolate recursive resolution Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(cdef): preserve resolver failure state Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(cdef): isolate invalid graph expressions Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(cdef): abort unsafe consumer operations Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(cdef): close consumer failure paths Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(cdef): make aggregate updates atomic Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(cdef): keep repair queries auditable Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(cdef): bind bulk deletes and escape item types Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(cdef): guard corrupt types and repair reporting Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(aggregate): propagate push-out failures Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(aggregate): document mutable message checks Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: TheWitness <thewitness@cacti.net> |
||
|
|
1e5329dd89 |
security: consolidate verified GHSA-rjvj win32 cmd.exe hardening for develop (#8056)
* fix(win32): harden the cmd.exe shell sinks on develop (GHSA-rjvj-r52f-8v5q) Forward-port of the 1.2.x win32 command-injection remediation. On Windows the SNMP/ping/data-query/trap commands run through cmd.exe, which ignores the \" escape and toggles quoting on every ", so cacti_escapeshellarg cannot stop & | ^ < > ( ). - add cacti_escapeshellarg_cmd(), stripping those operators on win32 before quoting (a Unix pass-through) - snmp_escape_string(): strip the operators in the win32 branch - route the SNMP binary hostname, the data-query device values (get_script_query_path), the data-input arg builders, the Windows ping hostname, and the SNMP trap notification arguments through the strip get_script_query_path is device-reachable (a rogue monitored device supplies an SNMP index/system field that executes on the Windows poller); the rest are post-auth. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(win32): strip %VAR% from the hostname on Windows (GHSA-rjvj-r52f-8v5q) cmd.exe expands %VAR% even inside quotes, so a device hostname of %USERNAME% would expand into the SNMP/ping command line. Add an opt-in $strip_env flag to cacti_escapeshellarg_cmd() and set it for the SNMP binary and ping hostnames, which never legitimately contain a percent. Community and credential values are left untouched because they can legitimately contain %. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs(changelog): note win32 cmd.exe hardening for develop * security: require Package Management permission to trust new package signers package_accept_key() (reachable via the repository-based package import flow) inserted new keys into package_public_keys, the global trust store consulted by import_validate_signature() for every future import by every user, without checking for the Package Management (realm 29) permission that gates package_keys.php/package.php/package_repos.php for the same table. An Import Templates (realm 17) user could therefore add themselves as a trusted signer for the whole install. Also add the 'accept' action to the CSRF-protected bad_actions list so the acceptance step requires POST plus a valid token like every other state-changing action. GHSA-gxgm-8rhv-r7jv * docs(changelog): note package-signer trust authorization fix * security: close tab-based open redirect bypass in CSRF timeout handler sanitize_uri()'s guard ( |
||
|
|
344ed3dcef |
fix(snmpagent): clarify missing SNMP notification receiver message on develop (#8040)
* fix(snmpagent): clarify missing SNMP notification receiver message * fix(snmpagent): point notice at the real SNMP Managers menu and isolate test config * fix(js): regenerate DOMPurify 3.4.15 asset and skip node_modules cleanup in CI * chore: add PR number to CHANGELOG entry |
||
|
|
2f14d78927 |
fix(js): regenerate DOMPurify 3.4.15 asset and keep node_modules during CI (#8043)
* fix(js): regenerate DOMPurify 3.4.15 asset and skip node_modules cleanup in CI * chore: add PR number to CHANGELOG entry |
||
|
|
e87d87f0cb |
fix(cli): replace dead github_actions check with a real TTY check before stty size (#8041)
* fix(cli): detect a real TTY instead of a dead github_actions check before calling stty size * chore: add CHANGELOG entry for #8041 |
||
|
|
cb49f31ff9 |
Replace csrf-magic with maintained CSRF protection (#7744)
* build: add symfony/security-csrf Backs the CSRF token core that replaces the vendored csrf-magic fork. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: fix security-csrf package path assertion symfony/security-csrf ships CsrfTokenManager.php at the package root, not under src/. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * refactor: register the composer autoloader before the CSRF include CSRF validation ran before the autoloader existed, which blocks any class-based guard. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * feat(csrf): add CactiCsrfGuard over symfony/security-csrf Issues and validates session-scoped tokens; not yet wired into the request path. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * feat(csrf): accept pre-upgrade csrf-magic tokens during the grace window Legacy tokens carry their own expiry, so the fallback closes itself without a config flag. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * feat(csrf): port the output buffer rewriter to CactiCsrfGuard Keeps the hidden field name and JS globals that third-party plugins rely on. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): use json_encode for the JS script context in rewriteBuffer htmlspecialchars() protects the HTML attribute context but not the <script> string literal, which relied on Symfony's token generator never emitting a quote rather than being safe by construction. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * refactor(csrf): move the XHR shim to include/js as Cacti-owned code It has been maintained by the Cacti Group since 2020 and is not an upstream package. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * refactor(csrf): retire the vendored csrf-magic fork The procedural csrf_* surface stays as a deprecated shim so plugins keep working. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * feat(csrf): validate requests through CactiCsrfGuard csrf-magic self-invoked from its own file; the guard is called explicitly. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(install): stop gating the permission step on the csrf secret Retiring csrf-magic removed the directory its default path lives in, and setStep() clamps to the first errored step, so no fresh install could advance. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): key the legacy fallback on the raw secret bytes refresh_csrf.php writes PHP source with a trailing newline, and trimming that yields a different HMAC key than csrf-magic used. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): log when the guard degrades to disabled in a web context The installer is the only web path that can reach it, and failing open in silence is not something csrf-magic could do. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: changelog for the CSRF library replacement Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): mint the token before the session write callback closes it csrf_startup() minted lazily from the output buffer callback, which runs after session_write_close()'s shutdown-function registration, so a token minted there on a legacy-fallback POST was silently dropped. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): make refresh_csrf.php a no-op Its default secret path no longer ships and live tokens are session-bound, not HMACs over the secret, so rotation neither worked nor did anything meaningful; running it during the upgrade grace window used to delete the legacy secret and kill validation for pre-upgrade tokens outright. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): fall back to the old default secret path when reading it csrf-magic tried its own directory as a second candidate regardless of $path_csrf_secret; the new reader only tried the configured path, so a site pointing $path_csrf_secret at a file that was never created lost the legacy-token grace window entirely. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs(csrf): point the JS header at its BSD license sidecar The header reduces the original BSD terms to prose and the actual text sits in an unreferenced csrf.js.LICENSE, so add a pointer to it. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): restore csrf_check()'s bool return and $fatal contract The shim ignored $fatal and always returned void, so audit/audit.php's `!csrf_check(false)` evaluated `!null` (always true) and denied every request instead of getting a real pass/fail result back. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: reference the pull request number in the changelog entry Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: resolve includes through Cacti path constants Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(csrf): enforce full coverage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Harden CSRF fallback handling Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(csrf): assert the component stays out of the index Committing it would leave a second copy to drift against the lock. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: align CSRF checks with PHP 8.2 Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: normalize the CSRF changelog entry * Fix CHANGELOG entry ordering Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(csrf): support constrained test environments * fix(csrf): narrow nullable guard state * test: place CSRF coverage in security domain Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security(test): match disabled exec exactly Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: run CSRF coverage on PHP 8.3 Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: TheWitness <thewitness@cacti.net> |
||
|
|
157a4458ae |
fix(auth): reject malformed remember cookies (#7976)
* fix(auth): reject malformed remember cookies Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: load cookie contracts lazily * test(cookie): fail clearly when contract markers move Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(auth): align persistent credential lifecycle Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(auth): find cookie function boundaries robustly Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: TheWitness <thewitness@cacti.net> |
||
|
|
055c5ef5fa |
security: reject LDAP logins that skip a domain bind (#8009)
* hardening: validate the login realm and escape the LDAP username per context domains_login_process() now rejects a realm get_auth_realms() does not list and fails closed on one that is listed but has no domain behind it, and the Ldap class escapes the username for the DN and the search filter separately rather than relying on a filter-only blocklist. - an unlisted realm sent with a non-empty password used to match no branch at all and returned an empty user with no error, which auth_login.php reads as an authenticated user and provisions from the template account Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: reject LDAP logins that skip a domain bind Posted realms outside user_domains no longer fall through to template or guest login. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(ldap): align escaping contract with username lookup Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: cover LDAP domain login through OpenLDAP The e2e stack now binds a real directory user and checks that a forged realm cannot skip that bind. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(ldap): address Copilot review feedback Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix: substitute LDAP filter placeholders in one pass LDAP_ESCAPE_FILTER leaves angle brackets intact, so a looped str_replace can rescan one value as another key. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Change realm retrieval function from gnrv to gfrv * tests: add gfrv() stub to harnesses that exercise gfrv()-calling code domains_login_process() and api_aggregate_convert_template() call gfrv() for realm/aggregate_template_id, but their test harnesses only stubbed gnrv(), so Pest failed with 'Call to undefined function gfrv()'. --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: TheWitness <thewitness@cacti.net> |
||
|
|
182b21dc53 |
fix(csv): align export and graph sample windows (#7987)
* fix(csv): align export and graph sample windows Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci(csv): satisfy release policy checks * test(csv): align legacy capacity contract * test(csv): add standard license headers * fix(rrd): infer step from trailing fetch row Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci(csv): trigger on resolution query coverage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): mirror fetch helper arguments Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): isolate percentile globals Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): annotate intentional eval Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): restore integration config Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): enable strict types Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(rrd): restore font config Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: align CSV coverage with supported PHP versions Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: TheWitness <thewitness@cacti.net> |
||
|
|
a2c8df612e |
fix(csrf): require POST tokens for state-changing actions (#7991)
* fix(csrf): require POST tokens for item actions * test(csrf): cover every guarded action path * test(csrf): keep legacy guard contract extensible * fix(csrf): hide POST-only targets from crawlers * test(csrf): reject every crawlable state-action link * fix(csrf): fail closed without logging crawler probes * fix(csrf): post data-query item actions safely Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): normalize stripped token separators Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): distinguish method and token failures Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): escape POST action URL attributes Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): delegate POST action events Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(csrf): post data template add action Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * style(html): align POST button class Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
4744d0d9db |
Forward-port data query source guard (#7985)
* issue#7809: stop reading a missing source key on output-only data query fields
query_snmp_host() tested $field_array['source'] as the left-most term of the
method-fix guard, so PHP raised "Undefined array key source" for every
output-only field before the direction test could short-circuit. Testing
direction first reads source only for input fields, which always define it.
The boolean result is unchanged.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
(cherry picked from commit
|
||
|
|
95060c49ba | Close test-suite discovery and coverage gaps (#7970) | ||
|
|
1fdf9acf3b | Fix detached select menus on scroll (#8000) | ||
|
|
130f58243b | Fix SNMP uptime selection across polling paths (#7984) | ||
|
|
a155419ff3 |
Serialize process registry admission with portable locks (#7771)
* Serialize process registry admission with Symfony Lock Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Fix PDO process lock mode handling Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: run process lock coverage on PHP 8.2 Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix: confirm a pid is still ours before signalling it #7574 added the still-running guard to dsstats but left six byte-identical siblings signalling a pid straight out of the processes table. After a crash or a power loss the row survives, the pid is recycled by an unrelated daemon, and the next start SIGTERMs a stranger. That is issue #7425, still live in rrdcheck, boost, poller_commands, float_rrdfiles, poller_reindex_hosts and rebuild_poller_cache. Wrap each kill in cacti_process_still_running(), matching the dsstats shape, and leave unregister_process() outside the guard so a stale row is still cleaned up. Cover all seven with a test that walks every kill site, so a new variant cannot reintroduce it. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: assert the guard plainly toContain() takes needles rather than a failure message, so the file name was being asserted as a second required substring and the test always failed. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs(poller): describe required lock parameters --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
b489dbfab3 | fix(build): stop tracking partial Composer vendor tree (#7960) | ||
|
|
da7015e497 |
Break out of the --bulk_walk case in change_device.php (#7904)
* Break out of the --bulk_walk case in change_device.php * Add CHANGELOG entry for #7904 * Fix CHANGELOG entry ordering Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(cli): pin bulk walk option control flow 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: Sean Mancini <sean@seanmancini.com> |
||
|
|
66a2808cc9 |
Let one notification address several recipients (#7782)
* feat(notify): let one notification address several recipients Symfony calls a channel once per recipient, so a caller that needs a single message sent to several people could not express it. The email 'to' option folds the extra addresses into the same mailer() call and drops any that match the recipient. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(notify): compare the local part of an address exactly RFC 5321 leaves local part case to the receiving host, so folding the whole address deduplicated OPS@example.com and ops@example.com into one mailbox. Only the domain folds now. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
d07758c48b |
security: substitute query data before escaping graph titles and axis labels (#7846)
* security: substitute query data before escaping graph titles and labels rrd_substitute_host_query_data() ran over the whole graph command after each argument was cacti_escapeshellarg'd, so a device-supplied SNMP value expanded from a |query_*| token in a graph title, vertical-label or right-axis-label could contain a quote and break out of the RRDtool argument. Move the substitution inside cacti_escapeshellarg at those three fields and drop the post-escape whole-command pass. Forward-port of the 1.2.x fix. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: finish resolve-before-escape refactor, drop redundant inner substitution $value is already resolved (credential-stripped and host/query substituted) by rrdtool_resolve_graph_text() at the top of the graph-options loop, so the inner rrd_substitute_host_query_data() in the title, vertical-label and right-axis-label argument builders was a redundant second pass. Reconcile the older escape test to match; the device-quote-neutralisation behavior test is unchanged. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
ca2e4f07c2 |
Build releases from managed dependencies (#7888)
* chore: manage front-end JavaScript libraries with npm and Dependabot Move all third-party front-end JavaScript to npm so Dependabot tracks it, and drop the committed copies in favour of a build. package.json pins jquery, jquery-ui, jstree (3.3.12 -> 3.3.17), billboard.js, pace-js, tablesorter and jquery-validation; build/sync-js.mjs copies their dist files into include/js/ and runs on npm install via postinstall. pace-js carries a one-line local fix (a stray regex alternation that made it match the empty string) applied through patch-package (patches/pace-js+1.2.4.patch); the fix should be sent upstream so the patch can be dropped. Only Cacti's own themed jquery-ui/jstree CSS stays committed. An npm ecosystem is added to dependabot.yml for develop. The release pipeline and any workflow that serves Cacti pages must run 'npm ci' (which builds via postinstall) before use, since the generated files are no longer in the tree. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * hardening: remove vendored development artifacts * feat(release): attach the built artifact to the release The workflow already builds an attested, checksummed archive carrying the Composer dependencies, then discards it after thirty days. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: fail the publish step when the bundle is empty An unmatched glob would otherwise reach gh as a literal path. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: treat the maintenance lock notice as expected log output The line records the lock working, so a second maintenance run overlapping in CI failed unrelated pull requests. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: consolidate release dependency changelog * ci: build managed JavaScript in release artifacts * test: cover managed JavaScript build end to end * deps: complete phpseclib 4 migration * deps: update patch-package to audited release * ci: satisfy workflow shell policy * chore: source DOMPurify from npm and update it to 3.4.14 Add dompurify to the npm-managed set (was committed at 3.4.7) and bump to 3.4.14. DOMPurify is the client-side XSS sanitizer used on tree labels, device tooltips and plugin messages; keeping it current with upstream bypass fixes matters more than for the UI libraries. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: preserve release changelog ordering * test: preserve DOMPurify source map in npm build * chore: source htmx, d3, big.js, lzjs and screenfull from npm Add the remaining unmodified third-party libraries to the npm-managed build: htmx.org 2.0.6, d3 7.8.2, big.js 6.2.2, lzjs 1.3.1 and screenfull 3.3.3. Each was verified byte-identical (lzjs differs only in a JSDoc comment) to the copies being removed. htmx in particular moves from a hand-tracked SHA pin to npm with lockfile integrity. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: cover phpseclib 4 integration * ci: build managed assets before htmx tests --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
ac0b2c9515 |
Fix confirmed poller, database, automation, and UI defects (#7861)
* issue#7024: do not delete still-running poller_time rows on cycle start The overrun path deleted every poller_time row for the poller, including the in-flight ones it had just counted, so overrunning processes lost their tracking. Restrict the delete to completed rows. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7028: restore identifier and connection safety in the db layer _db_replace interpolated caller-supplied column keys as backtick identifiers without escaping, and db_commit_transaction checked @@in_transaction on the default connection rather than the one passed in. Both were correct on 1.2.x and regressed on develop. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7341: size the CSV export maxrows to the requested span The export hardcoded --maxrows=10000, truncating wide date ranges regardless of the data source profile step. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7421: offset automation_get_next_host through the 32-bit integer The hand-rolled octet walk subtracted the wrong magnitude per octet and emitted out-of-range octets for ranges wider than a /16. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7030: skip the poller_output ENGINE=MEMORY conversion when already applied The output-table refresh ran ALTER TABLE poller_output ENGINE=MEMORY every cycle even though the swapped-in copy already inherits the engine, adding a metadata-locking DDL to the hot path. Probe the current engine and convert only when needed. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7342: prefer snmpEngineTime only when it covers system uptime update_system_mibs preferred snmpEngineTime (x100) over sysUpTime whenever it was present, so an SNMP engine that restarts independently of the system (for example OpenBSD snmpd) made the stored uptime drop, which reads as a reboot and forces a perpetual reindex with mass 'U' results. Capture both values and use snmpEngineTime only when it is at least the system uptime, which still covers the 32-bit sysUpTime wrap. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7403: scale lmsensors readings in the get path like the query path The get path returned the raw milli-unit SNMP counter while the query path divided voltage and temperature by 1000 (and corrected negative voltages), so a get gave values 1000x too large. Apply the same scaling before returning. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7029: propagate the reconnected handle back to the caller db_check_reconnect() closed the dead connection, opened a new one, and returned true without giving the new handle back, so the db_execute_prepared retry ran its query against the connection that was just closed. Take $db_conn by reference and assign the fresh handle; the one caller that passed a literal false now passes a variable. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: refresh sink inventory baseline Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: refresh architectural hotspots baseline Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7474: return valid after correcting the theme to selected_theme is_valid_theme() corrected an invalid theme to selected_theme but left $valid false, so callers saw the theme as invalid even though it had been fixed. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7462: allow SELECT aliases as sortable automation columns site_name and host_template_name are aliases (s.name AS site_name), valid in ORDER BY but not real columns, so api_automation_column_exists() rejected them and the site-name sort silently failed. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7456: bind the OS value in the automation OS filter The OS filter built 'os = ?' but bound the network value, so filtering by OS matched on the wrong input. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7491: filter host_template_id against its own column html_make_device_where() compared h.location to the host_template_id value instead of h.host_template_id. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7479: apply the hostname and description filters in get_hosts The REST get_hosts() honored host_id/poller/site/template/location but ignored the hostname and description filters its callers pass; add them as bound LIKE. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7475: authorize a direct client-IP poller match before the hostname guard A poller configured by IP with no hostname-based pollers was rejected because the empty-hostname guard ran before the direct-match check, even though the client address exactly matched a poller's configured address. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Guard two divisors that PHP 8 makes fatal Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: consolidate functional fix changelog * test: cover consolidated functional fixes * docs: identify consolidated functional fixes --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
22d19cfcc6 |
issue#7355: add ENTITY-SENSOR, JUNIPER and F5-BIGIP script data queries (#7839)
* issue#7355: add a vendor-neutral ENTITY-SENSOR-MIB script data query ENTITY-SENSOR-MIB (RFC 3433) exposes physical sensors (temperature, fan, PSU, voltage, current) on most modern gear, so one data query covers F5, Juniper, Arista, Cisco NX-OS and others. ss_entity_sensor collects the sensor table and scales each reading through entPhySensorScale and entPhySensorPrecision; the SNMP I/O sits behind an injectable walker so every logic branch is unit tested. A dedicated coverage job enforces 100% line coverage on the collector. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7355: add a JUNIPER-MIB jnxOperatingTable script data query Junos routers and switches expose per-subject health (Routing Engine, FPC, PSU, fan) through JUNIPER-MIB jnxOperatingTable, which is the signature Juniper data beyond the IF-MIB and HOST-RESOURCES standards. ss_juniper_operating collects CPU, temperature, buffer and state; the multi-index table is keyed on the full OID suffix. SNMP I/O sits behind an injectable walker so every branch is unit tested, and a dedicated job enforces 100% line coverage. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * issue#7355: add an F5-BIGIP-SYSTEM-MIB per-CPU utilization script data query BIG-IP reports per-CPU utilization as sliding 5s/1m/5m averages in sysMultiHostCpuTable, the signature F5 metric beyond the IF-MIB and HOST-RESOURCES standards. ss_f5_cpu collects that multi-indexed table, keyed on the full OID suffix. Every OID was resolved from the published F5-BIGIP-SYSTEM-MIB with snmptranslate. SNMP I/O sits behind an injectable walker so every branch is unit tested, and a dedicated job enforces 100% line coverage. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * style: apply php-cs-fixer to ss_entity_sensor.php Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
668333b7c9 |
security(import): validate Data Source item fields coming from Template XML (#7720)
* security(import): validate Data Source item fields coming from Template XML data_source_name, rrd_minimum and rrd_maximum reach an RRDtool command line but never pass through the data_sources.php form on the import path, so the same field rules are applied at the XML handoff instead. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * chore: add the CHANGELOG entry Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(import): name the rejection and keep the value out of the log lines Code 7 reads as an XML parse error, which this is not, and the value comes from the file being imported. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * style: use a line comment to satisfy php-cs-fixer Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: resolve includes through Cacti path constants Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: restore changelog entry ordering Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(changelog): order the 7720 issue entry before features and drop a duplicate Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |
||
|
|
c77906b144 |
Use a maintained finder for recursive MD5 discovery (#7718)
* Use Symfony Finder for MD5 traversal Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * chore: add the CHANGELOG entry Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(md5sum): reject a bad ignore pattern instead of ignoring every file preg_match() returns false on a bad pattern and false is not 0, so the old test skipped the whole tree and wrote an empty manifest. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * style: use a line comment to satisfy php-cs-fixer Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: resolve includes through Cacti path constants Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test(md5): enforce full finder coverage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * Move Finder import before CLI bootstrap Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * build: lock Symfony Finder runtime dependency Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * build: leave Composer autoload metadata generated Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: run Finder coverage on PHP 8.2 Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix: widen the symfony/finder constraint for PHP 8.5 Pinning ^6.4 left the dev dependency graph unsatisfiable on PHP 8.5 in the native-dependencies job. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> |