Merge pull request #1955 from volatilityfoundation/issues/shift-to-ruff-for-formatting

Switch to using ruff for formatting as well as linting
This commit is contained in:
ikelos
2026-03-09 21:35:49 +00:00
committed by GitHub
22 changed files with 68 additions and 83 deletions
-15
View File
@@ -1,15 +0,0 @@
name: Black python formatter
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: psf/black@stable
with:
options: "--check --diff --verbose"
src: "./volatility3"
# FIXME: Remove when Volatility3 minimum Python version is >3.8
version: "24.8.0"
+3 -1
View File
@@ -4,7 +4,7 @@ name: Ruff
on: [push, pull_request]
jobs:
lint:
lint-and-format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -13,3 +13,5 @@ jobs:
with:
args: check
src: "."
- run: "ruff format --check --diff"
+1 -1
View File
@@ -5,7 +5,7 @@ The coding standards for volatility are mostly by our linter and our code format
All code submissions will be vetted automatically through tests from both and the submission will not be accepted if either of these fail.
Code Linter: Ruff
Code Formatter: Black
Code Formatter: Ruff
In addition, there are some coding practices that we employ to prevent specific failure cases and ensure consistency across the codebase. These are documented below along with the rationale for the decision.
+3 -3
View File
@@ -464,9 +464,9 @@ class PrettyTextRenderer(CLIRenderer):
accumulator.append((node.path_depth, line))
return accumulator
final_output: List[Tuple[int, Dict[interfaces.renderers.Column, list[str]]]] = (
[]
)
final_output: List[
Tuple[int, Dict[interfaces.renderers.Column, list[str]]]
] = []
if not grid.populated:
grid.populate(visitor, final_output)
else:
+1 -3
View File
@@ -165,9 +165,7 @@ class LinuxIntelStacker(interfaces.automagic.StackerLayerInterface):
"init_mm"
).address and init_task.tasks.next.cast(
"long unsigned int"
) == init_task.tasks.prev.cast(
"long unsigned int"
):
) == init_task.tasks.prev.cast("long unsigned int"):
# The idle task steals `mm` from previously running task, i.e.,
# `init_mm` is only used as long as no CPU has ever been idle.
# This catches cases where we found a fragment of the
+1 -2
View File
@@ -160,8 +160,7 @@ class AVMLLayer(segmented.NonLinearlySegmentedLayer):
if frame_type == 0xFF:
if (
data[
offset
+ frame_header_len : offset
offset + frame_header_len : offset
+ frame_header_len
+ frame_size
]
+3 -3
View File
@@ -948,9 +948,9 @@ class AggregateType(interfaces.objects.ObjectInterface):
if isinstance(cls, agg_type):
agg_name = agg_type.__name__
assert isinstance(
members, collections.abc.Mapping
), f"{agg_name} members parameter must be a mapping: {type(members)}"
assert isinstance(members, collections.abc.Mapping), (
f"{agg_name} members parameter must be a mapping: {type(members)}"
)
assert all(
(isinstance(member, tuple) and len(member) == 2)
for member in members.values()
@@ -88,7 +88,12 @@ class Malfind(interfaces.plugins.PluginInterface):
for page_addr in malicious_pages:
offset = page_addr - vma.vm_start
data = proc_layer.read(page_addr, dump_size, pad=True)
yield vma, f"{vma_name}, page address: {page_addr:#x}, offset: {offset:#x}", data, offset
yield (
vma,
f"{vma_name}, page address: {page_addr:#x}, offset: {offset:#x}",
data,
offset,
)
else:
# Original behaviour - Dump the start of the region (not necessarily matching the dirty page)
data = proc_layer.read(vma.vm_start, dump_size, pad=True)
@@ -194,15 +194,11 @@ class PIDHashTable(plugins.PluginInterface):
has_pid_numbers = vmlinux.has_type("pid") and vmlinux.get_type(
"pid"
).has_member(
"numbers"
) # kernels >= 2.6.24
).has_member("numbers") # kernels >= 2.6.24
has_pid_chain = vmlinux.has_type("upid") and vmlinux.get_type(
"upid"
).has_member(
"pid_chain"
) # 2.6.24 <= kernels < 4.15
).has_member("pid_chain") # 2.6.24 <= kernels < 4.15
# kernels >= 4.15
pid_idr = vmlinux.has_type("pid_namespace") and vmlinux.get_type(
+3 -3
View File
@@ -70,9 +70,9 @@ class Maps(plugins.PluginInterface):
def list_vmas(
cls,
task: interfaces.objects.ObjectInterface,
filter_func: Callable[
[interfaces.objects.ObjectInterface], bool
] = lambda _: True,
filter_func: Callable[[interfaces.objects.ObjectInterface], bool] = lambda _: (
True
),
) -> Generator[interfaces.objects.ObjectInterface, None, None]:
"""Lists the Virtual Memory Areas of a specific process.
@@ -34,7 +34,9 @@ class PerfEvents(plugins.PluginInterface):
]
@classmethod
def list_perf_events(cls, context, vmlinux_module_name: str) -> Generator[
def list_perf_events(
cls, context, vmlinux_module_name: str
) -> Generator[
Tuple[
interfaces.objects.ObjectInterface,
interfaces.objects.ObjectInterface,
@@ -65,9 +65,9 @@ class Maps(interfaces.plugins.PluginInterface):
def list_vmas(
cls,
task: interfaces.objects.ObjectInterface,
filter_func: Callable[
[interfaces.objects.ObjectInterface], bool
] = lambda _: True,
filter_func: Callable[[interfaces.objects.ObjectInterface], bool] = lambda _: (
True
),
) -> Generator[interfaces.objects.ObjectInterface, None, None]:
"""Lists the Virtual Memory Areas of a specific process.
+3 -1
View File
@@ -49,7 +49,9 @@ class PsList(interfaces.plugins.PluginInterface):
]
@classmethod
def get_list_tasks(cls, method: str) -> Callable[
def get_list_tasks(
cls, method: str
) -> Callable[
[interfaces.context.ContextInterface, str, Callable[[int], bool]],
Iterable[interfaces.objects.ObjectInterface],
]:
@@ -19,9 +19,7 @@ vollog = logging.getLogger(__name__)
def createservicesid(svc) -> str:
"""Calculate the Service SID"""
uni = "".join([c + "\x00" for c in svc])
sha = hashlib.sha1(
uni.upper().encode("utf-8")
).digest() # pylint: disable-msg=E1101
sha = hashlib.sha1(uni.upper().encode("utf-8")).digest() # pylint: disable-msg=E1101
dec = list()
for i in range(5):
## The use of struct here is OK. It doesn't make much sense
@@ -37,7 +37,9 @@ class PebMasquerade(interfaces.plugins.PluginInterface):
]
@classmethod
def get_process_names(cls, proc: interfaces.objects.ObjectInterface) -> Tuple[
def get_process_names(
cls, proc: interfaces.objects.ObjectInterface
) -> Tuple[
Union[str, renderers.NotAvailableValue],
Union[str, renderers.NotAvailableValue],
Union[str, renderers.NotAvailableValue],
+12 -10
View File
@@ -167,13 +167,15 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
Filter function for passing to the `list_processes` method
"""
return lambda x: not (
x.is_valid()
and x.ActiveThreads > 0
and x.UniqueProcessId != 4
and x.InheritedFromUniqueProcessId != 4
and x.ExitTime.QuadPart == 0
and x.get_handle_count() != renderers.UnreadableValue()
return lambda x: (
not (
x.is_valid()
and x.ActiveThreads > 0
and x.UniqueProcessId != 4
and x.InheritedFromUniqueProcessId != 4
and x.ExitTime.QuadPart == 0
and x.get_handle_count() != renderers.UnreadableValue()
)
)
@classmethod
@@ -214,9 +216,9 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
cls,
context: interfaces.context.ContextInterface,
kernel_module_name: str,
filter_func: Callable[
[interfaces.objects.ObjectInterface], bool
] = lambda _: False,
filter_func: Callable[[interfaces.objects.ObjectInterface], bool] = lambda _: (
False
),
) -> Iterator["extensions.EPROCESS"]:
"""Lists all the processes in the given layer that are in the pid
config option.
@@ -150,9 +150,9 @@ class PsScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
cls,
context: interfaces.context.ContextInterface,
kernel_module_name: str,
filter_func: Callable[
[interfaces.objects.ObjectInterface], bool
] = lambda _: False,
filter_func: Callable[[interfaces.objects.ObjectInterface], bool] = lambda _: (
False
),
) -> Iterable[interfaces.objects.ObjectInterface]:
"""Scans for processes using the poolscanner module and constraints.
@@ -53,9 +53,9 @@ class PsTree(interfaces.plugins.PluginInterface):
def find_level(
self,
pid: int,
filter_func: Callable[
[interfaces.objects.ObjectInterface], bool
] = lambda _: False,
filter_func: Callable[[interfaces.objects.ObjectInterface], bool] = lambda _: (
False
),
) -> None:
"""Finds how deep the pid is in the processes list."""
seen = {pid}
@@ -77,9 +77,9 @@ class PsTree(interfaces.plugins.PluginInterface):
def _generator(
self,
filter_func: Callable[
[interfaces.objects.ObjectInterface], bool
] = lambda _: False,
filter_func: Callable[[interfaces.objects.ObjectInterface], bool] = lambda _: (
False
),
):
"""Generates the Tree of processes."""
kernel = self.context.modules[self.config["kernel"]]
@@ -99,12 +99,8 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface)
thread_tid = ethread.Cid.UniqueThread
thread_start_addr = ethread.StartAddress
thread_win32start_addr = ethread.Win32StartAddress
thread_create_time = (
ethread.get_create_time()
) # datetime.datetime object / volatility3.framework.renderers.UnparsableValue object
thread_exit_time = (
ethread.get_exit_time()
) # datetime.datetime object / volatility3.framework.renderers.UnparsableValue object
thread_create_time = ethread.get_create_time() # datetime.datetime object / volatility3.framework.renderers.UnparsableValue object
thread_exit_time = ethread.get_exit_time() # datetime.datetime object / volatility3.framework.renderers.UnparsableValue object
owner_proc = None
if vads_cache is not None:
@@ -115,9 +115,9 @@ class VadInfo(interfaces.plugins.PluginInterface):
def list_vads(
cls,
proc: interfaces.objects.ObjectInterface,
filter_func: Callable[
[interfaces.objects.ObjectInterface], bool
] = lambda _: False,
filter_func: Callable[[interfaces.objects.ObjectInterface], bool] = lambda _: (
False
),
) -> Generator[interfaces.objects.ObjectInterface, None, None]:
"""Lists the Virtual Address Descriptors of a specific process.
@@ -198,7 +198,9 @@ class VadInfo(interfaces.plugins.PluginInterface):
return file_handle
def _generator(self, procs: List[interfaces.objects.ObjectInterface]) -> Generator[
def _generator(
self, procs: List[interfaces.objects.ObjectInterface]
) -> Generator[
Tuple[
int,
Tuple[
@@ -126,8 +126,7 @@ class POOL_HEADER(objects.StructType):
infomask_value = infomask_data[addr + infomask_offset]
pointercount_value = int.from_bytes(
infomask_data[
addr
+ pointercount_offset : addr
addr + pointercount_offset : addr
+ pointercount_offset
+ pointercount_size
],
@@ -165,8 +164,7 @@ class POOL_HEADER(objects.StructType):
(padding_length,) = struct.unpack(
"<I",
infomask_data[
addr
- optional_headers_length : addr
addr - optional_headers_length : addr
- optional_headers_length
+ 4
],
@@ -552,9 +552,7 @@ class PdbSignatureScanner(interfaces.layers.ScannerInterface):
)
for match in re.finditer(pattern, data, flags=re.DOTALL):
pdb_name = data[
match.start(0)
+ 4
+ self._RSDS_format.size : match.start(0)
match.start(0) + 4 + self._RSDS_format.size : match.start(0)
+ len(match.group())
- 1
]