For each check, compiles the regex and walks source_path. Returns one finding dict per (check, file, line) match. De-duplicates by (id, file, line).
(self, checks: list, extensions: tuple = None)
| 515 | # ------------------------------------------------------------------ |
| 516 | |
| 517 | def _scan_pattern(self, checks: list, extensions: tuple = None) -> list: |
| 518 | """ |
| 519 | For each check, compiles the regex and walks source_path. |
| 520 | Returns one finding dict per (check, file, line) match. |
| 521 | De-duplicates by (id, file, line). |
| 522 | """ |
| 523 | if extensions is None: |
| 524 | extensions = self.SCAN_EXTENSIONS |
| 525 | |
| 526 | compiled_checks = [] |
| 527 | for chk in checks: |
| 528 | try: |
| 529 | compiled_checks.append((chk, re.compile(chk["pattern"], re.IGNORECASE))) |
| 530 | except re.error as e: |
| 531 | util.mod_log(f"[-] Bad pattern for {chk['id']}: {e}", util.WARNING) |
| 532 | |
| 533 | findings = [] |
| 534 | seen = set() |
| 535 | |
| 536 | for root, _, files in os.walk(self.source_path): |
| 537 | for fname in files: |
| 538 | if not fname.endswith(extensions): |
| 539 | continue |
| 540 | fpath = os.path.join(root, fname) |
| 541 | try: |
| 542 | with open(fpath, "r", encoding="utf-8", errors="ignore") as f: |
| 543 | for line_no, line in enumerate(f, 1): |
| 544 | for chk, compiled in compiled_checks: |
| 545 | if compiled.search(line): |
| 546 | key = (chk["id"], fpath, line_no) |
| 547 | if key in seen: |
| 548 | continue |
| 549 | seen.add(key) |
| 550 | rel_path = os.path.relpath(fpath, self.source_path) |
| 551 | findings.append({ |
| 552 | "id": chk["id"], |
| 553 | "title": chk["title"], |
| 554 | "severity": chk["severity"], |
| 555 | "owasp": chk["owasp"], |
| 556 | "description": chk["description"], |
| 557 | "file": rel_path, |
| 558 | "line": line_no, |
| 559 | "evidence": line.strip()[:200], |
| 560 | }) |
| 561 | except Exception: |
| 562 | continue |
| 563 | |
| 564 | return findings |
no test coverage detected