Parse SQLMap output directory
(self, output_dir: str, scan_id: str, target: str)
| 1709 | so this can be False even with systemd — in which case we don't wrap |
| 1710 | (the flag would be silently ignored anyway). |
| 1711 | """ |
| 1712 | if not shutil.which('systemd-run'): |
| 1713 | return False |
| 1714 | try: |
| 1715 | with open('/sys/fs/cgroup/cgroup.controllers') as f: |
| 1716 | return 'memory' in f.read().split() |
| 1717 | except Exception: |
| 1718 | return False |
| 1719 | |
| 1720 | def _nuclei_memory_precheck(self, nuclei_env: Dict[str, str]) -> Optional[str]: |
| 1721 | """Return an error string if there isn't enough free RAM to run nuclei |
| 1722 | safely under this tier, else None. |
| 1723 | |
| 1724 | Only guards constrained tiers (those that set a GOMEMLIMIT). GOMEMLIMIT |
| 1725 | is a soft cap, so on a small board that's already low on free memory, |
| 1726 | starting nuclei can push it into swap thrash and lock the whole board |
| 1727 | up — a clean refusal with the numbers is the right call. |
| 1728 | """ |
| 1729 | m = re.match(r'(\d+)MiB', nuclei_env.get('GOMEMLIMIT', '')) |
| 1730 | if not m: |
| 1731 | return None # unconstrained board — plenty of headroom |
| 1732 | need_mib = int(int(m.group(1)) * 1.6) # heap cap + parsing/runtime overhead |
| 1733 | free_mib = self._available_mib() |
| 1734 | if free_mib is None or free_mib >= need_mib: |
| 1735 | return None |
| 1736 | return (f"Not enough free memory to run Nuclei safely: {free_mib}MB free, " |
| 1737 | f"need ~{need_mib}MB. Nuclei is memory-hungry and a 512MB board is " |
| 1738 | f"borderline — stop other Ragnar features to free RAM, or run Nuclei " |
| 1739 | f"from a larger unit. Refusing rather than risk locking up the board.") |
| 1740 | |
| 1741 | def _hard_kill(self, process: subprocess.Popen) -> None: |
| 1742 | """Kill a scan process — the whole group if we started it in its own |
| 1743 | session, so children (and a systemd-run scope) go too.""" |
no test coverage detected