Commit Graph
39 Commits
Author SHA1 Message Date
dependabot[bot] f26a9ba236 deps(deps): bump the composer group with 3 updates (#8083)
Bumps the composer group with 3 updates: [jfcherng/php-diff](https://github.com/jfcherng/php-diff), [league/oauth2-client](https://github.com/thephpleague/oauth2-client) and [friendsofphp/php-cs-fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer).


Updates `jfcherng/php-diff` from 6.16.0 to 7.0.1
- [Release notes](https://github.com/jfcherng/php-diff/releases)
- [Commits](https://github.com/jfcherng/php-diff/compare/6.16.0...7.0.1)

Updates `league/oauth2-client` from 2.9.0 to 2.9.1
- [Release notes](https://github.com/thephpleague/oauth2-client/releases)
- [Changelog](https://github.com/thephpleague/oauth2-client/blob/master/CHANGELOG.md)
- [Commits](https://github.com/thephpleague/oauth2-client/compare/2.9.0...2.9.1)

Updates `friendsofphp/php-cs-fixer` from 3.95.25 to 3.95.26
- [Release notes](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/releases)
- [Changelog](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/compare/v3.95.25...v3.95.26)

---
updated-dependencies:
- dependency-name: jfcherng/php-diff
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: composer
- dependency-name: league/oauth2-client
  dependency-version: 2.9.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: composer
- dependency-name: friendsofphp/php-cs-fixer
  dependency-version: 3.95.26
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: composer
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-28 07:48:42 -04:00
TheWitness a52368125e feat(auth): rename User Domains to Login Providers, add SAML2 and OpenID Connect (#8066)
* feat(auth): rename User Domains to Login Providers

Collapses user_domains/user_domains_ldap into a single login_providers table with a JSON parameters column, migrated in place during the 1.3.0 upgrade. Renames the admin page, menu, breadcrumbs, and help links to match.

* feat(auth): rework login providers as Cacti\Auth classes

Introduces LoginProviderInterface with credential (LDAP/AD) and redirect (SAML2/OpenID) flavors, replacing the procedural domains_login_process()/domains_ldap_*() functions. Adds blank-field group membership gating shared by every provider type.

* feat(auth): add SAML2 and OpenID Connect login providers

Adds onelogin/php-saml and firebase/php-jwt, a new cacti_http() SSRF-hardened outbound request helper for every OpenID discovery/token/JWKS call, and login_sso.php to handle the redirect-based SSO flow. Login page now shows a button per enabled SAML2/OpenID provider, and per-provider auth cookie opt-out is enforced on both the password and SSO login paths.

* chore(i18n): regenerate cacti.pot

* feat(auth): add Local and Basic auth as Cacti\Auth providers

LocalAuthLoginProvider (CredentialLoginProviderInterface) and BasicAuthLoginProvider (new PreAuthenticatedLoginProviderInterface, since Basic Auth has no password for Cacti to check) are thin adapters over the existing local_auth_login_process()/basic_auth_login_process() functions, which are left untouched to avoid disturbing their regression-tested lockout/timing/rehash behavior.

* feat(auth): move local password verification into LocalAuthLoginProvider

secpass_login_process() and local_auth_login_process() are retired; their lockout, constant-time verification, forced-password-change, and rehash-on-login logic now live end to end in the class (verifyCredential/enforcePasswordPolicy/rehashIfNeeded). secpass_check_pass() stays a shared lib/auth.php function since password change/reset/user_admin also call it outside any login flow. Local auth still has no login_providers row: isEnabled() is always true and it cannot be disabled or deleted.

* feat(auth): move Login Provider CRUD into Cacti\Auth classes

AbstractLoginProvider gains static deleteById()/enableById()/disableById()/makeDefaultById()/persist(); each concrete provider owns its own collectParameters(), dispatched via LoginProviderFactory. login_providers.php's form_save()/form_actions() call these instead of doing raw SQL, and the retired provider_remove()/provider_disable()/provider_enable()/provider_default()/provider_collect_parameters() procedural functions are gone. Local/Basic auth are unaffected: they never extend AbstractLoginProvider, so they structurally cannot expose delete/disable.

* fix(auth): address Copilot review findings on SSO/SAML/OIDC security

Fixes callback/ACS/SLS/metadata URLs that used the raw provider id instead of the login realm (broke every SSO login), adds InResponseTo correlation for SAML and sub/azp validation for OIDC, requires HTTPS for OIDC discovery/endpoints, pins cacti_http() connections against DNS rebinding via CURLOPT_RESOLVE, exempts login_sso.php from the authenticated-page redirect guard and gates it on auth_method, wraps provider dispatch in a exception boundary, adds a dedicated SAML SLO path instead of routing it through login completion, makes remember-me an explicit opt-in for SSO, fixes disabled/deleted providers not revoking existing auth cookies, restricts the default-realm action to LDAP/AD, and fixes the 1.3.0 migration silently enabling group enforcement for installs that had it off. Also updates the E2E seed script for the login_providers schema.

* chore(auth): refresh CI security baselines and document no-op validation

Regenerate the sink inventory baseline for the new/renamed lib/Auth/* and login_providers.php files, and add '// no-validation:' comments on the intentionally-unconstrained admin/free-text/secret fields (LDAP DNs/filters, SAML certs/keys, OIDC client credentials, provider display fields) flagged by the validator constraint ratchet.

Refreshes the validator baseline to drop the deleted user_domains.php entries.

* refactor(ldap): remove dead DB-lookup path from Ldap::__construct

The domain_id>0 branch duplicated the JSON-parameter-to-property mapping already owned by LdapLoginProvider::buildLdap(), and nothing constructs Ldap with a real id anymore (all call sites pass 0). Drop the parameter and the branch so Ldap stays a pure connection/protocol class with no DB coupling.

Also fixes a latent bug: group_require is a typed bool property, but LdapLoginProvider::authenticate() assigned it an int (1/0) from a strict_types=1 file, which throws a TypeError on every LDAP/AD login attempt. Assign a real bool instead.

* fix(auth): fix LDAP login, upgrade ordering, and hardening guard failures

LdapLoginProvider compared LdapError::GetErrorDetails()'s int error_num against the string '0' with strict equality, so it never matched and every LDAP/AD login was rejected regardless of valid credentials. Compare against int 0 instead.

install/upgrades/1_3_0.php called login_providers_convert_1_3_0() (which reads and then drops user_domains/user_domains_ldap) before the pre-existing legacy ALTER TABLE statements that add the debug/network_timeout/bind_timeout columns those reads depend on, so upgrades failed once the tables were already gone. Moved the call to run after those ALTERs.

OpenIdLoginProvider::complete() read state/code from raw \ instead of gnrv(), tripping the hardening pattern guard; switched to the request helper.

* style(auth): apply php-cs-fixer formatting and normalize line endings to LF

Runs php-cs-fixer across the new lib/Auth/* classes, login_providers.php, login_sso.php, and the other touched files, fixing indentation/alignment/docblock style to match project convention. Also normalizes several files that had picked up CRLF line endings back to the LF the project's .php-cs-fixer.php config (setLineEnding) and the rest of the tracked tree actually use.

* fix(auth): address second Copilot review round (9 high/medium findings)

- Make login_providers_convert_1_3_0() resumable: CREATE TABLE IF NOT EXISTS and INSERT ... ON DUPLICATE KEY UPDATE so an interrupted upgrade can be re-run instead of leaving a half-migrated, unrecoverable table.

- SamlLoginProvider::complete() now fails closed when no saved AuthnRequest ID exists instead of passing null to processResponse(), which skipped InResponseTo validation and accepted unsolicited IdP-initiated assertions.

- LoginResult gains an isCredentialFailure flag; only a genuine wrong-password LDAP bind (LdapError::Failure) counts toward the lockout counter now, not connection errors or group-membership denials.

- Fixed button_label/debug being read from the JSON parameters column in OpenIdLoginProvider/SamlLoginProvider/LdapLoginProvider when they are actually top-level login_providers columns; AbstractLoginProvider now hydrates and exposes both.

- Removed SamlLoginProvider's wantMessagesSigned, which silently required the outer SAML message (not just the assertion) to be signed, rejecting IdPs that only sign the assertion as the UI promises.

- Added getTemplateUserId() to CredentialLoginProviderInterface and implemented it on LocalAuthLoginProvider so the contract (not just incidental AbstractLoginProvider inheritance) guarantees the method lib/auth.php calls.

- cacti_http()'s CURLOPT_RESOLVE entries now bracket IPv6 literals correctly, and safe-IP validation strips parse_url()'s brackets before checking, fixing IPv6 target pinning.

- login_providers.php's type dropdown now swaps the Full Name attribute default (cn/displayName) on an actual user-driven type change, not on page load, so a new Active Directory provider does not silently save the LDAP default.

- Extracted auth_apply_group_login_opts() and call it from both auth_login.php and login_sso.php, so SSO logins honor a user's group-derived login_opts the same way password logins already do.

* fix(auth): fix PHPStan level 8 errors and pest harness stub drift

Test harness fix: the LoginProvidersLoginRealmValidationTest stub LoginResult class was missing the isCredentialFailure property added to the real class, causing 'Undefined property' warnings that broke the harness's JSON output. Added the property and set it on the simulated bad-password failure.

PHPStan (48+ errors, all newly introduced by this branch's rewrite, never actually verified until now): narrowed db_fetch_row_prepared()/db_fetch_assoc()'s array|bool (including bare true, which survives a '?: []' short-circuit - fixed with explicit is_array() checks instead) at every call site across auth_login.php, login_sso.php, lib/auth.php, lib/Auth/LocalAuthLoginProvider.php, lib/Auth/LoginProviderFactory.php, and install/upgrades/1_3_0.php.

Fixed OpenIdLoginProvider::discover()'s return shape to match its declared docblock instead of returning the raw decoded JSON. Fixed lib/functions.php's cacti_http() to narrow curl_exec()'s string|bool result with is_string() (not ===false, which still leaves 'true' as a residual type) and guard / as non-empty for curl_setopt_array()'s stubs.

Fixed a real bug in SamlLoginProvider::processLogout(): processSLO(true) was passing 'true' as \ (the first parameter) instead of \ (the fifth), so it always redirected/exited internally with the default \=false, making Cacti's own logout.php never regain control. Now calls processSLO(keepLocalSession: true, stay: true) and is typed ': never' to match; login_sso.php's now-genuinely-unreachable break statements after processLogout()/initiate() are removed.

Fixed login_providers.php passing a expression (not a variable) to inject_form_variables()'s by-reference parameter.

Verified: PHPStan analyse clean (0 errors), full Pest Unit/Security suite passes (128 tests), hardening guard/sink inventory/validator ratchet all still clean.

* fix(auth): fix ambiguous column and array+bool crash in user_log filter

The user filter dropdown query selected a bare 'id' column after joining user_auth and login_providers, which is ambiguous now that login_providers also has an id column (unlike the old user_domains.domain_id) - MySQL rejected the query outright. Qualified as ua.id.

Also narrow db_fetch_assoc()'s array|bool result before the \ + \ + \ merge, which was throwing a TypeError whenever the query failed instead of surfacing the real SQL error.

* fix(auth): address third Copilot review round (5 findings + tests)

- AbstractLoginProvider::persist() now disables the template account for every provider type; SAML2/OpenID also copy it via user_copy() in login_sso_complete() and were left directly usable as a local login.

- cacti_http_resolve_safe_ips() now detects IPv4-mapped IPv6 literals (::ffff:0:0/96) via inet_pton() and validates the embedded IPv4 address, closing an SSRF bypass via e.g. ::ffff:169.254.169.254.

- login_providers_convert_1_3_0() now tracks db_install_execute()'s status for every row and only drops the legacy user_domains/user_domains_ldap tables once every row (and the final row count) is confirmed migrated.

- Ldap::Getcn() now looks up ldap_get_entries()'s always-lowercased attribute keys case-insensitively while still storing the result under the originally-requested key, fixing AD's displayName (and any other mixed-case configured attribute) always resolving to a blank full name.

- SamlLoginProvider::processLogout() now redirects to the LogoutResponse URL processSLO() returns for a LogoutRequest (stay:true), instead of discarding it and always redirecting to Cacti's own logout page - federated logout was never actually acknowledged to the IdP.

- Added tests/Unit/Security/Auth/OpenIdLoginProviderTest.php (13 tests) covering verifyIdToken() signature/issuer/audience/azp/nonce validation, discover()'s HTTPS enforcement, and complete()'s callback-state and UserInfo-subject-matching checks, against a locally-generated RSA keypair/JWKS.

- Regenerated the sink inventory baseline for the new header_redirect call in SamlLoginProvider::processLogout().

Verified: PHPStan clean, full Pest Security/Auth suite passes (830 tests including the 13 new ones), php-cs-fixer/hardening-guard/sink-inventory/validator-ratchet all clean.
2026-09-24 17:51:18 -04:00
TheWitness 1a37594ad6 Replace unmaintained phpdiff vendor lib with jfcherng/php-diff (develop) (#8050)
* chore: replace unmaintained phpdiff vendor lib with jfcherng/php-diff

The manually-vendored include/vendor/phpdiff (chrisboulton/php-diff v1.1,
2009 - unmaintained since ~2013) backed the package-import file diff
viewer (package_import.php's package_diff_file()), its only call site.

Replace it with jfcherng/php-diff (^6.16, BSD-3-Clause), an actively
maintained continuation of the same library, declared as a real Composer
dependency in composer.json/composer.lock (installed at build/CI time,
same as this branch's other composer.json dependencies - not committed
to include/vendor, unlike the old hand-vendored phpdiff).

package_import.php now uses Jfcherng\Diff\Differ + RendererFactory in
place of the old Diff/Diff_Renderer_Html_Inline classes. Preserved the
existing nosemgrep justification comment, updated to reference the new
library's AbstractHtml::htmlSafe() escaping.

Adopted the vendor's own diff-table.css as the Diff.css in all 10 themes,
replacing the bespoke per-theme stylesheets that were tied to the old
library's class names.

* fix: address review feedback on jfcherng/php-diff migration

- package_import.php: narrow $oldfile/$newfile to array before
  constructing Jfcherng\Diff\Differ so PHPStan can see the
  false branch is excluded (fixes level 6/8 analysis failure).
- tests/tools/check_vendor_policy.php: drop the removed
  include/vendor/phpdiff/ path from the legacy allowlist.
- tests/Unit/Security/Xss/PackageDiffRendererTest.php: rewrite
  against the new Jfcherng\Diff\Differ/RendererFactory API instead
  of the deleted vendored phpdiff classes.
2026-09-21 13:59:50 -04:00
dependabot[bot] 5bbfc23a1d deps(deps-dev): bump the composer group with 3 updates (#8048)
Bumps the composer group with 3 updates: [friendsofphp/php-cs-fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer), [overtrue/phplint](https://github.com/overtrue/phplint) and [rector/rector](https://github.com/rectorphp/rector).


Updates `friendsofphp/php-cs-fixer` from 3.95.24 to 3.95.25
- [Release notes](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/releases)
- [Changelog](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/compare/v3.95.24...v3.95.25)

Updates `overtrue/phplint` from 9.6.3 to 9.7.2
- [Release notes](https://github.com/overtrue/phplint/releases)
- [Changelog](https://github.com/overtrue/phplint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/overtrue/phplint/compare/9.6.3...9.7.2)

Updates `rector/rector` from 2.6.6 to 2.6.7
- [Release notes](https://github.com/rectorphp/rector/releases)
- [Commits](https://github.com/rectorphp/rector/compare/2.6.6...2.6.7)

---
updated-dependencies:
- dependency-name: friendsofphp/php-cs-fixer
  dependency-version: 3.95.25
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: composer
- dependency-name: overtrue/phplint
  dependency-version: 9.7.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: composer
- dependency-name: rector/rector
  dependency-version: 2.6.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: composer
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-21 04:02:56 -07:00
TheWitness 22584d45bb chore: bump composer.lock to Pest v3 (already permitted by composer.json) (#8044)
composer.json's require-dev already allows pestphp/pest "^2 || ^3" and
pestphp/pest-plugin-drift "^2.0 || ^3.0", but composer.lock was still
pinned to pest v2.36.1, whose transitive deps (nikic/php-parser v4.19.5,
brianium/paratest v7.4.9) are incompatible with pest v3.

This breaks the plugin-ci-workflow template used by Cacti/plugin_* repos:
their CI does `composer require "pestphp/pest: ^3" ...` as a partial
update, which Composer refuses to resolve because it won't bump other
locked packages (nikic/php-parser, paratest) without --with-all-dependencies,
so every plugin CI run against develop fails at the Install Composer
Dependencies step with "Your requirements could not be resolved".

Ran `composer update pestphp/pest pestphp/pest-plugin-drift
--with-all-dependencies` to bump the lock file to the latest versions
already allowed by composer.json (no composer.json changes needed):
pest v2.36.1 -> v3.8.7, pest-plugin-drift v2.5.0 -> v3.0.0,
phpunit/phpunit v10.5.63 -> v11.5.56, nikic/php-parser v4.19.5 -> v5.9.0,
paratest v7.4.9 -> v7.8.5, plus their transitive deps.

Verified: composer validate --strict passes, composer install from the
updated lock is clean, and re-running the plugin workflow's `composer
require "pestphp/pest: ^3" ...` step against this lock now reports
"Nothing to modify in lock file" instead of a conflict.
2026-09-19 14:27:35 -04:00
Thomas VincentandTheWitness 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>
2026-09-18 00:16:39 -04:00
dependabot[bot] 115073e66e deps(deps): bump the composer group with 3 updates (#8021)
Bumps the composer group with 3 updates: [slim/slim](https://github.com/slimphp/Slim), [friendsofphp/php-cs-fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) and [rector/rector](https://github.com/rectorphp/rector).


Updates `slim/slim` from 4.15.2 to 4.15.3
- [Release notes](https://github.com/slimphp/Slim/releases)
- [Changelog](https://github.com/slimphp/Slim/blob/4.x/CHANGELOG.md)
- [Commits](https://github.com/slimphp/Slim/compare/4.15.2...4.15.3)

Updates `friendsofphp/php-cs-fixer` from 3.95.23 to 3.95.24
- [Release notes](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/releases)
- [Changelog](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/compare/v3.95.23...v3.95.24)

Updates `rector/rector` from 2.6.5 to 2.6.6
- [Release notes](https://github.com/rectorphp/rector/releases)
- [Commits](https://github.com/rectorphp/rector/compare/2.6.5...2.6.6)

---
updated-dependencies:
- dependency-name: slim/slim
  dependency-version: 4.15.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: composer
- dependency-name: friendsofphp/php-cs-fixer
  dependency-version: 3.95.24
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: composer
- dependency-name: rector/rector
  dependency-version: 2.6.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: composer
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-14 06:22:52 -07:00
Thomas Vincent 1ae479d4f5 feat(cli): add unified command frontend and normalize legacy failures (#7903)
* feat(cli): add unified command frontend and normalize legacy failures

Add the Symfony-backed bin/cacti entry point while preserving legacy argument, terminal, signal, and exit-status behavior. Fold in the focused legacy CLI correctness fixes from #7906 without adding its unused parser abstraction.

Keep path containment and the PHP 8.3 floor out of this review; the latter remains in #7939.

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

* fix(cli): enforce PHP floor and deny web dispatch

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2026-09-07 18:36:55 -07:00
dependabot[bot] 49b10f8046 deps(deps): bump the composer group with 2 updates (#8004)
Bumps the composer group with 2 updates: [phpseclib/phpseclib](https://github.com/phpseclib/phpseclib) and [rector/rector](https://github.com/rectorphp/rector).


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

Updates `rector/rector` from 2.6.3 to 2.6.5
- [Release notes](https://github.com/rectorphp/rector/releases)
- [Commits](https://github.com/rectorphp/rector/compare/2.6.3...2.6.5)

---
updated-dependencies:
- dependency-name: phpseclib/phpseclib
  dependency-version: 4.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: composer
- dependency-name: rector/rector
  dependency-version: 2.6.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: composer
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-07 17:35:43 -07:00
Thomas Vincent 79a9ae0351 build: raise the 1.3 floor to PHP 8.3 (#7939)
* build: raise the 1.3 floor to PHP 8.3

RHEL 10 ships 8.3 in AppStream and dropped modularity, so an 8.4 floor would
put every RHEL, Alma and Rocky 10 install on Remi. Ubuntu 24.04 is 8.3 as
well, which makes it the lowest common denominator of the current LTS fleet.

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

* docs: raise the documented PHP floor to 8.3

The 1.2.x column keeps 8.1, which still matches that branch's composer constraint.

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

* ci: run process lock coverage on PHP 8.3

* fix: finish PHP 8.3 floor cleanup

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

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2026-09-06 08:44:40 -07:00
Thomas Vincent 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>
2026-09-04 19:36:42 -07:00
Thomas Vincent 4afe89966e build: analyse at PHPStan level 8 and unpin the analyser (#7918)
* build: analyse at PHPStan level 8 and unpin the analyser

The level lived in the composer script as --level 6 while .phpstan.neon
declared none, so anyone running phpstan directly analysed at level 0 and saw
nothing. The level now sits in the config where both CI and a developer get
the same answer.

Level 8 finds 2787 issues on the current tree, so the baseline is regenerated
rather than the debt fixed here. The gate passes on what exists and fails on
anything new, which is the point: a fresh offset access on a db_fetch_row()
result is now caught in review instead of at runtime.

The debt is not 2787 unrelated problems. 1556 of them are the same shape,
"Cannot access offset X on array|bool", from the db_fetch_* family declaring
bool|array and call sites indexing the result without testing it. Narrowing
those return types would clear more than half in one change, which is worth
doing on its own.

phpstan was pinned to an exact 2.2.9, so patch releases were not reaching CI.
It now floats on ^2.2.12.

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

* build: refresh the PHPStan baseline against current develop

The baseline was generated while phpseclib was temporarily pinned back to the
3.x line. develop has since migrated the call sites to phpseclib4, so three
entries no longer match anything.

reportUnmatchedIgnoredErrors is false in .phpstan.neon, so stale entries are
ignored rather than reported and would have sat there indefinitely. The
migration introduced no new level 8 findings: 1483 entries become 1480, with
nothing added.

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

* build: refresh PHPStan baseline after rebase

* build: refresh baseline after transaction fix

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

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2026-09-02 20:33:22 -07:00
dependabot[bot] 648ae108af deps(deps): bump the composer group across 1 directory with 3 updates (#7867)
Bumps the composer group with 3 updates in the / directory: [phpseclib/phpseclib](https://github.com/phpseclib/phpseclib), [phpstan/phpstan](https://github.com/phpstan/phpstan-phar-composer-source) and [rector/rector](https://github.com/rectorphp/rector).


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

Updates `phpstan/phpstan` from 2.2.8 to 2.2.9
- [Commits](https://github.com/phpstan/phpstan-phar-composer-source/commits)

Updates `rector/rector` from 2.6.2 to 2.6.3
- [Release notes](https://github.com/rectorphp/rector/releases)
- [Commits](https://github.com/rectorphp/rector/compare/2.6.2...2.6.3)

---
updated-dependencies:
- dependency-name: phpseclib/phpseclib
  dependency-version: 4.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: composer
- dependency-name: phpstan/phpstan
  dependency-version: 2.2.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: composer
- dependency-name: rector/rector
  dependency-version: 2.6.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: composer
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-01 11:13:16 -07:00
Thomas Vincent 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>
2026-08-31 17:07:36 -04:00
Thomas Vincent 11117e812d fix(php85): remove test and authenticator deprecations (#7632) 2026-08-29 17:38:51 -07:00
Thomas Vincent 44c7e9e636 chore: require PHP 8.2 and move Symfony to 7.4 (#7831)
PHP 8.1 left security support in December 2025 and Symfony 7.4 requires 8.2,
so the platform floor has to move before any component can advance.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2026-08-29 16:00:57 -07:00
Thomas Vincent 4d021a93e3 Add plugin-extensible notification API (#7775) 2026-08-21 14:29:33 -07:00
Thomas Vincent 2e372e5b88 Make PHP 8.1 dependency builds reproducible (#7746)
* Make PHP 8.1 dependency builds reproducible

* Tighten integration runner permissions

* Harden and standardize GitHub Actions

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

* Restore ripgrep for security guards

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

* Wait for Cacti daemon readiness in CI

* Satisfy strict shell policy in diagnostics

* Preserve Cacti config group ownership

* Run stateful Cacti checks as the web user

* Run privileged page-crawl harness as root

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2026-08-16 22:06:36 +01:00
TheWitness cd2ea4bbfb Return exit code and increase max_allowed_packet (#6693)
* Return exit code and increase max_allowed_packet

* Adding max_allowed_packet to client section

* Command not recognized

* Trying to re-introduce command

* Moving the max-allowed-packet

* Moving the max-allowed-packet

* One more try to change max_allowed_packet size

* Set the global when creating the database

* Plumbing in PHP Pest without running

* Fixing composer.json, composer.loc, swapping net_dns2 as it's abandoned

* Removing composer lock file

* Removing dev components
2026-03-02 15:39:07 -05:00
TheWitness a819197e6c Adding the latest net_dns2 for various plugins (#6623) 2026-02-16 09:53:30 -05:00
TheWitnessandCopilot fb1d7ea006 Put the Scripts Directory in Scope for Quality Checks (#6584)
* Allow form_selectable_cell to more easily port

* Removing exclusion for scripts directory

* More fixes for scripts

* Some issues with ss_host_disk.php that passed locally

* More issues not detected locally

* Issues with typing in cacti_snmp_walk

* Adding base files for non-savy composer users

* One more try on ss_host_disk.php

* Aparantly I have to add the lock file

* More changes to lib/snmp.php after testing

* More changes to lib/snmp.php after testing

* Fix number script from Copilot review

* More Composer reviews

* Update scripts/ss_apache_stats.php

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

* Update scripts/motorola_surfboard_SB6141.py

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

* Update scripts/motorola_surfboard_SB6141.py

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

* Changing syntax of PHP requirement

* Updating composer

* Attempt to quiet some warnings

* Add Syntax Check

* Wrong file name

* Wrong file name

* Better to report before and after

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-30 08:04:27 -05:00
dependabot[bot] 6fa9b18f76 Bump symfony/process in the composer group across 1 directory (#6581)
Bumps the composer group with 1 update in the / directory: [symfony/process](https://github.com/symfony/process).


Updates `symfony/process` from 6.4.24 to 6.4.33
- [Release notes](https://github.com/symfony/process/releases)
- [Changelog](https://github.com/symfony/process/blob/8.1/CHANGELOG.md)
- [Commits](https://github.com/symfony/process/compare/v6.4.24...v6.4.33)

---
updated-dependencies:
- dependency-name: symfony/process
  dependency-version: 6.4.33
  dependency-type: indirect
  dependency-group: composer
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-28 17:43:40 -05:00
TheWitness d38eb0ba43 QA: Make compatible with php8.1++ 2025-08-20 22:23:45 -04:00
TheWitness 6d7e81e1d4 Feature: Adding slim and beginnings of an API 2025-08-20 21:14:39 -04:00
TheWitness 7bb52187fd QA: Composer issues 2025-08-17 19:59:35 -04:00
TheWitness 3a4ac4a968 QA: Removing pest for the moment 2025-08-17 19:54:43 -04:00
TheWitness 3a9ba82620 QA: Preparing for Deeper Inspection 2025-08-17 19:44:17 -04:00
TheWitness b8fe5315b0 Feature: Update phpseclib for Service Check Plugin 2025-08-14 15:10:24 -04:00
TheWitness 6f261a928b QA: Update composer components 2025-08-14 14:27:53 -04:00
TheWitness 1dff3da461 QA: Update PHPMailer to 6.10 2025-08-14 14:22:20 -04:00
root 3ec13e1ca4 Updating composer file and dependencies 2025-03-04 09:46:49 -05:00
Jimmy Conner 217fe35419 Remove Rector / PHPStan for now (#6107)
I staged my own vendor directory elsewhere for them
2025-02-24 13:13:37 -06:00
Jimmy ConnerandTheWitness 65ab16f5cf Start converting to newer PHP Syntax and Functions (#6103)
* Add Rector

* Add Rector

* Fix "Cashed" misspelling

Also harmonize the phrase with the one below it

* Fix implode error in db_table_create

Only relevant when multiple primary keys

* Fix auth issue, parentheses in the wrong location

Was causing too many arguments to be sent to cacti_sizeof which only take 1, instead of get_allowed_devices.

* Fix issue with session_var not properly using class variable

* Fix pass by reference error in get_allowed_devices

get_allowed_devices has a pass by reference on the "total_rows" field.  It is used in several places to pass the total_rows back to a counter.  Here though, we are passing a number directly to the function, which errors out with "Uncaught Error: get_allowed_devices(): Argument #4 ($total_rows) cannot be passed by reference".  So we will just place a dummy variable in front to catch the pass.

This wasn't caught before because the previous parentheses issue.

* Fix undefined variable "field_array" in html_filter

* Fix undefined function 'get_nfilter_filter_request_var'

* Fix undefined variable 'resizable'

I corrected the function parameter, as that was technically the incorrect spelling

* Fix invalid variable $user_id

* Fix undefined vars in spikekill class

* Fix copy and paste error

Oops

* Forgot to use the dummy variables

* Add missing $

Oops

* Start converting to newer PHP Syntax and Functions

* Test fixing the workflow by install composer

* Lets not valid the composer file right now
Seems we have a few things to fix it in

* Validate composer

* Lite formating changes

* lite formatting

* lite formatting

* lite format changes

* lite format changes

* lite format changes

* lite format changes

* lite format changes

* lite format changes

* lite format changes

* lite format changes

---------

Co-authored-by: TheWitness <thewitness@cacti.net>
2025-02-23 15:14:54 -05:00
TheWitness 2eabf8d1d3 QA: More composer for future steams support 2025-01-09 20:40:29 -05:00
TheWitness 4162de3a77 QA: Use composer correctly 2025-01-08 18:57:37 -05:00
netniV e63466be5a QA: Fix composer issue 2023-01-05 11:40:03 +00:00
Mark Brugnoli-Vinten e4d60297fd Update copyright year for 2023 2023-01-04 13:36:25 +00:00
Mark Brugnoli-Vinten 433423ad90 Update PHPMailer to 6.7.1 2022-12-23 13:12:20 +00:00
Mark Brugnoli-Vinten 80f70aa908 Lets add some CodeStandard support 2022-12-15 14:01:07 +00:00