Log entry to track the propagation of taints in the AST
| 82 | node = None |
| 83 | ) |
| 84 | class TaintLog: |
| 85 | """ |
| 86 | Log entry to track the propagation of taints in the AST |
| 87 | """ |
| 88 | __slots__ = ("path", "taint_level", "line_no", "message", "extra", "node") |
| 89 | path: Path # Path to the affected source code |
| 90 | taint_level: typing.Optional[Taints] |
| 91 | line_no: typing.Optional[int] |
| 92 | message: typing.Optional[str] |
| 93 | extra: dict |
| 94 | node: typing.Optional[NodeType] |
| 95 | |
| 96 | def __post_init__(self): |
| 97 | self.path = Path(self.path).absolute() |
| 98 | |
| 99 | def json(self) -> dict: |
| 100 | d = { |
| 101 | 'line_no': self.line_no, |
| 102 | 'message': self.message |
| 103 | } |
| 104 | |
| 105 | if self.path: |
| 106 | # TODO: normalize the path |
| 107 | d['path'] = os.fspath(self.path) |
| 108 | |
| 109 | if self.taint_level: |
| 110 | d['taint_level'] = self.taint_level.name |
| 111 | |
| 112 | if self.extra: |
| 113 | d['extra'] = self.extra |
| 114 | |
| 115 | return d |
| 116 | |
| 117 | @classmethod |
| 118 | def extract_log(cls, node: ASTNode): |
| 119 | """ |
| 120 | Extract a sequential log from the provided node |
| 121 | This will follow the path of chained nodes and their logs concatenated together |
| 122 | """ |
| 123 | log = [x.json() for x in node._taint_log] |
| 124 | |
| 125 | # Find the first node in chain that affected the propagation of a taint into the current node |
| 126 | for n in node._taint_log: |
| 127 | if isinstance(n.node, ASTNode) and n.node._taint_log and n.node._taint_class == node._taint_class: |
| 128 | log = cls.extract_log(n.node) + log |
| 129 | break |
| 130 | |
| 131 | return log |
| 132 | |
| 133 | |
| 134 |
no outgoing calls
no test coverage detected