Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
ed66905
Initial commit
klimaj Sep 19, 2025
d6ebb3e
Update prefix pattern matching
klimaj Sep 19, 2025
81cee73
Merge branch 'main' into unpickle
klimaj Sep 19, 2025
f1b100c
Add pickle alternatives
klimaj Sep 20, 2025
e48d6fd
Fix Exception in self.assertRaises
klimaj Sep 20, 2025
e870cdd
Update docstrings/exceptions
klimaj Sep 20, 2025
708bde3
Set SecureSerializerBase._pickle_protocol to pickle.DEFAULT_PROTOCOL
klimaj Sep 20, 2025
17abab2
Docstrings
klimaj Sep 20, 2025
67724a0
Raise from caller
klimaj Sep 20, 2025
6c83e0b
Define PyRosettaModuleNotFoundError
klimaj Sep 20, 2025
24b3f85
Clean up
klimaj Sep 20, 2025
071f7cb
Add packages
klimaj Sep 20, 2025
15f08c0
Set digest_size=16
klimaj Sep 20, 2025
cc3248e
Update lru_cache
klimaj Sep 20, 2025
bfb506b
Raise exception from ex
klimaj Sep 20, 2025
40b01cc
Allow copyreg methods depending on incoming stream pickle protocol
klimaj Sep 20, 2025
30d86ca
Add numpy.array roundtrip test
klimaj Sep 20, 2025
ba377fc
Update module parsing under pyrosetta.rosetta namespace
klimaj Sep 20, 2025
027f85f
Fix keyword argument
klimaj Sep 21, 2025
d0e2989
Fix SecureSerializerBase.from_base64
klimaj Sep 21, 2025
c336098
Fix _get_stream_protocol for protocol <= 2
klimaj Sep 21, 2025
53c92cd
Clean up
klimaj Sep 21, 2025
0c0ad09
Skip re-import
klimaj Sep 21, 2025
67240f4
Update builtins
klimaj Sep 21, 2025
5cbd5f1
Debug
klimaj Sep 21, 2025
5467725
Revert "Debug"
klimaj Sep 21, 2025
ba9b0c1
Skip assertion that rosetta.so must be under the pyrosetta package ba…
klimaj Sep 21, 2025
69ce7e3
Update unpickle exception handling
klimaj Sep 21, 2025
e2ceb7c
Prevent re-import; walk down attributes of imported virtual submodule
klimaj Sep 21, 2025
40f0f60
Update self.assertIn calls
klimaj Sep 21, 2025
0b19189
Update blocked globals
klimaj Sep 21, 2025
c48f2d8
raise UnpickleCompatibilityError for unpickle-allowed packages missin…
klimaj Sep 22, 2025
8236ea5
Update typing
klimaj Sep 22, 2025
4126b56
Clean up builtins parsing
klimaj Sep 22, 2025
9dc01f3
Handle MemoryError and KeyboardInterrupt exceptions
klimaj Sep 22, 2025
15eb2ba
Fix _get_stream_protocol if missing pickle.PROTO
klimaj Sep 22, 2025
79eee40
Add type to builtins
klimaj Sep 22, 2025
d54a135
Clean up
klimaj Sep 22, 2025
95f0237
Update disallowed builtins UnpickleSecurityError message
klimaj Sep 22, 2025
49a17a5
Add tests for secure builtins roundtrip and disallowed packages
klimaj Sep 22, 2025
0e12865
Add test for disallowed globals
klimaj Sep 22, 2025
4a75a48
Add test for disallowed prefixes
klimaj Sep 22, 2025
6eb7156
Add getattr(pickle, 'PROTO')
klimaj Sep 22, 2025
470f43f
Make globals frozensets
klimaj Sep 22, 2025
f9efe92
Add _secure_packages variable
klimaj Sep 22, 2025
3435ebd
Removing type
klimaj Sep 22, 2025
818ab79
Add thread lock for mutating global variables
klimaj Sep 22, 2025
5429899
Clean up
klimaj Sep 22, 2025
6496966
Run secure_loads in Serialization.decompress_packed_pose method
klimaj Sep 23, 2025
a927295
Add warning for untrusted data in secure unpickling
rclune Sep 23, 2025
2364cdc
Revise warning for secure unpickling in PyRosetta
rclune Sep 23, 2025
c2bc266
Remove imports
klimaj Sep 24, 2025
c0b6599
Update error messages reflecting import change
klimaj Sep 24, 2025
76b33b0
Update unit test reflecting import change
klimaj Sep 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,36 @@
__author__ = "Jason C. Klima"


import base64
import collections
import pickle

from pyrosetta.secure_unpickle import SecureSerializerBase


class PoseScoreSerializerBase(object):
"""Base class for `PoseScoreSerializer` methods."""

