ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
suppression_shell_lex.py
Go to the documentation of this file.
1# SPDX-License-Identifier: MIT
2# Copyright (c) 2026 Brighton Sikarskie
3"""Shell operator masking for suppression inventory scans."""
4
5from __future__ import annotations
6
7from dataclasses import dataclass, field
8
9
10@dataclass
11class ShellFrame:
12 """One active shell lexical context."""
13
14 kind: str
15 depth: int = 0
16
17
18@dataclass
19class ShellOperatorState:
20 """Cross-line quote and command-substitution state."""
21
22 frames: list[ShellFrame] = field(default_factory=lambda: [ShellFrame("normal")])
23
24
25def _mask_escape(code: str, index: int, masked: list[str]) -> int:
26 """Mask one escape and its following byte."""
27 masked.append(" ")
28 if index + 1 < len(code):
29 masked.append(" ")
30 return index + 2
31 return index + 1
32
33
34def _consume_single(code: str, index: int, state: ShellOperatorState, masked: list[str]) -> int:
35 """Consume one byte from a single-quoted literal."""
36 masked.append(" ")
37 if code[index] == "'":
38 state.frames.pop()
39 return index + 1
40
41
42def _consume_double(code: str, index: int, state: ShellOperatorState, masked: list[str]) -> int:
43 """Consume one byte from double quotes, exposing command substitutions."""
44 char = code[index]
45 if char == "\\":
46 return _mask_escape(code, index, masked)
47 if code.startswith("$(", index):
48 masked.extend(" ")
49 state.frames.append(ShellFrame("command", 1))
50 return index + 2
51 masked.append(" ")
52 if char == '"':
53 state.frames.pop()
54 return index + 1
55
56
57def _consume_active(code: str, index: int, state: ShellOperatorState, masked: list[str]) -> int:
58 """Consume one byte from ordinary or command-substitution shell syntax."""
59 char = code[index]
60 frame = state.frames[-1]
61 if char == "\\":
62 return _mask_escape(code, index, masked)
63 if char == "'":
64 masked.append(" ")
65 state.frames.append(ShellFrame("single"))
66 elif char == '"':
67 masked.append(" ")
68 state.frames.append(ShellFrame("double"))
69 elif char == "`":
70 masked.append(" ")
71 if frame.kind == "backtick":
72 state.frames.pop()
73 else:
74 state.frames.append(ShellFrame("backtick"))
75 elif code.startswith("$(", index):
76 masked.extend(" ")
77 state.frames.append(ShellFrame("command", 1))
78 return index + 2
79 elif frame.kind == "command" and char == "(":
80 masked.append(char)
81 frame.depth += 1
82 elif frame.kind == "command" and char == ")":
83 masked.append(char)
84 frame.depth -= 1
85 if frame.depth == 0:
86 state.frames.pop()
87 else:
88 masked.append(char)
89 return index + 1
90
91
92def mask_shell_operators(code: str, state: ShellOperatorState) -> str:
93 """Mask literal data but retain operators executed by this shell line."""
94 masked: list[str] = []
95 index = 0
96 while index < len(code):
97 frame = state.frames[-1]
98 if frame.kind == "single":
99 index = _consume_single(code, index, state, masked)
100 elif frame.kind == "double":
101 index = _consume_double(code, index, state, masked)
102 else:
103 index = _consume_active(code, index, state, masked)
104 return "".join(masked)