- bundled cryptography: replace with dependency to fix CVE-2026-26007
- bundled PyJWT: upgrade to v2.12.1 to fix CVE-2026-32597 Resolves: RHEL-148437, RHEL-155677
This commit is contained in:
parent
aac981a316
commit
242f3d9748
@ -1,68 +0,0 @@
|
||||
--- a/aws/urllib3/response.py 2023-10-17 19:42:56.000000000 +0200
|
||||
+++ b/aws/urllib3/response.py 2026-01-02 11:19:25.583808492 +0100
|
||||
@@ -135,8 +135,18 @@
|
||||
they were applied.
|
||||
"""
|
||||
|
||||
+ # Maximum allowed number of chained HTTP encodings in the
|
||||
+ # Content-Encoding header.
|
||||
+ max_decode_links = 5
|
||||
+
|
||||
def __init__(self, modes):
|
||||
- self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")]
|
||||
+ encodings = [m.strip() for m in modes.split(",")]
|
||||
+ if len(encodings) > self.max_decode_links:
|
||||
+ raise DecodeError(
|
||||
+ "Too many content encodings in the chain: "
|
||||
+ f"{len(encodings)} > {self.max_decode_links}"
|
||||
+ )
|
||||
+ self._decoders = [_get_decoder(e) for e in encodings]
|
||||
|
||||
def flush(self):
|
||||
return self._decoders[0].flush()
|
||||
|
||||
--- a/azure/urllib3/response.py 2023-10-17 19:42:56.000000000 +0200
|
||||
+++ b/azure/urllib3/response.py 2026-01-02 11:19:25.583808492 +0100
|
||||
@@ -135,8 +135,18 @@
|
||||
they were applied.
|
||||
"""
|
||||
|
||||
+ # Maximum allowed number of chained HTTP encodings in the
|
||||
+ # Content-Encoding header.
|
||||
+ max_decode_links = 5
|
||||
+
|
||||
def __init__(self, modes):
|
||||
- self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")]
|
||||
+ encodings = [m.strip() for m in modes.split(",")]
|
||||
+ if len(encodings) > self.max_decode_links:
|
||||
+ raise DecodeError(
|
||||
+ "Too many content encodings in the chain: "
|
||||
+ f"{len(encodings)} > {self.max_decode_links}"
|
||||
+ )
|
||||
+ self._decoders = [_get_decoder(e) for e in encodings]
|
||||
|
||||
def flush(self):
|
||||
return self._decoders[0].flush()
|
||||
|
||||
--- a/google/urllib3/response.py 2023-10-17 19:42:56.000000000 +0200
|
||||
+++ b/google/urllib3/response.py 2026-01-02 11:19:25.583808492 +0100
|
||||
@@ -135,8 +135,18 @@
|
||||
they were applied.
|
||||
"""
|
||||
|
||||
+ # Maximum allowed number of chained HTTP encodings in the
|
||||
+ # Content-Encoding header.
|
||||
+ max_decode_links = 5
|
||||
+
|
||||
def __init__(self, modes):
|
||||
- self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")]
|
||||
+ encodings = [m.strip() for m in modes.split(",")]
|
||||
+ if len(encodings) > self.max_decode_links:
|
||||
+ raise DecodeError(
|
||||
+ "Too many content encodings in the chain: "
|
||||
+ f"{len(encodings)} > {self.max_decode_links}"
|
||||
+ )
|
||||
+ self._decoders = [_get_decoder(e) for e in encodings]
|
||||
|
||||
def flush(self):
|
||||
return self._decoders[0].flush()
|
||||
@ -1,845 +0,0 @@
|
||||
--- a/aws/urllib3/response.py 2026-01-20 10:46:57.006470161 +0100
|
||||
+++ b/aws/urllib3/response.py 2026-01-20 10:55:44.090084896 +0100
|
||||
@@ -23,6 +23,7 @@
|
||||
from .exceptions import (
|
||||
BodyNotHttplibCompatible,
|
||||
DecodeError,
|
||||
+ DependencyWarning,
|
||||
HTTPError,
|
||||
IncompleteRead,
|
||||
InvalidChunkLength,
|
||||
@@ -41,34 +42,60 @@
|
||||
class DeflateDecoder(object):
|
||||
def __init__(self):
|
||||
self._first_try = True
|
||||
- self._data = b""
|
||||
+ self._first_try_data = b""
|
||||
+ self._unfed_data = b""
|
||||
self._obj = zlib.decompressobj()
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._obj, name)
|
||||
|
||||
- def decompress(self, data):
|
||||
- if not data:
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ data = self._unfed_data + data
|
||||
+ self._unfed_data = b""
|
||||
+ if not data and not self._obj.unconsumed_tail:
|
||||
return data
|
||||
+ original_max_length = max_length
|
||||
+ if original_max_length < 0:
|
||||
+ max_length = 0
|
||||
+ elif original_max_length == 0:
|
||||
+ # We should not pass 0 to the zlib decompressor because 0 is
|
||||
+ # the default value that will make zlib decompress without a
|
||||
+ # length limit.
|
||||
+ # Data should be stored for subsequent calls.
|
||||
+ self._unfed_data = data
|
||||
+ return b""
|
||||
|
||||
+ # Subsequent calls always reuse `self._obj`. zlib requires
|
||||
+ # passing the unconsumed tail if decompression is to continue.
|
||||
if not self._first_try:
|
||||
- return self._obj.decompress(data)
|
||||
+ return self._obj.decompress(
|
||||
+ self._obj.unconsumed_tail + data, max_length=max_length
|
||||
+ )
|
||||
|
||||
- self._data += data
|
||||
+ # First call tries with RFC 1950 ZLIB format.
|
||||
+ self._first_try_data += data
|
||||
try:
|
||||
- decompressed = self._obj.decompress(data)
|
||||
+ decompressed = self._obj.decompress(data, max_length=max_length)
|
||||
if decompressed:
|
||||
self._first_try = False
|
||||
- self._data = None
|
||||
+ self._first_try_data = b""
|
||||
return decompressed
|
||||
+ # On failure, it falls back to RFC 1951 DEFLATE format.
|
||||
except zlib.error:
|
||||
self._first_try = False
|
||||
self._obj = zlib.decompressobj(-zlib.MAX_WBITS)
|
||||
try:
|
||||
- return self.decompress(self._data)
|
||||
+ return self.decompress(
|
||||
+ self._first_try_data, max_length=original_max_length
|
||||
+ )
|
||||
finally:
|
||||
- self._data = None
|
||||
+ self._first_try_data = b""
|
||||
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return bool(self._unfed_data) or (
|
||||
+ bool(self._obj.unconsumed_tail) and not self._first_try
|
||||
+ )
|
||||
|
||||
class GzipDecoderState(object):
|
||||
|
||||
@@ -81,30 +108,64 @@
|
||||
def __init__(self):
|
||||
self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
self._state = GzipDecoderState.FIRST_MEMBER
|
||||
+ self._unconsumed_tail = b""
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._obj, name)
|
||||
|
||||
- def decompress(self, data):
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
ret = bytearray()
|
||||
- if self._state == GzipDecoderState.SWALLOW_DATA or not data:
|
||||
+ if self._state == GzipDecoderState.SWALLOW_DATA:
|
||||
+ return bytes(ret)
|
||||
+
|
||||
+ if max_length == 0:
|
||||
+ # We should not pass 0 to the zlib decompressor because 0 is
|
||||
+ # the default value that will make zlib decompress without a
|
||||
+ # length limit.
|
||||
+ # Data should be stored for subsequent calls.
|
||||
+ self._unconsumed_tail += data
|
||||
+ return b""
|
||||
+
|
||||
+ # zlib requires passing the unconsumed tail to the subsequent
|
||||
+ # call if decompression is to continue.
|
||||
+ data = self._unconsumed_tail + data
|
||||
+ if not data and self._obj.eof:
|
||||
return bytes(ret)
|
||||
+
|
||||
while True:
|
||||
try:
|
||||
- ret += self._obj.decompress(data)
|
||||
+ ret += self._obj.decompress(
|
||||
+ data, max_length=max(max_length - len(ret), 0)
|
||||
+ )
|
||||
except zlib.error:
|
||||
previous_state = self._state
|
||||
# Ignore data after the first error
|
||||
self._state = GzipDecoderState.SWALLOW_DATA
|
||||
+ self._unconsumed_tail = b""
|
||||
if previous_state == GzipDecoderState.OTHER_MEMBERS:
|
||||
# Allow trailing garbage acceptable in other gzip clients
|
||||
return bytes(ret)
|
||||
raise
|
||||
- data = self._obj.unused_data
|
||||
+
|
||||
+ self._unconsumed_tail = data = (
|
||||
+ self._obj.unconsumed_tail or self._obj.unused_data
|
||||
+ )
|
||||
+ if max_length > 0 and len(ret) >= max_length:
|
||||
+ break
|
||||
+
|
||||
if not data:
|
||||
return bytes(ret)
|
||||
- self._state = GzipDecoderState.OTHER_MEMBERS
|
||||
- self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
+ # When the end of a gzip member is reached, a new decompressor
|
||||
+ # must be created for unused (possibly future) data.
|
||||
+ if self._obj.eof:
|
||||
+ self._state = GzipDecoderState.OTHER_MEMBERS
|
||||
+ self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
+
|
||||
+ return bytes(ret)
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return bool(self._unconsumed_tail)
|
||||
|
||||
|
||||
if brotli is not None:
|
||||
@@ -116,9 +177,35 @@
|
||||
def __init__(self):
|
||||
self._obj = brotli.Decompressor()
|
||||
if hasattr(self._obj, "decompress"):
|
||||
- self.decompress = self._obj.decompress
|
||||
+ setattr(self, "_decompress", self._obj.decompress)
|
||||
else:
|
||||
- self.decompress = self._obj.process
|
||||
+ setattr(self, "_decompress", self._obj.process)
|
||||
+
|
||||
+ # Requires Brotli >= 1.2.0 for `output_buffer_limit`.
|
||||
+ def _decompress(self, data: bytes, output_buffer_limit: int = -1) -> bytes:
|
||||
+ raise NotImplementedError()
|
||||
+
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ try:
|
||||
+ if max_length > 0:
|
||||
+ return self._decompress(data, output_buffer_limit=max_length)
|
||||
+ else:
|
||||
+ return self._decompress(data)
|
||||
+ except TypeError:
|
||||
+ # Fallback for Brotli/brotlicffi/brotlipy versions without
|
||||
+ # the `output_buffer_limit` parameter.
|
||||
+ warnings.warn(
|
||||
+ "Brotli >= 1.2.0 is required to prevent decompression bombs.",
|
||||
+ DependencyWarning,
|
||||
+ )
|
||||
+ return self._decompress(data)
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ try:
|
||||
+ return not self._obj.can_accept_more_data()
|
||||
+ except AttributeError:
|
||||
+ return False
|
||||
|
||||
def flush(self):
|
||||
if hasattr(self._obj, "flush"):
|
||||
@@ -151,10 +238,35 @@
|
||||
def flush(self):
|
||||
return self._decoders[0].flush()
|
||||
|
||||
- def decompress(self, data):
|
||||
- for d in reversed(self._decoders):
|
||||
- data = d.decompress(data)
|
||||
- return data
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ if max_length <= 0:
|
||||
+ for d in reversed(self._decoders):
|
||||
+ data = d.decompress(data)
|
||||
+ return data
|
||||
+
|
||||
+ ret = bytearray()
|
||||
+ # Every while loop iteration goes through all decoders once.
|
||||
+ # It exits when enough data is read or no more data can be read.
|
||||
+ # It is possible that the while loop iteration does not produce
|
||||
+ # any data because we retrieve up to `max_length` from every
|
||||
+ # decoder, and the amount of bytes may be insufficient for the
|
||||
+ # next decoder to produce enough/any output.
|
||||
+ while True:
|
||||
+ any_data = False
|
||||
+ for d in reversed(self._decoders):
|
||||
+ data = d.decompress(data, max_length=max_length - len(ret))
|
||||
+ if data:
|
||||
+ any_data = True
|
||||
+ # We should not break when no data is returned because
|
||||
+ # next decoders may produce data even with empty input.
|
||||
+ ret += data
|
||||
+ if not any_data or len(ret) >= max_length:
|
||||
+ return bytes(ret)
|
||||
+ data = b""
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return any(d.has_unconsumed_tail for d in self._decoders)
|
||||
|
||||
|
||||
def _get_decoder(mode):
|
||||
@@ -405,16 +517,25 @@
|
||||
if brotli is not None:
|
||||
DECODER_ERROR_CLASSES += (brotli.error,)
|
||||
|
||||
- def _decode(self, data, decode_content, flush_decoder):
|
||||
+ def _decode(
|
||||
+ self,
|
||||
+ data: bytes,
|
||||
+ decode_content: bool,
|
||||
+ flush_decoder: bool,
|
||||
+ max_length: int = None,
|
||||
+ ) -> bytes:
|
||||
"""
|
||||
Decode the data passed in and potentially flush the decoder.
|
||||
"""
|
||||
if not decode_content:
|
||||
return data
|
||||
|
||||
+ if max_length is None or flush_decoder:
|
||||
+ max_length = -1
|
||||
+
|
||||
try:
|
||||
if self._decoder:
|
||||
- data = self._decoder.decompress(data)
|
||||
+ data = self._decoder.decompress(data, max_length=max_length)
|
||||
except self.DECODER_ERROR_CLASSES as e:
|
||||
content_encoding = self.headers.get("content-encoding", "").lower()
|
||||
raise DecodeError(
|
||||
@@ -634,7 +755,10 @@
|
||||
for line in self.read_chunked(amt, decode_content=decode_content):
|
||||
yield line
|
||||
else:
|
||||
- while not is_fp_closed(self._fp):
|
||||
+ while (
|
||||
+ not is_fp_closed(self._fp)
|
||||
+ or (self._decoder and self._decoder.has_unconsumed_tail)
|
||||
+ ):
|
||||
data = self.read(amt=amt, decode_content=decode_content)
|
||||
|
||||
if data:
|
||||
@@ -840,7 +964,10 @@
|
||||
break
|
||||
chunk = self._handle_chunk(amt)
|
||||
decoded = self._decode(
|
||||
- chunk, decode_content=decode_content, flush_decoder=False
|
||||
+ chunk,
|
||||
+ decode_content=decode_content,
|
||||
+ flush_decoder=False,
|
||||
+ max_length=amt,
|
||||
)
|
||||
if decoded:
|
||||
yield decoded
|
||||
|
||||
--- a/azure/urllib3/response.py 2026-01-20 10:46:57.006470161 +0100
|
||||
+++ b/azure/urllib3/response.py 2026-01-20 10:55:44.090084896 +0100
|
||||
@@ -23,6 +23,7 @@
|
||||
from .exceptions import (
|
||||
BodyNotHttplibCompatible,
|
||||
DecodeError,
|
||||
+ DependencyWarning,
|
||||
HTTPError,
|
||||
IncompleteRead,
|
||||
InvalidChunkLength,
|
||||
@@ -41,34 +42,60 @@
|
||||
class DeflateDecoder(object):
|
||||
def __init__(self):
|
||||
self._first_try = True
|
||||
- self._data = b""
|
||||
+ self._first_try_data = b""
|
||||
+ self._unfed_data = b""
|
||||
self._obj = zlib.decompressobj()
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._obj, name)
|
||||
|
||||
- def decompress(self, data):
|
||||
- if not data:
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ data = self._unfed_data + data
|
||||
+ self._unfed_data = b""
|
||||
+ if not data and not self._obj.unconsumed_tail:
|
||||
return data
|
||||
+ original_max_length = max_length
|
||||
+ if original_max_length < 0:
|
||||
+ max_length = 0
|
||||
+ elif original_max_length == 0:
|
||||
+ # We should not pass 0 to the zlib decompressor because 0 is
|
||||
+ # the default value that will make zlib decompress without a
|
||||
+ # length limit.
|
||||
+ # Data should be stored for subsequent calls.
|
||||
+ self._unfed_data = data
|
||||
+ return b""
|
||||
|
||||
+ # Subsequent calls always reuse `self._obj`. zlib requires
|
||||
+ # passing the unconsumed tail if decompression is to continue.
|
||||
if not self._first_try:
|
||||
- return self._obj.decompress(data)
|
||||
+ return self._obj.decompress(
|
||||
+ self._obj.unconsumed_tail + data, max_length=max_length
|
||||
+ )
|
||||
|
||||
- self._data += data
|
||||
+ # First call tries with RFC 1950 ZLIB format.
|
||||
+ self._first_try_data += data
|
||||
try:
|
||||
- decompressed = self._obj.decompress(data)
|
||||
+ decompressed = self._obj.decompress(data, max_length=max_length)
|
||||
if decompressed:
|
||||
self._first_try = False
|
||||
- self._data = None
|
||||
+ self._first_try_data = b""
|
||||
return decompressed
|
||||
+ # On failure, it falls back to RFC 1951 DEFLATE format.
|
||||
except zlib.error:
|
||||
self._first_try = False
|
||||
self._obj = zlib.decompressobj(-zlib.MAX_WBITS)
|
||||
try:
|
||||
- return self.decompress(self._data)
|
||||
+ return self.decompress(
|
||||
+ self._first_try_data, max_length=original_max_length
|
||||
+ )
|
||||
finally:
|
||||
- self._data = None
|
||||
+ self._first_try_data = b""
|
||||
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return bool(self._unfed_data) or (
|
||||
+ bool(self._obj.unconsumed_tail) and not self._first_try
|
||||
+ )
|
||||
|
||||
class GzipDecoderState(object):
|
||||
|
||||
@@ -81,30 +108,64 @@
|
||||
def __init__(self):
|
||||
self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
self._state = GzipDecoderState.FIRST_MEMBER
|
||||
+ self._unconsumed_tail = b""
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._obj, name)
|
||||
|
||||
- def decompress(self, data):
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
ret = bytearray()
|
||||
- if self._state == GzipDecoderState.SWALLOW_DATA or not data:
|
||||
+ if self._state == GzipDecoderState.SWALLOW_DATA:
|
||||
+ return bytes(ret)
|
||||
+
|
||||
+ if max_length == 0:
|
||||
+ # We should not pass 0 to the zlib decompressor because 0 is
|
||||
+ # the default value that will make zlib decompress without a
|
||||
+ # length limit.
|
||||
+ # Data should be stored for subsequent calls.
|
||||
+ self._unconsumed_tail += data
|
||||
+ return b""
|
||||
+
|
||||
+ # zlib requires passing the unconsumed tail to the subsequent
|
||||
+ # call if decompression is to continue.
|
||||
+ data = self._unconsumed_tail + data
|
||||
+ if not data and self._obj.eof:
|
||||
return bytes(ret)
|
||||
+
|
||||
while True:
|
||||
try:
|
||||
- ret += self._obj.decompress(data)
|
||||
+ ret += self._obj.decompress(
|
||||
+ data, max_length=max(max_length - len(ret), 0)
|
||||
+ )
|
||||
except zlib.error:
|
||||
previous_state = self._state
|
||||
# Ignore data after the first error
|
||||
self._state = GzipDecoderState.SWALLOW_DATA
|
||||
+ self._unconsumed_tail = b""
|
||||
if previous_state == GzipDecoderState.OTHER_MEMBERS:
|
||||
# Allow trailing garbage acceptable in other gzip clients
|
||||
return bytes(ret)
|
||||
raise
|
||||
- data = self._obj.unused_data
|
||||
+
|
||||
+ self._unconsumed_tail = data = (
|
||||
+ self._obj.unconsumed_tail or self._obj.unused_data
|
||||
+ )
|
||||
+ if max_length > 0 and len(ret) >= max_length:
|
||||
+ break
|
||||
+
|
||||
if not data:
|
||||
return bytes(ret)
|
||||
- self._state = GzipDecoderState.OTHER_MEMBERS
|
||||
- self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
+ # When the end of a gzip member is reached, a new decompressor
|
||||
+ # must be created for unused (possibly future) data.
|
||||
+ if self._obj.eof:
|
||||
+ self._state = GzipDecoderState.OTHER_MEMBERS
|
||||
+ self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
+
|
||||
+ return bytes(ret)
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return bool(self._unconsumed_tail)
|
||||
|
||||
|
||||
if brotli is not None:
|
||||
@@ -116,9 +177,35 @@
|
||||
def __init__(self):
|
||||
self._obj = brotli.Decompressor()
|
||||
if hasattr(self._obj, "decompress"):
|
||||
- self.decompress = self._obj.decompress
|
||||
+ setattr(self, "_decompress", self._obj.decompress)
|
||||
else:
|
||||
- self.decompress = self._obj.process
|
||||
+ setattr(self, "_decompress", self._obj.process)
|
||||
+
|
||||
+ # Requires Brotli >= 1.2.0 for `output_buffer_limit`.
|
||||
+ def _decompress(self, data: bytes, output_buffer_limit: int = -1) -> bytes:
|
||||
+ raise NotImplementedError()
|
||||
+
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ try:
|
||||
+ if max_length > 0:
|
||||
+ return self._decompress(data, output_buffer_limit=max_length)
|
||||
+ else:
|
||||
+ return self._decompress(data)
|
||||
+ except TypeError:
|
||||
+ # Fallback for Brotli/brotlicffi/brotlipy versions without
|
||||
+ # the `output_buffer_limit` parameter.
|
||||
+ warnings.warn(
|
||||
+ "Brotli >= 1.2.0 is required to prevent decompression bombs.",
|
||||
+ DependencyWarning,
|
||||
+ )
|
||||
+ return self._decompress(data)
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ try:
|
||||
+ return not self._obj.can_accept_more_data()
|
||||
+ except AttributeError:
|
||||
+ return False
|
||||
|
||||
def flush(self):
|
||||
if hasattr(self._obj, "flush"):
|
||||
@@ -151,10 +238,35 @@
|
||||
def flush(self):
|
||||
return self._decoders[0].flush()
|
||||
|
||||
- def decompress(self, data):
|
||||
- for d in reversed(self._decoders):
|
||||
- data = d.decompress(data)
|
||||
- return data
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ if max_length <= 0:
|
||||
+ for d in reversed(self._decoders):
|
||||
+ data = d.decompress(data)
|
||||
+ return data
|
||||
+
|
||||
+ ret = bytearray()
|
||||
+ # Every while loop iteration goes through all decoders once.
|
||||
+ # It exits when enough data is read or no more data can be read.
|
||||
+ # It is possible that the while loop iteration does not produce
|
||||
+ # any data because we retrieve up to `max_length` from every
|
||||
+ # decoder, and the amount of bytes may be insufficient for the
|
||||
+ # next decoder to produce enough/any output.
|
||||
+ while True:
|
||||
+ any_data = False
|
||||
+ for d in reversed(self._decoders):
|
||||
+ data = d.decompress(data, max_length=max_length - len(ret))
|
||||
+ if data:
|
||||
+ any_data = True
|
||||
+ # We should not break when no data is returned because
|
||||
+ # next decoders may produce data even with empty input.
|
||||
+ ret += data
|
||||
+ if not any_data or len(ret) >= max_length:
|
||||
+ return bytes(ret)
|
||||
+ data = b""
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return any(d.has_unconsumed_tail for d in self._decoders)
|
||||
|
||||
|
||||
def _get_decoder(mode):
|
||||
@@ -405,16 +517,25 @@
|
||||
if brotli is not None:
|
||||
DECODER_ERROR_CLASSES += (brotli.error,)
|
||||
|
||||
- def _decode(self, data, decode_content, flush_decoder):
|
||||
+ def _decode(
|
||||
+ self,
|
||||
+ data: bytes,
|
||||
+ decode_content: bool,
|
||||
+ flush_decoder: bool,
|
||||
+ max_length: int = None,
|
||||
+ ) -> bytes:
|
||||
"""
|
||||
Decode the data passed in and potentially flush the decoder.
|
||||
"""
|
||||
if not decode_content:
|
||||
return data
|
||||
|
||||
+ if max_length is None or flush_decoder:
|
||||
+ max_length = -1
|
||||
+
|
||||
try:
|
||||
if self._decoder:
|
||||
- data = self._decoder.decompress(data)
|
||||
+ data = self._decoder.decompress(data, max_length=max_length)
|
||||
except self.DECODER_ERROR_CLASSES as e:
|
||||
content_encoding = self.headers.get("content-encoding", "").lower()
|
||||
raise DecodeError(
|
||||
@@ -634,7 +755,10 @@
|
||||
for line in self.read_chunked(amt, decode_content=decode_content):
|
||||
yield line
|
||||
else:
|
||||
- while not is_fp_closed(self._fp):
|
||||
+ while (
|
||||
+ not is_fp_closed(self._fp)
|
||||
+ or (self._decoder and self._decoder.has_unconsumed_tail)
|
||||
+ ):
|
||||
data = self.read(amt=amt, decode_content=decode_content)
|
||||
|
||||
if data:
|
||||
@@ -840,7 +964,10 @@
|
||||
break
|
||||
chunk = self._handle_chunk(amt)
|
||||
decoded = self._decode(
|
||||
- chunk, decode_content=decode_content, flush_decoder=False
|
||||
+ chunk,
|
||||
+ decode_content=decode_content,
|
||||
+ flush_decoder=False,
|
||||
+ max_length=amt,
|
||||
)
|
||||
if decoded:
|
||||
yield decoded
|
||||
|
||||
--- a/google/urllib3/response.py 2026-01-20 10:46:57.006470161 +0100
|
||||
+++ b/google/urllib3/response.py 2026-01-20 10:55:44.090084896 +0100
|
||||
@@ -23,6 +23,7 @@
|
||||
from .exceptions import (
|
||||
BodyNotHttplibCompatible,
|
||||
DecodeError,
|
||||
+ DependencyWarning,
|
||||
HTTPError,
|
||||
IncompleteRead,
|
||||
InvalidChunkLength,
|
||||
@@ -41,34 +42,60 @@
|
||||
class DeflateDecoder(object):
|
||||
def __init__(self):
|
||||
self._first_try = True
|
||||
- self._data = b""
|
||||
+ self._first_try_data = b""
|
||||
+ self._unfed_data = b""
|
||||
self._obj = zlib.decompressobj()
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._obj, name)
|
||||
|
||||
- def decompress(self, data):
|
||||
- if not data:
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ data = self._unfed_data + data
|
||||
+ self._unfed_data = b""
|
||||
+ if not data and not self._obj.unconsumed_tail:
|
||||
return data
|
||||
+ original_max_length = max_length
|
||||
+ if original_max_length < 0:
|
||||
+ max_length = 0
|
||||
+ elif original_max_length == 0:
|
||||
+ # We should not pass 0 to the zlib decompressor because 0 is
|
||||
+ # the default value that will make zlib decompress without a
|
||||
+ # length limit.
|
||||
+ # Data should be stored for subsequent calls.
|
||||
+ self._unfed_data = data
|
||||
+ return b""
|
||||
|
||||
+ # Subsequent calls always reuse `self._obj`. zlib requires
|
||||
+ # passing the unconsumed tail if decompression is to continue.
|
||||
if not self._first_try:
|
||||
- return self._obj.decompress(data)
|
||||
+ return self._obj.decompress(
|
||||
+ self._obj.unconsumed_tail + data, max_length=max_length
|
||||
+ )
|
||||
|
||||
- self._data += data
|
||||
+ # First call tries with RFC 1950 ZLIB format.
|
||||
+ self._first_try_data += data
|
||||
try:
|
||||
- decompressed = self._obj.decompress(data)
|
||||
+ decompressed = self._obj.decompress(data, max_length=max_length)
|
||||
if decompressed:
|
||||
self._first_try = False
|
||||
- self._data = None
|
||||
+ self._first_try_data = b""
|
||||
return decompressed
|
||||
+ # On failure, it falls back to RFC 1951 DEFLATE format.
|
||||
except zlib.error:
|
||||
self._first_try = False
|
||||
self._obj = zlib.decompressobj(-zlib.MAX_WBITS)
|
||||
try:
|
||||
- return self.decompress(self._data)
|
||||
+ return self.decompress(
|
||||
+ self._first_try_data, max_length=original_max_length
|
||||
+ )
|
||||
finally:
|
||||
- self._data = None
|
||||
+ self._first_try_data = b""
|
||||
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return bool(self._unfed_data) or (
|
||||
+ bool(self._obj.unconsumed_tail) and not self._first_try
|
||||
+ )
|
||||
|
||||
class GzipDecoderState(object):
|
||||
|
||||
@@ -81,30 +108,64 @@
|
||||
def __init__(self):
|
||||
self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
self._state = GzipDecoderState.FIRST_MEMBER
|
||||
+ self._unconsumed_tail = b""
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._obj, name)
|
||||
|
||||
- def decompress(self, data):
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
ret = bytearray()
|
||||
- if self._state == GzipDecoderState.SWALLOW_DATA or not data:
|
||||
+ if self._state == GzipDecoderState.SWALLOW_DATA:
|
||||
+ return bytes(ret)
|
||||
+
|
||||
+ if max_length == 0:
|
||||
+ # We should not pass 0 to the zlib decompressor because 0 is
|
||||
+ # the default value that will make zlib decompress without a
|
||||
+ # length limit.
|
||||
+ # Data should be stored for subsequent calls.
|
||||
+ self._unconsumed_tail += data
|
||||
+ return b""
|
||||
+
|
||||
+ # zlib requires passing the unconsumed tail to the subsequent
|
||||
+ # call if decompression is to continue.
|
||||
+ data = self._unconsumed_tail + data
|
||||
+ if not data and self._obj.eof:
|
||||
return bytes(ret)
|
||||
+
|
||||
while True:
|
||||
try:
|
||||
- ret += self._obj.decompress(data)
|
||||
+ ret += self._obj.decompress(
|
||||
+ data, max_length=max(max_length - len(ret), 0)
|
||||
+ )
|
||||
except zlib.error:
|
||||
previous_state = self._state
|
||||
# Ignore data after the first error
|
||||
self._state = GzipDecoderState.SWALLOW_DATA
|
||||
+ self._unconsumed_tail = b""
|
||||
if previous_state == GzipDecoderState.OTHER_MEMBERS:
|
||||
# Allow trailing garbage acceptable in other gzip clients
|
||||
return bytes(ret)
|
||||
raise
|
||||
- data = self._obj.unused_data
|
||||
+
|
||||
+ self._unconsumed_tail = data = (
|
||||
+ self._obj.unconsumed_tail or self._obj.unused_data
|
||||
+ )
|
||||
+ if max_length > 0 and len(ret) >= max_length:
|
||||
+ break
|
||||
+
|
||||
if not data:
|
||||
return bytes(ret)
|
||||
- self._state = GzipDecoderState.OTHER_MEMBERS
|
||||
- self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
+ # When the end of a gzip member is reached, a new decompressor
|
||||
+ # must be created for unused (possibly future) data.
|
||||
+ if self._obj.eof:
|
||||
+ self._state = GzipDecoderState.OTHER_MEMBERS
|
||||
+ self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
+
|
||||
+ return bytes(ret)
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return bool(self._unconsumed_tail)
|
||||
|
||||
|
||||
if brotli is not None:
|
||||
@@ -116,9 +177,35 @@
|
||||
def __init__(self):
|
||||
self._obj = brotli.Decompressor()
|
||||
if hasattr(self._obj, "decompress"):
|
||||
- self.decompress = self._obj.decompress
|
||||
+ setattr(self, "_decompress", self._obj.decompress)
|
||||
else:
|
||||
- self.decompress = self._obj.process
|
||||
+ setattr(self, "_decompress", self._obj.process)
|
||||
+
|
||||
+ # Requires Brotli >= 1.2.0 for `output_buffer_limit`.
|
||||
+ def _decompress(self, data: bytes, output_buffer_limit: int = -1) -> bytes:
|
||||
+ raise NotImplementedError()
|
||||
+
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ try:
|
||||
+ if max_length > 0:
|
||||
+ return self._decompress(data, output_buffer_limit=max_length)
|
||||
+ else:
|
||||
+ return self._decompress(data)
|
||||
+ except TypeError:
|
||||
+ # Fallback for Brotli/brotlicffi/brotlipy versions without
|
||||
+ # the `output_buffer_limit` parameter.
|
||||
+ warnings.warn(
|
||||
+ "Brotli >= 1.2.0 is required to prevent decompression bombs.",
|
||||
+ DependencyWarning,
|
||||
+ )
|
||||
+ return self._decompress(data)
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ try:
|
||||
+ return not self._obj.can_accept_more_data()
|
||||
+ except AttributeError:
|
||||
+ return False
|
||||
|
||||
def flush(self):
|
||||
if hasattr(self._obj, "flush"):
|
||||
@@ -151,10 +238,35 @@
|
||||
def flush(self):
|
||||
return self._decoders[0].flush()
|
||||
|
||||
- def decompress(self, data):
|
||||
- for d in reversed(self._decoders):
|
||||
- data = d.decompress(data)
|
||||
- return data
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ if max_length <= 0:
|
||||
+ for d in reversed(self._decoders):
|
||||
+ data = d.decompress(data)
|
||||
+ return data
|
||||
+
|
||||
+ ret = bytearray()
|
||||
+ # Every while loop iteration goes through all decoders once.
|
||||
+ # It exits when enough data is read or no more data can be read.
|
||||
+ # It is possible that the while loop iteration does not produce
|
||||
+ # any data because we retrieve up to `max_length` from every
|
||||
+ # decoder, and the amount of bytes may be insufficient for the
|
||||
+ # next decoder to produce enough/any output.
|
||||
+ while True:
|
||||
+ any_data = False
|
||||
+ for d in reversed(self._decoders):
|
||||
+ data = d.decompress(data, max_length=max_length - len(ret))
|
||||
+ if data:
|
||||
+ any_data = True
|
||||
+ # We should not break when no data is returned because
|
||||
+ # next decoders may produce data even with empty input.
|
||||
+ ret += data
|
||||
+ if not any_data or len(ret) >= max_length:
|
||||
+ return bytes(ret)
|
||||
+ data = b""
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return any(d.has_unconsumed_tail for d in self._decoders)
|
||||
|
||||
|
||||
def _get_decoder(mode):
|
||||
@@ -405,16 +517,25 @@
|
||||
if brotli is not None:
|
||||
DECODER_ERROR_CLASSES += (brotli.error,)
|
||||
|
||||
- def _decode(self, data, decode_content, flush_decoder):
|
||||
+ def _decode(
|
||||
+ self,
|
||||
+ data: bytes,
|
||||
+ decode_content: bool,
|
||||
+ flush_decoder: bool,
|
||||
+ max_length: int = None,
|
||||
+ ) -> bytes:
|
||||
"""
|
||||
Decode the data passed in and potentially flush the decoder.
|
||||
"""
|
||||
if not decode_content:
|
||||
return data
|
||||
|
||||
+ if max_length is None or flush_decoder:
|
||||
+ max_length = -1
|
||||
+
|
||||
try:
|
||||
if self._decoder:
|
||||
- data = self._decoder.decompress(data)
|
||||
+ data = self._decoder.decompress(data, max_length=max_length)
|
||||
except self.DECODER_ERROR_CLASSES as e:
|
||||
content_encoding = self.headers.get("content-encoding", "").lower()
|
||||
raise DecodeError(
|
||||
@@ -634,7 +755,10 @@
|
||||
for line in self.read_chunked(amt, decode_content=decode_content):
|
||||
yield line
|
||||
else:
|
||||
- while not is_fp_closed(self._fp):
|
||||
+ while (
|
||||
+ not is_fp_closed(self._fp)
|
||||
+ or (self._decoder and self._decoder.has_unconsumed_tail)
|
||||
+ ):
|
||||
data = self.read(amt=amt, decode_content=decode_content)
|
||||
|
||||
if data:
|
||||
@@ -840,7 +964,10 @@
|
||||
break
|
||||
chunk = self._handle_chunk(amt)
|
||||
decoded = self._decode(
|
||||
- chunk, decode_content=decode_content, flush_decoder=False
|
||||
+ chunk,
|
||||
+ decode_content=decode_content,
|
||||
+ flush_decoder=False,
|
||||
+ max_length=amt,
|
||||
)
|
||||
if decoded:
|
||||
yield decoded
|
||||
@ -503,7 +503,7 @@ index 612450568..f30a1da28 100644
|
||||
|
||||
-import sys, re
|
||||
+import sys, os, re
|
||||
sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
try:
|
||||
import pexpect
|
||||
@@ -73,11 +73,11 @@ def main():
|
||||
|
||||
@ -1,95 +0,0 @@
|
||||
--- a/aws/urllib3/response.py 2026-02-03 08:20:11.000000000 +0100
|
||||
+++ b/aws/urllib3/response.py 2026-02-03 09:11:38.017998476 +0100
|
||||
@@ -350,6 +350,7 @@
|
||||
self.reason = reason
|
||||
self.strict = strict
|
||||
self.decode_content = decode_content
|
||||
+ self._has_decoded_content = False
|
||||
self.retries = retries
|
||||
self.enforce_content_length = enforce_content_length
|
||||
self.auto_close = auto_close
|
||||
@@ -414,7 +415,11 @@
|
||||
Unread data in the HTTPResponse connection blocks the connection from being released back to the pool.
|
||||
"""
|
||||
try:
|
||||
- self.read()
|
||||
+ self.read(
|
||||
+ # Do not spend resources decoding the content unless
|
||||
+ # decoding has already been initiated.
|
||||
+ decode_content=self._has_decoded_content,
|
||||
+ )
|
||||
except (HTTPError, SocketError, BaseSSLError, HTTPException):
|
||||
pass
|
||||
|
||||
@@ -536,6 +541,7 @@
|
||||
try:
|
||||
if self._decoder:
|
||||
data = self._decoder.decompress(data, max_length=max_length)
|
||||
+ self._has_decoded_content = True
|
||||
except self.DECODER_ERROR_CLASSES as e:
|
||||
content_encoding = self.headers.get("content-encoding", "").lower()
|
||||
raise DecodeError(
|
||||
|
||||
--- a/azure/urllib3/response.py 2026-02-03 08:20:11.000000000 +0100
|
||||
+++ b/azure/urllib3/response.py 2026-02-03 09:11:38.017998476 +0100
|
||||
@@ -350,6 +350,7 @@
|
||||
self.reason = reason
|
||||
self.strict = strict
|
||||
self.decode_content = decode_content
|
||||
+ self._has_decoded_content = False
|
||||
self.retries = retries
|
||||
self.enforce_content_length = enforce_content_length
|
||||
self.auto_close = auto_close
|
||||
@@ -414,7 +415,11 @@
|
||||
Unread data in the HTTPResponse connection blocks the connection from being released back to the pool.
|
||||
"""
|
||||
try:
|
||||
- self.read()
|
||||
+ self.read(
|
||||
+ # Do not spend resources decoding the content unless
|
||||
+ # decoding has already been initiated.
|
||||
+ decode_content=self._has_decoded_content,
|
||||
+ )
|
||||
except (HTTPError, SocketError, BaseSSLError, HTTPException):
|
||||
pass
|
||||
|
||||
@@ -536,6 +541,7 @@
|
||||
try:
|
||||
if self._decoder:
|
||||
data = self._decoder.decompress(data, max_length=max_length)
|
||||
+ self._has_decoded_content = True
|
||||
except self.DECODER_ERROR_CLASSES as e:
|
||||
content_encoding = self.headers.get("content-encoding", "").lower()
|
||||
raise DecodeError(
|
||||
|
||||
--- a/google/urllib3/response.py 2026-02-03 08:20:11.000000000 +0100
|
||||
+++ b/google/urllib3/response.py 2026-02-03 09:11:38.017998476 +0100
|
||||
@@ -350,6 +350,7 @@
|
||||
self.reason = reason
|
||||
self.strict = strict
|
||||
self.decode_content = decode_content
|
||||
+ self._has_decoded_content = False
|
||||
self.retries = retries
|
||||
self.enforce_content_length = enforce_content_length
|
||||
self.auto_close = auto_close
|
||||
@@ -414,7 +415,11 @@
|
||||
Unread data in the HTTPResponse connection blocks the connection from being released back to the pool.
|
||||
"""
|
||||
try:
|
||||
- self.read()
|
||||
+ self.read(
|
||||
+ # Do not spend resources decoding the content unless
|
||||
+ # decoding has already been initiated.
|
||||
+ decode_content=self._has_decoded_content,
|
||||
+ )
|
||||
except (HTTPError, SocketError, BaseSSLError, HTTPException):
|
||||
pass
|
||||
|
||||
@@ -536,6 +541,7 @@
|
||||
try:
|
||||
if self._decoder:
|
||||
data = self._decoder.decompress(data, max_length=max_length)
|
||||
+ self._has_decoded_content = True
|
||||
except self.DECODER_ERROR_CLASSES as e:
|
||||
content_encoding = self.headers.get("content-encoding", "").lower()
|
||||
raise DecodeError(
|
||||
@ -1,5 +1,5 @@
|
||||
--- a/google/pyasn1/codec/ber/decoder.py 2019-10-17 07:00:19.000000000 +0200
|
||||
+++ b/google/pyasn1/codec/ber/decoder.py 2026-01-27 10:43:12.757563432 +0100
|
||||
--- a/google/lib/python#PYTHON3_VERSION#/site-packages/pyasn1/codec/ber/decoder.py 2019-10-17 07:00:19.000000000 +0200
|
||||
+++ b/google/lib/python#PYTHON3_VERSION#/site-packages/pyasn1/codec/ber/decoder.py 2026-01-27 10:43:12.757563432 +0100
|
||||
@@ -22,6 +22,10 @@
|
||||
|
||||
noValue = base.noValue
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
From accff72ecc2f6cf5a76d9570198a93ac7c90270e Mon Sep 17 00:00:00 2001
|
||||
From: Quentin Pradet <quentin.pradet@gmail.com>
|
||||
Date: Mon, 17 Jun 2024 11:09:06 +0400
|
||||
Subject: [PATCH] Merge pull request from GHSA-34jh-p97f-mpxf
|
||||
|
||||
* Strip Proxy-Authorization header on redirects
|
||||
|
||||
* Fix test_retry_default_remove_headers_on_redirect
|
||||
|
||||
* Set release date
|
||||
---
|
||||
CHANGES.rst | 5 +++++
|
||||
src/urllib3/util/retry.py | 4 +++-
|
||||
test/test_retry.py | 6 ++++-
|
||||
test/with_dummyserver/test_poolmanager.py | 27 ++++++++++++++++++++---
|
||||
4 files changed, 37 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/ibm/urllib3/util/retry.py b/ibm/urllib3/util/retry.py
|
||||
index 7a76a4a6ad..0456cceba4 100644
|
||||
--- a/ibm/urllib3/util/retry.py
|
||||
+++ b/ibm/urllib3/util/retry.py
|
||||
@@ -189,7 +189,9 @@ class Retry:
|
||||
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
|
||||
|
||||
#: Default headers to be used for ``remove_headers_on_redirect``
|
||||
- DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Cookie", "Authorization"])
|
||||
+ DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(
|
||||
+ ["Cookie", "Authorization", "Proxy-Authorization"]
|
||||
+ )
|
||||
|
||||
#: Default maximum backoff time.
|
||||
DEFAULT_BACKOFF_MAX = 120
|
||||
@ -1,22 +0,0 @@
|
||||
--- a/ibm/urllib3/response.py 2023-10-17 19:42:56.000000000 +0200
|
||||
+++ b/ibm/urllib3/response.py 2026-01-02 11:19:25.583808492 +0100
|
||||
@@ -135,8 +135,18 @@
|
||||
they were applied.
|
||||
"""
|
||||
|
||||
+ # Maximum allowed number of chained HTTP encodings in the
|
||||
+ # Content-Encoding header.
|
||||
+ max_decode_links = 5
|
||||
+
|
||||
def __init__(self, modes):
|
||||
- self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")]
|
||||
+ encodings = [m.strip() for m in modes.split(",")]
|
||||
+ if len(encodings) > self.max_decode_links:
|
||||
+ raise DecodeError(
|
||||
+ "Too many content encodings in the chain: "
|
||||
+ f"{len(encodings)} > {self.max_decode_links}"
|
||||
+ )
|
||||
+ self._decoders = [_get_decoder(e) for e in encodings]
|
||||
|
||||
def flush(self):
|
||||
return self._decoders[0].flush()
|
||||
@ -1,281 +0,0 @@
|
||||
--- a/ibm/urllib3/response.py 2026-01-20 10:46:57.006470161 +0100
|
||||
+++ b/ibm/urllib3/response.py 2026-01-20 10:55:44.090084896 +0100
|
||||
@@ -23,6 +23,7 @@
|
||||
from .exceptions import (
|
||||
BodyNotHttplibCompatible,
|
||||
DecodeError,
|
||||
+ DependencyWarning,
|
||||
HTTPError,
|
||||
IncompleteRead,
|
||||
InvalidChunkLength,
|
||||
@@ -41,34 +42,60 @@
|
||||
class DeflateDecoder(object):
|
||||
def __init__(self):
|
||||
self._first_try = True
|
||||
- self._data = b""
|
||||
+ self._first_try_data = b""
|
||||
+ self._unfed_data = b""
|
||||
self._obj = zlib.decompressobj()
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._obj, name)
|
||||
|
||||
- def decompress(self, data):
|
||||
- if not data:
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ data = self._unfed_data + data
|
||||
+ self._unfed_data = b""
|
||||
+ if not data and not self._obj.unconsumed_tail:
|
||||
return data
|
||||
+ original_max_length = max_length
|
||||
+ if original_max_length < 0:
|
||||
+ max_length = 0
|
||||
+ elif original_max_length == 0:
|
||||
+ # We should not pass 0 to the zlib decompressor because 0 is
|
||||
+ # the default value that will make zlib decompress without a
|
||||
+ # length limit.
|
||||
+ # Data should be stored for subsequent calls.
|
||||
+ self._unfed_data = data
|
||||
+ return b""
|
||||
|
||||
+ # Subsequent calls always reuse `self._obj`. zlib requires
|
||||
+ # passing the unconsumed tail if decompression is to continue.
|
||||
if not self._first_try:
|
||||
- return self._obj.decompress(data)
|
||||
+ return self._obj.decompress(
|
||||
+ self._obj.unconsumed_tail + data, max_length=max_length
|
||||
+ )
|
||||
|
||||
- self._data += data
|
||||
+ # First call tries with RFC 1950 ZLIB format.
|
||||
+ self._first_try_data += data
|
||||
try:
|
||||
- decompressed = self._obj.decompress(data)
|
||||
+ decompressed = self._obj.decompress(data, max_length=max_length)
|
||||
if decompressed:
|
||||
self._first_try = False
|
||||
- self._data = None
|
||||
+ self._first_try_data = b""
|
||||
return decompressed
|
||||
+ # On failure, it falls back to RFC 1951 DEFLATE format.
|
||||
except zlib.error:
|
||||
self._first_try = False
|
||||
self._obj = zlib.decompressobj(-zlib.MAX_WBITS)
|
||||
try:
|
||||
- return self.decompress(self._data)
|
||||
+ return self.decompress(
|
||||
+ self._first_try_data, max_length=original_max_length
|
||||
+ )
|
||||
finally:
|
||||
- self._data = None
|
||||
+ self._first_try_data = b""
|
||||
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return bool(self._unfed_data) or (
|
||||
+ bool(self._obj.unconsumed_tail) and not self._first_try
|
||||
+ )
|
||||
|
||||
class GzipDecoderState(object):
|
||||
|
||||
@@ -81,30 +108,64 @@
|
||||
def __init__(self):
|
||||
self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
self._state = GzipDecoderState.FIRST_MEMBER
|
||||
+ self._unconsumed_tail = b""
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._obj, name)
|
||||
|
||||
- def decompress(self, data):
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
ret = bytearray()
|
||||
- if self._state == GzipDecoderState.SWALLOW_DATA or not data:
|
||||
+ if self._state == GzipDecoderState.SWALLOW_DATA:
|
||||
+ return bytes(ret)
|
||||
+
|
||||
+ if max_length == 0:
|
||||
+ # We should not pass 0 to the zlib decompressor because 0 is
|
||||
+ # the default value that will make zlib decompress without a
|
||||
+ # length limit.
|
||||
+ # Data should be stored for subsequent calls.
|
||||
+ self._unconsumed_tail += data
|
||||
+ return b""
|
||||
+
|
||||
+ # zlib requires passing the unconsumed tail to the subsequent
|
||||
+ # call if decompression is to continue.
|
||||
+ data = self._unconsumed_tail + data
|
||||
+ if not data and self._obj.eof:
|
||||
return bytes(ret)
|
||||
+
|
||||
while True:
|
||||
try:
|
||||
- ret += self._obj.decompress(data)
|
||||
+ ret += self._obj.decompress(
|
||||
+ data, max_length=max(max_length - len(ret), 0)
|
||||
+ )
|
||||
except zlib.error:
|
||||
previous_state = self._state
|
||||
# Ignore data after the first error
|
||||
self._state = GzipDecoderState.SWALLOW_DATA
|
||||
+ self._unconsumed_tail = b""
|
||||
if previous_state == GzipDecoderState.OTHER_MEMBERS:
|
||||
# Allow trailing garbage acceptable in other gzip clients
|
||||
return bytes(ret)
|
||||
raise
|
||||
- data = self._obj.unused_data
|
||||
+
|
||||
+ self._unconsumed_tail = data = (
|
||||
+ self._obj.unconsumed_tail or self._obj.unused_data
|
||||
+ )
|
||||
+ if max_length > 0 and len(ret) >= max_length:
|
||||
+ break
|
||||
+
|
||||
if not data:
|
||||
return bytes(ret)
|
||||
- self._state = GzipDecoderState.OTHER_MEMBERS
|
||||
- self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
+ # When the end of a gzip member is reached, a new decompressor
|
||||
+ # must be created for unused (possibly future) data.
|
||||
+ if self._obj.eof:
|
||||
+ self._state = GzipDecoderState.OTHER_MEMBERS
|
||||
+ self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
+
|
||||
+ return bytes(ret)
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return bool(self._unconsumed_tail)
|
||||
|
||||
|
||||
if brotli is not None:
|
||||
@@ -116,9 +177,35 @@
|
||||
def __init__(self):
|
||||
self._obj = brotli.Decompressor()
|
||||
if hasattr(self._obj, "decompress"):
|
||||
- self.decompress = self._obj.decompress
|
||||
+ setattr(self, "_decompress", self._obj.decompress)
|
||||
else:
|
||||
- self.decompress = self._obj.process
|
||||
+ setattr(self, "_decompress", self._obj.process)
|
||||
+
|
||||
+ # Requires Brotli >= 1.2.0 for `output_buffer_limit`.
|
||||
+ def _decompress(self, data: bytes, output_buffer_limit: int = -1) -> bytes:
|
||||
+ raise NotImplementedError()
|
||||
+
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ try:
|
||||
+ if max_length > 0:
|
||||
+ return self._decompress(data, output_buffer_limit=max_length)
|
||||
+ else:
|
||||
+ return self._decompress(data)
|
||||
+ except TypeError:
|
||||
+ # Fallback for Brotli/brotlicffi/brotlipy versions without
|
||||
+ # the `output_buffer_limit` parameter.
|
||||
+ warnings.warn(
|
||||
+ "Brotli >= 1.2.0 is required to prevent decompression bombs.",
|
||||
+ DependencyWarning,
|
||||
+ )
|
||||
+ return self._decompress(data)
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ try:
|
||||
+ return not self._obj.can_accept_more_data()
|
||||
+ except AttributeError:
|
||||
+ return False
|
||||
|
||||
def flush(self):
|
||||
if hasattr(self._obj, "flush"):
|
||||
@@ -151,10 +238,35 @@
|
||||
def flush(self):
|
||||
return self._decoders[0].flush()
|
||||
|
||||
- def decompress(self, data):
|
||||
- for d in reversed(self._decoders):
|
||||
- data = d.decompress(data)
|
||||
- return data
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ if max_length <= 0:
|
||||
+ for d in reversed(self._decoders):
|
||||
+ data = d.decompress(data)
|
||||
+ return data
|
||||
+
|
||||
+ ret = bytearray()
|
||||
+ # Every while loop iteration goes through all decoders once.
|
||||
+ # It exits when enough data is read or no more data can be read.
|
||||
+ # It is possible that the while loop iteration does not produce
|
||||
+ # any data because we retrieve up to `max_length` from every
|
||||
+ # decoder, and the amount of bytes may be insufficient for the
|
||||
+ # next decoder to produce enough/any output.
|
||||
+ while True:
|
||||
+ any_data = False
|
||||
+ for d in reversed(self._decoders):
|
||||
+ data = d.decompress(data, max_length=max_length - len(ret))
|
||||
+ if data:
|
||||
+ any_data = True
|
||||
+ # We should not break when no data is returned because
|
||||
+ # next decoders may produce data even with empty input.
|
||||
+ ret += data
|
||||
+ if not any_data or len(ret) >= max_length:
|
||||
+ return bytes(ret)
|
||||
+ data = b""
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return any(d.has_unconsumed_tail for d in self._decoders)
|
||||
|
||||
|
||||
def _get_decoder(mode):
|
||||
@@ -405,16 +517,25 @@
|
||||
if brotli is not None:
|
||||
DECODER_ERROR_CLASSES += (brotli.error,)
|
||||
|
||||
- def _decode(self, data, decode_content, flush_decoder):
|
||||
+ def _decode(
|
||||
+ self,
|
||||
+ data: bytes,
|
||||
+ decode_content: bool,
|
||||
+ flush_decoder: bool,
|
||||
+ max_length: int = None,
|
||||
+ ) -> bytes:
|
||||
"""
|
||||
Decode the data passed in and potentially flush the decoder.
|
||||
"""
|
||||
if not decode_content:
|
||||
return data
|
||||
|
||||
+ if max_length is None or flush_decoder:
|
||||
+ max_length = -1
|
||||
+
|
||||
try:
|
||||
if self._decoder:
|
||||
- data = self._decoder.decompress(data)
|
||||
+ data = self._decoder.decompress(data, max_length=max_length)
|
||||
except self.DECODER_ERROR_CLASSES as e:
|
||||
content_encoding = self.headers.get("content-encoding", "").lower()
|
||||
raise DecodeError(
|
||||
@@ -634,7 +755,10 @@
|
||||
for line in self.read_chunked(amt, decode_content=decode_content):
|
||||
yield line
|
||||
else:
|
||||
- while not is_fp_closed(self._fp):
|
||||
+ while (
|
||||
+ not is_fp_closed(self._fp)
|
||||
+ or (self._decoder and self._decoder.has_unconsumed_tail)
|
||||
+ ):
|
||||
data = self.read(amt=amt, decode_content=decode_content)
|
||||
|
||||
if data:
|
||||
@@ -840,7 +964,10 @@
|
||||
break
|
||||
chunk = self._handle_chunk(amt)
|
||||
decoded = self._decode(
|
||||
- chunk, decode_content=decode_content, flush_decoder=False
|
||||
+ chunk,
|
||||
+ decode_content=decode_content,
|
||||
+ flush_decoder=False,
|
||||
+ max_length=amt,
|
||||
)
|
||||
if decoded:
|
||||
yield decoded
|
||||
@ -1,31 +0,0 @@
|
||||
--- a/ibm/urllib3/response.py 2026-02-03 08:20:11.000000000 +0100
|
||||
+++ b/ibm/urllib3/response.py 2026-02-03 09:11:38.017998476 +0100
|
||||
@@ -350,6 +350,7 @@
|
||||
self.reason = reason
|
||||
self.strict = strict
|
||||
self.decode_content = decode_content
|
||||
+ self._has_decoded_content = False
|
||||
self.retries = retries
|
||||
self.enforce_content_length = enforce_content_length
|
||||
self.auto_close = auto_close
|
||||
@@ -414,7 +415,11 @@
|
||||
Unread data in the HTTPResponse connection blocks the connection from being released back to the pool.
|
||||
"""
|
||||
try:
|
||||
- self.read()
|
||||
+ self.read(
|
||||
+ # Do not spend resources decoding the content unless
|
||||
+ # decoding has already been initiated.
|
||||
+ decode_content=self._has_decoded_content,
|
||||
+ )
|
||||
except (HTTPError, SocketError, BaseSSLError, HTTPException):
|
||||
pass
|
||||
|
||||
@@ -536,6 +541,7 @@
|
||||
try:
|
||||
if self._decoder:
|
||||
data = self._decoder.decompress(data, max_length=max_length)
|
||||
+ self._has_decoded_content = True
|
||||
except self.DECODER_ERROR_CLASSES as e:
|
||||
content_encoding = self.headers.get("content-encoding", "").lower()
|
||||
raise DecodeError(
|
||||
@ -1,32 +0,0 @@
|
||||
From accff72ecc2f6cf5a76d9570198a93ac7c90270e Mon Sep 17 00:00:00 2001
|
||||
From: Quentin Pradet <quentin.pradet@gmail.com>
|
||||
Date: Mon, 17 Jun 2024 11:09:06 +0400
|
||||
Subject: [PATCH] Merge pull request from GHSA-34jh-p97f-mpxf
|
||||
|
||||
* Strip Proxy-Authorization header on redirects
|
||||
|
||||
* Fix test_retry_default_remove_headers_on_redirect
|
||||
|
||||
* Set release date
|
||||
---
|
||||
CHANGES.rst | 5 +++++
|
||||
src/urllib3/util/retry.py | 4 +++-
|
||||
test/test_retry.py | 6 ++++-
|
||||
test/with_dummyserver/test_poolmanager.py | 27 ++++++++++++++++++++---
|
||||
4 files changed, 37 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/kubevirt/urllib3/util/retry.py b/kubevirt/urllib3/util/retry.py
|
||||
index 7a76a4a6ad..0456cceba4 100644
|
||||
--- a/kubevirt/urllib3/util/retry.py
|
||||
+++ b/kubevirt/urllib3/util/retry.py
|
||||
@@ -189,7 +189,9 @@ class Retry:
|
||||
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
|
||||
|
||||
#: Default headers to be used for ``remove_headers_on_redirect``
|
||||
- DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Cookie", "Authorization"])
|
||||
+ DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(
|
||||
+ ["Cookie", "Authorization", "Proxy-Authorization"]
|
||||
+ )
|
||||
|
||||
#: Default maximum backoff time.
|
||||
DEFAULT_BACKOFF_MAX = 120
|
||||
@ -1,22 +0,0 @@
|
||||
--- a/kubevirt/urllib3/response.py 2023-10-17 19:42:56.000000000 +0200
|
||||
+++ b/kubevirt/urllib3/response.py 2026-01-02 11:19:25.583808492 +0100
|
||||
@@ -135,8 +135,18 @@
|
||||
they were applied.
|
||||
"""
|
||||
|
||||
+ # Maximum allowed number of chained HTTP encodings in the
|
||||
+ # Content-Encoding header.
|
||||
+ max_decode_links = 5
|
||||
+
|
||||
def __init__(self, modes):
|
||||
- self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")]
|
||||
+ encodings = [m.strip() for m in modes.split(",")]
|
||||
+ if len(encodings) > self.max_decode_links:
|
||||
+ raise DecodeError(
|
||||
+ "Too many content encodings in the chain: "
|
||||
+ f"{len(encodings)} > {self.max_decode_links}"
|
||||
+ )
|
||||
+ self._decoders = [_get_decoder(e) for e in encodings]
|
||||
|
||||
def flush(self):
|
||||
return self._decoders[0].flush()
|
||||
@ -1,281 +0,0 @@
|
||||
--- a/kubevirt/urllib3/response.py 2026-01-20 10:46:57.006470161 +0100
|
||||
+++ b/kubevirt/urllib3/response.py 2026-01-20 10:55:44.090084896 +0100
|
||||
@@ -23,6 +23,7 @@
|
||||
from .exceptions import (
|
||||
BodyNotHttplibCompatible,
|
||||
DecodeError,
|
||||
+ DependencyWarning,
|
||||
HTTPError,
|
||||
IncompleteRead,
|
||||
InvalidChunkLength,
|
||||
@@ -41,34 +42,60 @@
|
||||
class DeflateDecoder(object):
|
||||
def __init__(self):
|
||||
self._first_try = True
|
||||
- self._data = b""
|
||||
+ self._first_try_data = b""
|
||||
+ self._unfed_data = b""
|
||||
self._obj = zlib.decompressobj()
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._obj, name)
|
||||
|
||||
- def decompress(self, data):
|
||||
- if not data:
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ data = self._unfed_data + data
|
||||
+ self._unfed_data = b""
|
||||
+ if not data and not self._obj.unconsumed_tail:
|
||||
return data
|
||||
+ original_max_length = max_length
|
||||
+ if original_max_length < 0:
|
||||
+ max_length = 0
|
||||
+ elif original_max_length == 0:
|
||||
+ # We should not pass 0 to the zlib decompressor because 0 is
|
||||
+ # the default value that will make zlib decompress without a
|
||||
+ # length limit.
|
||||
+ # Data should be stored for subsequent calls.
|
||||
+ self._unfed_data = data
|
||||
+ return b""
|
||||
|
||||
+ # Subsequent calls always reuse `self._obj`. zlib requires
|
||||
+ # passing the unconsumed tail if decompression is to continue.
|
||||
if not self._first_try:
|
||||
- return self._obj.decompress(data)
|
||||
+ return self._obj.decompress(
|
||||
+ self._obj.unconsumed_tail + data, max_length=max_length
|
||||
+ )
|
||||
|
||||
- self._data += data
|
||||
+ # First call tries with RFC 1950 ZLIB format.
|
||||
+ self._first_try_data += data
|
||||
try:
|
||||
- decompressed = self._obj.decompress(data)
|
||||
+ decompressed = self._obj.decompress(data, max_length=max_length)
|
||||
if decompressed:
|
||||
self._first_try = False
|
||||
- self._data = None
|
||||
+ self._first_try_data = b""
|
||||
return decompressed
|
||||
+ # On failure, it falls back to RFC 1951 DEFLATE format.
|
||||
except zlib.error:
|
||||
self._first_try = False
|
||||
self._obj = zlib.decompressobj(-zlib.MAX_WBITS)
|
||||
try:
|
||||
- return self.decompress(self._data)
|
||||
+ return self.decompress(
|
||||
+ self._first_try_data, max_length=original_max_length
|
||||
+ )
|
||||
finally:
|
||||
- self._data = None
|
||||
+ self._first_try_data = b""
|
||||
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return bool(self._unfed_data) or (
|
||||
+ bool(self._obj.unconsumed_tail) and not self._first_try
|
||||
+ )
|
||||
|
||||
class GzipDecoderState(object):
|
||||
|
||||
@@ -81,30 +108,64 @@
|
||||
def __init__(self):
|
||||
self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
self._state = GzipDecoderState.FIRST_MEMBER
|
||||
+ self._unconsumed_tail = b""
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._obj, name)
|
||||
|
||||
- def decompress(self, data):
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
ret = bytearray()
|
||||
- if self._state == GzipDecoderState.SWALLOW_DATA or not data:
|
||||
+ if self._state == GzipDecoderState.SWALLOW_DATA:
|
||||
+ return bytes(ret)
|
||||
+
|
||||
+ if max_length == 0:
|
||||
+ # We should not pass 0 to the zlib decompressor because 0 is
|
||||
+ # the default value that will make zlib decompress without a
|
||||
+ # length limit.
|
||||
+ # Data should be stored for subsequent calls.
|
||||
+ self._unconsumed_tail += data
|
||||
+ return b""
|
||||
+
|
||||
+ # zlib requires passing the unconsumed tail to the subsequent
|
||||
+ # call if decompression is to continue.
|
||||
+ data = self._unconsumed_tail + data
|
||||
+ if not data and self._obj.eof:
|
||||
return bytes(ret)
|
||||
+
|
||||
while True:
|
||||
try:
|
||||
- ret += self._obj.decompress(data)
|
||||
+ ret += self._obj.decompress(
|
||||
+ data, max_length=max(max_length - len(ret), 0)
|
||||
+ )
|
||||
except zlib.error:
|
||||
previous_state = self._state
|
||||
# Ignore data after the first error
|
||||
self._state = GzipDecoderState.SWALLOW_DATA
|
||||
+ self._unconsumed_tail = b""
|
||||
if previous_state == GzipDecoderState.OTHER_MEMBERS:
|
||||
# Allow trailing garbage acceptable in other gzip clients
|
||||
return bytes(ret)
|
||||
raise
|
||||
- data = self._obj.unused_data
|
||||
+
|
||||
+ self._unconsumed_tail = data = (
|
||||
+ self._obj.unconsumed_tail or self._obj.unused_data
|
||||
+ )
|
||||
+ if max_length > 0 and len(ret) >= max_length:
|
||||
+ break
|
||||
+
|
||||
if not data:
|
||||
return bytes(ret)
|
||||
- self._state = GzipDecoderState.OTHER_MEMBERS
|
||||
- self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
+ # When the end of a gzip member is reached, a new decompressor
|
||||
+ # must be created for unused (possibly future) data.
|
||||
+ if self._obj.eof:
|
||||
+ self._state = GzipDecoderState.OTHER_MEMBERS
|
||||
+ self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
||||
+
|
||||
+ return bytes(ret)
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return bool(self._unconsumed_tail)
|
||||
|
||||
|
||||
if brotli is not None:
|
||||
@@ -116,9 +177,35 @@
|
||||
def __init__(self):
|
||||
self._obj = brotli.Decompressor()
|
||||
if hasattr(self._obj, "decompress"):
|
||||
- self.decompress = self._obj.decompress
|
||||
+ setattr(self, "_decompress", self._obj.decompress)
|
||||
else:
|
||||
- self.decompress = self._obj.process
|
||||
+ setattr(self, "_decompress", self._obj.process)
|
||||
+
|
||||
+ # Requires Brotli >= 1.2.0 for `output_buffer_limit`.
|
||||
+ def _decompress(self, data: bytes, output_buffer_limit: int = -1) -> bytes:
|
||||
+ raise NotImplementedError()
|
||||
+
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ try:
|
||||
+ if max_length > 0:
|
||||
+ return self._decompress(data, output_buffer_limit=max_length)
|
||||
+ else:
|
||||
+ return self._decompress(data)
|
||||
+ except TypeError:
|
||||
+ # Fallback for Brotli/brotlicffi/brotlipy versions without
|
||||
+ # the `output_buffer_limit` parameter.
|
||||
+ warnings.warn(
|
||||
+ "Brotli >= 1.2.0 is required to prevent decompression bombs.",
|
||||
+ DependencyWarning,
|
||||
+ )
|
||||
+ return self._decompress(data)
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ try:
|
||||
+ return not self._obj.can_accept_more_data()
|
||||
+ except AttributeError:
|
||||
+ return False
|
||||
|
||||
def flush(self):
|
||||
if hasattr(self._obj, "flush"):
|
||||
@@ -151,10 +238,35 @@
|
||||
def flush(self):
|
||||
return self._decoders[0].flush()
|
||||
|
||||
- def decompress(self, data):
|
||||
- for d in reversed(self._decoders):
|
||||
- data = d.decompress(data)
|
||||
- return data
|
||||
+ def decompress(self, data: bytes, max_length: int = -1) -> bytes:
|
||||
+ if max_length <= 0:
|
||||
+ for d in reversed(self._decoders):
|
||||
+ data = d.decompress(data)
|
||||
+ return data
|
||||
+
|
||||
+ ret = bytearray()
|
||||
+ # Every while loop iteration goes through all decoders once.
|
||||
+ # It exits when enough data is read or no more data can be read.
|
||||
+ # It is possible that the while loop iteration does not produce
|
||||
+ # any data because we retrieve up to `max_length` from every
|
||||
+ # decoder, and the amount of bytes may be insufficient for the
|
||||
+ # next decoder to produce enough/any output.
|
||||
+ while True:
|
||||
+ any_data = False
|
||||
+ for d in reversed(self._decoders):
|
||||
+ data = d.decompress(data, max_length=max_length - len(ret))
|
||||
+ if data:
|
||||
+ any_data = True
|
||||
+ # We should not break when no data is returned because
|
||||
+ # next decoders may produce data even with empty input.
|
||||
+ ret += data
|
||||
+ if not any_data or len(ret) >= max_length:
|
||||
+ return bytes(ret)
|
||||
+ data = b""
|
||||
+
|
||||
+ @property
|
||||
+ def has_unconsumed_tail(self) -> bool:
|
||||
+ return any(d.has_unconsumed_tail for d in self._decoders)
|
||||
|
||||
|
||||
def _get_decoder(mode):
|
||||
@@ -405,16 +517,25 @@
|
||||
if brotli is not None:
|
||||
DECODER_ERROR_CLASSES += (brotli.error,)
|
||||
|
||||
- def _decode(self, data, decode_content, flush_decoder):
|
||||
+ def _decode(
|
||||
+ self,
|
||||
+ data: bytes,
|
||||
+ decode_content: bool,
|
||||
+ flush_decoder: bool,
|
||||
+ max_length: int = None,
|
||||
+ ) -> bytes:
|
||||
"""
|
||||
Decode the data passed in and potentially flush the decoder.
|
||||
"""
|
||||
if not decode_content:
|
||||
return data
|
||||
|
||||
+ if max_length is None or flush_decoder:
|
||||
+ max_length = -1
|
||||
+
|
||||
try:
|
||||
if self._decoder:
|
||||
- data = self._decoder.decompress(data)
|
||||
+ data = self._decoder.decompress(data, max_length=max_length)
|
||||
except self.DECODER_ERROR_CLASSES as e:
|
||||
content_encoding = self.headers.get("content-encoding", "").lower()
|
||||
raise DecodeError(
|
||||
@@ -634,7 +755,10 @@
|
||||
for line in self.read_chunked(amt, decode_content=decode_content):
|
||||
yield line
|
||||
else:
|
||||
- while not is_fp_closed(self._fp):
|
||||
+ while (
|
||||
+ not is_fp_closed(self._fp)
|
||||
+ or (self._decoder and self._decoder.has_unconsumed_tail)
|
||||
+ ):
|
||||
data = self.read(amt=amt, decode_content=decode_content)
|
||||
|
||||
if data:
|
||||
@@ -840,7 +964,10 @@
|
||||
break
|
||||
chunk = self._handle_chunk(amt)
|
||||
decoded = self._decode(
|
||||
- chunk, decode_content=decode_content, flush_decoder=False
|
||||
+ chunk,
|
||||
+ decode_content=decode_content,
|
||||
+ flush_decoder=False,
|
||||
+ max_length=amt,
|
||||
)
|
||||
if decoded:
|
||||
yield decoded
|
||||
@ -1,31 +0,0 @@
|
||||
--- a/kubevirt/urllib3/response.py 2026-02-03 08:20:11.000000000 +0100
|
||||
+++ b/kubevirt/urllib3/response.py 2026-02-03 09:11:38.017998476 +0100
|
||||
@@ -350,6 +350,7 @@
|
||||
self.reason = reason
|
||||
self.strict = strict
|
||||
self.decode_content = decode_content
|
||||
+ self._has_decoded_content = False
|
||||
self.retries = retries
|
||||
self.enforce_content_length = enforce_content_length
|
||||
self.auto_close = auto_close
|
||||
@@ -414,7 +415,11 @@
|
||||
Unread data in the HTTPResponse connection blocks the connection from being released back to the pool.
|
||||
"""
|
||||
try:
|
||||
- self.read()
|
||||
+ self.read(
|
||||
+ # Do not spend resources decoding the content unless
|
||||
+ # decoding has already been initiated.
|
||||
+ decode_content=self._has_decoded_content,
|
||||
+ )
|
||||
except (HTTPError, SocketError, BaseSSLError, HTTPException):
|
||||
pass
|
||||
|
||||
@@ -536,6 +541,7 @@
|
||||
try:
|
||||
if self._decoder:
|
||||
data = self._decoder.decompress(data, max_length=max_length)
|
||||
+ self._has_decoded_content = True
|
||||
except self.DECODER_ERROR_CLASSES as e:
|
||||
content_encoding = self.headers.get("content-encoding", "").lower()
|
||||
raise DecodeError(
|
||||
@ -1,5 +1,5 @@
|
||||
--- a/kubevirt/pyasn1/codec/ber/decoder.py 2019-10-17 07:00:19.000000000 +0200
|
||||
+++ b/kubevirt/pyasn1/codec/ber/decoder.py 2026-01-27 10:43:12.757563432 +0100
|
||||
--- a/kubevirt/lib/python#PYTHON3_VERSION#/site-packages/pyasn1/codec/ber/decoder.py 2019-10-17 07:00:19.000000000 +0200
|
||||
+++ b/kubevirt/lib/python#PYTHON3_VERSION#/site-packages/pyasn1/codec/ber/decoder.py 2026-01-27 10:43:12.757563432 +0100
|
||||
@@ -22,6 +22,10 @@
|
||||
|
||||
noValue = base.noValue
|
||||
@ -16,7 +16,7 @@
|
||||
+
|
||||
|
||||
try:
|
||||
sys.path.insert(0, '/usr/lib/fence-agents/support/aliyun')
|
||||
sys.path.insert(0, '/usr/lib/fence-agents/support/aliyun/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
from aliyunsdkcore import client
|
||||
from aliyunsdkcore.auth.credentials import EcsRamRoleCredential
|
||||
+ from aliyunsdkcore.profile import region_provider
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
From accff72ecc2f6cf5a76d9570198a93ac7c90270e Mon Sep 17 00:00:00 2001
|
||||
From: Quentin Pradet <quentin.pradet@gmail.com>
|
||||
Date: Mon, 17 Jun 2024 11:09:06 +0400
|
||||
Subject: [PATCH] Merge pull request from GHSA-34jh-p97f-mpxf
|
||||
|
||||
* Strip Proxy-Authorization header on redirects
|
||||
|
||||
* Fix test_retry_default_remove_headers_on_redirect
|
||||
|
||||
* Set release date
|
||||
---
|
||||
CHANGES.rst | 5 +++++
|
||||
src/urllib3/util/retry.py | 4 +++-
|
||||
test/test_retry.py | 6 ++++-
|
||||
test/with_dummyserver/test_poolmanager.py | 27 ++++++++++++++++++++---
|
||||
4 files changed, 37 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/aws/urllib3/util/retry.py b/aws/urllib3/util/retry.py
|
||||
index 7a76a4a6ad..0456cceba4 100644
|
||||
--- a/aws/urllib3/util/retry.py
|
||||
+++ b/aws/urllib3/util/retry.py
|
||||
@@ -189,7 +189,9 @@ class Retry:
|
||||
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
|
||||
|
||||
#: Default headers to be used for ``remove_headers_on_redirect``
|
||||
- DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Cookie", "Authorization"])
|
||||
+ DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(
|
||||
+ ["Cookie", "Authorization", "Proxy-Authorization"]
|
||||
+ )
|
||||
|
||||
#: Default maximum backoff time.
|
||||
DEFAULT_BACKOFF_MAX = 120
|
||||
|
||||
diff --git a/azure/urllib3/util/retry.py b/azure/urllib3/util/retry.py
|
||||
index 7a76a4a6ad..0456cceba4 100644
|
||||
--- a/azure/urllib3/util/retry.py
|
||||
+++ b/azure/urllib3/util/retry.py
|
||||
@@ -189,7 +189,9 @@ class Retry:
|
||||
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
|
||||
|
||||
#: Default headers to be used for ``remove_headers_on_redirect``
|
||||
- DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Cookie", "Authorization"])
|
||||
+ DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(
|
||||
+ ["Cookie", "Authorization", "Proxy-Authorization"]
|
||||
+ )
|
||||
|
||||
#: Default maximum backoff time.
|
||||
DEFAULT_BACKOFF_MAX = 120
|
||||
|
||||
diff --git a/google/urllib3/util/retry.py b/google/urllib3/util/retry.py
|
||||
index 7a76a4a6ad..0456cceba4 100644
|
||||
--- a/google/urllib3/util/retry.py
|
||||
+++ b/google/urllib3/util/retry.py
|
||||
@@ -189,7 +189,9 @@ class Retry:
|
||||
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
|
||||
|
||||
#: Default headers to be used for ``remove_headers_on_redirect``
|
||||
- DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Cookie", "Authorization"])
|
||||
+ DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(
|
||||
+ ["Cookie", "Authorization", "Proxy-Authorization"]
|
||||
+ )
|
||||
|
||||
#: Default maximum backoff time.
|
||||
DEFAULT_BACKOFF_MAX = 120
|
||||
@ -5,7 +5,7 @@
|
||||
from fencing import fail_usage
|
||||
|
||||
-import sys
|
||||
-sys.path.insert(0, '/usr/lib/fence-agents/support/azure')
|
||||
-sys.path.insert(0, '/usr/lib/fence-agents/support/azure/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
-
|
||||
FENCE_SUBNET_NAME = "fence-subnet"
|
||||
FENCE_INBOUND_RULE_NAME = "FENCE_DENY_ALL_INBOUND"
|
||||
@ -403,8 +403,8 @@
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import sys, re
|
||||
sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
+sys.path.insert(1, '/usr/lib/fence-agents/support/azure')
|
||||
sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+sys.path.insert(1, '/usr/lib/fence-agents/support/azure/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
try:
|
||||
import pexpect
|
||||
except:
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
--- a/google/pkg_resources/__init__.py 2025-06-12 09:41:54.535219946 +0000
|
||||
+++ b/google/pkg_resources/__init__.py 2025-06-12 09:42:07.508276281 +0000
|
||||
@@ -95,16 +95,6 @@
|
||||
from _typeshed.importlib import LoaderProtocol
|
||||
from typing_extensions import Self, TypeAlias
|
||||
|
||||
-warnings.warn(
|
||||
- "pkg_resources is deprecated as an API. "
|
||||
- "See https://setuptools.pypa.io/en/latest/pkg_resources.html. "
|
||||
- "The pkg_resources package is slated for removal as early as "
|
||||
- "2025-11-30. Refrain from using this package or pin to "
|
||||
- "Setuptools<81.",
|
||||
- UserWarning,
|
||||
- stacklevel=2,
|
||||
-)
|
||||
-
|
||||
_T = TypeVar("_T")
|
||||
_DistributionT = TypeVar("_DistributionT", bound="Distribution")
|
||||
# Type aliases
|
||||
--- a/kubevirt/pkg_resources/__init__.py 2025-06-12 09:41:54.535219946 +0000
|
||||
+++ b/kubevirt/pkg_resources/__init__.py 2025-06-12 09:42:07.508276281 +0000
|
||||
@@ -95,16 +95,6 @@
|
||||
from _typeshed.importlib import LoaderProtocol
|
||||
from typing_extensions import Self, TypeAlias
|
||||
|
||||
-warnings.warn(
|
||||
- "pkg_resources is deprecated as an API. "
|
||||
- "See https://setuptools.pypa.io/en/latest/pkg_resources.html. "
|
||||
- "The pkg_resources package is slated for removal as early as "
|
||||
- "2025-11-30. Refrain from using this package or pin to "
|
||||
- "Setuptools<81.",
|
||||
- UserWarning,
|
||||
- stacklevel=2,
|
||||
-)
|
||||
-
|
||||
_T = TypeVar("_T")
|
||||
_DistributionT = TypeVar("_DistributionT", bound="Distribution")
|
||||
# Type aliases
|
||||
@ -6,7 +6,7 @@ diff --color -uNr a/agents/azure_arm/fence_azure_arm.py b/agents/azure_arm/fence
|
||||
|
||||
-import sys, re, pexpect
|
||||
+import sys, re
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+try:
|
||||
+ import pexpect
|
||||
+except:
|
||||
@ -22,7 +22,7 @@ diff --color -uNr a/agents/hpblade/fence_hpblade.py b/agents/hpblade/fence_hpbla
|
||||
|
||||
import sys, re
|
||||
-import pexpect
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+try:
|
||||
+ import pexpect
|
||||
+except:
|
||||
@ -39,7 +39,7 @@ diff --color -uNr a/agents/ilo/fence_ilo.py b/agents/ilo/fence_ilo.py
|
||||
|
||||
-import sys, re, pexpect
|
||||
+import sys, re
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+try:
|
||||
+ import pexpect
|
||||
+except:
|
||||
@ -56,7 +56,7 @@ diff --color -uNr a/agents/ldom/fence_ldom.py b/agents/ldom/fence_ldom.py
|
||||
|
||||
-import sys, re, pexpect
|
||||
+import sys, re
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+try:
|
||||
+ import pexpect
|
||||
+except:
|
||||
@ -72,11 +72,11 @@ diff --color -uNr a/agents/Makefile.am b/agents/Makefile.am
|
||||
$(eval INPUT=$(subst .delay-check,,$@))
|
||||
FENCE_TEST_ARGS_CISCO_MDS=$$(printf '$(FENCE_TEST_ARGS)' | sed 's#port=1#port=fc1/1#'); \
|
||||
- test `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib /usr/bin/time -p \
|
||||
+ test `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common /usr/bin/time -p \
|
||||
+ test `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages /usr/bin/time -p \
|
||||
sh -c "printf 'delay=10\n $$FENCE_TEST_ARGS_CISCO_MDS' | $(PYTHON) ./$(INPUT)" 2>&1 |\
|
||||
awk -F"[. ]" -vOFS= '/real/ {print $$2,$$3}'` -ge 1000 || ( \
|
||||
- PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib /usr/bin/time -p \
|
||||
+ PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common /usr/bin/time -p \
|
||||
+ PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages /usr/bin/time -p \
|
||||
sh -c "printf "delay=0\n $$FENCE_TEST_ARGS_CISCO_MDS" | $(PYTHON) ./$(INPUT)"; false )
|
||||
|
||||
include $(top_srcdir)/make/fencebuild.mk
|
||||
@ -88,7 +88,7 @@ diff --color -uNr a/agents/netio/fence_netio.py b/agents/netio/fence_netio.py
|
||||
|
||||
-import sys, re, pexpect
|
||||
+import sys, re
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+try:
|
||||
+ import pexpect
|
||||
+except:
|
||||
@ -104,7 +104,7 @@ diff --color -uNr a/agents/raritan/fence_raritan.py b/agents/raritan/fence_rarit
|
||||
|
||||
-import sys, re, pexpect
|
||||
+import sys, re
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+try:
|
||||
+ import pexpect
|
||||
+except:
|
||||
@ -121,7 +121,7 @@ diff --color -uNr a/agents/sanbox2/fence_sanbox2.py b/agents/sanbox2/fence_sanbo
|
||||
|
||||
-import sys, re, pexpect
|
||||
+import sys, re
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+try:
|
||||
+ import pexpect
|
||||
+except:
|
||||
@ -138,7 +138,7 @@ diff --color -uNr a/agents/vmware/fence_vmware.py b/agents/vmware/fence_vmware.p
|
||||
|
||||
-import sys, re, pexpect
|
||||
+import sys, re
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+try:
|
||||
+ import pexpect
|
||||
+except:
|
||||
@ -155,7 +155,7 @@ diff --color -uNr a/agents/wti/fence_wti.py b/agents/wti/fence_wti.py
|
||||
|
||||
-import sys, re, pexpect
|
||||
+import sys, re
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+try:
|
||||
+ import pexpect
|
||||
+except:
|
||||
@ -181,7 +181,7 @@ diff --color -uNr a/lib/fencing.py.py b/lib/fencing.py.py
|
||||
|
||||
import sys, getopt, time, os, uuid, pycurl, stat
|
||||
-import pexpect, re, syslog
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+try:
|
||||
+ import pexpect
|
||||
+except:
|
||||
@ -255,7 +255,7 @@ diff --color -uNr a/lib/fencing_snmp.py.py b/lib/fencing_snmp.py.py
|
||||
|
||||
-import re, pexpect
|
||||
+import sys
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+try:
|
||||
+ import pexpect
|
||||
+except:
|
||||
@ -272,10 +272,10 @@ diff --color -uNr a/make/agentpycheck.mk b/make/agentpycheck.mk
|
||||
%.xml-check: %.8
|
||||
$(eval INPUT=$(subst .xml-check,,$(@F)))
|
||||
- for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
+ for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
+ for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
TEMPFILE=$$(mktemp); \
|
||||
- PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$$x -o metadata | $(AWK) $(AWK_VAL) > $$TEMPFILE && \
|
||||
+ PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common $(PYTHON) $(@D)/$$x -o metadata | $(AWK) $(AWK_VAL) > $$TEMPFILE && \
|
||||
+ PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages $(PYTHON) $(@D)/$$x -o metadata | $(AWK) $(AWK_VAL) > $$TEMPFILE && \
|
||||
diff $$TEMPFILE $(DATADIR)/$$x.xml || exit 1 && \
|
||||
rm $$TEMPFILE; \
|
||||
done
|
||||
@ -284,8 +284,8 @@ diff --color -uNr a/make/agentpycheck.mk b/make/agentpycheck.mk
|
||||
$(eval INPUT=$(subst .xml-upload,,$(@F)))
|
||||
- for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
- PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$$x -o metadata | $(AWK) $(AWK_VAL) > $(DATADIR)/$$x.xml; \
|
||||
+ for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
+ PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common $(PYTHON) $(@D)/$$x -o metadata | $(AWK) $(AWK_VAL) > $(DATADIR)/$$x.xml; \
|
||||
+ for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
+ PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages $(PYTHON) $(@D)/$$x -o metadata | $(AWK) $(AWK_VAL) > $(DATADIR)/$$x.xml; \
|
||||
done
|
||||
|
||||
# If test will fail, rerun fence agents to show problems
|
||||
@ -293,12 +293,12 @@ diff --color -uNr a/make/agentpycheck.mk b/make/agentpycheck.mk
|
||||
$(eval INPUT=$(subst .delay-check,,$(@F)))
|
||||
- for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
- test `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib /usr/bin/time -p \
|
||||
+ for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
+ test `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common /usr/bin/time -p \
|
||||
+ for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
+ test `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages /usr/bin/time -p \
|
||||
sh -c "printf 'delay=10\n $(FENCE_TEST_ARGS)' | $(PYTHON) $(@D)/$$x" 2>&1 |\
|
||||
awk -F"[. ]" -vOFS= '/real/ {print $$2,$$3}'` -ge 1000 || ( \
|
||||
- PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib /usr/bin/time -p \
|
||||
+ PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common /usr/bin/time -p \
|
||||
+ PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages /usr/bin/time -p \
|
||||
sh -c "printf 'delay=0\n $(FENCE_TEST_ARGS)' | $(PYTHON) $(@D)/$$x"; false ); \
|
||||
done
|
||||
|
||||
@ -306,8 +306,8 @@ diff --color -uNr a/make/agentpycheck.mk b/make/agentpycheck.mk
|
||||
$(eval INPUT=$(subst .rng-check,,$(@F)))
|
||||
- for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
- PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@D)/$$x -o metadata | \
|
||||
+ for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
+ PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common $(PYTHON) $(@D)/$$x -o metadata | \
|
||||
+ for x in $(INPUT) `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages $(PYTHON) $(@D)/$(INPUT) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
+ PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages $(PYTHON) $(@D)/$$x -o metadata | \
|
||||
xsltproc ${abs_top_srcdir}/lib/fence2rng.xsl - | \
|
||||
sed -e 's/ rha:description=/ description=/g' -e 's/ rha:name=/ name=/g' | \
|
||||
xmllint --nsclean --noout -; \
|
||||
@ -319,11 +319,11 @@ diff --color -uNr a/make/fencebuild.mk b/make/fencebuild.mk
|
||||
|
||||
if [ 0 -eq `echo "$(@)" | grep fence_ > /dev/null 2>&1; echo $$?` ]; then \
|
||||
- PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(top_srcdir)/lib/check_used_options.py $@; \
|
||||
+ PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common $(PYTHON) $(top_srcdir)/lib/check_used_options.py $@; \
|
||||
+ PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages $(PYTHON) $(top_srcdir)/lib/check_used_options.py $@; \
|
||||
else true ; fi
|
||||
|
||||
- for x in `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(@) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
+for x in `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common $(PYTHON) $(@) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
+for x in `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages $(PYTHON) $(@) -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
cp -f $(@) $(@D)/$$x; \
|
||||
$(MAKE) $(@D)/$$x.8; \
|
||||
done
|
||||
@ -332,7 +332,7 @@ diff --color -uNr a/make/fencebuild.mk b/make/fencebuild.mk
|
||||
for p in $(TARGET); do \
|
||||
dir=`dirname $$p`; \
|
||||
- for x in `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $$p -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
+ for x in `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common $(PYTHON) $$p -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
+ for x in `PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages $(PYTHON) $$p -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"`; do \
|
||||
echo " $(INSTALL_SCRIPT) $$dir/$$x '$(DESTDIR)$(sbindir)'"; \
|
||||
$(INSTALL_SCRIPT) $$dir/$$x "$(DESTDIR)$(sbindir)" || exit $$?; \
|
||||
echo " $(INSTALL_DATA) '$$dir/$$x.8' '$(DESTDIR)$(man8dir)'"; \
|
||||
@ -341,7 +341,7 @@ diff --color -uNr a/make/fencebuild.mk b/make/fencebuild.mk
|
||||
uninstall-hook: $(TARGET)
|
||||
files=`for p in $(TARGET); do \
|
||||
- for x in \`PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $$p -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"\`; do \
|
||||
+ for x in \`PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common $(PYTHON) $$p -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"\`; do \
|
||||
+ for x in \`PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages $(PYTHON) $$p -o metadata | grep symlink | sed -e "s/.*\(fence.*\)\" .*/\1/g"\`; do \
|
||||
echo " rm -f '$(DESTDIR)$(sbindir)/$$x'"; \
|
||||
rm -f "$(DESTDIR)$(sbindir)/$$x"; \
|
||||
echo " rm -f '$(DESTDIR)$(man8dir)/$$x.8'"; \
|
||||
@ -352,7 +352,7 @@ diff --color -uNr a/make/fenceman.mk b/make/fenceman.mk
|
||||
%.8: % $(top_srcdir)/lib/fence2man.xsl
|
||||
set -e && \
|
||||
- PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/../lib:$(abs_builddir)/lib \
|
||||
+ PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/../lib:$(abs_builddir)/lib:$(abs_top_builddir)/support/common \
|
||||
+ PYTHONPATH=$(abs_srcdir)/lib:$(abs_builddir)/../lib:$(abs_builddir)/lib:$(abs_top_builddir)/support/common/lib/python#PYTHON3_VERSION#/site-packages \
|
||||
$(PYTHON) $* -o manpage > $(@D)/.$(@F).tmp && \
|
||||
xmllint --noout --relaxng $(top_srcdir)/lib/metadata.rng $(@D)/.$(@F).tmp && \
|
||||
xsltproc $(top_srcdir)/lib/fence2man.xsl $(@D)/.$(@F).tmp > $@
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
#!@PYTHON@ -tt
|
||||
|
||||
import sys
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common')
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
import shutil, tempfile, suds
|
||||
import logging, requests
|
||||
import atexit, signal
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
--- fence-agents-4.10.0/agents/kubevirt/fence_kubevirt.py 2021-07-08 13:09:05.000000000 +0200
|
||||
+++ /home/oalbrigt/rhpkg/fence-agents-8.6/fence-agents-4.2.1/agents/kubevirt/fence_kubevirt.py 2021-11-02 15:35:46.217440426 +0100
|
||||
@@ -2,24 +2,25 @@
|
||||
--- a/agents/kubevirt/fence_kubevirt.py 2026-04-14 15:49:53.368718050 +0200
|
||||
+++ b/agents/kubevirt/fence_kubevirt.py 2026-04-14 15:51:18.996925630 +0200
|
||||
@@ -2,24 +2,26 @@
|
||||
|
||||
import sys
|
||||
import logging
|
||||
@ -11,7 +11,8 @@
|
||||
+from fencing import fail, fail_usage, run_delay, EC_STATUS, EC_FETCH_VM_UUID
|
||||
|
||||
try:
|
||||
+ sys.path.insert(0, '/usr/lib/fence-agents/support/kubevirt')
|
||||
+ sys.path.insert(0, '/usr/lib/fence-agents/support/kubevirt/lib64/python#PYTHON3_VERSION#/site-packages')
|
||||
+ sys.path.insert(1, '/usr/lib/fence-agents/support/kubevirt/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
from kubernetes.client.exceptions import ApiException
|
||||
except ImportError:
|
||||
logging.error("Couldn\'t import kubernetes.client.exceptions.ApiException - not found or not accessible")
|
||||
@ -30,7 +31,7 @@
|
||||
vm_list = vm_api.get(namespace=namespace)
|
||||
for vm in vm_list.items:
|
||||
result[vm.metadata.name] = ("", None)
|
||||
@@ -30,18 +31,21 @@
|
||||
@@ -30,18 +32,21 @@
|
||||
def get_power_status(conn, options):
|
||||
logging.debug("Starting get status operation")
|
||||
try:
|
||||
@ -58,7 +59,7 @@
|
||||
return "off"
|
||||
logging.error("Failed to get power status, with API Exception: %s", e)
|
||||
fail(EC_STATUS)
|
||||
@@ -49,38 +53,53 @@
|
||||
@@ -49,38 +54,53 @@
|
||||
logging.error("Failed to get power status, with Exception: %s", e)
|
||||
fail(EC_STATUS)
|
||||
|
||||
@ -131,7 +132,7 @@
|
||||
return conn.request('put', path, header_params={'accept': '*/*'})
|
||||
|
||||
def validate_options(required_options_list, options):
|
||||
@@ -92,8 +111,13 @@
|
||||
@@ -92,8 +112,13 @@
|
||||
def main():
|
||||
conn = None
|
||||
|
||||
@ -146,7 +147,7 @@
|
||||
options = check_input(device_opt, process_input(device_opt))
|
||||
|
||||
docs = {}
|
||||
@@ -106,6 +130,11 @@
|
||||
@@ -106,6 +131,11 @@
|
||||
|
||||
validate_options(['--namespace'], options)
|
||||
|
||||
|
||||
@ -22,8 +22,8 @@
|
||||
-from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action
|
||||
+from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action, run_command
|
||||
try:
|
||||
sys.path.insert(0, '/usr/lib/fence-agents/support/google')
|
||||
import httplib2
|
||||
sys.path.insert(0, '/usr/lib/fence-agents/support/google/lib64/python#PYTHON3_VERSION#/site-packages')
|
||||
sys.path.insert(1, '/usr/lib/fence-agents/support/google/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
@@ -42,6 +42,19 @@
|
||||
|
||||
METADATA_SERVER = 'http://metadata.google.internal/computeMetadata/v1/'
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
--- a/kubevirt/dateutil/zoneinfo/rebuild.py 2023-01-26 16:29:30.000000000 +0100
|
||||
+++ b/kubevirt/dateutil/zoneinfo/rebuild.py 2023-07-19 10:12:42.277559948 +0200
|
||||
--- a/kubevirt/lib/python#PYTHON3_VERSION#/site-packages/dateutil/zoneinfo/rebuild.py 2023-01-26 16:29:30.000000000 +0100
|
||||
+++ b/kubevirt/lib/python#PYTHON3_VERSION#/site-packages/dateutil/zoneinfo/rebuild.py 2023-07-19 10:12:42.277559948 +0200
|
||||
@@ -21,7 +21,12 @@
|
||||
try:
|
||||
with TarFile.open(filename) as tf:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
--- a/aws/dateutil/zoneinfo/rebuild.py 2023-01-26 16:29:30.000000000 +0100
|
||||
+++ b/aws/dateutil/zoneinfo/rebuild.py 2023-07-19 10:12:42.277559948 +0200
|
||||
--- a/aws/lib/python#PYTHON3_VERSION#/site-packages/dateutil/zoneinfo/rebuild.py 2023-01-26 16:29:30.000000000 +0100
|
||||
+++ b/aws/lib/python#PYTHON3_VERSION#/site-packages/dateutil/zoneinfo/rebuild.py 2023-07-19 10:12:42.277559948 +0200
|
||||
@@ -21,7 +21,12 @@
|
||||
try:
|
||||
with TarFile.open(filename) as tf:
|
||||
@ -15,8 +15,8 @@
|
||||
|
||||
_run_zic(zonedir, filepaths)
|
||||
|
||||
--- a/azure/dateutil/zoneinfo/rebuild.py 2023-01-26 16:29:30.000000000 +0100
|
||||
+++ b/azure/dateutil/zoneinfo/rebuild.py 2023-07-19 10:12:42.277559948 +0200
|
||||
--- a/azure/lib/python#PYTHON3_VERSION#/site-packages/dateutil/zoneinfo/rebuild.py 2023-01-26 16:29:30.000000000 +0100
|
||||
+++ b/azure/lib/python#PYTHON3_VERSION#/site-packages/dateutil/zoneinfo/rebuild.py 2023-07-19 10:12:42.277559948 +0200
|
||||
@@ -21,7 +21,12 @@
|
||||
try:
|
||||
with TarFile.open(filename) as tf:
|
||||
|
||||
@ -31,24 +31,14 @@
|
||||
%global dateutil_version 2.8.1
|
||||
%global pyyaml PyYAML
|
||||
%global pyyaml_version 5.1
|
||||
%global six six
|
||||
%global six_version 1.16.0
|
||||
%global urllib3 urllib3
|
||||
%global urllib3_version 1.26.18
|
||||
%global websocketclient websocket-client
|
||||
%global websocketclient_version 1.2.1
|
||||
%global websocketclient websocket_client
|
||||
%global websocketclient_version 1.9.0
|
||||
%global jinja2 jinja2
|
||||
%global jinja2_version 3.1.6
|
||||
%global markupsafe MarkupSafe
|
||||
%global markupsafe_version 2.0.1
|
||||
%global stringutils string-utils
|
||||
%global stringutils_version 1.0.0
|
||||
%global requests requests
|
||||
%global requests_version 2.26.0
|
||||
%global chrstnormalizer charset-normalizer
|
||||
%global chrstnormalizer_version 2.0.7
|
||||
%global idna idna
|
||||
%global idna_version 3.3
|
||||
%global reqstsoauthlib requests-oauthlib
|
||||
%global reqstsoauthlib_version 1.3.0
|
||||
%global ruamelyaml ruamel.yaml
|
||||
@ -57,7 +47,7 @@
|
||||
Name: fence-agents
|
||||
Summary: Set of unified programs capable of host isolation ("fencing")
|
||||
Version: 4.10.0
|
||||
Release: 110%{?alphatag:.%{alphatag}}%{?dist}
|
||||
Release: 111%{?alphatag:.%{alphatag}}%{?dist}
|
||||
License: GPLv2+ and LGPLv2+
|
||||
URL: https://github.com/ClusterLabs/fence-agents
|
||||
Source0: https://fedorahosted.org/releases/f/e/fence-agents/%{name}-%{version}.tar.gz
|
||||
@ -69,117 +59,89 @@ Source103: requirements-azure.txt
|
||||
Source104: requirements-google.txt
|
||||
Source105: requirements-ibm.txt
|
||||
### HA support libs/utils ###
|
||||
# update with ./update-ha-support.sh and replace lines below with output
|
||||
### BEGIN ###
|
||||
# aliyun
|
||||
Source1000: aliyun-python-sdk-core-2.11.5.tar.gz
|
||||
Source1001: aliyun_python_sdk_ecs-4.24.7-py2.py3-none-any.whl
|
||||
Source1002: cffi-1.14.5-cp39-cp39-manylinux1_x86_64.whl
|
||||
Source1003: colorama-0.3.3.tar.gz
|
||||
Source1004: jmespath-0.7.1-py2.py3-none-any.whl
|
||||
Source1005: pycryptodome-3.20.0.tar.gz
|
||||
Source1006: pycparser-2.20-py2.py3-none-any.whl
|
||||
# common (pexpect / suds)
|
||||
Source1000: pexpect-4.8.0-py2.py3-none-any.whl
|
||||
Source1001: ptyprocess-0.7.0-py2.py3-none-any.whl
|
||||
Source1002: suds_community-0.8.5-py3-none-any.whl
|
||||
Source1100: aliyun-python-sdk-core-2.16.0.tar.gz
|
||||
Source1101: aliyun-python-sdk-ecs-4.24.82.tar.gz
|
||||
Source1102: colorama-0.3.3.tar.gz
|
||||
Source1103: jmespath-0.10.0.tar.gz
|
||||
# aliyun-cli
|
||||
Source2000: aliyun-cli-3.0.198.tar.gz
|
||||
Source1200: aliyun-cli-3.0.198.tar.gz
|
||||
## TAG=$(git log --pretty="format:%h" -n 1)
|
||||
## distdir="aliyun-openapi-meta-${TAG}"
|
||||
## TARFILE="${distdir}.tar.gz"
|
||||
## rm -rf $TARFILE $distdir
|
||||
## git archive --prefix=$distdir/ HEAD | gzip > $TARFILE
|
||||
Source2001: aliyun-openapi-meta-5cf98b660.tar.gz
|
||||
Source1201: aliyun-openapi-meta-5cf98b660.tar.gz
|
||||
## go mod vendor
|
||||
Source2002: aliyun-cli-go-vendor.tar.gz
|
||||
Source1202: aliyun-cli-go-vendor.tar.gz
|
||||
# aws
|
||||
Source1007: boto3-1.40.13.tar.gz
|
||||
Source1008: botocore-1.40.13.tar.gz
|
||||
Source1009: python_%{dateutil}-%{dateutil_version}-py2.py3-none-any.whl
|
||||
Source1010: s3transfer-0.13.1.tar.gz
|
||||
Source1011: %{urllib3}-%{urllib3_version}.tar.gz
|
||||
Source1300: boto3-1.40.13.tar.gz
|
||||
Source1301: botocore-1.40.13.tar.gz
|
||||
Source1302: python_%{dateutil}-%{dateutil_version}-py2.py3-none-any.whl
|
||||
Source1303: s3transfer-0.13.1.tar.gz
|
||||
# azure
|
||||
Source1012: adal-1.2.7.tar.gz
|
||||
Source1013: azure-common-1.1.28.zip
|
||||
Source1014: azure_core-1.32.0.tar.gz
|
||||
Source1015: azure_mgmt_compute-34.0.0.tar.gz
|
||||
Source1016: azure_mgmt_core-1.5.0.tar.gz
|
||||
Source1017: azure_mgmt_network-28.1.0.tar.gz
|
||||
Source1018: azure_identity-1.19.0.tar.gz
|
||||
Source1019: chardet-4.0.0-py2.py3-none-any.whl
|
||||
Source1020: isodate-0.6.1.tar.gz
|
||||
Source1021: msrest-0.7.1.zip
|
||||
Source1022: msrestazure-0.6.4.post1.tar.gz
|
||||
Source1023: %{oauthlib}-%{oauthlib_version}.tar.gz
|
||||
Source1024: PyJWT-2.1.0-py3-none-any.whl
|
||||
Source1025: requests_oauthlib-1.3.0-py2.py3-none-any.whl
|
||||
Source1026: msal-1.31.1.tar.gz
|
||||
Source1027: msal_extensions-1.2.0.tar.gz
|
||||
Source1028: portalocker-2.5.1.tar.gz
|
||||
Source1029: cryptography-3.3.2-cp36-abi3-manylinux2010_x86_64.whl
|
||||
Source1030: typing_extensions-4.12.2.tar.gz
|
||||
Source1400: adal-1.2.7.tar.gz
|
||||
Source1401: azure-common-1.1.28.zip
|
||||
Source1402: azure_core-1.32.0.tar.gz
|
||||
Source1403: azure_mgmt_core-1.5.0.tar.gz
|
||||
Source1404: azure_mgmt_compute-34.0.0.tar.gz
|
||||
Source1405: azure_mgmt_network-28.1.0.tar.gz
|
||||
Source1406: azure_identity-1.25.3.tar.gz
|
||||
Source1407: isodate-0.6.1.tar.gz
|
||||
Source1408: msrest-0.7.1.zip
|
||||
Source1409: msrestazure-0.6.4.post1.tar.gz
|
||||
Source1410: %{oauthlib}-%{oauthlib_version}.tar.gz
|
||||
Source1411: pyjwt-2.12.1.tar.gz
|
||||
Source1412: requests_oauthlib-1.3.0-py2.py3-none-any.whl
|
||||
Source1413: msal-1.36.0.tar.gz
|
||||
Source1414: msal_extensions-1.3.1.tar.gz
|
||||
Source1415: portalocker-2.5.1.tar.gz
|
||||
Source1416: typing_extensions-4.12.2.tar.gz
|
||||
# google
|
||||
Source1031: cachetools-4.2.2-py3-none-any.whl
|
||||
Source1032: chardet-3.0.4-py2.py3-none-any.whl
|
||||
Source1033: google_api_core-1.30.0-py2.py3-none-any.whl
|
||||
Source1034: google_api_python_client-1.12.8-py2.py3-none-any.whl
|
||||
Source1035: googleapis_common_protos-1.53.0-py2.py3-none-any.whl
|
||||
Source1036: google_auth-1.32.0-py2.py3-none-any.whl
|
||||
Source1037: google_auth_httplib2-0.1.0-py2.py3-none-any.whl
|
||||
Source1038: httplib2-0.19.1-py3-none-any.whl
|
||||
Source1039: packaging-20.9-py2.py3-none-any.whl
|
||||
Source1040: protobuf-3.17.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl
|
||||
Source1041: pyasn1-0.4.8-py2.py3-none-any.whl
|
||||
Source1042: pyasn1_modules-0.2.8-py2.py3-none-any.whl
|
||||
Source1043: pyparsing-2.4.7-py2.py3-none-any.whl
|
||||
Source1044: pyroute2-0.7.12.tar.gz
|
||||
Source1045: pyroute2.core-0.6.13.tar.gz
|
||||
Source1046: pyroute2.ethtool-0.6.13.tar.gz
|
||||
Source1047: pyroute2.ipdb-0.6.13.tar.gz
|
||||
Source1048: pyroute2.ipset-0.6.13.tar.gz
|
||||
Source1049: pyroute2.ndb-0.6.13.tar.gz
|
||||
Source1050: pyroute2.nftables-0.6.13.tar.gz
|
||||
Source1051: pyroute2.nslink-0.6.13.tar.gz
|
||||
Source1052: pytz-2021.1-py2.py3-none-any.whl
|
||||
Source1053: rsa-4.7.2-py3-none-any.whl
|
||||
Source1054: setuptools-80.9.0.tar.gz
|
||||
Source1055: uritemplate-3.0.1-py2.py3-none-any.whl
|
||||
# common (pexpect / suds)
|
||||
Source1056: pexpect-4.8.0-py2.py3-none-any.whl
|
||||
Source1057: ptyprocess-0.7.0-py2.py3-none-any.whl
|
||||
Source1058: suds_community-0.8.5-py3-none-any.whl
|
||||
### END ###
|
||||
Source1500: %{cachetools}-%{cachetools_version}.tar.gz
|
||||
Source1501: google_api_core-1.30.0-py2.py3-none-any.whl
|
||||
Source1502: google_api_python_client-1.12.8-py2.py3-none-any.whl
|
||||
Source1503: googleapis_common_protos-1.53.0-py2.py3-none-any.whl
|
||||
Source1504: google_auth-1.32.0-py2.py3-none-any.whl
|
||||
Source1505: google_auth_httplib2-0.1.0-py2.py3-none-any.whl
|
||||
Source1506: httplib2-0.19.1-py3-none-any.whl
|
||||
Source1507: protobuf-3.17.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl
|
||||
Source1508: pyasn1-0.4.8-py2.py3-none-any.whl
|
||||
Source1509: pyasn1_modules-0.2.8-py2.py3-none-any.whl
|
||||
Source1510: pyroute2-0.7.12.tar.gz
|
||||
Source1511: pytz-2021.1-py2.py3-none-any.whl
|
||||
Source1512: rsa-4.7.2-py3-none-any.whl
|
||||
Source1513: uritemplate-3.0.1-py2.py3-none-any.whl
|
||||
# kubevirt
|
||||
## pip download --no-binary :all: openshift "ruamel.yaml.clib>=0.1.2"
|
||||
### BEGIN
|
||||
Source1060: %{openshift}-%{openshift_version}.tar.gz
|
||||
Source1061: %{ruamelyamlclib}-%{ruamelyamlclib_version}.tar.gz
|
||||
Source1062: %{kubernetes}-%{kubernetes_version}.tar.gz
|
||||
Source1063: %{certifi}-%{certifi_version}.tar.gz
|
||||
Source1064: %{googleauth}-%{googleauth_version}.tar.gz
|
||||
Source1065: %{cachetools}-%{cachetools_version}.tar.gz
|
||||
Source1066: %{pyasn1modules}-%{pyasn1modules_version}.tar.gz
|
||||
Source1067: %{pyasn1}-%{pyasn1_version}.tar.gz
|
||||
Source1068: %{pyyaml}-%{pyyaml_version}.tar.gz
|
||||
Source1600: %{openshift}-%{openshift_version}.tar.gz
|
||||
Source1601: %{ruamelyamlclib}-%{ruamelyamlclib_version}.tar.gz
|
||||
Source1602: %{kubernetes}-%{kubernetes_version}.tar.gz
|
||||
Source1603: %{certifi}-%{certifi_version}.tar.gz
|
||||
Source1604: %{googleauth}-%{googleauth_version}.tar.gz
|
||||
Source1605: %{pyasn1modules}-%{pyasn1modules_version}.tar.gz
|
||||
Source1606: %{pyasn1}-%{pyasn1_version}.tar.gz
|
||||
Source1607: %{pyyaml}-%{pyyaml_version}.tar.gz
|
||||
## rsa is dependency for "pip install",
|
||||
## but gets removed to use cryptography lib instead
|
||||
Source1069: rsa-4.7.2.tar.gz
|
||||
Source1070: %{six}-%{six_version}.tar.gz
|
||||
Source1071: %{websocketclient}-%{websocketclient_version}.tar.gz
|
||||
Source1072: %{jinja2}-%{jinja2_version}.tar.gz
|
||||
Source1073: %{markupsafe}-%{markupsafe_version}.tar.gz
|
||||
Source1074: python-%{stringutils}-%{stringutils_version}.tar.gz
|
||||
Source1075: %{requests}-%{requests_version}.tar.gz
|
||||
Source1076: %{chrstnormalizer}-%{chrstnormalizer_version}.tar.gz
|
||||
Source1077: %{idna}-%{idna_version}.tar.gz
|
||||
Source1078: %{reqstsoauthlib}-%{reqstsoauthlib_version}.tar.gz
|
||||
Source1079: %{ruamelyaml}-%{ruamelyaml_version}.tar.gz
|
||||
Source1608: %{websocketclient}-%{websocketclient_version}.tar.gz
|
||||
Source1609: %{jinja2}-%{jinja2_version}.tar.gz
|
||||
Source1610: %{markupsafe}-%{markupsafe_version}.tar.gz
|
||||
Source1611: python-%{stringutils}-%{stringutils_version}.tar.gz
|
||||
Source1612: %{reqstsoauthlib}-%{reqstsoauthlib_version}.tar.gz
|
||||
Source1613: %{ruamelyaml}-%{ruamelyaml_version}.tar.gz
|
||||
## required for installation
|
||||
Source1080: setuptools_scm-8.1.0.tar.gz
|
||||
Source1081: packaging-21.2-py3-none-any.whl
|
||||
Source1082: poetry-core-1.0.7.tar.gz
|
||||
Source1083: pyparsing-3.0.1.tar.gz
|
||||
Source1084: tomli-2.0.1.tar.gz
|
||||
Source1085: flit_core-3.9.0.tar.gz
|
||||
Source1086: wheel-0.37.0-py2.py3-none-any.whl
|
||||
### END
|
||||
Source1900: setuptools_scm-8.1.0.tar.gz
|
||||
Source1901: packaging-26.0.tar.gz
|
||||
Source1902: tomli-2.0.1.tar.gz
|
||||
Source1903: flit_core-3.12.0.tar.gz
|
||||
Source1904: pip-26.0.1.tar.gz
|
||||
Source1905: setuptools-82.0.1.tar.gz
|
||||
Source1906: wheel-0.46.3.tar.gz
|
||||
|
||||
Patch0: ha-cloud-support-aliyun.patch
|
||||
Patch1: ha-cloud-support-aws.patch
|
||||
@ -262,24 +224,10 @@ Patch76: RHEL-145088-fence_ibm_vpc-fix-missing-statuses.patch
|
||||
### HA support libs/utils ###
|
||||
# all archs
|
||||
Patch1000: bz2217902-1-kubevirt-fix-bundled-dateutil-CVE-2007-4559.patch
|
||||
Patch1001: RHEL-146344-kubevirt-1-fix-bundled-urllib3-CVE-2024-37891.patch
|
||||
Patch1002: RHEL-146344-kubevirt-2-fix-bundled-urllib3-CVE-2025-66418.patch
|
||||
Patch1003: RHEL-146344-kubevirt-3-fix-bundled-urllib3-CVE-2025-66471.patch
|
||||
Patch1004: RHEL-146344-kubevirt-4-RHEL-146282-fix-bundled-urllib3-CVE-2026-21441.patch
|
||||
Patch1005: RHEL-146344-kubevirt-5-fix-bundled-pyasn1-CVE-2026-23490.patch
|
||||
Patch1001: RHEL-146344-kubevirt-fix-bundled-pyasn1-CVE-2026-23490.patch
|
||||
# cloud (x86_64 only)
|
||||
Patch2000: bz2217902-2-aws-azure-fix-bundled-dateutil-CVE-2007-4559.patch
|
||||
Patch2001: RHEL-43562-fix-bundled-urllib3-CVE-2024-37891.patch
|
||||
Patch2002: RHEL-95901-pkg_resources-suppress-UserWarning.patch
|
||||
Patch2003: RHEL-136069-fix-bundled-urllib3-CVE-2025-66418.patch
|
||||
Patch2004: RHEL-139799-fix-bundled-urllib3-CVE-2025-66471.patch
|
||||
Patch2005: RHEL-140796-RHEL-146282-fix-bundled-urllib3-CVE-2026-21441.patch
|
||||
Patch2006: RHEL-142460-fix-bundled-pyasn1-CVE-2026-23490.patch
|
||||
# cloud (ppc64le only)
|
||||
Patch3000: RHEL-146344-ibm-1-fix-bundled-urllib3-CVE-2024-37891.patch
|
||||
Patch3001: RHEL-146344-ibm-2-fix-bundled-urllib3-CVE-2025-66418.patch
|
||||
Patch3002: RHEL-146344-ibm-3-fix-bundled-urllib3-CVE-2025-66471.patch
|
||||
Patch3003: RHEL-146344-ibm-4-RHEL-146282-fix-bundled-urllib3-CVE-2026-21441.patch
|
||||
Patch2001: RHEL-142460-fix-bundled-pyasn1-CVE-2026-23490.patch
|
||||
|
||||
%global supportedagents amt_ws apc apc_snmp bladecenter brocade cisco_mds cisco_ucs compute drac5 eaton_snmp emerson eps evacuate hpblade ibmblade ibm_powervs ibm_vpc ifmib ilo ilo_moonshot ilo_mp ilo_ssh intelmodular ipdu ipmilan kdump kubevirt lpar mpath nutanix_ahv redfish rhevm rsa rsb sbd scsi vmware_rest vmware_soap wti
|
||||
%ifarch x86_64
|
||||
@ -350,7 +298,7 @@ BuildRequires: gcc
|
||||
BuildRequires: libxslt
|
||||
## Python dependencies
|
||||
%if 0%{?fedora} || 0%{?centos} > 7 || 0%{?rhel} > 7 || 0%{?suse_version}
|
||||
BuildRequires: python3-devel
|
||||
BuildRequires: python3-devel python3-cryptography
|
||||
# dependencies for building HA support subpackages
|
||||
BuildRequires: python3-pip python3-wheel
|
||||
%ifarch x86_64
|
||||
@ -481,12 +429,12 @@ sed -i.orig 's|FENCE_ZVM=1|FENCE_ZVM=0|' configure.ac
|
||||
|
||||
# aliyun-cli
|
||||
%ifarch x86_64
|
||||
tar zxf %SOURCE2000
|
||||
tar zxf %SOURCE1200
|
||||
pushd aliyun-cli-*
|
||||
git init
|
||||
rmdir aliyun-openapi-meta
|
||||
tar zxf %SOURCE2001
|
||||
tar zxf %SOURCE2002
|
||||
tar zxf %SOURCE1201
|
||||
tar zxf %SOURCE1202
|
||||
mv aliyun-openapi-meta-* aliyun-openapi-meta
|
||||
%define aliyun_cli_version 3.0.198
|
||||
# based on https://github.com/containers/podman/blob/main/rpm/podman.spec
|
||||
@ -498,6 +446,9 @@ popd
|
||||
%endif
|
||||
|
||||
# support libs
|
||||
%{__python3} -m pip install --no-build-isolation --user --upgrade --no-index --find-links %{_sourcedir} flit-core
|
||||
%{__python3} -m pip install --no-build-isolation --user --upgrade --no-index --find-links %{_sourcedir} packaging
|
||||
%{__python3} -m pip install --no-build-isolation --user --upgrade --no-index --find-links %{_sourcedir} pip setuptools wheel
|
||||
%ifarch x86_64
|
||||
LIBS="%{_sourcedir}/requirements-*.txt"
|
||||
%endif
|
||||
@ -509,47 +460,40 @@ LIBS="%{_sourcedir}/requirements-common.txt"
|
||||
%endif
|
||||
for x in $LIBS; do
|
||||
[ "%{_arch}" = "x86_64" ] && [ "$x" = "%{_sourcedir}/requirements-ibm.txt" ] && continue
|
||||
%{__python3} -m pip install --target support/$(echo $x | sed -E "s/.*requirements-(.*).txt/\1/") --no-index --find-links %{_sourcedir} -r $x
|
||||
# use --prefix "usr" due to default varying per arch (and "" uses default unlike on RHEL10+)
|
||||
%{__python3} -m pip install --no-build-isolation --use-deprecated=legacy-resolver --prefix "usr" --root support/$(echo $x | sed -E "s/.*requirements-(.*).txt/\1/") --no-index --find-links %{_sourcedir} -r $x
|
||||
done
|
||||
|
||||
# fix incorrect #! detected by CI
|
||||
%ifarch x86_64
|
||||
sed -i -e "/^#\!\/Users/c#\!%{__python3}" support/aws/bin/jp
|
||||
%endif
|
||||
|
||||
# kubevirt
|
||||
%{__python3} -m pip install --user --no-index --find-links %{_sourcedir} setuptools-scm
|
||||
%{__python3} -m pip install --target support/kubevirt --no-index --find-links %{_sourcedir} openshift
|
||||
%{__python3} -m pip install --no-build-isolation --user --no-index --find-links %{_sourcedir} tomli
|
||||
%{__python3} -m pip install --no-build-isolation --user --no-index --find-links %{_sourcedir} setuptools-scm
|
||||
# use --prefix "usr" due to default varying per arch (and "" uses default unlike on RHEL10+)
|
||||
%{__python3} -m pip install --no-build-isolation --prefix "usr" --root support/kubevirt --no-index --find-links %{_sourcedir} openshift
|
||||
rm -rf kubevirt/rsa*
|
||||
|
||||
# workaround due to --prefix and jmespath bugs mentioned above
|
||||
for d in support/*; do
|
||||
mv "$d/usr/lib" "$d"
|
||||
[ -d "$d/usr/lib64" ] && mv "$d/usr/lib64" "$d"
|
||||
rm -rfv "$d/usr"
|
||||
done
|
||||
|
||||
sed -i -e "s/#PYTHON3_VERSION#/%{python3_version}/" %{_sourcedir}/*.patch make/*.mk lib/*.py agents/*/*.py
|
||||
|
||||
# regular patch doesnt work in build-section
|
||||
pushd support
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=2 < %{PATCH1000}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=2 < %{PATCH1001}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH1002}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH1003}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH1004}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH1005}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH1001}
|
||||
|
||||
%ifarch x86_64
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=2 < %{PATCH2000}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=2 < %{PATCH2001}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH2002}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH2003}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH2004}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH2005}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH2006}
|
||||
%endif
|
||||
%ifarch ppc64le
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=2 < %{PATCH3000}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH3001}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH3002}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH3003}
|
||||
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH2001}
|
||||
%endif
|
||||
popd
|
||||
|
||||
export PYTHONPATH="support/common/lib/python%{python3_version}/site-packages:support/aliyun/lib/python%{python3_version}/site-packages:support/aws/lib/python%{python3_version}/site-packages:support/azure/lib/python%{python3_version}/site-packages:support/google/lib/python%{python3_version}/site-packages:support/kubevirt/lib/python%{python3_version}/site-packages"
|
||||
./autogen.sh
|
||||
%{configure} --disable-libvirt-qmf-plugin PYTHONPATH="support/aliyun:support/aws:support/azure:support/google:support/common" \
|
||||
%{configure} --disable-libvirt-qmf-plugin \
|
||||
%if %{defined _tmpfilesdir}
|
||||
SYSTEMD_TMPFILES_DIR=%{_tmpfilesdir} \
|
||||
--with-fencetmpdir=/run/fence-agents \
|
||||
@ -565,7 +509,7 @@ rm -rf %{buildroot}
|
||||
mkdir -p %{buildroot}%{_usr}/lib/%{name}
|
||||
mv support %{buildroot}%{_usr}/lib/%{name}
|
||||
|
||||
export PYTHONPATH=%{buildroot}%{_usr}/lib/%{name}/support
|
||||
export PYTHONPATH="%{buildroot}%{_usr}/lib/%{name}/support/common/lib/python%{python3_version}/site-packages:%{buildroot}%{_usr}/lib/%{name}/support/aliyun/lib/python%{python3_version}/site-packages:%{buildroot}%{_usr}/lib/%{name}/support/aws/lib/python%{python3_version}/site-packages:%{buildroot}%{_usr}/lib/%{name}/support/azure/lib/python%{python3_version}/site-packages:%{buildroot}%{_usr}/lib/%{name}/support/google/lib/python%{python3_version}/site-packages:%{buildroot}%{_usr}/lib/%{name}/support/kubevirt/lib/python%{python3_version}/site-packages"
|
||||
make install DESTDIR=%{buildroot}
|
||||
mkdir -p %{buildroot}/%{_unitdir}/
|
||||
%ifarch x86_64
|
||||
@ -670,95 +614,67 @@ This package contains support files including the Python fencing library.
|
||||
%package -n ha-cloud-support
|
||||
License: GPL-2.0-or-later AND LGPL-2.0-or-later AND LGPL-2.1-or-later AND Apache-2.0 AND MIT AND BSD-2-Clause AND BSD-3-Clause AND MPL-2.0 AND Apache-2.0 AND PSF-2.0 AND Unlicense AND ISC
|
||||
Summary: Support libraries for HA Cloud agents
|
||||
Requires: python3-cryptography python3-requests python3-urllib3
|
||||
%ifarch x86_64
|
||||
Requires: awscli2
|
||||
# aliyun
|
||||
Provides: bundled(python-aliyun-python-sdk-core) = 2.11.5
|
||||
Provides: bundled(python-aliyun-python-sdk-ecs) = 4.24.7
|
||||
Provides: bundled(python-cffi) = 1.14.5
|
||||
Provides: bundled(python-colorama) = 0.3.3
|
||||
Provides: bundled(python-jmespath) = 0.7.1
|
||||
Provides: bundled(python-pycryptodome) = 3.20.0
|
||||
Provides: bundled(python-pycparser) = 2.20
|
||||
Provides: bundled(python-aliyun-sdk-core) = 2.16.0
|
||||
Provides: bundled(python-aliyun-sdk-ecs) = 4.24.82
|
||||
Provides: bundled(python-jmespath) = 0.10.0
|
||||
# aliyuncli (golang)
|
||||
Provides: bundled(aliyun-cli) = 3.0.198
|
||||
Provides: bundled(aliyun-openapi-meta) = 5cf98b660
|
||||
# aws
|
||||
Provides: bundled(python-boto3) = 1.40.13
|
||||
Provides: bundled(python-botocore) = 1.40.13
|
||||
Provides: bundled(python-%{dateutil}) = %{dateutil_version}
|
||||
Provides: bundled(python-jmespath) = 0.10.0
|
||||
Provides: bundled(python-s3transfer) = 0.13.1
|
||||
Provides: bundled(python-urllib3) = 1.26.18
|
||||
# azure
|
||||
Provides: bundled(python-adal) = 1.2.7
|
||||
Provides: bundled(python-azure-common) = 1.1.28
|
||||
Provides: bundled(python-azure-core) = 1.32.0
|
||||
Provides: bundled(python-azure-identity) = 1.19.0
|
||||
Provides: bundled(python-azure-mgmt-compute) = 34.0.0
|
||||
Provides: bundled(python-azure-identity) = 1.25.3
|
||||
Provides: bundled(python-azure-mgmt-core) = 1.5.0
|
||||
Provides: bundled(python-azure-mgmt-compute) = 34.0.0
|
||||
Provides: bundled(python-azure-mgmt-network) = 28.1.0
|
||||
Provides: bundled(python-chardet) = 4.0.0
|
||||
Provides: bundled(python-cffi) = 1.14.5
|
||||
Provides: bundled(python-%{chrstnormalizer}) = %{chrstnormalizer_version}
|
||||
Provides: bundled(python-cryptography) = 3.3.2
|
||||
Provides: bundled(python-%{dateutil}) = %{dateutil_version}
|
||||
Provides: bundled(python-%{idna}) = %{idna_version}
|
||||
Provides: bundled(python-isodate) = 0.6.1
|
||||
Provides: bundled(python-msal) = 1.31.1
|
||||
Provides: bundled(python-msal-extensions) = 1.2.0
|
||||
Provides: bundled(python-msal) = 1.36.0
|
||||
Provides: bundled(python-msal-extensions) = 1.3.1
|
||||
Provides: bundled(python-msrest) = 0.7.1
|
||||
Provides: bundled(python-msrestazure) = 0.6.4.post1
|
||||
Provides: bundled(python-%{oauthlib}) = %{oauthlib_version}
|
||||
Provides: bundled(python-portalocker) = 2.5.1
|
||||
Provides: bundled(python-pycparser) = 2.20
|
||||
Provides: bundled(python-PyJWT) = 2.1.0
|
||||
Provides: bundled(python-%{requests}) = %{requests_version}
|
||||
Provides: bundled(python-PyJWT) = 2.12.1
|
||||
Provides: bundled(python-requests-oauthlib) = 1.3.0
|
||||
Provides: bundled(python-%{six}) = %{six_version}
|
||||
Provides: bundled(python-typing-extensions) = 4.12.2
|
||||
Provides: bundled(python-%{urllib3}) = %{urllib3_version}
|
||||
# google
|
||||
Provides: bundled(python-cachetools) = 4.2.2
|
||||
Provides: bundled(python-chardet) = 3.0.4
|
||||
Provides: bundled(python3-%{cachetools}) = %{cachetools_version}
|
||||
Provides: bundled(python-google-api-core) = 1.30.0
|
||||
Provides: bundled(python-google-api-client) = 1.12.8
|
||||
Provides: bundled(python-googleapis-common-protos) = 1.53.0
|
||||
Provides: bundled(python-google-auth) = 1.32.0
|
||||
Provides: bundled(python-google-auth-httplib2) = 0.1.0
|
||||
Provides: bundled(python-httplib2) = 0.19.1
|
||||
Provides: bundled(python-packaging) = 20.9
|
||||
Provides: bundled(python-protobuf) = 3.17.3
|
||||
Provides: bundled(python-pyasn1) = 0.4.8
|
||||
Provides: bundled(python-pyasn1-modules) = 0.2.8
|
||||
Provides: bundled(python-pyparsing) = 2.4.7
|
||||
Provides: bundled(python-pyroute2) = 0.7.12
|
||||
Provides: bundled(python-pyroute2-core) = 0.6.13
|
||||
Provides: bundled(python-pyroute2-ethtool) = 0.6.13
|
||||
Provides: bundled(python-pyroute2-ipdb) = 0.6.13
|
||||
Provides: bundled(python-pyroute2-ipset) = 0.6.13
|
||||
Provides: bundled(python-pyroute2-ndb) = 0.6.13
|
||||
Provides: bundled(python-pyroute2-nftables) = 0.6.13
|
||||
Provides: bundled(python-pyroute2-nslink) = 0.6.13
|
||||
Provides: bundled(python-pytz) = 2021.1
|
||||
Provides: bundled(python-rsa) = 4.7.2
|
||||
Provides: bundled(python3-setuptools) = 80.9.0
|
||||
Provides: bundled(python-uritemplate) = 3.0.1
|
||||
%endif
|
||||
%ifarch ppc64le
|
||||
# ibm
|
||||
Provides: bundled(python3-%{certifi}) = %{certifi_version}
|
||||
Provides: bundled(python3-%{chrstnormalizer}) = %{chrstnormalizer_version}
|
||||
Provides: bundled(python3-%{idna}) = %{idna_version}
|
||||
Provides: bundled(python3-%{requests}) = %{requests_version}
|
||||
Provides: bundled(python3-%{urllib3}) = %{urllib3_version}
|
||||
%endif
|
||||
%description -n ha-cloud-support
|
||||
Support libraries for Fence Agents.
|
||||
%files -n ha-cloud-support
|
||||
%ifnarch ppc64le
|
||||
%dir %{_usr}/lib/%{name}
|
||||
%{_usr}/lib/%{name}/support
|
||||
%exclude %{_usr}/lib/%{name}/support/common
|
||||
%exclude %{_usr}/lib/%{name}/support/kubevirt
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%package all
|
||||
License: GPLv2+ and LGPLv2+ and ASL 2.0
|
||||
@ -787,7 +703,6 @@ Group: System Environment/Base
|
||||
Summary: Fence agent for Alibaba Cloud (Aliyun)
|
||||
Requires: fence-agents-common >= %{version}-%{release}
|
||||
Requires: ha-cloud-support = %{version}-%{release}
|
||||
Requires: python3-jmespath >= 0.9.0
|
||||
Obsoletes: %{name} < %{version}-%{release}
|
||||
%description aliyun
|
||||
The fence-agents-aliyun package contains a fence agent for Alibaba Cloud (Aliyun) instances.
|
||||
@ -1265,28 +1180,22 @@ License: GPLv2+ and LGPLv2+ and ASL 2.0 and BSD and BSD-2-Clause and BSD-3-Claus
|
||||
Summary: Fence agent for KubeVirt platform
|
||||
Requires: fence-agents-common = %{version}-%{release}
|
||||
Provides: bundled(python3-%{openshift}) = %{openshift_version}
|
||||
Provides: bundled(python3-%{ruamelyamlclib}) = %{ruamelyamlclib_version}
|
||||
Provides: bundled(python3-%{kubernetes}) = %{kubernetes_version}
|
||||
Provides: bundled(python3-%{certifi}) = %{certifi_version}
|
||||
Provides: bundled(python3-%{googleauth}) = %{googleauth_version}
|
||||
Provides: bundled(python3-%{cachetools}) = %{cachetools_version}
|
||||
Provides: bundled(python3-%{pyasn1modules}) = %{pyasn1modules_version}
|
||||
Provides: bundled(python3-%{pyasn1}) = %{pyasn1_version}
|
||||
Provides: bundled(python3-%{pyasn1modules}) = %{pyasn1modules_version}
|
||||
Provides: bundled(python3-%{dateutil}) = %{dateutil_version}
|
||||
Provides: bundled(python3-%{pyyaml}) = %{pyyaml_version}
|
||||
Provides: bundled(python3-%{six}) = %{six_version}
|
||||
Provides: bundled(python3-%{urllib3}) = %{urllib3_version}
|
||||
Provides: bundled(python3-%{websocketclient}) = %{websocketclient_version}
|
||||
Provides: bundled(python3-%{jinja2}) = %{jinja2_version}
|
||||
Provides: bundled(python3-%{markupsafe}) = %{markupsafe_version}
|
||||
Provides: bundled(python3-%{stringutils}) = %{stringutils_version}
|
||||
Provides: bundled(python3-%{requests}) = %{requests_version}
|
||||
Provides: bundled(python3-%{chrstnormalizer}) = %{chrstnormalizer_version}
|
||||
Provides: bundled(python3-%{idna}) = %{idna_version}
|
||||
Provides: bundled(python3-%{reqstsoauthlib}) = %{reqstsoauthlib_version}
|
||||
Provides: bundled(python3-%{oauthlib}) = %{oauthlib_version}
|
||||
Provides: bundled(python3-%{ruamelyaml}) = %{ruamelyaml_version}
|
||||
Provides: bundled(python3-setuptools) = 80.9.0
|
||||
Provides: bundled(python3-%{ruamelyamlclib}) = %{ruamelyamlclib_version}
|
||||
%description kubevirt
|
||||
Fence agent for KubeVirt platform.
|
||||
%files kubevirt
|
||||
@ -1605,6 +1514,11 @@ are located on corosync cluster nodes.
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Thu Apr 16 2026 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-111
|
||||
- bundled cryptography: replace with dependency to fix CVE-2026-26007
|
||||
- bundled PyJWT: upgrade to v2.12.1 to fix CVE-2026-32597
|
||||
Resolves: RHEL-148437, RHEL-155677
|
||||
|
||||
* Tue Feb 10 2026 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-110
|
||||
- bundled urllib3: fix CVE-2024-37891, CVE-2025-66418, CVE-2025-66471,
|
||||
CVE-2026-21441, and pyasn1 CVE-2026-23490 on all archs
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay
|
||||
|
||||
try:
|
||||
+ sys.path.insert(0, '/usr/lib/fence-agents/support/aliyun')
|
||||
+ sys.path.insert(0, '/usr/lib/fence-agents/support/aliyun/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
from aliyunsdkcore import client
|
||||
from aliyunsdkcore.auth.credentials import EcsRamRoleCredential
|
||||
from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
from requests import HTTPError
|
||||
|
||||
try:
|
||||
+ sys.path.insert(0, '/usr/lib/fence-agents/support/aws')
|
||||
+ sys.path.insert(0, '/usr/lib/fence-agents/support/aws/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
import boto3
|
||||
from botocore.exceptions import ConnectionError, ClientError, EndpointConnectionError, NoRegionError
|
||||
except ImportError:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
from fencing import fail_usage
|
||||
|
||||
+import sys
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/azure')
|
||||
+sys.path.insert(0, '/usr/lib/fence-agents/support/azure/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+
|
||||
FENCE_SUBNET_NAME = "fence-subnet"
|
||||
FENCE_INBOUND_RULE_NAME = "FENCE_DENY_ALL_INBOUND"
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
diff --color -uNr a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py
|
||||
--- a/agents/gce/fence_gce.py 2021-06-03 13:10:44.752999470 +0200
|
||||
+++ b/agents/gce/fence_gce.py 2021-06-03 13:10:36.512971619 +0200
|
||||
--- a/agents/gce/fence_gce.py 2026-04-15 10:38:15.742597179 +0200
|
||||
+++ b/agents/gce/fence_gce.py 2026-04-15 10:40:20.021924656 +0200
|
||||
@@ -9,7 +9,6 @@
|
||||
#
|
||||
|
||||
@ -9,13 +8,13 @@ diff --color -uNr a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py
|
||||
import logging
|
||||
import json
|
||||
import re
|
||||
@@ -30,6 +29,8 @@
|
||||
@@ -30,6 +29,9 @@
|
||||
|
||||
from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action
|
||||
try:
|
||||
+ sys.path.insert(0, '/usr/lib/fence-agents/support/google')
|
||||
+ sys.path.insert(0, '/usr/lib/fence-agents/support/google/lib64/python#PYTHON3_VERSION#/site-packages')
|
||||
+ sys.path.insert(1, '/usr/lib/fence-agents/support/google/lib/python#PYTHON3_VERSION#/site-packages')
|
||||
+ import httplib2
|
||||
import googleapiclient.discovery
|
||||
import socks
|
||||
try:
|
||||
Binary files a/agents/gce/.fence_gce.py.swp and b/agents/gce/.fence_gce.py.swp differ
|
||||
|
||||
67
sources
67
sources
@ -3,94 +3,71 @@ SHA512 (requirements-common.txt) = 48725599ca3e019f34ce59b78a6ac1deb0cc459e062cd
|
||||
SHA512 (requirements-aliyun.txt) = 0c4f89de63246c406535ee73310232f3986b37dedbeed52f25000386d73af6735e1bf8e7ecaa97419df98f55058d76e4ff289d856b815afaaaf69744c5924f7e
|
||||
SHA512 (requirements-aws.txt) = ca39604d09f4b05589ddaa437be13b7f5d1868218745df107564d73a6c32efb7e4761436197a69653edc47a78f40dd7d5f0894935ec21b8f23b7c7bc71dfd0d1
|
||||
SHA512 (requirements-azure.txt) = 8071c96bb3e2b82852b10fd68b77b69a7fce6153ab315298ceb07456fe66f3aca056d3273f11eb87ff30049759e8b4fddf62e39acb91953d36e933e44dce8c9b
|
||||
SHA512 (requirements-google.txt) = d916eb72588e55f5243b9e5391ab07d65eaafe583e073ef79d0e865f4c5e911d7b10310f7ccb98b5fdc1383c2214cc0cc082fa3c5fac6aa3d1931e4779149241
|
||||
SHA512 (requirements-google.txt) = 2b7f30430692e70f531665c1f0e6b905124c8d1891f07a03d143e1a1d2218bda46b5c5e5558165d36005b4276665ef0f9a4bb113bd5313341fe4b585df2b4835
|
||||
SHA512 (requirements-ibm.txt) = f702e6e21228b71442d8b9a8b2cc9a2fd50c629b080ece14efb6099307df65d9b542936851120f9bd9ae9c3e532104a151d769779f8e89e9fdbc5577de0157f5
|
||||
SHA512 (aliyun-python-sdk-core-2.11.5.tar.gz) = 4178056b2b94b314924c671c26a15696493412ab0a61c13ff64eeff72f0e0c80960269db34471adce34d35e23578b8b54953a242fd575560c2312d672871b951
|
||||
SHA512 (aliyun_python_sdk_ecs-4.24.7-py2.py3-none-any.whl) = e479191136e74eaa1f52ba0b317c721cdb1fc1972f074377dd6a7616ef79d93b8b494a53d7d745d8438be748e3d14dbbab6e8433381d1ea589fa073d1ed0e52e
|
||||
SHA512 (cffi-1.14.5-cp39-cp39-manylinux1_x86_64.whl) = 3c73e06bef8e9646beacc584d59ecf42de013034194d6eb59f1abf279e8fe5468e106fcd47802ce1d264d3c1d9122af3c66ea1229db78a768f7ea069ddc2fd72
|
||||
SHA512 (pexpect-4.8.0-py2.py3-none-any.whl) = 79b3a33866f8fec11a5ccf079387b7de393cdee65167671db0ac42cf3d6c2e544c40ee344c1b5f7deb13d97057300c86f605df30fbfff9c6773944886c5158c0
|
||||
SHA512 (ptyprocess-0.7.0-py2.py3-none-any.whl) = aa6c925add18a9603f130887e2a0ec645eb5bbf6b8020c78450a7cee934454dc46d1a435068368347f851d45550ea0fda8fb2ba0864c24c41e17a58bc7a9e84f
|
||||
SHA512 (suds_community-0.8.5-py3-none-any.whl) = 0719c3c2988ff96bd8698df326fb332f85f830ef8d4bfca13c285cc0e917a6cf575f71a2b037df9270cd64edf2ea543779630f08d9d2eb77b82233ea0c5ac215
|
||||
SHA512 (aliyun-python-sdk-core-2.16.0.tar.gz) = 046158c75c5878a61c3674ed0fcb6a24423297540aaef9500d381e1fe49f0e5f990c3da21102a41595d89b76f2ee6ce94f4820800e334ddc67e430297b1a44f0
|
||||
SHA512 (aliyun-python-sdk-ecs-4.24.82.tar.gz) = b48d0de469e24d3078f09f01b2da67105f82d6f09271aa2b7dbe29c424c244edab32c4bdd5e01a06076279f30220045b0835b673855efa1e3dbc140fdec72beb
|
||||
SHA512 (colorama-0.3.3.tar.gz) = 8e6177ea60ab8f1267ce982f23803a9d2eb0c4550d7eac4776416d62a99d1ce03254fc64cc959ca95e2409ceeff081d4d19359c383e969dfb921b44c56914495
|
||||
SHA512 (jmespath-0.7.1-py2.py3-none-any.whl) = e035bbd4e716066fc6a6282505a51dac8ec738a2794db958aef9edefb9871aa2424ead0ffb80d8cda75436b23ebc02f96201b3960e48d3ea3299e9b4aa8a6958
|
||||
SHA512 (pycryptodome-3.20.0.tar.gz) = 9fed02190db9ae71b6895af2525d7670858817acf213c494969104da81138dacb11bc00be83b308e070a2c90766cd763e25a611ada402b32f6160a8ac9283f85
|
||||
SHA512 (pycparser-2.20-py2.py3-none-any.whl) = 06dc9cefdcde6b97c96d0452a77db42a629c48ee545edd7ab241763e50e3b3c56d21f9fcce4e206817aa1a597763d948a10ccc73572490d739c89eea7fede0a1
|
||||
SHA512 (jmespath-0.10.0.tar.gz) = 9e229b5809d2dd74eb7dbf518953f848175743fb0ee91ffc901777be2f4809cc0c4f4ba40890746533e344f64e900ec189d6a8c847c864fa47fbf67e5106a7bc
|
||||
SHA512 (aliyun-cli-3.0.198.tar.gz) = d39f36205c1325ab7596da836d59db458beb877f870ddb9e61e85bc6a2be07c1db9042417fc0ef0edd82d307b0f45577ca62f977f37701215f50a806a4dc6473
|
||||
SHA512 (aliyun-cli-go-vendor.tar.gz) = 0e545d545245051efc10acdb3d0f22d3b81f60c5946f8479e5a0df16a8bcb390763212ca59ff9298633432434ebb221cce9a35e1bf00db9245eba32bfb84eb23
|
||||
SHA512 (aliyun-openapi-meta-5cf98b660.tar.gz) = 0476feef9085f77a60ef80ae06ca703af0be807d3bdf1a9a7dfffb415409c1c45fcd184c86346c22a48b5794f84cebc410eeee2dfbf7dcef91c79c6fea8e15b9
|
||||
SHA512 (aliyun-cli-go-vendor.tar.gz) = 0e545d545245051efc10acdb3d0f22d3b81f60c5946f8479e5a0df16a8bcb390763212ca59ff9298633432434ebb221cce9a35e1bf00db9245eba32bfb84eb23
|
||||
SHA512 (boto3-1.40.13.tar.gz) = c1e4532e2d04d192dd23aac25a34d9a6d12f93604793f141ee32aee8808cbe91867055ae745c6c9e62ccc68cfd288e6448cef80d2db407c9558036c148d5822e
|
||||
SHA512 (botocore-1.40.13.tar.gz) = f0cbd8fd70141feef46c19002daf8c973eb2971362c56b06562ef1b35e5fcf896a575877c942cb6f2110b16c457e94f055a1aef66a3522598d5fc43386451f3a
|
||||
SHA512 (python_dateutil-2.8.1-py2.py3-none-any.whl) = ff083825ef3c8a3c6887ceae79a4249b938f529b72d0b931b1e30c81856ec7c8ee0adf0e29e2a41d3c76ab4e1faabc1c4161fe977d14589d346a658e343aa122
|
||||
SHA512 (s3transfer-0.13.1.tar.gz) = 46ae91946ecb7f1c11cef7547e7f9532326298ba30e7b363738133963a86aed6477fa6128a13dd57c7668e11a3ad9505b55638acffcc9470e6162b8b73206429
|
||||
SHA512 (urllib3-1.26.18.tar.gz) = c89e93a032bf6b11375c06ef7c5abc1868f93e7655cfdca09e9bd939ad415d206ea159fe151ecd2e5f725e0e18a831c7a5382ad01dbc32264154fc8af7aec156
|
||||
SHA512 (adal-1.2.7.tar.gz) = b46dd3ebb72123e9c2d2eb75eae17b1175f09908b44430131251b0deb0f96f4f3646aa5c0553894c89e664d448ad90bf7436a0a48e18b6a2eff491dad3d8a8a8
|
||||
SHA512 (azure-common-1.1.28.zip) = cfa8d08e11ff7d855342a589f9780ba1b2386fd63cddcbcc04d83be8d4d8e41dceba494b617e27ed4e3da4366b9f1203819ec391ef4466a6700cc2c8b85f0c38
|
||||
SHA512 (azure_core-1.32.0.tar.gz) = a1b975e5f9560b5a9b0800c7cd41afc8040582f9b5e73aeb9216f7b076b3821337b741a5f5b7b183008108552dd62da120e0f8334492a06ea729188c85ffcbc0
|
||||
SHA512 (azure_mgmt_compute-34.0.0.tar.gz) = 038ccac0792000778386769f81b908e35865ce20fc29d9d95e1ee774442d31b14162cdc7fed8dfcf4b7ef592a15d302968eca63ccc4363da3404e2ad53756254
|
||||
SHA512 (azure_mgmt_core-1.5.0.tar.gz) = ac88496015552ee473ebf8c7fe312bc7e79f10b33019c8a9d51e32cdcb237e8db45a5cc6bbbd94ca87bfc9090954417dd64c674847a78765377cb61468fd9987
|
||||
SHA512 (azure_mgmt_compute-34.0.0.tar.gz) = 038ccac0792000778386769f81b908e35865ce20fc29d9d95e1ee774442d31b14162cdc7fed8dfcf4b7ef592a15d302968eca63ccc4363da3404e2ad53756254
|
||||
SHA512 (azure_mgmt_network-28.1.0.tar.gz) = 43acf01c26efbb40a877feafeba659f27a4e903b3d2bbc01dcbf3e880d1ab4d9cca551b8ffb46ea939c3630221b6881f854213cfce7bcd5194b7593c506a7f59
|
||||
SHA512 (azure_identity-1.19.0.tar.gz) = a0df8139b82cfb4f1887c340d8637f80575088e699106285ceca1211b884bc7154f237b279e9b086740a3fb9cc98f714613ab7ae98cf6eff08a48b32691c7de8
|
||||
SHA512 (certifi-2023.7.22.tar.gz) = 220ec0a4251f301f057b4875e5966a223085b0c764c911450b43df7f49dbc5af50f14eeb692d935c0baa95d7c800055fa03efa4aaabba397a82c7b07c042bd90
|
||||
SHA512 (chardet-4.0.0-py2.py3-none-any.whl) = cc8cdd5e73b4eace0131bbeaf6099e322ba5c2f827f26ad3316c674c60529d77f39f68d9fb83199ab78d16902021ab1ae58d74ab62d770cf95ceb804b9242e90
|
||||
SHA512 (azure_identity-1.25.3.tar.gz) = 6fb0bc607048ba96dac27329804d34fac247a0c4ce911fec527e7e870f76096340bd471ef165975196b11ee2b0adc75748a7a8c6fc1caca9291dce6a0ebb2184
|
||||
SHA512 (isodate-0.6.1.tar.gz) = 437e420ec7ee68dedded825f30d3289eeb0da526208443e5a8e50fe70f12309515e1285b21132d26e6d4c1683f90dfa1d401582042b5e4381fe7ab0e34af26b6
|
||||
SHA512 (msrest-0.7.1.zip) = 430e982adf89c79356e59182587c62ecb935e983f2e339738b54c48d0cd3cfa66ab48aad52d342b3efe5938d5e02693f24d603a4d637e3e5818bac6d03cc19db
|
||||
SHA512 (msrestazure-0.6.4.post1.tar.gz) = 8fc4eba2520cecae612e9f1ab279662a1b531c73da3ee9af5abf59bc478b4edbf7ce0ea17d4491ff498d17269c31a82a9327eea4d1f1c704a4a7f434ef284acb
|
||||
SHA512 (msal-1.31.1.tar.gz) = 2d52681bf2229d9a87c195c777e90b4a1b567355ceba91a93220483bbea6ab108bfb934c70b3a60080c7cc3ecd4a07cae39ece3891c38e3c4cff77560875fee3
|
||||
SHA512 (msal_extensions-1.2.0.tar.gz) = 8a56049bfb0c8237fe81f6d39c3368bb1c79ee9fcb211382f8b407ba89cea4f9405a2a4e54ef7f817b2d59091a036440009c2c5858e44da5cf790c1a97fef17e
|
||||
SHA512 (portalocker-2.5.1.tar.gz) = a1aeea4cb09a05d4fc65a346965b5af509963f84c6b440bed974770576cab8d5c94c8535f2debd72613f3c603cf9fe3cc236fac6bec2fd69d7d48d206ba4c344
|
||||
SHA512 (cryptography-3.3.2-cp36-abi3-manylinux2010_x86_64.whl) = d6cb4ee14cdfbf17226c5caec3ee182c1e812b6630dcab07dc5869d29a828f0fded2c2e2d85be2c5952dc2b1c0a0cedcd01d520f3e1c4aa385badb07a17d62c4
|
||||
SHA512 (oauthlib-3.2.2.tar.gz) = c147b96e0ab0d1a8845f525e80831cfd04495134dd1f17fd95eac62f3a95c91e6dca9d38e34206537d77f3c12dd5b553252239318ba39546979c350e96536b8b
|
||||
SHA512 (PyJWT-2.1.0-py3-none-any.whl) = d2f632379ecb3eb9c02d67f6da30d0c363f439936b5a6bc1172a0a33dc7e4784ee8b10c258d24ac40b5efbb252e7921c0842699f4b2d40eff99333557b531fcc
|
||||
SHA512 (pyjwt-2.12.1.tar.gz) = ad1e925b9aa39017bd83863233b39de06a919daed664d5835e58def47f6fb4435fab057a37a5fa8a7543f691f5fc9f82e6d879ef0ad60960f982a214b305078a
|
||||
SHA512 (requests_oauthlib-1.3.0-py2.py3-none-any.whl) = 17d5e66d174e57ef1dae451a20bce215a3cc3d7ab1a5b922d4a66cb49b497c9a0799bd90b5a378648335daee7cf80f843f065d90410bfa791f989f76300a02d7
|
||||
SHA512 (msal-1.36.0.tar.gz) = 228617a9bb1465595867f8429d2127e03ba395f3054ebc78ba5805a4712c6776b2db7e2496ef2b2675173e54e4ff2c8f39b4119ed1d91138f61b77bc67b39025
|
||||
SHA512 (msal_extensions-1.3.1.tar.gz) = ea0409a7ff3e3a885203b35efbbdd674a08baadfdf2f80e96d849a4949197ef9702a6f051595c1346eab5c8f178254b79fe60180e17888fbc8bb73e8d4c93589
|
||||
SHA512 (portalocker-2.5.1.tar.gz) = a1aeea4cb09a05d4fc65a346965b5af509963f84c6b440bed974770576cab8d5c94c8535f2debd72613f3c603cf9fe3cc236fac6bec2fd69d7d48d206ba4c344
|
||||
SHA512 (typing_extensions-4.12.2.tar.gz) = b06f26ae55194f37ee48dcb894bf583051c9e74f639f25195990f56330eae7b585ab4b8655ca575539f48254c20f1920628db6db10512953d1f6364e3c076a27
|
||||
SHA512 (cachetools-4.2.2-py3-none-any.whl) = 4e585eda01b37ca6a2e1e6aadc0ceb8a789811357806b3ab2a76180d89496b6608c8aaaa4a44dc11785850236493daff646b1f04759bc4dc78c7b76c977feb09
|
||||
SHA512 (chardet-3.0.4-py2.py3-none-any.whl) = bfae58c8ea19c87cc9c9bf3d0b6146bfdb3630346bd954fe8e9f7da1f09da1fc0d6943ff04802798a665ea3b610ee2d65658ce84fe5a89f9e93625ea396a17f4
|
||||
SHA512 (cachetools-4.2.4.tar.gz) = 29a6bb3a064e5603cd3e3882d8e5a6a6ef95ba3029716692c9a82d7186a0befcfb8ed4a0ee3ecb591fdff93a46836d5b25acca7ba5eab1ba837e86404aea8fcf
|
||||
SHA512 (google_api_core-1.30.0-py2.py3-none-any.whl) = b024d8612de3ad6f903a1c376b84f03dcddd0cf5c4078749bbd6b0d2231a3ef1e968dcb5621b6470972b116d6aaff5d05deab79ed4a2873c29eec74c37778916
|
||||
SHA512 (google_api_python_client-1.12.8-py2.py3-none-any.whl) = 59bb36abda556192f972943eb8a620779fb4315ff61b0492a6e8808b29cc433726a2550b20364cc560507061fde2971a2174dc1d3fe41f1b2d117a9f020e2ae8
|
||||
SHA512 (googleapis_common_protos-1.53.0-py2.py3-none-any.whl) = 3ac0b7f9a2097723e24c60d6af893c98759ab000bec92470fe05a2f0bf451b88bd10ff5ea2cfed5af779904169d6f3ca0117f1d15261baeaf4f4b4d4de921e02
|
||||
SHA512 (google_auth-1.32.0-py2.py3-none-any.whl) = 1de07118862770cf12afc544ca07db585de5952959f8bcb63cc32ad80b31b3b55c90eb75a260e3d74cb4d9241d5648561b396837b951ea98d6c77b64aab2eded
|
||||
SHA512 (google_auth_httplib2-0.1.0-py2.py3-none-any.whl) = c4b8c2b7b83f241fd9504bafdcb886ed3ef6b35016cf7fee7f36b5871e381658ab6b18ff43407dc2b9d1e9fa60827c352dfbbde667dfe8de245c27bdfe705cc5
|
||||
SHA512 (httplib2-0.19.1-py3-none-any.whl) = 83b9b36fe27e6ac5b931f0889bd63f6f9e952cfb87baa09ccb0f8eeed9cae1932b002109832d21f54c5c0a204bd4e3d218e86a8f8104c8df9e29b76d9e0cf3d1
|
||||
SHA512 (packaging-20.9-py2.py3-none-any.whl) = 6a4f69737814acbf43a3d0644d8dbbe4446075c7dfd1ec4d36ad73af9d5f2a4a5bd5a8d8f19e31d4ef63a1617dd3e0554812803bdcaf81888925267a16969b0b
|
||||
SHA512 (protobuf-3.17.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl) = ad5b03c9ce55dcaf4b1732c6449975574f8e666460e48af90bcb22ced57c5e709744ae915f03b51d938634be62fd0193b50eca98df556d54d941ccf82f1f9235
|
||||
SHA512 (pyasn1-0.4.8-py2.py3-none-any.whl) = ab0ccbe261323925ca46a4f4e0e674f730f8b93f6db87b6bf94e26f2e190c3e9afd2ea6ede0d99b100eda282e54c03d87c3357bf3bdfa399469d56a92e2aabbb
|
||||
SHA512 (pyasn1_modules-0.2.8-py2.py3-none-any.whl) = 8248686f74d000f29c9a5a2dfd14883d44a276286caf7c34c100ea9660e5f644765452fb62c88c534093ea330d5e3d9389fa6398477231e2d1b6331b98861a62
|
||||
SHA512 (pyparsing-2.4.7-py2.py3-none-any.whl) = acb6b4ff90254d73804621d302926deb69bc99ffde16d7aa16cba7d0af7a53c25b7197d422309d9e82a766704fd7ea4c8b078a48d2e7d8658a8b237266fe24f5
|
||||
SHA512 (pyroute2-0.7.12.tar.gz) = 928e7f45569d43c1849d9c8d5972b38343ed8dd79137d6bfc757557d3bde23526af6baea61acc720b7e2d5d26731066b93f180138a6227b7d76d094e04111df7
|
||||
SHA512 (pyroute2.core-0.6.13.tar.gz) = 6b7472eb830f4b7f28dd5a9182300859440cefdd75cac2a88b9e15cfabb1d6edf7e2eb454fd50e985f6b6de16f076b59c227d0059448e6cf2ae41b1cc7133a1c
|
||||
SHA512 (pyroute2.ethtool-0.6.13.tar.gz) = 6abd1c529109ba330d11c213d22bd10a6aa34497d6f2db0064b14df4325196a057a45e5bc86ec14c9189107c6604aeb17f6b47053000bb53c51f84749cc362e3
|
||||
SHA512 (pyroute2.ipdb-0.6.13.tar.gz) = 2fb251b2e01a7e79afe15e736b1e91825ddc5af67f3c80d317a551f19d2140e3c11187882573f496df22910804876566447c45704633ba17e29043e008c8eb3b
|
||||
SHA512 (pyroute2.ipset-0.6.13.tar.gz) = c64382c9297745f461da4ee548986dc35c928176e46a694e0ca47f7f59f7d41aeaf550c8174acb404d8aaae67e8d4719b2e91f77ed507b4364b0897ec9668832
|
||||
SHA512 (pyroute2.ndb-0.6.13.tar.gz) = 17a992483c34d6bc0ae12dc1f077f52ed0de0dc37db8e723e28dbd59ab99da27abe6f2d621a6309193559245ecc80cc21cde000c52e1d709f97c281fb4d253bb
|
||||
SHA512 (pyroute2.nftables-0.6.13.tar.gz) = bb9426bda897ebda74fdccf59782b9d8dc665ba7f07aaa92fd80e039a9098f581256b66318431113a7b3da19b2dba279492661b97a67a724e41b41dd89e20bfe
|
||||
SHA512 (pyroute2.nslink-0.6.13.tar.gz) = 16b3c8ea6d5319520a4d777f5ad76c265ea38c0b8ecc98922ddc6d898d05cfc931acd6b4a2884b1803b318e17744bf93961312ac60ea227ff2d01245ceedf935
|
||||
SHA512 (pytz-2021.1-py2.py3-none-any.whl) = 7ef08f53204664d6426bcb77e6f74bad8263d0f96128254aa41a752eaa9a0d1c9dac64134f5fd40c36a7385cfb453ec95ae7f714ba88993de000c34c32835619
|
||||
SHA512 (rsa-4.7.2-py3-none-any.whl) = 39d2295a067501d94808f109c846e5c4719b2f3e1129494ade51291627fb5d1728d7bafeac7db557e69b5e53a8c0a09cdda59d8b672164fbd61bf6b70da30d62
|
||||
SHA512 (setuptools-80.9.0.tar.gz) = 36eb1f219d29c6b9e135936bde2001ad70a971c8069cd0175d3a5325b450e6843a903d3f70043c9f534768ebeab8ab0c544b8f44456555d333f1ed72daa5c18b
|
||||
SHA512 (uritemplate-3.0.1-py2.py3-none-any.whl) = 0d4cfc2eb14b73f17ef9d82a08d9bc7fbc8a1efd1e51693e20c51c01812e7597ebe964904f79fd86e21d06bd690abfdf9bd2824e8f957dd8a9486e3b860d58d0
|
||||
SHA512 (pexpect-4.8.0-py2.py3-none-any.whl) = 79b3a33866f8fec11a5ccf079387b7de393cdee65167671db0ac42cf3d6c2e544c40ee344c1b5f7deb13d97057300c86f605df30fbfff9c6773944886c5158c0
|
||||
SHA512 (ptyprocess-0.7.0-py2.py3-none-any.whl) = aa6c925add18a9603f130887e2a0ec645eb5bbf6b8020c78450a7cee934454dc46d1a435068368347f851d45550ea0fda8fb2ba0864c24c41e17a58bc7a9e84f
|
||||
SHA512 (suds_community-0.8.5-py3-none-any.whl) = 0719c3c2988ff96bd8698df326fb332f85f830ef8d4bfca13c285cc0e917a6cf575f71a2b037df9270cd64edf2ea543779630f08d9d2eb77b82233ea0c5ac215
|
||||
SHA512 (openshift-0.12.1.tar.gz) = 35a0ecfbc12d657f5f79d4c752a7c023a2a5e3fc5e7b377d9f11ce4a7d5f666ca5c6296f31adb44b7680d051af42d3638ced1092fb7e9146d2cc998f2c3a7b80
|
||||
SHA512 (ruamel.yaml.clib-0.2.6.tar.gz) = 12307a3c3bae09cf65d9672894c9a869a7ed5483ca3afb9ee39d8bcbf1948b012a0dbf570e315cc8b9a8b55184de9e10324953ec4819d214379e01522ee13b20
|
||||
SHA512 (kubernetes-12.0.1.tar.gz) = ff4739dc185dbf46050e53382b9260a0a69c55b43820ccb1df498718c78d1bf42842f4ab1b6d0c3520c5edab45d9c9c9527aea9ccb0b6347f34e18202f9155a2
|
||||
SHA512 (certifi-2023.7.22.tar.gz) = 220ec0a4251f301f057b4875e5966a223085b0c764c911450b43df7f49dbc5af50f14eeb692d935c0baa95d7c800055fa03efa4aaabba397a82c7b07c042bd90
|
||||
SHA512 (google-auth-2.3.0.tar.gz) = cf0040d238880ea4bbad64f0a47311f2ed3922a7301a0d5287319b39ea8e76dca66dc78fd860cc12386b078bd2147a1cba01de97381420ef94cc44fca0c90ad1
|
||||
SHA512 (cachetools-4.2.4.tar.gz) = 29a6bb3a064e5603cd3e3882d8e5a6a6ef95ba3029716692c9a82d7186a0befcfb8ed4a0ee3ecb591fdff93a46836d5b25acca7ba5eab1ba837e86404aea8fcf
|
||||
SHA512 (pyasn1-modules-0.2.8.tar.gz) = fdfcaa065deffdd732deaa1fa30dec2fc4a90ffe15bd12de40636ce0212f447611096d2f4e652ed786b5c47544439e6a93721fabe121f3320f13965692a1ca5b
|
||||
SHA512 (pyasn1-0.4.8.tar.gz) = e64e70b325c8067f87ace7c0673149e82fe564aa4b0fa146d29b43cb588ecd6e81b1b82803b8cfa7a17d3d0489b6d88b4af5afb3aa0052bf92e8a1769fe8f7b0
|
||||
SHA512 (PyYAML-5.1.tar.gz) = 8f27f92bdfa310a99dd6d83947332cc033fa18f0011998bb585ad5c4340a2da20d8c20bfdb53beaae15651198d1240c986818379b0a05b230f74d1f30f53e7fd
|
||||
SHA512 (rsa-4.7.2.tar.gz) = 63f561774dbaa10511167cba31e0f852e32b3250f2803edaa2729dc2b28baa2c42cb79dfbd49e38eb42ce82f665ed4c3d9dcc810c37380401e2c62202b1c7948
|
||||
SHA512 (six-1.16.0.tar.gz) = 076fe31c8f03b0b52ff44346759c7dc8317da0972403b84dfe5898179f55acdba6c78827e0f8a53ff20afe8b76432c6fe0d655a75c24259d9acbaa4d9e8015c0
|
||||
SHA512 (websocket-client-1.2.1.tar.gz) = fdbeb7ac2add27478a17b388ac62e9378094a368f29749d8b63c274ee41836506369dddd083956f42f1f2d74948392b3ddd59b801c98f9e028c126bdb54c636b
|
||||
SHA512 (websocket_client-1.9.0.tar.gz) = 63385845aaaf792167d681c4b3089b09ea4dedbf931fa1f4ebc55648b6d864c2a479ac61f758d6a7967ce84e59e197613c976069f64381599c274f89c3edd0b4
|
||||
SHA512 (jinja2-3.1.6.tar.gz) = bddd5e142f1462426c57b2efafdfafdfc6b66de257668707940896feae71eabdf19e0b6e34ef49b965153baf9b1eb59bb5a97349bb287ea0921dd2a751e967ab
|
||||
SHA512 (MarkupSafe-2.0.1.tar.gz) = 77249bda784111ece15d59eb3de1cbb37a58fb9f22902fe6b73fea9eb0f23857ccbe53dc55463278e3b91f78dc35e2b027fd823ca50d88d8985d5a98ce2327f1
|
||||
SHA512 (python-string-utils-1.0.0.tar.gz) = 23ee48053848edd74915a985ee9edec48bbba468e228745f7d27b6a855c67f6b7ddf1cf71049458bf0b1c6c4d4f905ebacfac960597cbadbbe2daa1fe9472280
|
||||
SHA512 (requests-2.26.0.tar.gz) = c3397d77f0d2f1afb05661c4b98adad6c1ddaf360906254150b33ab0d9479fd306905bd6d61b8cf8becd9a40bdcf9b03542e8267c644ef19f03f44bfca0bc461
|
||||
SHA512 (charset-normalizer-2.0.7.tar.gz) = 7096fa23fade52c8eee2577b87aa574deffe6f66e8986f71172f3b9212bd6c6fb17901cceab90144c9d07de8bc6f5e320497daa3d3f749f436788232d4cba088
|
||||
SHA512 (idna-3.3.tar.gz) = 70b7cc8718e7d7899c75cfe476f044eae5a2fa03801fc9c12e3a092627ca943ffc4a578f9b8a55e181a11564835e125cfaaa577c02a6461dbb97366e620e53ad
|
||||
SHA512 (requests-oauthlib-1.3.0.tar.gz) = 7ef206aaf50cd3289f04175ff3a08022d00aeaaba57a6580912f37c30880322ec71ae9f6af7edc99efe6043fc6c19ba2c9f6fc0f29c126be28cde22bb885510d
|
||||
SHA512 (ruamel.yaml-0.17.16.tar.gz) = 61780127c23a2fa20c6ce29b27790b72538b5ea0370906d38f4cfe760c30a3756022a385d3f241dd88199358ff152d624dc372fbe7e1fd6d2959f873daf1263d
|
||||
SHA512 (setuptools_scm-8.1.0.tar.gz) = 205f1c122539d107a61a7ef01ff9ec225f7b2e6d92fc33a9f2a0c616051cbf32163ac4e6878d898e51cc1ff81fce6c6521a18fc5e09bdbc9d7d2467ba013c57f
|
||||
SHA512 (packaging-21.2-py3-none-any.whl) = 620a077783da21db677eda413c7cfcd9a9112afd573deda853615fad5b7f79b0ddfae4a7ee5d69834ba45e2299ebf343c6398b8eb60bb04569883520ada4a381
|
||||
SHA512 (poetry-core-1.0.7.tar.gz) = 0d93daefd7cb785059d1faa04b347cbaa908e0698d59543a18eeb6d86c8aae6f922b9105cb794b23895d676a05eea339f8f19bf41252e9940381be6b1c5d2d1a
|
||||
SHA512 (pyparsing-3.0.1.tar.gz) = 4a91daaf962a4d689ac26a712a83e8c4fbebc33270b6e46f0ae34fe247f6858d6334fbb59bdbbafa448703d24763fe1c86ce164e095de5003c7f1390960ba520
|
||||
SHA512 (packaging-26.0.tar.gz) = 27a066a7d65ba76189212973b6a0d162f3d361848b1b0c34a82865cf180b3284a837cc34206c297f002a73feae414e25a26c5960bb884a74ea337f582585f1d2
|
||||
SHA512 (tomli-2.0.1.tar.gz) = fd410039e255e2b3359e999d69a5a2d38b9b89b77e8557f734f2621dfbd5e1207e13aecc11589197ec22594c022f07f41b4cfe486a3a719281a595c95fd19ecf
|
||||
SHA512 (flit_core-3.9.0.tar.gz) = 1205589930d2c51d6aa6b2533a122a912e63b157e94adba2a0649a58d324fa98a5b84609d9b53e9d236f1cdb6a6984de2cefcf2f11abc2cd83956df21f269ad6
|
||||
SHA512 (wheel-0.37.0-py2.py3-none-any.whl) = 340ab4ad7337db653b173f4283fdacc3d5e8b3a1b133e3017d53c41f79f0cf7b327d8f530d07a0344435c4ffcdb10d36a4881586e6637658b70f88835ca8afa7
|
||||
SHA512 (flit_core-3.12.0.tar.gz) = 189dcd674722164b165e18b11c4dc72b8309fa2e3c82fc1ed6a9160bb5c6c1f86e2b2cfa111603cf73dca0dba74a496a664d5cbb6242587b47f139c42f7ae8bd
|
||||
SHA512 (pip-26.0.1.tar.gz) = 7fbcdd1f3f49ccc2b635b3f464488fedbafc71c2c18e2f801b2bc00c765c3ffbe3068050ea9a2964c93975c87a1f27d0188e7d01a9a17893dd6d2593ec58cf69
|
||||
SHA512 (setuptools-82.0.1.tar.gz) = 5d70e9efd818245fb8119a4eed64d776078469ed884facc188f141ea491efd9fde5c10c928d3236ea5e2e431b16616f18ed14870b867f95e6320251707332395
|
||||
SHA512 (wheel-0.46.3.tar.gz) = 4bda170a085b00bead5bd5beb1cd865af3699a940774615c087b9e96c86a56a1f3992613df162bc055aebcc84bc0e13df310a38c6102cfc1d5d78e8af33d4e1a
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
PYTHON_VERSION=$(python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')")
|
||||
|
||||
err=0
|
||||
|
||||
if [ "$(pcs stonith list 2> /dev/null | wc -l)" -eq 0 ]; then
|
||||
@ -11,20 +13,20 @@ fi
|
||||
|
||||
# test bundled libraries
|
||||
declare -A libs=(
|
||||
# aliyun
|
||||
["aliyunsdkcore"]="sys.path.insert(0, '/usr/lib/fence-agents/support/aliyun');"
|
||||
["aliyunsdkecs"]="sys.path.insert(0, '/usr/lib/fence-agents/support/aliyun');"
|
||||
# aws
|
||||
["boto3"]="sys.path.insert(0, '/usr/lib/fence-agents/support/aws');"
|
||||
# azure
|
||||
["azure"]="sys.path.insert(0, '/usr/lib/fence-agents/support/azure');"
|
||||
["msrestazure"]="sys.path.insert(0, '/usr/lib/fence-agents/support/azure');"
|
||||
# common
|
||||
["pexpect"]="sys.path.insert(0, '/usr/lib/fence-agents/support/common');"
|
||||
["suds"]="sys.path.insert(0, '/usr/lib/fence-agents/support/common');"
|
||||
["pexpect"]="sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python${PYTHON_VERSION}/site-packages');"
|
||||
["suds"]="sys.path.insert(0, '/usr/lib/fence-agents/support/common/lib/python${PYTHON_VERSION}/site-packages');"
|
||||
# aliyun
|
||||
["aliyunsdkcore"]="sys.path.insert(0, '/usr/lib/fence-agents/support/aliyun/lib/python${PYTHON_VERSION}/site-packages');"
|
||||
["aliyunsdkecs"]="sys.path.insert(0, '/usr/lib/fence-agents/support/aliyun/lib/python${PYTHON_VERSION}/site-packages');"
|
||||
# aws
|
||||
["boto3"]="sys.path.insert(0, '/usr/lib/fence-agents/support/aws/lib/python${PYTHON_VERSION}/site-packages');"
|
||||
# azure
|
||||
["azure"]="sys.path.insert(0, '/usr/lib/fence-agents/support/azure/lib/python${PYTHON_VERSION}/site-packages');"
|
||||
["msrestazure"]="sys.path.insert(0, '/usr/lib/fence-agents/support/azure/lib/python${PYTHON_VERSION}/site-packages');"
|
||||
# google
|
||||
["googleapiclient"]="sys.path.insert(0, '/usr/lib/fence-agents/support/google');"
|
||||
["pyroute2"]="sys.path.insert(0, '/usr/lib/fence-agents/support/google');"
|
||||
["googleapiclient"]="sys.path.insert(0, '/usr/lib/fence-agents/support/google/lib/python${PYTHON_VERSION}/site-packages');"
|
||||
["pyroute2"]="sys.path.insert(0, '/usr/lib/fence-agents/support/google/lib/python${PYTHON_VERSION}/site-packages');"
|
||||
)
|
||||
|
||||
for lib in "${!libs[@]}"; do
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo -e "Run \"pip download --no-binary PyYAML,msgpack,netifaces -r requirements-$1.txt\" to update,\n\
|
||||
and add output from \"sha512sum --tag <updated-files>\" to sources, and update spec-file."
|
||||
exit 0
|
||||
|
||||
##
|
||||
|
||||
export PYTHON_KEYRING_BACKEND="keyring.backends.null.Keyring"
|
||||
|
||||
find -maxdepth 1 -not -name "fence-agents-*.tar.gz" -and -not -name "awscli-*.tar.gz" -and -not -name "botocore-2*.zip" -and \( -name "*.whl" -or -name "*.tar.?z*" \) -delete
|
||||
sed -i -n -E '/\(fence-agents-|\(awscli-|\(botocore-2/p' sources
|
||||
sha512sum --tag requirements-*.txt >> sources
|
||||
|
||||
for x in requirements-*.txt; do
|
||||
echo "# $x" | sed -E "s/requirements-(.*).txt/\1/" >> sources
|
||||
pip download --no-binary PyYAML,msgpack,netifaces -r $x | awk '/Saved/{gsub("./", "", $2); print $2}' | sort | xargs sha512sum --tag >> sources
|
||||
done
|
||||
|
||||
awk 'NR<11{next} /^# /{print}; /^[^#]/{gsub("[()]", "", $2); printf "Source%d: %s\n", 1000+c++, $2}' sources
|
||||
|
||||
sed -i '/^#/d' sources
|
||||
|
||||
if ! git diff --quiet sources; then
|
||||
cat << EOF
|
||||
|
||||
Upload new sources by running:
|
||||
awk '/^[^#]/{gsub("[()]", "", \$2); printf "%s ", \$2}' sources | xargs centpkg new-sources
|
||||
|
||||
EOF
|
||||
fi
|
||||
Loading…
Reference in New Issue
Block a user