@staticmethod
def to_pickle(value):
try:
return pickle.dumps(value)
except (TypeError, OverflowError, MemoryError, pickle.PicklingError) as ex:
raise TypeError(
"Only pickle-serializable object types are allowed to be set "
+ "as score values. Received: %r. %s" % (type(value), ex)
)
return SecureSerializerBase.to_pickle(value)

@staticmethod
def from_pickle(value):
try:
return pickle.loads(value)
except (TypeError, OverflowError, MemoryError, EOFError, pickle.UnpicklingError) as ex:
raise TypeError(
"Could not deserialize score value of type %r. %s" % (type(value), ex)
)
return SecureSerializerBase.secure_loads(value)

@staticmethod
def to_base64(value):
return base64.b64encode(value).decode()
return SecureSerializerBase.to_base64(value)

@staticmethod
def from_base64(value):
return base64.b64decode(value, validate=True)
return SecureSerializerBase.from_base64(value)

@staticmethod
def to_base64_pickle(value):
return PoseScoreSerializerBase.to_base64(PoseScoreSerializerBase.to_pickle(value))
def to_base64_pickle(obj):
return SecureSerializerBase.secure_to_base64_pickle(obj)

@staticmethod
def from_base64_pickle(value):
return PoseScoreSerializerBase.from_pickle(PoseScoreSerializerBase.from_base64(value))
return SecureSerializerBase.secure_from_base64_pickle(value)

@staticmethod
def bool_from_str(value):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"run",
"update_scores",
]
__version__: str = "2.1.1"
__version__: str = "2.1.2"

_print_conda_warnings()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

from functools import singledispatch, wraps
from pyrosetta.distributed.packed_pose.core import PackedPose
from pyrosetta.secure_unpickle import SecureSerializerBase
from typing import (
Any,
Dict,
Expand Down Expand Up @@ -189,7 +190,7 @@ def compress_packed_pose(self, packed_pose: Any) -> Union[NoReturn, None, bytes]
compressed_packed_pose = None
elif isinstance(packed_pose, PackedPose):
packed_pose = update_scores(packed_pose)
compressed_packed_pose = self.encoder(packed_pose.pickled_pose)
compressed_packed_pose = self.encoder(io.to_pickle(packed_pose))
else:
raise TypeError(
"The 'packed_pose' argument parameter must be of type `NoneType` or `PackedPose`."
Expand All @@ -200,8 +201,8 @@ def compress_packed_pose(self, packed_pose: Any) -> Union[NoReturn, None, bytes]
@requires_compression
def decompress_packed_pose(self, compressed_packed_pose: Any) -> Union[NoReturn, None, PackedPose]:
"""
Decompress a `bytes` object with the custom serialization and `cloudpickle` modules. If the 'compressed_packed_pose'
argument parameter is `None`, then just return `None`.
Decompress a `bytes` object with the custom serialization module and secure implementation of the `pickle` module.
If the 'compressed_packed_pose' argument parameter is `None`, then just return `None`.

Args:
compressed_packed_pose: the input `bytes` object to decompress. If `None`, then just return `None`.
Expand All @@ -215,7 +216,7 @@ def decompress_packed_pose(self, compressed_packed_pose: Any) -> Union[NoReturn,
if compressed_packed_pose is None:
packed_pose = None
elif isinstance(compressed_packed_pose, bytes):
pose = cloudpickle.loads(self.decoder(compressed_packed_pose))
pose = SecureSerializerBase.secure_loads(self.decoder(compressed_packed_pose))
packed_pose = io.to_packed(pose)
else:
raise TypeError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
import pyrosetta.rosetta.core.pose as pose
import pyrosetta.distributed

from pyrosetta.secure_unpickle import SecureSerializerBase


__all__ = ["pack_result", "pose_result", "to_packed", "to_pose", "to_dict", "to_base64", "to_pickle", "PackedPose"]


Expand All @@ -38,7 +41,7 @@ class PackedPose:
def __init__(self, pose_or_pack):
"""Create a packed pose from pose, pack, or pickled bytes."""
if isinstance(pose_or_pack, pose.Pose):
self.pickled_pose = pickle.dumps(pose_or_pack)
self.pickled_pose = SecureSerializerBase.to_pickle(pose_or_pack)
self.scores = dict(pose_or_pack.cache)

elif isinstance(pose_or_pack, PackedPose):
Expand All @@ -55,7 +58,7 @@ def __init__(self, pose_or_pack):
@property
@pyrosetta.distributed.requires_init
def pose(self):
return pickle.loads(self.pickled_pose)
return SecureSerializerBase.secure_loads(self.pickled_pose)

def update_scores(self, *score_dicts, **score_kwargs):
new_scores = {}
Expand All @@ -71,7 +74,9 @@ def update_scores(self, *score_dicts, **score_kwargs):

def clone(self):
result = PackedPose(self.pose)
result.scores = pickle.loads(pickle.dumps(self.scores))
result.scores = SecureSerializerBase.secure_loads(
SecureSerializerBase.to_pickle(self.scores)
)
return result

def empty(self):
Expand Down
Loading