skylos 1.0.10__py3-none-any.whl → 2.5.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- skylos/__init__.py +9 -3
- skylos/analyzer.py +674 -168
- skylos/cfg_visitor.py +60 -0
- skylos/cli.py +719 -235
- skylos/codemods.py +277 -0
- skylos/config.py +50 -0
- skylos/constants.py +78 -0
- skylos/gatekeeper.py +147 -0
- skylos/linter.py +18 -0
- skylos/rules/base.py +20 -0
- skylos/rules/danger/calls.py +119 -0
- skylos/rules/danger/danger.py +157 -0
- skylos/rules/danger/danger_cmd/cmd_flow.py +75 -0
- skylos/rules/danger/danger_fs/__init__.py +0 -0
- skylos/rules/danger/danger_fs/path_flow.py +79 -0
- skylos/rules/danger/danger_net/__init__.py +0 -0
- skylos/rules/danger/danger_net/ssrf_flow.py +80 -0
- skylos/rules/danger/danger_sql/__init__.py +0 -0
- skylos/rules/danger/danger_sql/sql_flow.py +245 -0
- skylos/rules/danger/danger_sql/sql_raw_flow.py +96 -0
- skylos/rules/danger/danger_web/__init__.py +0 -0
- skylos/rules/danger/danger_web/xss_flow.py +170 -0
- skylos/rules/danger/taint.py +110 -0
- skylos/rules/quality/__init__.py +0 -0
- skylos/rules/quality/complexity.py +95 -0
- skylos/rules/quality/logic.py +96 -0
- skylos/rules/quality/nesting.py +101 -0
- skylos/rules/quality/structure.py +99 -0
- skylos/rules/secrets.py +325 -0
- skylos/server.py +554 -0
- skylos/visitor.py +502 -90
- skylos/visitors/__init__.py +0 -0
- skylos/visitors/framework_aware.py +437 -0
- skylos/visitors/test_aware.py +74 -0
- skylos-2.5.2.dist-info/METADATA +21 -0
- skylos-2.5.2.dist-info/RECORD +42 -0
- {skylos-1.0.10.dist-info → skylos-2.5.2.dist-info}/WHEEL +1 -1
- {skylos-1.0.10.dist-info → skylos-2.5.2.dist-info}/top_level.txt +0 -1
- skylos-1.0.10.dist-info/METADATA +0 -8
- skylos-1.0.10.dist-info/RECORD +0 -21
- test/compare_tools.py +0 -604
- test/diagnostics.py +0 -364
- test/sample_repo/app.py +0 -13
- test/sample_repo/sample_repo/commands.py +0 -81
- test/sample_repo/sample_repo/models.py +0 -122
- test/sample_repo/sample_repo/routes.py +0 -89
- test/sample_repo/sample_repo/utils.py +0 -36
- test/test_skylos.py +0 -456
- test/test_visitor.py +0 -220
- {test → skylos/rules}/__init__.py +0 -0
- {test/sample_repo → skylos/rules/danger}/__init__.py +0 -0
- {test/sample_repo/sample_repo → skylos/rules/danger/danger_cmd}/__init__.py +0 -0
- {skylos-1.0.10.dist-info → skylos-2.5.2.dist-info}/entry_points.txt +0 -0
test/test_visitor.py
DELETED
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
import ast
|
|
4
|
-
import unittest
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
import tempfile
|
|
7
|
-
|
|
8
|
-
from skylos.visitor import Visitor, Definition, PYTHON_BUILTINS, DYNAMIC_PATTERNS
|
|
9
|
-
|
|
10
|
-
class TestDefinition(unittest.TestCase):
|
|
11
|
-
"""Test the Definition class."""
|
|
12
|
-
|
|
13
|
-
def test_definition_creation(self):
|
|
14
|
-
"""Test basic definition creation."""
|
|
15
|
-
definition = Definition("module.function", "function", "test.py", 10)
|
|
16
|
-
|
|
17
|
-
self.assertEqual(definition.name, "module.function")
|
|
18
|
-
self.assertEqual(definition.type, "function")
|
|
19
|
-
self.assertEqual(definition.filename, "test.py")
|
|
20
|
-
self.assertEqual(definition.line, 10)
|
|
21
|
-
self.assertEqual(definition.simple_name, "function")
|
|
22
|
-
self.assertEqual(definition.confidence, 100)
|
|
23
|
-
self.assertEqual(definition.references, 0)
|
|
24
|
-
self.assertFalse(definition.is_exported)
|
|
25
|
-
|
|
26
|
-
def test_definition_to_dict_function(self):
|
|
27
|
-
"""Test to_dict method for functions."""
|
|
28
|
-
definition = Definition("mymodule.my_function", "function", "test.py", 5)
|
|
29
|
-
result = definition.to_dict()
|
|
30
|
-
|
|
31
|
-
expected = {
|
|
32
|
-
"name": "my_function",
|
|
33
|
-
"full_name": "mymodule.my_function",
|
|
34
|
-
"simple_name": "my_function",
|
|
35
|
-
"type": "function",
|
|
36
|
-
"file": "test.py",
|
|
37
|
-
"basename": "test.py",
|
|
38
|
-
"line": 5,
|
|
39
|
-
"confidence": 100,
|
|
40
|
-
"references": 0
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
self.assertEqual(result, expected)
|
|
44
|
-
|
|
45
|
-
def test_definition_to_dict_method(self):
|
|
46
|
-
"""Test to_dict method for methods."""
|
|
47
|
-
definition = Definition("mymodule.MyClass.my_method", "method", "test.py", 15)
|
|
48
|
-
result = definition.to_dict()
|
|
49
|
-
|
|
50
|
-
# show last two parts for methods
|
|
51
|
-
self.assertEqual(result["name"], "MyClass.my_method")
|
|
52
|
-
self.assertEqual(result["full_name"], "mymodule.MyClass.my_method")
|
|
53
|
-
self.assertEqual(result["simple_name"], "my_method")
|
|
54
|
-
|
|
55
|
-
def test_init_file_detection(self):
|
|
56
|
-
"""Test detection of __init__.py files."""
|
|
57
|
-
definition = Definition("pkg.func", "function", "/path/to/__init__.py", 1)
|
|
58
|
-
self.assertTrue(definition.in_init)
|
|
59
|
-
|
|
60
|
-
definition2 = Definition("pkg.func", "function", "/path/to/module.py", 1)
|
|
61
|
-
self.assertFalse(definition2.in_init)
|
|
62
|
-
|
|
63
|
-
class TestVisitor(unittest.TestCase):
|
|
64
|
-
"""Test the Visitor class."""
|
|
65
|
-
|
|
66
|
-
def setUp(self):
|
|
67
|
-
"""Set up test fixtures."""
|
|
68
|
-
self.temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False)
|
|
69
|
-
self.visitor = Visitor("test_module", self.temp_file.name)
|
|
70
|
-
|
|
71
|
-
def tearDown(self):
|
|
72
|
-
"""Clean up test fixtures."""
|
|
73
|
-
Path(self.temp_file.name).unlink()
|
|
74
|
-
|
|
75
|
-
def parse_and_visit(self, code):
|
|
76
|
-
"""Helper method to parse code and visit with the visitor."""
|
|
77
|
-
tree = ast.parse(code)
|
|
78
|
-
self.visitor.visit(tree)
|
|
79
|
-
return self.visitor
|
|
80
|
-
|
|
81
|
-
def test_simple_function(self):
|
|
82
|
-
"""Test detection of simple function definitions."""
|
|
83
|
-
code = """
|
|
84
|
-
def my_function():
|
|
85
|
-
pass
|
|
86
|
-
"""
|
|
87
|
-
visitor = self.parse_and_visit(code)
|
|
88
|
-
|
|
89
|
-
self.assertEqual(len(visitor.defs), 1)
|
|
90
|
-
definition = visitor.defs[0]
|
|
91
|
-
self.assertEqual(definition.type, "function")
|
|
92
|
-
self.assertEqual(definition.simple_name, "my_function")
|
|
93
|
-
|
|
94
|
-
def test_class_with_methods(self):
|
|
95
|
-
"""Test detection of classes and methods."""
|
|
96
|
-
code = """
|
|
97
|
-
class MyClass:
|
|
98
|
-
def __init__(self):
|
|
99
|
-
pass
|
|
100
|
-
|
|
101
|
-
def method(self):
|
|
102
|
-
pass
|
|
103
|
-
"""
|
|
104
|
-
visitor = self.parse_and_visit(code)
|
|
105
|
-
|
|
106
|
-
# technically should find class and two methods
|
|
107
|
-
self.assertEqual(len(visitor.defs), 3)
|
|
108
|
-
|
|
109
|
-
class_def = next(d for d in visitor.defs if d.type == "class")
|
|
110
|
-
self.assertEqual(class_def.simple_name, "MyClass")
|
|
111
|
-
|
|
112
|
-
methods = [d for d in visitor.defs if d.type == "method"]
|
|
113
|
-
self.assertEqual(len(methods), 2)
|
|
114
|
-
method_names = {m.simple_name for m in methods}
|
|
115
|
-
self.assertEqual(method_names, {"__init__", "method"})
|
|
116
|
-
|
|
117
|
-
def test_imports(self):
|
|
118
|
-
"""Test import statement detection."""
|
|
119
|
-
code = """
|
|
120
|
-
import os
|
|
121
|
-
import sys as system
|
|
122
|
-
from pathlib import Path
|
|
123
|
-
from collections import defaultdict, Counter
|
|
124
|
-
"""
|
|
125
|
-
visitor = self.parse_and_visit(code)
|
|
126
|
-
|
|
127
|
-
imports = [d for d in visitor.defs if d.type == "import"]
|
|
128
|
-
self.assertTrue(len(imports) >= 4)
|
|
129
|
-
|
|
130
|
-
self.assertEqual(visitor.alias["system"], "sys")
|
|
131
|
-
self.assertEqual(visitor.alias["Path"], "pathlib.Path")
|
|
132
|
-
self.assertEqual(visitor.alias["defaultdict"], "collections.defaultdict")
|
|
133
|
-
|
|
134
|
-
def test_nested_functions(self):
|
|
135
|
-
"""Test nested function detection."""
|
|
136
|
-
code = """
|
|
137
|
-
def outer():
|
|
138
|
-
def inner():
|
|
139
|
-
def deeply_nested():
|
|
140
|
-
pass
|
|
141
|
-
return deeply_nested()
|
|
142
|
-
return inner()
|
|
143
|
-
"""
|
|
144
|
-
visitor = self.parse_and_visit(code)
|
|
145
|
-
|
|
146
|
-
functions = [d for d in visitor.defs if d.type == "function"]
|
|
147
|
-
self.assertEqual(len(functions), 3)
|
|
148
|
-
|
|
149
|
-
names = {f.name for f in functions}
|
|
150
|
-
expected_names = {
|
|
151
|
-
"test_module.outer",
|
|
152
|
-
"test_module.outer.inner",
|
|
153
|
-
"test_module.outer.inner.deeply_nested"
|
|
154
|
-
}
|
|
155
|
-
self.assertEqual(names, expected_names)
|
|
156
|
-
|
|
157
|
-
def test_getattr_detection(self):
|
|
158
|
-
"""Test detection of getattr calls."""
|
|
159
|
-
code = """
|
|
160
|
-
obj = SomeClass()
|
|
161
|
-
value = getattr(obj, 'attribute_name')
|
|
162
|
-
check = hasattr(obj, 'other_attr')
|
|
163
|
-
"""
|
|
164
|
-
visitor = self.parse_and_visit(code)
|
|
165
|
-
|
|
166
|
-
ref_names = {ref[0] for ref in visitor.refs}
|
|
167
|
-
self.assertIn('attribute_name', ref_names)
|
|
168
|
-
self.assertIn('other_attr', ref_names)
|
|
169
|
-
|
|
170
|
-
def test_all_detection(self):
|
|
171
|
-
"""Test __all__ detection."""
|
|
172
|
-
code = """
|
|
173
|
-
__all__ = ['function1', 'Class1', 'CONSTANT']
|
|
174
|
-
|
|
175
|
-
def function1():
|
|
176
|
-
pass
|
|
177
|
-
|
|
178
|
-
class Class1:
|
|
179
|
-
pass
|
|
180
|
-
|
|
181
|
-
CONSTANT = 42
|
|
182
|
-
"""
|
|
183
|
-
visitor = self.parse_and_visit(code)
|
|
184
|
-
|
|
185
|
-
ref_names = {ref[0] for ref in visitor.refs}
|
|
186
|
-
self.assertIn('function1', ref_names)
|
|
187
|
-
self.assertIn('Class1', ref_names)
|
|
188
|
-
self.assertIn('CONSTANT', ref_names)
|
|
189
|
-
|
|
190
|
-
def test_builtin_detection(self):
|
|
191
|
-
"""Test that builtins are correctly identified."""
|
|
192
|
-
code = """
|
|
193
|
-
def my_function():
|
|
194
|
-
result = len([1, 2, 3])
|
|
195
|
-
print(result)
|
|
196
|
-
data = list(range(10))
|
|
197
|
-
return data
|
|
198
|
-
"""
|
|
199
|
-
visitor = self.parse_and_visit(code)
|
|
200
|
-
|
|
201
|
-
ref_names = {ref[0] for ref in visitor.refs}
|
|
202
|
-
builtins_found = ref_names & PYTHON_BUILTINS
|
|
203
|
-
expected_builtins = {'len', 'print', 'list', 'range'}
|
|
204
|
-
self.assertTrue(expected_builtins.issubset(builtins_found))
|
|
205
|
-
|
|
206
|
-
class TestConstants(unittest.TestCase):
|
|
207
|
-
"""Test the module constants."""
|
|
208
|
-
|
|
209
|
-
def test_python_builtins(self):
|
|
210
|
-
"""Test that important builtins are included."""
|
|
211
|
-
important_builtins = {'print', 'len', 'str', 'int', 'list', 'dict', 'range'}
|
|
212
|
-
self.assertTrue(important_builtins.issubset(PYTHON_BUILTINS))
|
|
213
|
-
|
|
214
|
-
def test_dynamic_patterns(self):
|
|
215
|
-
"""Test dynamic pattern constants."""
|
|
216
|
-
expected_patterns = {'getattr', 'globals', 'eval', 'exec'}
|
|
217
|
-
self.assertTrue(expected_patterns.issubset(DYNAMIC_PATTERNS))
|
|
218
|
-
|
|
219
|
-
if __name__ == '__main__':
|
|
220
|
-
unittest.main(verbosity=2)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|