(release-3006.26)=
Salt 3006.26 release notes#
Changelog#
Removed#
Removed the unmaintained
linode-pythonpackage dependency to stop SyntaxWarnings during install for retired Linode API v3. #68992
Changed#
Changed
salt.returners.redis_returnto enumerate the Redis keyspace withSCANinstead of the blockingKEYS patterncommand in bothget_jidsandclean_old_jobs.KEYSwalks the entire keyspace synchronously and stalls the Redis server for the duration; on a master with hundreds of thousands of jobs this can block all clients of that Redis instance for seconds.SCANis incremental and non-blocking. Order of returned keys is no longer guaranteed (the returner does not rely on order); operators with custom scripts that readret:*orload:*directly may see them in a different order. #69037
Fixed#
Fixed multi-line scalar variables loaded via
import_yaml(orload_yaml) being rendered as literal\ninstead of actual newlines when the loaded data is interpolated into a YAML state file (e.g.- context: {{ data }}).PrintableDict.__str__/__repr__now emit string values containing newlines as YAML-safe double-quoted scalars rather than Pythonrepr()so they round-trip correctly through the subsequent YAML render pass. #30690Handle requisites correctly for empty SLS files #30971
Fixed
win_pkgfunctions ignoring thesaltenvsetting in minion configuration. All public functions (refresh_db,genrepo,install,remove,list_pkgs,latest_version,upgrade_available,list_upgrades,list_available,version,get_repo_data,get_package_info) now fall back to__opts__["saltenv"]whensaltenvis not passed explicitly, instead of always defaulting tobase. #38551dpkg_lowpkgno longer reads/var/lib/dpkg/availableor/var/lib/dpkg/info/<package>.listdirectly. It now usesdpkg-queryexclusively, addressing the lintianuses-dpkg-database-directlywarning reported in #52605.lowpkg.infoderives the package install time from dpkg's${db-fsys:Last-Modified}field instead of the.listfile mtime. #52605Added
encodingparameter tofile.replaceexecution module and state to support UTF-16, UTF-32, and other multi-byte encoded files that would otherwise be incorrectly treated as binary. #52793Fixed
postgres._find_pg_binaryignoringpostgres.bins_dirwhen apsqlbinary is also present on the system PATH, ensuring the configuredbins_diris always preferred over the system PATH. #53190Percent-encode the user and password when adding HTTP basic auth to a URL so reserved characters no longer corrupt the result #55561
Fixed a
SaltCacheError("maximum recursion depth exceeded") raised by the etcd data cache when listing an empty folder, which etcd reports as a child of itself. The directory walk now stops at the self-referential entry instead of recursing indefinitely. #57377Fixed
timezone.systemstate always returningresult=Falsewith "Failed to set UTC to True" on Windows. The hardware clock on Windows is always localtime and cannot be changed, so the UTC/hwclock block is now skipped entirely on Windows. #57754Fixed
archive.tarplacing the-C <dest>option after the source/member operands, where tar ignores it. The directory-change option is now emitted before the operands so it takes effect in both create and extract modes. #57847Fixed
OSError: The operation completed successfullyraised byCreateProcessWithTokenWon Windows when the underlying advapi32 call fails. The error code is now read fromctypes.get_last_error()(the ctypes-saved slot) instead ofwin32api.GetLastError()(the live Windows slot, which may be reset to 0 before it is read). #57848Improved documentation for the
runasandpasswordparameters incmd.run,cmd.script, and allsalt.modules.cmdmodexecution functions on Windows. The docs now accurately describe when a password is required: only when the salt-minion is not running as SYSTEM or as an elevated Administrator. Removed the inaccurate claim that the target user account must be in the Administrators group. Also changedcmd.scriptto log a warning instead of hard-failing whenrunasis used without a password on Windows, since a password is not always required. #57951Fixed
pkg.group_installed/pkg.group_infofailing to expand a dnf environment group whose member groups have multi-word names (e.g.Group '@Common NetworkManager submodules' not foundwhen installingWorkstationon RHEL/AlmaLinux 8, 9 and 10). The member group is now resolved by its bare name when the@-prefixed lookup fails. This affects dnf4 only; dnf5 group handling is unchanged. #60276Fix
tls.create_csrlog message path to useos.path.joininstead of f-string interpolation so paths render correctly when csr_path has a trailing slash. #60877Fixed the LDAP eauth group-membership lookup re-binding the user on every job payload when
auth.ldap.freeipais enabled. The user is now only re-bound on the first payload of a job, matching the standard LDAP code path, so single-use 2FA credentials (such as a FreeIPA OTP) are no longer consumed more than once. #61974Fixed
SSL: DECRYPTION_FAILED_OR_BAD_RECORD_MACerrors in the VMware cloud driver by reconnecting when a cached vCenter service instance is found to be stale or corrupted (for example when inherited across a fork by salt-cloud's parallel provider queries). #61983Fix metadata grain so EC2
user-datais returned verbatim instead of being mangled by the=line-splitter, which previously corrupted any user-data payload containing=(e.g. cloud-init#cloud-configblocks). #62061Fixed LGPO
get_policy_infoincorrectly returning a "multiple policies" error when duplicate ADMX policy definitions (e.g.TerminalServer.admxandTerminalServer-Server.admx) resolve to the same full path. #62732Re-enable test_interrupt_on_long_running_job by removing the initial-onedir-rollout skip marker. #63627
Fix missing
dns_plugin_propagate_secondsarg in acme state/module so DNS propagation timeout is actually forwarded to certbot. #63700Improve PAM eauth diagnostics when
salt-masterruns as a non-root user. Previously,salt-master/salt-apirunning as thesaltuser (the 3006.x packaging default) silently failed every PAM authentication with onlyPam auth failed for <user>:in the log; the cause is that the helper subprocess inherits the master's uid and PAM'sunix_chkpwdrefuses to validate other users without/etc/shadowaccess. The master now emits a one-shot CRITICAL log entry that names the cause and the two standard remediations (run asroot, or add the master user to theshadowgroup on Debian-derived distributions), and the module documentation describes the constraint. #64275Fixed incorrect minion presence events being sent out on hourly
Maintenanceprocess restarts #64505Catch StrictUndefined in salt jinja custom filters. #64915
Stopped logging the misleading "An extra return was detected from minion ... this could be a replay attack" ERROR for benign duplicate returns (also fixes #65516). The local_cache returner now compares a duplicate return to the cached one and logs at DEBUG when the payloads match (the common retry-after-timeout or syndic re-forward case) and at WARNING -- without the "replay attack" wording -- when the payloads differ. #65301
Fixed non-root salt CLI access when
publisher_aclorexternal_authis configured. Since 3006.3 the master defaults to running as thesaltuser, which leftsock_dirandcachedirmode0o750and blocked authorised non-root users from traversing into them to reachmaster_event_pub.ipc/publish_pull.ipcand their per-user.<user>_key. The master now adds the world-execute bit to those two directories when ACLs are configured, without exposing directory listings. #65317Fixed
salt.ext.tornado.netutilimport on Python 3.12+ wheressl.match_hostnamewas removed and the unmaintainedbackports.ssl_match_hostnamepackage is unavailable, which previously broke any Salt master-initiated job (e.g.test.ping,state.apply) on Fedora 39+/Ubuntu 24.04 masters. #65360See #65301 -- the same fix to
salt/returners/local_cache.pyquiets the spurious "extra return ... replay attack" ERROR that appeared in multimaster and master-of-masters/syndic setups when the same return arrived more than once. #65516Fix deadlock in parallel
cmd.scriptstates when the script is served by the master.Same fork-inherited ZeroMQ socket race as the
file.managedfix: acmd.scriptstate withparallel: Truedownloads the script viacp.cache_filein a forked child that inherited the parent's ZeroMQ REQ socket, deadlocking the asyncio loop at ~100% CPU. Resolved by the sameos.register_at_forkhandlers that drop inherited channel/socket references in forked children. #65709Fixed pip.uninstall rejecting the extra_args keyword argument, matching the behavior of pip.install. #65870
Fixed salt-ssh failing to fetch
gitfs_remotes.salt.config.master_configsets__fs_update = Trueto suppress fileserver refreshes done byFSChan(the master daemon's maintenance thread handles them). salt-ssh inherits the master config but has no maintenance thread, so itsFSClientnever refreshed the fileserver backends and wrappers such ascp.list_statessaw no gitfs content until the user ransalt-run fileserver.updateor manuallygit fetched the cached repos.salt.client.ssh.SSH.__init__now removes the suppression flag before instantiatingFSClientso gitfs is refreshed once at startup. #66148Fixed
salt/version.pyreporting the wrong major version on the 3006.x branch when built from a checkout that has nosalt/_version.txtand no usable.gitdirectory.SaltVersionsInfo.current_release()now returns the branch's own codename (Sulfur) instead of the next un-released codename in the table, so source builds and other tooling no longer leak3007.0into the reported version. #67061Fixed
saltutil.runnerandsaltutil.wheelrunning master-side functions as the minion's user (typicallyroot) instead of the master's configured user (the packaged default since 3006 issalt). Running as the wrong user left root-owned files in, and tripped git'ssafe.directorycheck on, the salt-owned master cache -- breaking, for example,git_pillar.updateinvoked viasaltutil.runner. These functions now drop to the master's configured user before executing when invoked from a more-privileged process. #67716Fixed
LocalClient.cmd_subsetraisingTypeError: argument of type 'bool' is not iterablewhen one or more targeted minions failed to respond to thesys.list_functionsprobe. Failed minions are now skipped during subset selection. #68103Fixed
slack_boltengine crashing withUnboundLocalErrorwhen a Slack workflow or other bot posts a message to a monitored channel. Bot messages (subtype: bot_message) carrybot_idandusernameinstead of auserfield, and these are now used as fallbacks so the engine continues running. #68105Fixed
user.presentto not fail withresult: Falsein test mode when a referenced group does not yet exist; the state now reports the pending changes so users can preview states that depend on groups created by agroup.presentrequisite in the same run. #68110Fixed
salt-minionandsalt-proxyleaving a privileged (root) keepalive supervisor process at the head of an otherwise unprivileged minion process tree whenuseris set to a non-root account. The supervisor now drops privileges to the configured user once the keepalive child has been spawned. #68115Fixed
ValueError: Formatting field not found in record: 'colorlevel'errors whenlog_fmt_consoleuses custom color attributes such as%(colorlevel)sor%(colormsg)s.SaltLogRecordnow always provides thecolor*attributes (uncolored by default) so that log records buffered by the temporary deferred stream handler can be formatted by a colorized console formatter once it is installed. #68129Fixed
salt-callsilently ignoring--file-root,--pillar-root, and--states-dirwhen--localwas not passed. These overrides only affect the local minion config and are clobbered by the master's values via the remote file client, sosalt-callnow emits a warning explaining that--localis required for the override to take effect. #68137Fixed event signature verification failing under
minion_sign_messages. The minion was signing the return load beforesalt.channel.client.AsyncReqChannel._package_loadattached transport metadata (nonce,ts,tok,id), so the bytes the master re-serialized to verify did not match what was signed and every signed return was dropped. Signing is now performed inside_package_loadafter the metadata is attached, against the same bytes the master verifies. #68181Fixed
pkgrepo.managedhonouringclean_file: Truewhen the desired repo line is already present in the managed file alongside unrelated stale lines. Previously the state returned "already configured" and silently skipped both the file truncation and the re-write, leaving the stale entries (for example an obsoletebullseye-backportsline in a file managed forbookworm-backports) in place. The clean + reconfigure path now runs whenever the managed file contains any non-comment, non-blank content other than the desired repo line; when the file already contains only the desired line the state remains idempotent. #68208Fixed
pkg.group_installedreporting failure on RPM-based systems when a package group's default or optional members are not available in any enabled repository. The state now only considers mandatory group members and explicitly requestedincludepackages when checking for install failures, matching the behavior ofyum/dnf group install(which reports "No match for group package" but still exits 0). #68210Pass
--disable-pip-version-checkwhenpip.list,pip.freeze,pip.list_upgrades,pip.upgrade, andpip.list_all_versionsinvoke pip, so these calls no longer hang for ~20s per invocation on airgapped minions while pip tries to reach PyPI for its self-version check. #68214Fixed
archive.extractedfailing to enforceuser/groupownership on archives whose tar/zip members include no explicit directory entries (e.g. Oracle's GraalVM JDK tarballs).archive.listnow derives the top-level directory from the common prefix of file and link members in addition to dir members, so ownership is applied to the extracted top-level directory in all cases. #68227Fixed deltaproxy sub-proxies returning identical grain data for every controlled minion.
subproxy_post_master_initnow re-packs each sub-proxy's freshly loaded per-minion grains into its execution-module, returner, executor and proxy LazyLoaders so__grains__inside loaded modules reflects that sub-proxy's device instead of the placeholder values captured during the first-pass grains load through the control proxy. #68248Fixed the salt-minion (and salt-api, salt-cloud, salt-master, salt-syndic) Debian postinst scripts hanging or erroring with "Bad file descriptor" when run from a non-interactive Debian preseed late_command chroot, by tearing down the debconf protocol with
db_stopand explicitly closing file descriptor 3 before the auto-generated#DEBHELPER#section runs. #68269Fixed
file.managedfailing withWinError 123on Windows when caching a remote URL whose path embeds another URL (e.g. an archive.org snapshot of anhttps://...resource). The URL-path portion of theextrn_filescache path is now sanitised the same way the network location already is. #68273Fixed
logrotate.setdropping the secondendscript(and turning embedded shell commands into bogus setting keys) when a stanza contained multiple script blocks such as bothprerotateandpostrotate. Script directives are now parsed as opaque multi-line bodies and round-trip with their ownendscriptterminator each. #68293Fixed the
salt.stateorchestrate state silently reporting onlyRun failed on minions: <minion>when a targeted minion returnedFalse, no return at all, or a list of error strings. The orchestrate comment now includes the per-minion failure detail (the minion's actual return value or "did not return a state result") so operators can diagnosesalt-run state.orchestratefailures without re-running with extra logging. #68326Fixed worker process crash when salt is used outside CLI tools. #68332
Fixed
clean_old_jobsin the default local job cache returner to use the jid file's modification time (st_mtime) instead of the inode change time (st_ctime). A package upgrade'schown -R /var/cache/salt/masterresetsst_ctimeon every existing jid file, which previously made the maintenance process treat every pre-upgrade job as freshly created and prevented cleanup untilkeep_jobs_secondshad elapsed. On busy masters this exhausted the partition's inodes within a day. #68351Fixed the
proxmoxsalt-cloud driver raisingCould not determine an IP address to usebefore the VM was created and started. The IP address is now determined after the VM is running, and the running VM's address reported by Proxmox is used as a fallback when neither a staticip_addressnoragent_get_ipis configured. #68353Changed
KillModein the shippedsalt-minion.servicesystemd unit fromprocesstomixedso thatsystemctl stop/systemctl restart salt-minionno longer leaves orphanedMinion._thread_returnworker processes outside the cgroup. SIGTERM is still sent only to the main PID (so the job return scheduled byservice.restart salt-minionfrom #68183 has time to finish), but any remaining children are reaped with SIGKILL after the main process exits orTimeoutStopSecelapses. #68406Fixed
task.edit_taskon Windows rejectingrestart_count=999even though the documented and error-message-stated maximum is 999. The validation now accepts the full 1..999 range. #68419Fixed
win_task.add_triggerso thatrepeat_duration="Indefinitely"actually produces an indefinite repetition pattern. Previously the empty string from the internal duration lookup was assigned toRepetition.Duration, which the Windows Task Scheduler treats as "0 seconds" and silently disables repetition. The Duration property is now left at its default for the "Indefinitely" case, which is the documented way to repeat forever. #68420Fixed
user.setpasswordon Windows reporting success (retcode: 0) when the target user does not exist. The execution module now returnsFalseand logs an error in that case, so callers and theuser.presentstate correctly detect the failure instead of swallowing the Win32 "user name could not be found" message as a successful return. #68428Fixed
user.presenton Windows so it actually updates a user's password when the existing password differs from the one specified in the state. Previously the state reported "User is already present and up to date" and left the password unchanged. #68429Stop salt-ssh state runs from clobbering the master-side fileclient
cachedirwith the on-targetthin_dircachedir. The state fileserver cache for salt-ssh state runs is now written under the configured mastercachedir(e.g./var/cache/salt/master/) instead of under the minion's thin_dir path on the master filesystem. #68458Fixed
pkg.add_repo_keyandpkgrepo.managedso APT keyring files that target an.ascdestination keep their ASCII armor instead of being dearmored, matching the apt-secure(8) convention and allowing armored keyfiles that bundle multiple keys to be installed even when thegpgbinary is not available on the minion. #68464Fixed
jobs.list_jobs search_metadataso it matches jobs whose metadata was passed as a CLI keyword argument (e.g.state.apply metadata={...}) and is therefore carried inside the job'sArgumentsrather than at the top of the job payload. #68481Fixed
lgpo.setstate reporting "Failed to set the following policies" on subsequent runs of policies with sub-elements (e.g. Storage Sense thresholds). The state compared a user-supplied dict keyed by element id with a current dict keyed by the ADML display name; both forms now normalize to the canonical element id before comparison so the state is idempotent. #68489Fixed minion rejecting the master with "Invalid master key" after restart when the cached
minion_master.pubdiffers from the master's payload pub_key only in trailing whitespace.AsyncAuth.verify_masternow normalizes both sides throughclean_keybefore comparing and caches the normalized form on first contact. #68493Fixed
TypeError: 'NoneType' object is not iterableraised fromAsyncReqMessageClient._send_recvwhen a per-message timeout completes the future before the send/receive coroutine catches a transient transport exception, which aborted the minion's connect loop and prevented it from connecting to the master. #68506Fixed
docker_network.presentrecreating networks on every run against Docker 29+. Docker 29 added an emptyIPRangefield to every IPAM Config entry;docker.compare_networksnow drops empty/None placeholder values before comparing pools, and the state's default-pool short-circuit treats the empty field as absent. #68518Fixed
pkg.installedverification on x86_64 hosts that mixx86_64andx86_64_v2packages (e.g. AlmaLinux 10.1).salt.utils.pkg.rpm.resolve_nameandsalt.modules.yumpkg.normalize_namenow treatx86_64_v2as compatible withx86_64instead of appending the arch suffix, so installed packages match the names Salt records. #68540Fixed
mysql_grants.presentreporting "Failed to execute" when grantingALL PRIVILEGESon*.*against MySQL 8.4+, where the server's privilege set drifted from Salt's hard-coded list (SET_USER_IDremoved, many dynamic privileges added).grant_existsnow derives the expected privilege set from the connected server'sSHOW PRIVILEGESoutput instead of a static list. #68567Fixed
cp.get_templateraisingAttributeError: 'NoneType' object has no attribute 'get'when the Jinja template uses{% from '...' import ... with context %}. The cp module's loader-backed__opts__is now unwrapped to a plain dict before the SaltCacheLoader instantiates the file client and channel that fetch the imported template. #68572Fixed
ImportError: cannot import name 'wait' from partially initialized module 'multiprocessing.connection'raised during salt-master/minion shutdown when a reentrant SIGTERM hitProcessManager.kill_children()midProcess.join(0).salt.utils.processnow eagerly importsmultiprocessing.connectionso the module is fully initialised before any signal handler can trigger its lazy import. #68573Fixed
cmd.scripton Windows raisingInvalid user: <runas>whenrunasis a domain account (DOMAIN\user,user@DOMAIN, or a SID). The pre-executionuser.infocheck is backed byNetUserGetInfowhich only resolves local-machine accounts and returns empty for many valid domain users; the missing lookup is now logged as a warning and execution continues so the underlyingwin_runasmachinery can authenticate the account. #68578Fixed
pkg.installon Windows silently downgrading the salt-minion when a numericversion=argument was passed (e.g.version=3007.10was YAML-parsed to the float3007.1and then matched the wrong winrepo entry). When the numeric version uniquely matches a string-keyed winrepo entry it is now resolved to that entry; when it is ambiguous (e.g. both3007.1and3007.10are in the winrepo) the install is refused with a clear error pointing the user at the quoted-version syntax. #68620Fixed the loader masking failure reasons when multiple modules declare the same
__virtualname__and each__virtual__()returns False, so users now see every reason (e.g. both x509 v1's "Superseded, using x509_v2" and x509_v2's "Could not load cryptography") instead of only the first one recorded. #68625Fix
NetapiClient.runnerraisingTypeErrorwhentimeoutarrives as a string from the salt-api HTTP form. #68653Fixed
master_job_cache: redis_returnraisingKeyError: 'redis_return.prep_jid'by registering theredisreturner under bothredisandredis_returnvirtual names, matching the documented--return redis_returnusage and the module's file name. #68663Fixed
ini.options_presentwithstrict: Trueto remove sections that are present in the ini file but absent from the suppliedsectionsmapping. #68673Handle
SaltDeserializationErrorin grains cache loading so a corrupted cache file no longer propagates as CRITICAL during minion startup. #68678Fixed
network.interfaceson Windows systems falling back to WMI (i.e. .NET older than 4.7.2): the default gateway is now reported undergatewayinstead of being mistakenly emitted asbroadcast. #68692Fixed
file.managed(and other template-rendering callers) silently overwriting user-suppliedslspath,sls_path,slsdotpathandslscolonpathvalues indefaults/contextwith values regenerated from the caller'sslskey. #68754Fixed
env_ordernot being honored when merging pillar data across environments.Pillar.render_pillarnow iterates matched environments in the configuredenv_orderso that, withtop_file_merging_strategy: merge_all, the last environment inenv_orderwins on conflicting pillar keys instead of the result depending on dict insertion order. #68785Improved the "Malformed topfile" error from
HighState.verify_topsto name the saltenv and the matcher whose state declarations were not formed as a list, so users can locate the offending entry in theirtop.sls. #68792Removed orphaned GnuPG dotlock files (
.#lk<addr>.<host>.<pid>) fromgpg_keydirbefore each decrypt in thegpgrenderer so they no longer accumulate when a gpg subprocess is killed mid-operation. #68869Fix
pkg.installedidempotency on FreeBSD whenwith_origin=Truecausespkg.list_pkgsto return per-package dicts instead of version lists; extract the version list before version-string comparison so a second state run no longer falsely reports packages as changed. #68886Fix gen_signature() signing raw pub key content instead of clean_key'd content, causing master_use_pubkey_signature verification to always fail. #68930
Fixed spurious
FileLockError: lock_fn ... exists and is not a fileraised bysalt.utils.files.wait_lockandsalt.utils.files.await_lock(and therefore bystate.applyqueue locking) when another process removed the lock file between the two separateos.path.exists/os.path.isfilestats. The pre-check now uses a singleos.statcall so a transient regular-file lock no longer trips the "not a file" branch. #68931Fixed pkg.installed(update_holds=True) for APT multiarch packages by preserving arch-qualified package names through install target parsing and verification. #68932
Fix deadlock in parallel
file.managedstates when source is served by the master.Forked parallel-state children previously inherited the parent's ZeroMQ REQ socket and asyncio loop from
salt.fileclient.RemoteClient,salt.crypt.AsyncAuth/SAuth, andsalt.utils.event.SaltEvent. Multiple sibling children racing those handles deadlocked the asyncio loop with ~98% CPU and never completed. Salt now registersos.register_at_forkhandlers on those classes that drop inherited channel/socket references in any forked child; the next use rebuilds them fresh. #68940Fixed grain and pillar targeting matching minions whose data cache entry was missing.
CkMinions._check_cache_minionsnow excludes accepted minions that have no cached grains/pillar data from greedy target results, instead of silently including them as candidates. #68976Avoid AttributeError on a closed IPCClient when the connect coroutine resolves after close(). #68993
Fixed
salt.utils.network.sanitize_hoststripping colons from IPv6 addresses, which brokenetwork.pingand any other caller that passed an IPv6 host. #68995Added support for MAINTAIN (m) privilege introduced in PostgreSQL 17 to salt.modules.postgres and salt.states.postgres_privileges #69003
Fixed
redis.get_master_ipsilently dropping thepasswordargument. The function was forwarding its arguments positionally to_connect, but_connect's third positional slot isdb, notpassword, so the caller's password landed in the database-index argument and the actual password fell through toconfig.option("redis.password"). Arguments are now passed by keyword. #69029Fixed
salt.modules.redismod._connectrejecting validdb=0. The helper used a truthy check (if not db) to decide whether to fall back toconfig.option("redis.db"), butnot 0isTrue, so an explicitly supplieddb=0was silently replaced by the configured value. The check is nowif db is None, matching the pattern already used by the sibling_sconnecthelper in the same module. Other arguments keep their truthy-check semantics on purpose. #69030Fixed two distinct bugs in the
salt.engines.redis_sentinelengine that together prevented it from being usable.start()no longer raisesAttributeError: 'dict_values' object has no attribute 'pop'on Python 3 (the dict.values() result is now wrapped inlist(...)).Listenerandstart()now accept an optionalpasswordargument and forward it to the redis client, allowing the engine to authenticate against a Sentinel that requires AUTH; the default ofNonekeeps existing configurations working unchanged. #69031Fixed
salt.returners.redis_returnsilently ignoring the documentedredis.passwordconfiguration option. The returner now readsredis.passwordfrom config (in both regular and proxy modes) and forwards it to both the single-serverredis.StrictRedisand theStrictRedisClusterconstructors. Operators with auth-protected Redis no longer lose every job return to a hiddenNOAUTH Authentication requiredfailure; deployments without a password are unaffected. #69032Fixed three closely-related bugs in
salt.cache.redis_cachethat together broke hierarchical-bank semantics:_build_bank_hiernow registers each child bank name in both the parent's$BANK_set (consumed byflush()tree traversal) and the parent's$BANKEYS_set (consumed bylist_());_get_banks_to_removenow decodes the bytes returned bysmembersand skips the"."placeholder, so recursiveflush()of a parent bank actually descends into sub-banks instead of corrupting the path; andflush(bank)of a sub-bank now removes the flushed bank's own reference from its parent's index sets solist_(parent)no longer reports it as present. Together these fixes restorecache.list("minions"),salt-run manage.presentandsalt-run manage.upfor masters configured withcache: redis. #69033Fixed
salt.tokens.redisclusterbeing unable to retrieve any eauth token. The cluster client was created withdecode_responses=True, which causedredis_client.get()to returnstrand brokesalt.payload.loads(msgpack rejectsstr); it also causedredis_client.keys()to returnstrand broke[k.decode("utf8") for k in ...](strhas no.decode). Both errors were swallowed by broadexcept Exceptionhandlers, so eauth appeared to silently reject every token.decode_responses=Trueis removed; values now round-trip as bytes through msgpack as the rest of the module already expected. #69035Fixed
salt.returners.redis_returnleaking<minion>:<fun>last-jid pointer keys indefinitely. The pointer was written withpipeline.setand noex=TTL, so any (minion, fun) pair that stopped running stuck in Redis forever -- O(minions × distinct funcs) keys accumulating over the lifetime of the master. The pointer now expires on the same TTL as the rest of the returner data (keep_jobs_seconds). Operators with external scripts reading these keys directly may observe them expiring; the documentation never promised they would not. #69038Fixed
salt.returners.redis_return.get_funalways returning an empty dict. The function read return data from a<minion>:<jid>key that no other code in the module ever wrote -- a leftover from an older storage schema. It now reads from the canonicalret:<jid>hash viaHGET ret:<jid> <minion>, matching the storage layout thatreturneractually produces and the read pattern thatget_jidalready uses. #69039Fixed
salt.returners.pgjsonbwriting database errors tosys.stderrinstead of Salt's logger. Errors from_get_serv,_purge_jobsand_archive_jobsare now reported vialog.exception, so they reach the configuredlog_file/ syslog destination on a daemonized master, including a full traceback. The unusedimport sysis also dropped. #69048Fixed
salt.returners.pgjsonb.returnerletting any non-connectionpsycopg2.DatabaseErrorpropagate to the caller — including the syndic-aggregate publish path insalt/master.pywhich had no outer catch — so a single bad row could escape into a master subprocess.event_returnhad no error handling at all and a database failure during a flush propagated similarly. Both functions now catchSaltMasterErrorandpsycopg2.DatabaseErrorlocally, log a contextual message (jid/id for returns, batch size for events), and drop the affected payload. While here, fixevent_returnpassing the events list as the positionalretargument to_get_serv, which was a copy-paste leftover fromreturner(ret). #69058Fixed
salt-api's/eventsendpoint accepting eauth tokens via query string (?token=...or?salt_token=...). Tokens supplied that way end up in HTTP access logs, the browserRefererheader, log- aggregation systems and shell history; the token retains validity fortoken_expire(12h by default), so any party reading those logs can replay the token. The endpoint now rejects query-string tokens with a 400 error pointing at theX-Auth-Tokenheader (for non-browser clients) or the session cookie established by/login(for browserEventSourceclients) as the supported channels.X-Auth-Tokenheader support is added; cookie-based auth continues to work unchanged. #69071LoadAuth.get_toknow distinguishes between corrupt token blobs (removed from the store) and transient backend errors such as Redis connection drops or NFS hangs (token kept, request treated as not-authenticated). Previously a single backend hiccup could log every authenticated user out by deleting valid tokens. #69073cmd.runand friends no longer include theenvandstdinarguments in theCommandExecutionErrorraised when the underlying subprocess fails to start (typicallyENOENT/ binary not found). Both fields routinely carry credentials passed in by the caller (env={"DB_PASSWORD": "..."}, password piped viastdin), and the error message ends up in master/minion logs and in event-bus return data visible to the API caller. #69075Lowered the "Cache version mismatch clearing" log message in
salt.utils.cache.verify_cache_versionfromWARNINGtoDEBUG; the cache is rebuilt as part of normal operation after upgrades or when an ephemeral cache directory has been removed, and does not warrant user attention. #69106Relenv 0.22.14
Update sqlite to 3.53.2.0
Update openssl to 3.5.7 #69129
Surface the real cause of a proxymodule load failure in salt-proxy's abort message. The misleading "Proxymodule X is missing an init() or a shutdown() or both" wording is now only used when init/shutdown really are missing from a loaded module; if the module failed to load (for example because its
__virtual__returned False), the underlying reason is included in the error. #69139Fixed
pkg.holdandpkg.list_holdson dnf5 systems (e.g. Fedora 42+):pkg.holdnow callsdnf5 versionlock add <pkg>(the bareversionlock <pkg>form was rejected by dnf5), andpkg.list_holdsreads/etc/dnf/versionlock.tomldirectly sopkg.installedwithhold: trueis again idempotent. #69181Fixed Salt-SSH syncing internal modules as extmods #69199
Fixed
lgpo_reg.value_absentfailing when the Registry.pol entry was already absent but the registry value still existed.lgpo_reg.delete_valuewas returning early before reaching the registry cleanup code, causing the state to see no changes and report failure. The registry value is now removed regardless of whether the pol entry was present. #69203Fixed
postgres_local_cache.save_loadraisingpsycopg2.errors.UniqueViolationwhen more than one master in an active-active multi-master cluster persists the same JID; the INSERT is now idempotent viaON CONFLICT (jid) DO NOTHINGon PostgreSQL >= 9.5, and the duplicate is tolerated on older servers. #69214Fixed Windows MSI self-upgrade via
pkg.installfailing with error 1603. The old product'sDeleteConfig_DECACcustom action was unconditionally deletingROOTDIR\varduringRemoveExistingProducts, destroying the MSI thatpkg.installhad cached toROOTDIR\var\cachebefore launching the upgrade. Users who hadREMOVE_CONFIG=1persisted in the registry (from checking "On uninstall" at install time) hit a worse variant where the entireROOTDIRwas deleted. The fix checksUPGRADINGPRODUCTCODE— set by Windows Installer whenever an uninstall is triggered by a major upgrade — and skips allROOTDIRdeletion during upgrades, matching the behaviour of the NSIS installer which has always preservedROOTDIRduring upgrades. #69219Fixed
TypeError: string indices must be integersin the minion when the master returns a bare string error response (e.g."bad load","Some exception handling minion payload") for a pillar request. The minion now raises a cleanAuthenticationErrorinstead of crashing, allowing the caller to retry or fail gracefully. #69228pkg.list_patches in yumpkg.py parses tdnf output on Photon OS #69229
Fix
git.tagso that the documentedmessageargument is actually forwarded togit tag, creating an annotated tag with the supplied message instead of silently producing a lightweight tag. #69298Fixed
salt.auth.pamconversation callback so it answersPAM_PROMPT_ECHO_ONprompts with the supplied username; previously onlyPAM_PROMPT_ECHO_OFFprompts were answered, which causedpam_authenticateto silently fail (and salt-api to return 401) against PAM stacks that re-prompt for the user. #69304Ensure multiple masters have their own job/state queues #69308
Fixed loading private keys from PKCS#12 containers with x509_v2 #69312
Fixed creating self-signed PKCS#12-encoded certificates #69319
Fixed minion state queue replacing the master-assigned JID on queued state runs, so returns now come back tagged with the JID the master actually published. #69386
Made the salt user's home directory and the relenv
extras-<py-ver>directory configurable in the Linux packaging. The DEB preinst scripts now source/etc/default/salt-setup(and/etc/sysconfig/salt-minion-setupfor cross-distro parity with RPM) before applying theSALT_HOME/SALT_USER/SALT_GROUP/SALT_NAMEdefaults, mirroring the long-standing RPM behavior. A newSALT_EXTRAS_DIRoverride is honored by both stacks so the extras tree can be relocated outside/opt/saltstack/saltand its ownership is correctly restored on upgrade. #69402Fixed minion worker threads hanging or crashing when returning job results to the master. The main process now fires an error event back to the worker when
req_channel.send()times out, so workers wake up immediately rather than waiting out their full timeout. Replaced the bareTimeoutErrorraised in_send_req_syncwithSaltReqTimeoutErrorso_return_pub's existing handler catches it correctly. The worker's wait timeout is now derived fromreturn_retry_timer_max * return_retry_triesto ensure it always outlasts the main process's retry budget. #69416Fixed zsh completion by using the proper python3 instead of python2. #69419
Fixed Photon OS Arm64 FIPS CI by re-enabling the OpenSSL default provider after installing openssl-fips-provider, working around the disabled-default-provider bug in
openssl-fips-provider <= 3.1.2-3.ph5on the lagging Photon aarch64 mirror. #69449Add regression test for changelog template multi-line rendering and harden template with indent filter so continuation lines are correctly indented under the bullet (defensive backport of #69458 to 3006.x). #69454
Fixed minion not honoring SIGTERM while stuck in the master DNS retry loop, which caused systemd to escalate to SIGKILL after 90 seconds. #69466
Fixed
lgpo_regmodule and state functions failing on Windows Domain Controllers withAccess is deniedwhen writing toHKLM\SOFTWARE\Policies\subkeys. Theset_value,disable_value, anddelete_valueexecution module functions now accept awrite_registryparameter (defaultNone) that auto-detects Domain Controllers via theProductTyperegistry key and skips the direct registry write when one is detected, instead relying on the Group Policy engine to apply the policy on the next refresh. An explicitTrueorFalseoverrides auto-detection. Arefresh_policyparameter (defaultFalse) has been added to all three functions to trigger an in-processuserenv.RefreshPolicycall immediately after theRegistry.polfile is updated. The corresponding state functionsvalue_present,value_disabled, andvalue_absentexpose the same parameters. A standalonelgpo_reg.refresh_policyexecution function andlgpo_reg.refresh_policystate have been added to allow a single Group Policy refresh to be issued after a batch of policy writes.is_domain_controllerhas been added tosalt.utils.win_functionsandrefresh_policyhas been added tosalt.utils.win_lgpo_reg. #69468Fixed 3006.x Windows nightly CI by pinning the runner-host Python to 3.14.6 (OpenSSL 3.5.7); the setup-python default
3.14was resolving to a cached 3.14.5 build whose OpenSSL 3.0.20 rejected the cert pypi.org currently serves. #69486Fixed 3006.x Windows nightly CI Deps by dropping a sitecustomize hook into the salt onedir's
Lib/site-packagesthat applies the cpython#104135 iter-and-skip patch before pip touches TLS; the prior runner-host Python pin in #69486 targeted the wrong interpreter (the failing pip runs in a venv created from the relenv-bundled Python 3.10) and is reverted. #69490Fixed
lgpo_regfailures on Windows whenRegistry.polis temporarily locked by the Group Policy service or other processes. Salt now usesEnterCriticalPolicySection/LeaveCriticalPolicySectionfromuserenv.dll— the same synchronization primitive used by the GP engine — to serialize read-modify-write access toRegistry.pol. A retry loop with configurable attempts and delay is also applied for non-GP lockers such as antivirus scanners or VSS snapshots that do not participate in the GP critical section handshake. #69492
Added#
Added
shadow.verify_passwordtosalt.modules.win_shadow, which validates a Windows user's password viaLogonUserwithLOGON32_LOGON_NETWORK(Microsoft's recommended approach perKB180548 <https://support.microsoft.com/en-us/help/180548>_) without creating an interactive session. If the check causes an account lockout, the account is automatically unlocked. Updateduser.presenton Windows to useshadow.verify_passwordso the password is only changed when it differs from the current value, matching the idempotent behaviour on other platforms. #41347Added ability to configure the pillar destination for the
netboxext_pillar viadestination_pillar_key#65531Migrate Salt documentation to the PyData Sphinx theme. This update modernizes the documentation UI, improves navigation with a persistent sidebar tree, and fixes issues with embedded video playback. #69185
fix etcdv3 module authentification when using etcd3-py lib #69202
Added
lgpo_reg.get_rsop_valueto query the Resultant Set of Policy (RSoP) for a registry key/value and detect whether it is managed by a Domain Group Policy Object. Thelgpo_regmodule functionsset_value,disable_value, anddelete_valuenow log a warning when a Domain GPO is detected for the target value. Thelgpo_regstate functionsvalue_present,value_disabled, andvalue_absentappend the same warning to the state comment so it is visible in state output. #69205