(release-3008.2)=
Salt 3008.2 release notes#
Changelog#
Removed#
Removed 11 stale
.txtfiles underrequirements/static/{pkg,ci}/py*/that were missed by the.txt->.lockmigration. Three are true orphans from dropped Python 3.8 support; eight shadowed current.locksiblings which are the authoritative artifacts. #69488
Changed#
Upgrade the bundled onedir Python from 3.10.20 to 3.11.15 on the 3006.x branch. Python 3.10 reaches end of security support in October 2026, while Salt 3006.x must ship security fixes through July 2027. Users upgrading from a previous 3006.x package will need to reinstall any Salt extensions installed via
salt-pipbecause the onedirextras-3.10directory is replaced byextras-3.11. #69526
Fixed#
Fixed
salt-sshTemplateNotFoundwhen a managed Jinja template imports from another template (e.g.{% from "formula/map.jinja" import x with context %}).SaltCacheLoadernow prefersopts["_caller_cachedir"](the master's cachedir, where the master-side fileclient caches requested files) overopts["cachedir"](the thin minion's remote path) for its Jinja search path. Backport of the 3007.x/3008.x fix. #31531Fixed the
mysqlreturner ignoring the configuredmysql.userfrom salt-ssh and other contexts where__salt__lacksconfig.option.get_returner_optionsfell back to__opts__and looked up bare attribute names in it, so the master's top-leveluseropt (the system user salt runs as, typicallyroot) masked the configured database user and the returner connected as the wrong user. The mysql returner now passes a scoped view of__opts__containing onlymysql.*keys so the lookup cannot collide. #32567Fixed non-deterministic pillar rendering when multiple
pillar_rootsenvironments matched the same minion.Pillar.get_topscollected saltenvs into asetand iterated them in hash order, so top-file processing order depended onPYTHONHASHSEEDand varied persalt-callinvocation. An earlier change made_get_envsreturn an ordered list, but the caller wrapped the result back into aset.get_topsnow uses an insertion-ordered dict so iteration followspillar_rootsconfig order. #44937Documented the supported approaches for relocating Salt's runtime directories when running rootless:
SALT_HOME/SALT_EXTRAS_DIRat install time,root_dirfor relative relocation, and the per-key (pki_dir,cachedir,log_file,pidfile,sock_dir) overrides. #55971Rewrote the non-root / unprivileged user configuration page for onedir packaging, consolidating the older overlapping pages and documenting
SALT_USER/SALT_HOME/SALT_EXTRAS_DIR,root_dirrelocation, and systemd drop-ins. #59955Fixed a race in
tests/pytests/integration/cli/test_salt.py::test_interrupt_on_long_running_jobthat intermittently failed on slow CI hosts (Photon OS 5 Arm64, both tcp(fips) and zeromq(fips)). The test used a fixedtime.sleep(2)before sendingSIGINT, but on slow hosts the salt CLI had not yet published its job (pub_data["jid"]was still unset), so the signal handler emitted onlyExiting gracefully on Ctrl-cwithout a jid and theThis job's jid isassertion failed. The test now waits on the master'ssalt/job/*/newevent viaevent_listenerto guarantee the job has been published before interrupting the CLI. #60963Rewrote the FAQ entry on restarting the minion after upgrade for the onedir packaging era. Removed the broken
policy-rc.d/prereqworkaround and documented the supported patterns based onKillMode=processin the shipped systemd unit. #61078Updated the packaging docs to explain how to install modules' optional Python dependencies into an onedir install via
salt-pip. #64160Documented
salt-pipfor installing optional Python dependencies into a onedir Salt install, including the extras directory layout,SALT_EXTRAS_DIRrelocation, and non-root behavior. #64291Fixed the EC2/cloud metadata grain crashing with
KeyError: 'headers'whensalt.utils.http.queryreturns an error response (4xx/5xx with a body, e.g. when the IMDS rejects a recursive sub-path lookup). Since 3006.3 the tornado backend has populatedbodyon HTTPError without also populatingheaders; the grain now treats the missingheaderskey as "no Content-Type information" instead of letting the lookup blow up the whole grain load. #65184Updated the non-root user docs for the onedir-era directory layout (
/opt/saltstack/salt,extras-3.N, package-managedsaltuser) and explained how to switch an existing install over to a different account. #65243Expanded the packaging test guide with single-test invocations, environment variables, common failures, and CI parity notes. #65253
Fixed master-initiated jobs failing on Python 3.12+ with "There is no current event loop in thread 'Thread-N (_target)'" by installing an asyncio event loop on the SyncWrapper worker thread. #65702
Fixed
TypeError: a coroutine was expected, got None(Python 3.10) /object NoneType can't be used in 'await' expressionraised repeatedly bysalt-apiandsalt-masterfromsalt.transport.tcp.PublishClient.on_recv_handler. The salt-apiEventListener._handle_event_socket_recvcallback was a plain function returningNoneand is now anasynccoroutine, so the TCP IPC publish client can schedule it viaasyncio.create_taskwithout errors and events are no longer silently dropped. #66177Fixed master 4505 publish port becoming unresponsive under load: TCP
PubServernow broadcasts to subscribers concurrently so a single slow subscriber no longer stalls the event publisher loop, and the ZeroMQ master PUB socket now enables ZMTP heartbeats so dead subscribers are reaped within seconds instead of waiting for the kernel TCP keepalive. #66282Refreshed the "running as a non-root user" page; replaced outdated 0.9.10-era guidance and added the onedir-aware steps for changing the runtime user. #66353
Documented how to install Salt Extensions (
saltext.<name>) into an onedir install withsalt-pip, and pointed the developer extensions doc at the install instructions. #66524Fixed
salt.utils.vmwareto use the supportedtoken/tokenTypearguments instead of the deprecatedb64token/mechanismarguments when callingpyVim.connect.SmartConnect. pyvmomi 9 raises an exception when either deprecated argument is truthy, which broke salt-cloud, thevsphereexecution module, and other VMware integrations as soon as pyvmomi was upgraded. #68211Fixed
state.event(andsalt-run state.event) crashing withUnicodeDecodeErrorwhen an event payload contains raw binary bytes such as the DER-encoded certificate returned byx509.sign_remote_certificate. Undecodable bytes are now base64-encoded in the JSON output instead of aborting the runner. #68411Fixed
salt.utils.url.createsosalt://URLs built from relative paths round-trip correctly on Python 3.13+, whereurllib.parse.urlunparseno longer emits afile:///prefix for relative paths. salt-sshfile.managedsource: salt://...references now resolve as expected on newer-Python targets (e.g. Debian trixie). #68421Fix
set_localeon Debian 13/14 where systemd-localed is unavailable; fall back to /etc/default/locale update. #68425Fixed a prereq chain bug where a state at the head of a chain (e.g.
state1 -prereq-> state2 -prereq-> state3) would always run when an intermediate state in the chain always produced changes in test mode (e.g.test.succeed_with_changes,module.run), even though the tail state of the chain produced no changes. #68438Fixed descriptor leaking in salt.utils.http.query #68456
Fixed Debian
salt-minionpackage failing to upgrade from a non-onedir release. Thesalt-minion.preinstscript assigned an unusedPY_VERvariable by exec'ing/opt/saltstack/salt/bin/python3, which does not exist when upgrading from a pre-onedir Debian package (e.g.3006.0+ds-1+240.1). Underset -ethis aborted the upgrade withsubprocess returned error exit status 127. The unused assignment is removed. #68460Fixed master cluster event forwarding when a clustered master has no explicit
idconfigured.apply_master_configappends_masterto the auto-detected id, butcluster_peersand the on-the-wiredata["peers"]dict are keyed by the bare names. The shared peer pubkey path written byMasterKeysand the lookup inMasterPubServerChannel.handle_pool_publishnow strip the suffix so peers can decrypt forwarded events instead of failing withKeyError: '<host>_master'. #68462Fixed salt-master package upgrades resetting state directory ownership and the debconf
salt-master/uservalue when the master was configured to run as a non-root user. #68577Don't insert local paths before standard library paths in LazyLoader, preventing sys.path reordering when loader modules are already importable. #68755
Fixed Salt minion package upgrades when the minion is configured to run as a non-root user via
user:in/etc/salt/minionor/etc/salt/minion.d/*.conf. The Debian preinst now reads the configured user before falling back to filesystem ownership, and the rpm pre-minion scriptlet no longer relies on rpm macro directives inside its shell body to communicate the chosen user to the post-minion scriptlet. #68793Fixed a file descriptor leak in the Salt minion: when the single-master sign-in path in
Minion.eval_masterraised any exception other thanSaltClientError(for exampleOSErrorfrom the underlying transport), or whentransport: detectrejected a candidate transport because it could not authenticate, theAsyncPubChannelthat had been created was not closed, leaking its socket. Minions with unstable network connectivity could exhaust the per-process file descriptor limit. The channel is now always closed on failure via atry/finally. #68901Fix
docker_container.runningdestroying the original container on theforce=True/skip_comparisonpath by passing the temp container's dict instead of its name to_replace.docker.renamethen failed afterdocker.rmhad already removed the original, leaving the minion with the temp container stranded under its generated name._replacenow receivestemp_container_nameon both call sites, matching the non-force path. #68959Restore the
reclassext_pillar adapter (salt.pillar.reclass_adapter) that was dropped when community extensions were purged from the 3008 tree. Existingext_pillar: - reclass:master configurations work again on 3008.x without downgrading. #69018Fixed
salt.utils.cache.ContextCache.cache_contextwriting the serialized pillar context to disk with whatever mode the process umask happened to allow (typically0o644on default Linux installs) inside a0o755parent directory. Pillar context can carry credentials (passwords, vault tokens, API keys), so any local user could read them; even with the file mode tightened, the directory mode let any local userlsthe cache and learn which modules and external-pillar backends were in use. The cache file is now written throughtempfile.mkstemp(creates with0o600by default) followed by atomicos.replace, and the parentcontext/directory is created withstat.S_IRWXU(0o700). #69069Fixed
kernelpkg.upgradeon Debian 13 (trixie) and other distros that ship a kernelrelease containing characters outside[\d.-](for example6.12.86+deb13-amd64).kernelpkg_linux_apt._kernel_typenow parses such releases instead of raisingAttributeError: 'NoneType' object has no attribute 'group'. #69131Added a regression test covering the
TypeError: string indices must be integerscrash inAsyncReqChannel.crypted_transfer_decode_dictentrywhen the master returns a bare-string error payload for a pillar request. The crash itself was already fixed on master by the layeredisinstance(ret, dict)guards insalt/channel/client.py; the test pins that behavior. #69228Fix PAM authentication always returning 401 on relenv/onedir installs by preferring
sys.executableover/usr/bin/python3when launching the PAM helper subprocess. #69303Fixed auth tokens being deleted from the
localfscache driver within one masterloop_interval(default 60s) of being minted:Cache.clean_expired's fallback path now consults the cache-level_expiresenvelope instead of file mtime, andLoadAuth.mk_tokenpasses a relative duration toCache.store(expires=...)rather than an absolute epoch. #69307Fixed
salt -b(sync batch mode) failing withSaltClientError: Some exception handling minion payloadwhen the salt-master runs as a non-root user (e.g.salt). The sync CLI batch driver had been writing batch-state persistence files (.batch.p,batch_active.p) under the master'scachedirfrom the CLI process — pre-creating the JID directory with root ownership and tripping aPermissionErrorinlocal_cache.prep_jidon the master.The sync CLI driver no longer writes anything under the master's
cachediritself. Instead it ships every state transition to the master-sideBatchManagerassalt/batch/<jid>/{new,progress,complete,halted}events; the manager — already running as the master daemon's user — persists.batch.pand maintains the active-batch index on the CLI's behalf.salt-run batch.status <jid>,salt-run batch.list_active, andsalt-run batch.stop <jid>now work for sync batches in the same deployment shape (non-root master, root CLI) where the original feature was broken. Event-bus failures degrade gracefully: the batch still completes, just without visibility from the runner commands. #69418Added a new opt-in
auth_retriesminion option that caps theAsyncAuth._authenticate()outer retry loop, so a minion that keeps gettingretryresponses fromsign_in()can bail out withSaltClientErrorinstead of looping silently forever. The default is0(unlimited), which preserves the existing 3006.x LTS behavior on upgrade; operators who want the new safety cap setauth_retriesexplicitly to a positive integer. #69442Fixed 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. #69448Fixed
AESFuncs._register_resourcesto fire aminion_data_cache_eventsnotification on the master event bus when resource grains are written to the cache, mirroring the existing notification fired by_pillarfor ordinary minion grains. #69451Fixed the towncrier changelog template splitting every multi-line fragment into separate top-level bullets with a duplicate
[#NNNN]link on each. Multi-line fragments now render as a single bullet with continuation lines indented under it, and the issue link is appended exactly once. #69454Fixed
salt.utils.url.parsesosalt:///path(three-slash URLs with an empty authority) resolves the same assalt://path. Restorescp.get_file salt:///path/to/fileand similar fileclient calls that previously failed because the surplus leading slash was rejected by the master fileserver's absolute-path guard. #69472Fixed
saltutil.runner/saltutil.wheelfailing git-backed master functions (e.g.git_pillar.update) withfailed to stat '/root/.gitconfig'when the master runs as a non-root user. Dropping to the master user withchugidleftHOME/USER/LOGNAMEpointing at the invoking (root) user; these are now aligned with the runas user, and pygit2's cached global-config search path is refreshed. #69569Stopped logging a spurious
random_master is True but there is only one master specified. Ignoring.warning once per master at startup for an all-hot multi-master minion. The warning now fires only for a genuinely single-master configuration. #69571Fix OpenNebula salt-cloud documentation to clarify that VM attributes (memory, cpu, vcpu, etc.) must be specified in the profile configuration, not as command-line arguments to
salt-cloud -p. #69573Removed bundled MD5/SHA-1 references that tripped FIPS-compliance scanners against the Salt onedir. The cryptography sdist's top-level
docs/directory (which contains Java/Rust test-vector sources naming weak algorithms, e.g.VerifyRSAOAEPSHA2.java) is now pruned from the onedir duringpre-archive-cleanup, and the unused__fetch_verifyhelper in the vendoredbootstrap-salt.shnow usessha256suminstead ofmd5sum. #69575Replace deprecated
asyncio.iscoroutinefunctionwithinspect.iscoroutinefunctioninsalt/utils/event.pyandsalt/cluster/consensus/raft/scheduler.pyto avoid DeprecationWarning on Python 3.12+ (slated for removal in Python 3.16). #69580Fixed
salt-run manage.status/manage.up/manage.downreporting every targeted minion as up because synthesizedno_returnrows fromLocalClient.get_cli_event_returnswere being counted as successful returns. #69582Fixed
salt.utils.atomicfile.atomic_opento fsync the temp file before the atomic rename so a crash after the rename cannot expose a truncated or partial file. #69583Fixed RPM upgrades leaving a previously-running
salt-minionservice stopped. The%pre minionscriptlet stops the unit so the ownership-restoration chowns don't race a live minion, but the%post/%posttransscriptlets only calledsystemctl try-restart- a no-op for an inactive unit. The scriptlets now record the pre-upgrade active state and start the unit unconditionally in%posttranswhen the minion was running at the start of the upgrade transaction. #69605Restore Rocky Linux 9
unit zeromq 4CI green after the 3006.x→3007.x merge-forward pulled in 3006.x-only regression tests that don't fit the 3007.x runtime APIs. Adapt thetest_verify_master_*,test_authenticate_*_69442,test_maintenance_duration,test_minion_manager_stop_unblocks_resolve_dns_69466, andtest_event_unpack_with_SaltDeserializationErrortests to the 3007.xcrypt.write_keys()/MasterKeys.gen_signature/io_loop.create_task/LoadAuthinit / debug-log-on-skip contracts; skip thetest_gen_signature_signs_clean_keyvariants because the 3007.x cache-refactoredMasterKeys.gen_signaturesignspub.public_bytes()and cannot exhibit the #68930 whitespace-drift bug. #69624
Added#
Added
tools/audit_doc_links.pyand a weeklydoc-linkcheckworkflow that wrap Sphinx linkcheck, strip the catch-all ignore, and emit a CSV report so external URL regressions in the docs can be tracked without gating PR CI. #60720added conditional X functionality to linux_acl #62852
Added
unmaskparameter topillar.ls,pillar.raw,pillar.ext,pillar.keys, andpillar.obfuscatefor API consistency withpillar.get/pillar.items/pillar.item/pillar.data. Default masking behavior is unchanged. #69453Documented the
gitcliGitFS provider (added in 3008.0) which shells out to the systemgitbinary, auto-detected afterpygit2andgitpythonand used as a silent fallback when neither Python library is installed. Documented thecluster_isolated_filesystemmaster option (added in 3008.0) which lets master clusters run without a shared filesystem; keys, denied keys,file_rootsandpillar_rootsare sync'd in-band over the cluster transport, withkeys.cache_driver: mmap_keyas the recommended companion. #69494