Skip to content

Commit 6eeadbb

Browse files
Make MLAllowlist opt-in
Analysis.__init_subclass__ put every subclass into Analysis.ALL, and fickling/__init__.py transitively imported fickling.ml via hook.py, wich registered MLAllowlist. The shorten_code() shadowing bug (GHSA-cffv-grgg-g429) made it dead code until the previous commit, and now it conflicts with other default analysis passes. This commit makes MLAllowlist opt-in; use `check_safety(analyze=...)` if you need it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b08e331 commit 6eeadbb

4 files changed

Lines changed: 28 additions & 5 deletions

File tree

fickling/analysis.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,10 @@ def __str__(self):
170170
class Analysis(ABC):
171171
ALL: list[Analysis] = []
172172

173-
def __init_subclass__(cls, **kwargs):
174-
Analysis.ALL.append(cls())
173+
def __init_subclass__(cls, *, register: bool = True, **kwargs):
174+
super().__init_subclass__(**kwargs)
175+
if register:
176+
Analysis.ALL.append(cls())
175177

176178
@abstractmethod
177179
def analyze(self, context: AnalysisContext) -> Iterator[AnalysisResult]:

fickling/ml.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@
288288
}
289289

290290

291-
class MLAllowlist(Analysis):
291+
class MLAllowlist(Analysis, register=False):
292292
def __init__(self):
293293
super().__init__()
294294
self.allowlist = ML_ALLOWLIST

test/test_analysis.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from unittest import TestCase
2+
3+
import fickling.fickle as op
4+
from fickling.analysis import Severity, check_safety
5+
from fickling.fickle import Pickled
6+
7+
8+
class TestAnalysis(TestCase):
9+
def test_benign_pickle(self):
10+
pickled = Pickled(
11+
[
12+
op.Proto.create(4),
13+
op.ShortBinUnicode("collections"),
14+
op.ShortBinUnicode("deque"),
15+
op.StackGlobal(),
16+
op.Stop(),
17+
]
18+
)
19+
self.assertEqual(check_safety(pickled).severity, Severity.LIKELY_SAFE)

test/test_bypasses.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
from unittest import TestCase
33

44
import fickling.fickle as op
5-
from fickling.analysis import Severity, UnsafeImportsML, check_safety
5+
from fickling.analysis import Analyzer, Severity, UnsafeImportsML, check_safety
66
from fickling.fickle import Pickled
7+
from fickling.ml import MLAllowlist
78

89

910
class TestBypasses(TestCase):
@@ -697,7 +698,8 @@ def test_ml_allowlist_not_shadowed_by_unsafe_imports_ml(self):
697698
op.Stop(),
698699
]
699700
)
700-
res = check_safety(pickled)
701+
analyzer = Analyzer([UnsafeImportsML(), MLAllowlist()])
702+
res = check_safety(pickled, analyzer=analyzer)
701703
self.assertGreater(res.severity, Severity.LIKELY_SAFE)
702704
detailed = res.detailed_results().get("AnalysisResult", {})
703705
self.assertIsNotNone(

0 commit comments

Comments
 (0)