update to 3007.9 and merge some patches to fix python 3.13 support

https://github.com/saltstack/salt/issues/66568

https://github.com/saltstack/salt/pull/68277

https://github.com/saltstack/salt/issues/66898

also switch to hashlib from crypto which has been removed
This commit is contained in:
robert
2025-11-30 19:48:38 +00:00
parent 6443e3e402
commit a8f622e1c0
8 changed files with 195 additions and 4 deletions
+1 -2
View File
@@ -15,9 +15,8 @@
COMMENT = remote execution and configuration management system
MODPY_DISTV = 3007.8
MODPY_DISTV = 3007.9
DISTNAME = salt-${MODPY_DISTV}
REVISION = 0
CATEGORIES = sysutils net devel
+2 -2
View File
@@ -1,2 +1,2 @@
SHA256 (salt-3007.8.tar.gz) = WfK1pIf9gyOeMaeNsAgrElCDOTEx2uENO5Cjs0h2meI=
SIZE (salt-3007.8.tar.gz) = 19520648
SHA256 (salt-3007.9.tar.gz) = H3cNa5ylVo+SbZjt/NJtznHAT2CUJD25EoV5U+PUpW0=
SIZE (salt-3007.9.tar.gz) = 19549730
@@ -0,0 +1,15 @@
Index: salt/__init__.py
--- salt/__init__.py.orig
+++ salt/__init__.py
@@ -110,6 +110,11 @@ warnings.filterwarnings(
category=DeprecationWarning,
)
+warnings.filterwarnings(
+ "ignore",
+ "datetime.datetime.utcnow().*",
+ category=DeprecationWarning,
+)
def __define_global_system_encoding_variable__():
import builtins
@@ -0,0 +1,15 @@
https://github.com/saltstack/salt/issues/66568
https://github.com/saltstack/salt/pull/68277
Index: salt/channel/client.py
--- salt/channel/client.py.orig
+++ salt/channel/client.py
@@ -556,7 +556,8 @@ class AsyncPubChannel:
# may have been restarted
yield self.send_id(self.token, self._reconnected)
self.connected = True
- self.event.fire_event({"master": self.opts["master"]}, "__master_connected")
+ if self.event:
+ self.event.fire_event({"master": self.opts["master"]}, "__master_connected")
if self._reconnected:
# On reconnects, fire a master event to notify that the minion is
# available.
@@ -0,0 +1,60 @@
https://github.com/saltstack/salt/issues/66568
https://github.com/saltstack/salt/pull/68277
Index: salt/transport/tcp.py
--- salt/transport/tcp.py.orig
+++ salt/transport/tcp.py
@@ -235,7 +235,6 @@ class PublishClient(salt.transport.base.PublishClient)
self.connected = False
self._closing = False
self._stream = None
- self._closing = False
self._closed = False
self.backoff = opts.get("tcp_reconnect_backoff", 1)
self.resolver = kwargs.get("resolver")
@@ -1769,6 +1768,7 @@ class RequestClient(salt.transport.base.RequestClient)
self._closed = False
self._stream_return_running = False
self._stream = None
+ self.task = None
self.disconnect_callback = _null_callback
self.connect_callback = _null_callback
self.backoff = opts.get("tcp_reconnect_backoff", 1)
@@ -1837,7 +1837,7 @@ class RequestClient(salt.transport.base.RequestClient)
message_id,
)
except tornado.iostream.StreamClosedError as e:
- log.error(
+ log.debug(
"tcp stream to %s:%s closed, unable to recv",
self.host,
self.port,
@@ -1879,6 +1879,8 @@ class RequestClient(salt.transport.base.RequestClient)
stream.close()
unpacker = salt.utils.msgpack.Unpacker()
await self.connect()
+ except asyncio.CancelledError:
+ log.debug("Stream return cancelled")
self._stream_return_running = False
def _message_id(self):
@@ -1927,9 +1929,20 @@ class RequestClient(salt.transport.base.RequestClient)
def close(self):
if self._closing:
return
+ self._closing = True
if self._stream is not None:
self._stream.close()
self._stream = None
+ if self.task is not None:
+ self.task.cancel()
+ # Wait for the task to finish via asyncio
+ group = asyncio.gather(self.task)
+ try:
+ self.task.get_loop().run_until_complete(group)
+ except RuntimeError:
+ # Ignore event loop was already running message
+ pass
+ self.task = None
def __enter__(self):
return self
@@ -0,0 +1,73 @@
crypt has been deprecated since version 3.11, removed in version 3.13
PEP 594
Index: salt/utils/pycrypto.py
--- salt/utils/pycrypto.py.orig
+++ salt/utils/pycrypto.py
@@ -24,11 +24,11 @@ except ImportError:
HAS_RANDOM = False
try:
- import crypt
+ import hashlib
- HAS_CRYPT = True
+ HAS_HASHLIB = True
except (ImportError, PermissionError):
- HAS_CRYPT = False
+ HAS_HASHLIB = False
try:
import passlib.context
@@ -101,8 +101,8 @@ def secure_password(
raise CommandExecutionError(str(exc))
-if HAS_CRYPT:
- methods = {m.name.lower(): m for m in crypt.methods}
+if HAS_HASHLIB:
+ methods = {m.lower(): m for m in hashlib.algorithms_guaranteed}
else:
methods = {}
known_methods = ["sha512", "sha256", "blowfish", "md5", "crypt"]
@@ -130,9 +130,9 @@ def _gen_hash_passlib(crypt_salt=None, password=None,
return ctx.hash(**kwargs)
-def _gen_hash_crypt(crypt_salt=None, password=None, algorithm=None):
+def _gen_hash_hashlib(crypt_salt=None, password=None, algorithm=None):
"""
- Generate /etc/shadow hash using the native crypt module
+ Generate /etc/shadow hash using the native hashlib module
"""
if crypt_salt is None:
# setting crypt_salt to the algorithm makes crypt generate
@@ -144,7 +144,9 @@ def _gen_hash_crypt(crypt_salt=None, password=None, al
crypt_salt = f"${methods[algorithm].ident}${crypt_salt}"
try:
- ret = crypt.crypt(password, crypt_salt)
+ h = hashlib.new(crypt_salt)
+ h.update(password.encode("utf-8"))
+ ret = h.hexdigest()
except OSError:
ret = None
return ret
@@ -159,13 +161,13 @@ def gen_hash(crypt_salt=None, password=None, algorithm
if algorithm is None:
# prefer the most secure natively supported method
- algorithm = crypt.methods[0].name.lower() if HAS_CRYPT else known_methods[0]
+ algorithm = crypt.methods[0].name.lower() if HAS_HASHLIB else known_methods[0]
if algorithm == "crypt" and crypt_salt and len(crypt_salt) != 2:
log.warning("Hash salt is too long for 'crypt' hash.")
- if HAS_CRYPT and algorithm in methods:
- return _gen_hash_crypt(
+ if HAS_HASHLIB and algorithm in methods:
+ return _gen_hash_hashlib(
crypt_salt=crypt_salt, password=password, algorithm=algorithm
)
elif HAS_PASSLIB and algorithm in known_methods:
@@ -0,0 +1,26 @@
https://github.com/saltstack/salt/issues/66898
Index: salt/utils/url.py
--- salt/utils/url.py.orig
+++ salt/utils/url.py
@@ -4,8 +4,9 @@ URL utils
import re
import sys
-from urllib.parse import urlparse, urlunparse
+from urllib.parse import urlparse, urlunparse, urlunsplit
+# Import salt libs
import salt.utils.data
import salt.utils.path
import salt.utils.platform
@@ -46,8 +47,7 @@ def create(path, saltenv=None):
path = salt.utils.data.decode(path)
query = f"saltenv={saltenv}" if saltenv else ""
- url = salt.utils.data.decode(urlunparse(("file", "", path, "", query, "")))
- return "salt://{}".format(url[len("file:///") :])
+ return f"salt://{salt.utils.data.decode(urlunsplit(("", "", path, query, "")))}"
def is_escaped(url):
+3
View File
@@ -4588,6 +4588,8 @@ lib/python${MODPY_VERSION}/site-packages/salt/utils/${MODPY_PYCACHE}ctx.${MODPY_
lib/python${MODPY_VERSION}/site-packages/salt/utils/${MODPY_PYCACHE}ctx.${MODPY_PYC_MAGIC_TAG}pyc
lib/python${MODPY_VERSION}/site-packages/salt/utils/${MODPY_PYCACHE}data.${MODPY_PYC_MAGIC_TAG}${MODPY_PYOEXTENSION}
lib/python${MODPY_VERSION}/site-packages/salt/utils/${MODPY_PYCACHE}data.${MODPY_PYC_MAGIC_TAG}pyc
lib/python${MODPY_VERSION}/site-packages/salt/utils/${MODPY_PYCACHE}datastructures.${MODPY_PYC_MAGIC_TAG}${MODPY_PYOEXTENSION}
lib/python${MODPY_VERSION}/site-packages/salt/utils/${MODPY_PYCACHE}datastructures.${MODPY_PYC_MAGIC_TAG}pyc
lib/python${MODPY_VERSION}/site-packages/salt/utils/${MODPY_PYCACHE}dateutils.${MODPY_PYC_MAGIC_TAG}${MODPY_PYOEXTENSION}
lib/python${MODPY_VERSION}/site-packages/salt/utils/${MODPY_PYCACHE}dateutils.${MODPY_PYC_MAGIC_TAG}pyc
lib/python${MODPY_VERSION}/site-packages/salt/utils/${MODPY_PYCACHE}debug.${MODPY_PYC_MAGIC_TAG}${MODPY_PYOEXTENSION}
@@ -4885,6 +4887,7 @@ lib/python${MODPY_VERSION}/site-packages/salt/utils/context.py
lib/python${MODPY_VERSION}/site-packages/salt/utils/crypt.py
lib/python${MODPY_VERSION}/site-packages/salt/utils/ctx.py
lib/python${MODPY_VERSION}/site-packages/salt/utils/data.py
lib/python${MODPY_VERSION}/site-packages/salt/utils/datastructures.py
lib/python${MODPY_VERSION}/site-packages/salt/utils/dateutils.py
lib/python${MODPY_VERSION}/site-packages/salt/utils/debug.py
lib/python${MODPY_VERSION}/site-packages/salt/utils/decorators/