From 665c91a701dbf53141c6edd5f6ba5335e85220bd Mon Sep 17 00:00:00 2001 From: siddiqui7864 Date: Fri, 5 Jun 2026 10:35:38 +0530 Subject: [PATCH 01/12] feat(ci): add plugin checksum drift verification - Add refresh_plugin_checksums.py script to generate plugin checksums - Add GitHub Actions workflow to verify checksums on PR/push - CI will fail when plugin files change without checksum update Fixes #581 --- .github/workflows/plugin-checksum.yml | 29 +++++++++++++++++ scripts/refresh_plugin_checksums.py | 46 +++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 .github/workflows/plugin-checksum.yml create mode 100644 scripts/refresh_plugin_checksums.py diff --git a/.github/workflows/plugin-checksum.yml b/.github/workflows/plugin-checksum.yml new file mode 100644 index 000000000..43589609a --- /dev/null +++ b/.github/workflows/plugin-checksum.yml @@ -0,0 +1,29 @@ +name: Plugin Checksum Verification + +on: + pull_request: + paths: + - 'plugins/**' + push: + branches: [main] + paths: + - 'plugins/**' + +jobs: + verify-checksums: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + pip install -r backend/requirements.txt + + - name: Verify plugin checksums + run: | + python scripts/refresh_plugin_checksums.py --dry-run diff --git a/scripts/refresh_plugin_checksums.py b/scripts/refresh_plugin_checksums.py new file mode 100644 index 000000000..3853edbc1 --- /dev/null +++ b/scripts/refresh_plugin_checksums.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +"""Refresh plugin checksums based on current metadata and parser files.""" + +import hashlib +import os +import sys + +PLUGINS_DIR = "plugins" +CHECKSUM_FILE = os.path.join(PLUGINS_DIR, "checksums.txt") + +def compute_checksum(filepath): + sha256 = hashlib.sha256() + with open(filepath, "rb") as f: + for chunk in iter(lambda: f.read(4096), b""): + sha256.update(chunk) + return sha256.hexdigest() + +def main(): + dry_run = "--dry-run" in sys.argv + + checksums = {} + for plugin in os.listdir(PLUGINS_DIR): + plugin_path = os.path.join(PLUGINS_DIR, plugin) + if not os.path.isdir(plugin_path): + continue + + metadata = os.path.join(plugin_path, "metadata.json") + if os.path.exists(metadata): + checksums[metadata] = compute_checksum(metadata) + + parser = os.path.join(plugin_path, "parser.py") + if os.path.exists(parser): + checksums[parser] = compute_checksum(parser) + + if dry_run: + print("Checksums that would be written:") + for path, cs in checksums.items(): + print(f"{cs} {path}") + else: + with open(CHECKSUM_FILE, "w") as f: + for path, cs in checksums.items(): + f.write(f"{cs} {path}\n") + print(f"Updated {CHECKSUM_FILE}") + +if __name__ == "__main__": + main() From 4319d0d69465d6a27ef8141d627919671a5d1c80 Mon Sep 17 00:00:00 2001 From: siddiqui7864 Date: Sat, 6 Jun 2026 10:01:04 +0530 Subject: [PATCH 02/12] fix(ci): verify-mode compares against manifest and exits 1 on drift --- plugins/checksums.json | 122 ++++++++++++++++++++++++++++ scripts/refresh_plugin_checksums.py | 82 +++++++++++++------ 2 files changed, 179 insertions(+), 25 deletions(-) create mode 100644 plugins/checksums.json diff --git a/plugins/checksums.json b/plugins/checksums.json new file mode 100644 index 000000000..63ee99456 --- /dev/null +++ b/plugins/checksums.json @@ -0,0 +1,122 @@ +{ + "plugins\\amass\\metadata.json": "72eedc0b74711b37e24f34ce92d9ad24137e7a8ff54f3d75f97d39b59e686003", + "plugins\\amass\\parser.py": "8656cdbb97a469659dbe2ee114c20194abdb4e2517ce19c80c8bbfac427085ab", + "plugins\\api_scanner\\metadata.json": "c5b6bd155a177ffa1f81a5a860b1306771fadc341baf9bbe26eebfbb5502fc25", + "plugins\\api_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\cloud_scanner\\metadata.json": "de37a8b28ee1e399cf39ca3ed3f4377b88e8b707a9595bc1a3d6ca3ec806be33", + "plugins\\cloud_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\cloud_storage_auditor\\metadata.json": "a1ad6618a351dea840d63fd37941b65668d1251d1f6becd1004ed99f8b627246", + "plugins\\cloud_storage_auditor\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\code_analyzer\\metadata.json": "c683305ceca0b6674bc351d244fa74538da4618bede2751090abdc49f7b299e4", + "plugins\\code_analyzer\\parser.py": "8f9112fc50b2e083880c7544b877a2458a51d7ac58ab633e7d2b87aced3fb100", + "plugins\\container_scanner\\metadata.json": "66b95e11fa071d59c37948f56344a0f0c977f446fb5a62cc4f66aad07245ffa2", + "plugins\\container_scanner\\parser.py": "1386eaaa649046714a051483749fc78e8bbd55f11cd635acd3cb7e9fa89310b9", + "plugins\\crawler\\metadata.json": "ef5097db30843d129b80481ac1b618e770867ad48b611fbe61d8d36562c55db7", + "plugins\\crawler\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\dir_discovery\\metadata.json": "4512cc4329621db861da7678947e93e048c746c6f59e828ecc6666ca76d9e732", + "plugins\\dir_discovery\\parser.py": "5bb25b93e9e94c59229261f69663d2822618448ceedf27a66602f9eeee577269", + "plugins\\dns_enum\\metadata.json": "8993461681dc2af02548af4c5ff21b1c96121ddaeac0cabc87900a9681bd5157", + "plugins\\dns_enum\\parser.py": "e364aac3b1962eef8c348cef4786418304d12120dc246c4197877b844fd57b74", + "plugins\\dnsx\\metadata.json": "da04bb9c8765102cda77085fb120174dd66a2c5a134cd1e4ea5b983c3dd10f22", + "plugins\\dnsx\\parser.py": "886d57da7c7c29201f8f67364c37635b09c08cbe9888abe0b4997381ff9d04d3", + "plugins\\domain-finder\\metadata.json": "7a35923bd837bdb3a7a72812d356f415fe861b75474efd364b82ea7da6dcb9d0", + "plugins\\domain-finder\\parser.py": "4297dcb82280011fab4cb4b8d0e70d15bed0280f1c4ed040ce28632c5ef44ac7", + "plugins\\droopescan\\metadata.json": "ac26896df547d64d895867cc225c21c73c96eafa170b3a285503e6689faa722b", + "plugins\\droopescan\\parser.py": "37d7c3bae730354218145c42d1d1d96ae9debf7ec5ad83012f10dcd2d801661d", + "plugins\\fuzzer\\metadata.json": "d9cdc0e7a75c96cfe38d5f43fba68921238cbcb6179f3527cc0e33b6398e26aa", + "plugins\\fuzzer\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\google-dorking\\metadata.json": "366e327a4646b8598108785c0e9b692d6fbb885b4814034c392bb36199fbbeae", + "plugins\\google-dorking\\parser.py": "bc89cafb7a9ff3a712a1379e3ddb75f2ed410c4d363a205171af2dc0211fd8b4", + "plugins\\hashcat\\metadata.json": "64f5471810907e970bc45055b9a7e68e4d6b0821e46d17fcece40b85db29edb8", + "plugins\\hashcat\\parser.py": "b45df99421ab5345b7d74f7c3bcdd8896d65c5d1b71dac4fca505b7b911960e2", + "plugins\\http_inspector\\metadata.json": "ed2e18caf97b4ee357e662cf89cf8aa7d055c82ac49fce1f616594d238d3a42c", + "plugins\\http_inspector\\parser.py": "3d71bdf96584e376f7b6aab8d2cd1efa20c3a01a8a2cdd86010988fe370d8880", + "plugins\\http_request_logger\\metadata.json": "f3d2cc72df923e4a8a44361ca8d2813ca05f2e2ac4a1e309217b466179df2f54", + "plugins\\http_request_logger\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\httpx\\metadata.json": "3694e964483f1c2ed91ebbfcda519302487e204d49532c071cc3929d7daf9794", + "plugins\\httpx\\parser.py": "64362f696959205094923a2b5e98e1084b16938a6376f9a5a354199b928bd67a", + "plugins\\iac_scanner\\metadata.json": "7caae20deacba06314eadd3256ef8f8cb5145bd68c903685de18f815b1ce630c", + "plugins\\iac_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\icmp_ping\\metadata.json": "8e5a2ef314bff3793fea001998c9d954fd3e417f40a291253b97fd5f50842a53", + "plugins\\icmp_ping\\parser.py": "15bf271e1c206fadbbfb665fa600875435962ad2707c382298ce2bbb676c15ad", + "plugins\\joomscan\\metadata.json": "c846d4d3812fdfed21923bf3de765b3c972667f7cae56ac43cd576f7b5d97368", + "plugins\\joomscan\\parser.py": "1b8386093cc7b22e6b5956b0cc6f02c57cc24e43f13f35269e6c41bc528c2da9", + "plugins\\katana\\metadata.json": "a7f6ec8327f0006d3c40349da96fafbc492b87632d6592bec822240ded4ad0ab", + "plugins\\katana\\parser.py": "76ba1db2ab383efbeb3f8dd96e621f2d5acde5172c10b548b53d78e70118d1d1", + "plugins\\kubernetes_scanner\\metadata.json": "71850e28d70bc23bf60cfe91d8638e162d5f91129a4bcd295f36590c1371e3c7", + "plugins\\kubernetes_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\metasploit\\metadata.json": "9a9e215624ea44fbadf5a1b9eea85887d61a3e0bf9c3d9b197453467a3d40133", + "plugins\\metasploit\\parser.py": "24b77483c28f71536d182f6849b30a2c9290db088528ce2e45f5c67335846ca0", + "plugins\\network_scanner\\metadata.json": "e5e1a7562dab8ab46a8fae45c3c51be85ddd8aeaace3c78d52aebcd6c13fcc55", + "plugins\\network_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\nikto\\metadata.json": "06a37edcb5fcd4ef9dda050663da8ab9a65bdaadd833cfe268e022bf4e8ece20", + "plugins\\nikto\\parser.py": "6fda2fe11eadd7e3181b27ba48b3833dc4ae55ed5d8a910b03d37f93f0ba4962", + "plugins\\nmap\\metadata.json": "28212089ea084ae57cc0be29fe7f693e2ffab0caf1f6aefcd3fb39a8e6fab680", + "plugins\\nmap\\parser.py": "e3fa70f90b728e3734474e05dd1743338334216aadee0a5088e89a8700a6a839", + "plugins\\nuclei\\metadata.json": "dd0259513d20328f470851af237e0ca543f8de77a231887657138c02d3134f7a", + "plugins\\nuclei\\parser.py": "661ec2465d5c92c4b57de69ba29c8da7434f022defdbf2764f7eeb53157601b7", + "plugins\\password_auditor\\metadata.json": "8870ec634eaa8828f1b1ff121f3e5723a53307cc8193b390e804dbcfafba49ed", + "plugins\\password_auditor\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\people-email-discovery\\metadata.json": "64e200fc41169fc010b5720274c8024750ed71b1147296d84f61118331c227a8", + "plugins\\people-email-discovery\\parser.py": "155fb61bc065a7f4df65af7a718968b2885add883bae5d7c921226512b7e3f81", + "plugins\\port-scanner\\metadata.json": "c51fb04ca08f7fc9731685db8d5f641935eb86a98b6fc2652c053e7df91cf887", + "plugins\\port-scanner\\parser.py": "4c1ced841432b844910ef8ba3730a74680c562cc192be57892abc149b1e18a29", + "plugins\\scapy_recon\\metadata.json": "eaa0c6a47f96abc783ecbe381c7ae84585761bec5ab21c82870946ee66287325", + "plugins\\scapy_recon\\parser.py": "86f1cb29268a8bc309f637e3391b6de35023a65e8d3969a160110896bcdab090", + "plugins\\secret_scanner\\metadata.json": "42914c6afc84cbdb1592933dc444688f268e33d8f072f64250df93c83a5a682c", + "plugins\\secret_scanner\\parser.py": "8028c30f509e153462a7115140deff83e331424a68342ddc6d3b5ae683ffe959", + "plugins\\sharepoint_scanner\\metadata.json": "0928feb3ee2807c6cfa00cbdb5e39f0b5e9d0aeecf268759b1dbdc309e4bd5b8", + "plugins\\sharepoint_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\sitemap_gen\\metadata.json": "2a5d37467f18a1de7f23293d07de0dc83eb7e1d61fe825bd664ee62ee805140f", + "plugins\\sitemap_gen\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\sniper\\metadata.json": "e0b50e6aa3eb14a15cbdea83e8932117f6faba07e9b2c172ecca172c20880891", + "plugins\\sniper\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\spider\\metadata.json": "926090c343a70f16589e5a2dfe9ff1997f9b9b13ebcd59ccfa775a16e29e059f", + "plugins\\spider\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\sqli_checker\\metadata.json": "b9b845e01f1cda924b8efba64444e8b17cca049ff34f5a692fb921c0befd6c20", + "plugins\\sqli_checker\\parser.py": "b70159da466dcabf704ed1b613a74d8d9fcae0685a7d11827985dc889204000b", + "plugins\\sqli_exploiter\\metadata.json": "23975fd204df51926a85c412116e8596e4ca14276d8cfcceafb28ea02fe8bf5b", + "plugins\\sqli_exploiter\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\sqlmap\\metadata.json": "dee11f891c498e2626d37d898c4549bdf0f9543f1707b7045bdf3d06e7c61ec1", + "plugins\\sqlmap\\parser.py": "edec2952eb88429ac5f43f9ef14f4ef444b93a2e2edc6a02d653fe913b3d02e6", + "plugins\\ssh_runner\\metadata.json": "fe6cc26646fc66ab9b9b8f08245ef78a40b801ade0aa333c26aa9e4445ec50da", + "plugins\\ssh_runner\\parser.py": "516483ac2296ed841edf482d922d3ee8278fb569d178322104809ffdfcb798c4", + "plugins\\subdomain-finder\\metadata.json": "f15344354b5bf43fba9a194a64525fd7222f3fc9e478d9b851cccc4083ed0b58", + "plugins\\subdomain-finder\\parser.py": "bac879e11de91f57ddc5cfbada3a5208db1344cfbb22c75d9a646aa0de090299", + "plugins\\subdomain_discovery\\metadata.json": "042c824b3010cc74ddfb4a3a7a7585527e7f1a30c90fd713ebf7124ad69ef4f5", + "plugins\\subdomain_discovery\\parser.py": "77f71fec9ca5154f77a71513831944247fde0fc45661949bd7991b45d576e36c", + "plugins\\subdomain_takeover\\metadata.json": "406d882f5b865448b74d69234fc8b391479a32634f31a99fad82fea702a9216a", + "plugins\\subdomain_takeover\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\subfinder\\metadata.json": "668b9627d23b15c666af3edd95b0d7b195bc3784ad82b04aa0462310195cb42b", + "plugins\\subfinder\\parser.py": "ba20913660007871c3d63ead34724936320b76838b48f9c2874f376a867ed8f4", + "plugins\\theharvester\\metadata.json": "31deca8a1a73b98f43dc6c7f9354f6dec028ce6f8917120a04ad8f7925030e0d", + "plugins\\theharvester\\parser.py": "5e4745e27414895654ccf473522d9b4cfdfa124b00de0d339d37df5125c38947", + "plugins\\tls_inspector\\metadata.json": "2a253b13f8eaea1d5b9375b0176f86578814334619d27b838043a67a95d78dc1", + "plugins\\tls_inspector\\parser.py": "2675151277a4dba1d4cda2d355e14b1cb11c3e2085f81cc928feb5993b13ba9a", + "plugins\\uncover\\metadata.json": "68a2d7aabd8d1bce3e1ee26cf0abe37c7b465e143c645c8e1777da318ac6d087", + "plugins\\uncover\\parser.py": "961a58f1527842c52ac881e1962cf131efef85360d0045654978e7ead4c8bf4f", + "plugins\\url-fuzzer-2\\metadata.json": "fc6a2787f0fd5d163e5ded78d517af8ad86f4eab9688a75fe3d025adb628491a", + "plugins\\url-fuzzer-2\\parser.py": "2ba06e6e60ffbf467ef01944c8f4bf23e87e7f04e71025f38576be1e577445d3", + "plugins\\urlfinder\\metadata.json": "46414d707f5de77d8ba46a34ff6a064a75b8f3d4a553f1b32b2c63d64c19e31e", + "plugins\\urlfinder\\parser.py": "55c09a4839f1e80573a0a207135cefe2628994a861ed692dc5e6dc7934350fc4", + "plugins\\virtual-host-finder\\metadata.json": "3410eeb44f6f11212a929b2a677589930e5e41c03a79a52f7c1144c3997ba8e1", + "plugins\\virtual-host-finder\\parser.py": "f30dbd2f5df147923036a1984c52e60c41fe4405c21ffcc08149d17ba2ad127a", + "plugins\\volatility\\metadata.json": "5c8114889597a9d393fbbfa39182088cd0e31fa7601ca2e4ba15509731b02858", + "plugins\\volatility\\parser.py": "3d82614761042d5bf1cc4309c58e089ec6b67350ec8315e84af5be051bba6248", + "plugins\\waf-detection\\metadata.json": "28199814b93e016f20fe1af874f2604f134dd705bf29fe8ac5421f5329bf87db", + "plugins\\waf-detection\\parser.py": "7c07fc0b6a0696973cdfea515fb46e6e4647e734b9d22b065fc4b02559000ec3", + "plugins\\waf_detector\\metadata.json": "961f96c7f962b4e10e69872f9fbfe718dc525784322e5005f8bbd0655d3f3783", + "plugins\\waf_detector\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\website-recon-2\\metadata.json": "972ec1ce8180bedad5fd02cdb45b51e21215ba197ada5765c69ec417abcd3468", + "plugins\\website-recon-2\\parser.py": "f4f675364dbf9a77b517a99f5977baf47b57b2132900363db893f657e1c3785b", + "plugins\\whois_lookup\\metadata.json": "3f5cec89ee87b378b7162e5d7b33c44b64c763bfc43a8e714cdbe110c4663727", + "plugins\\whois_lookup\\parser.py": "cf847a90319676a0064425c5637c69ab9e5d849674222e5904513616f993bfbb", + "plugins\\wpscan\\metadata.json": "e3156a00362117a76efa175283cda9ff4a7dc1752769043dc4a7849044264cc2", + "plugins\\wpscan\\parser.py": "663b104db5c9bba1a7dec242bd9462e7602e252e3b9bbeda59787c3599643263", + "plugins\\xss_exploiter\\metadata.json": "bd1412c2845c9f8b10a85fec398d38f5c5a4d51bd8923d6ebf6ad15e28a9e289", + "plugins\\xss_exploiter\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins\\yara_scan\\metadata.json": "9d42408310204d91590f2f0f59ed3c66bfdfda13f8e4fe89d0d5e24147252729", + "plugins\\yara_scan\\parser.py": "249cae0d5e3e9b039d8da19050301ce82d9f29fe318e5ebe82ed39c2324aa2af", + "plugins\\zap_scanner\\metadata.json": "60fc56f1b7f06b615c954e02524ab754792f80de110610165484c2a6dff5872e", + "plugins\\zap_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e" +} diff --git a/scripts/refresh_plugin_checksums.py b/scripts/refresh_plugin_checksums.py index 3853edbc1..ee0146af3 100644 --- a/scripts/refresh_plugin_checksums.py +++ b/scripts/refresh_plugin_checksums.py @@ -1,12 +1,13 @@ #!/usr/bin/env python3 -"""Refresh plugin checksums based on current metadata and parser files.""" - +"""Refresh or verify plugin checksums based on current metadata and parser files.""" import hashlib +import json import os import sys PLUGINS_DIR = "plugins" -CHECKSUM_FILE = os.path.join(PLUGINS_DIR, "checksums.txt") +MANIFEST_FILE = os.path.join(PLUGINS_DIR, "checksums.json") + def compute_checksum(filepath): sha256 = hashlib.sha256() @@ -15,32 +16,63 @@ def compute_checksum(filepath): sha256.update(chunk) return sha256.hexdigest() -def main(): - dry_run = "--dry-run" in sys.argv - + +def collect_live_checksums(): checksums = {} - for plugin in os.listdir(PLUGINS_DIR): + for plugin in sorted(os.listdir(PLUGINS_DIR)): plugin_path = os.path.join(PLUGINS_DIR, plugin) if not os.path.isdir(plugin_path): continue - - metadata = os.path.join(plugin_path, "metadata.json") - if os.path.exists(metadata): - checksums[metadata] = compute_checksum(metadata) - - parser = os.path.join(plugin_path, "parser.py") - if os.path.exists(parser): - checksums[parser] = compute_checksum(parser) - - if dry_run: - print("Checksums that would be written:") - for path, cs in checksums.items(): - print(f"{cs} {path}") - else: - with open(CHECKSUM_FILE, "w") as f: - for path, cs in checksums.items(): - f.write(f"{cs} {path}\n") - print(f"Updated {CHECKSUM_FILE}") + for filename in ("metadata.json", "parser.py"): + filepath = os.path.join(plugin_path, filename) + if os.path.exists(filepath): + checksums[filepath] = compute_checksum(filepath) + return checksums + + +def main(): + dry_run = "--dry-run" in sys.argv + + live = collect_live_checksums() + + if not dry_run: + with open(MANIFEST_FILE, "w") as f: + json.dump(live, f, indent=2) + f.write("\n") + print(f"Updated {MANIFEST_FILE} ({len(live)} entries)") + sys.exit(0) + + # --dry-run: verify mode — compare live against committed manifest + if not os.path.exists(MANIFEST_FILE): + print(f"ERROR: No manifest found at {MANIFEST_FILE}.") + print("Run without --dry-run first to generate it.") + sys.exit(1) + + with open(MANIFEST_FILE) as f: + committed = json.load(f) + + drift = False + + for path, sha in committed.items(): + if path not in live: + print(f"MISSING: {path}") + drift = True + elif live[path] != sha: + print(f"CHANGED: {path}") + drift = True + + for path in live: + if path not in committed: + print(f"EXTRA: {path} (not in manifest)") + drift = True + + if drift: + print("\nDrift detected. Run: python scripts/refresh_plugin_checksums.py") + sys.exit(1) + + print(f"OK: all {len(live)} plugin checksums match the manifest.") + sys.exit(0) + if __name__ == "__main__": main() From cddb82a6ad5298e9f33a6e55e58ab11281cbb1cd Mon Sep 17 00:00:00 2001 From: siddiqui7864 Date: Sat, 6 Jun 2026 10:06:32 +0530 Subject: [PATCH 03/12] fix(ci): install libcairo2-dev before pip install in checksum workflow --- .github/workflows/plugin-checksum.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/plugin-checksum.yml b/.github/workflows/plugin-checksum.yml index 43589609a..cf9dcd8c2 100644 --- a/.github/workflows/plugin-checksum.yml +++ b/.github/workflows/plugin-checksum.yml @@ -1,5 +1,4 @@ name: Plugin Checksum Verification - on: pull_request: paths: @@ -8,22 +7,18 @@ on: branches: [main] paths: - 'plugins/**' - jobs: verify-checksums: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.11' - + - name: Install system dependencies + run: sudo apt-get install -y libcairo2-dev pkg-config python3-dev - name: Install dependencies - run: | - pip install -r backend/requirements.txt - + run: pip install -r backend/requirements.txt - name: Verify plugin checksums - run: | - python scripts/refresh_plugin_checksums.py --dry-run + run: python scripts/refresh_plugin_checksums.py --dry-run From 4904712d50a5aafc2f5b367e7a1b8289cf881279 Mon Sep 17 00:00:00 2001 From: siddiqui7864 Date: Sat, 6 Jun 2026 10:10:15 +0530 Subject: [PATCH 04/12] fix(ci): normalize manifest paths to forward slashes for Linux CI --- plugins/checksums.json | 240 ++++++++++++++++++++--------------------- 1 file changed, 120 insertions(+), 120 deletions(-) diff --git a/plugins/checksums.json b/plugins/checksums.json index 63ee99456..8686d3913 100644 --- a/plugins/checksums.json +++ b/plugins/checksums.json @@ -1,122 +1,122 @@ { - "plugins\\amass\\metadata.json": "72eedc0b74711b37e24f34ce92d9ad24137e7a8ff54f3d75f97d39b59e686003", - "plugins\\amass\\parser.py": "8656cdbb97a469659dbe2ee114c20194abdb4e2517ce19c80c8bbfac427085ab", - "plugins\\api_scanner\\metadata.json": "c5b6bd155a177ffa1f81a5a860b1306771fadc341baf9bbe26eebfbb5502fc25", - "plugins\\api_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\cloud_scanner\\metadata.json": "de37a8b28ee1e399cf39ca3ed3f4377b88e8b707a9595bc1a3d6ca3ec806be33", - "plugins\\cloud_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\cloud_storage_auditor\\metadata.json": "a1ad6618a351dea840d63fd37941b65668d1251d1f6becd1004ed99f8b627246", - "plugins\\cloud_storage_auditor\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\code_analyzer\\metadata.json": "c683305ceca0b6674bc351d244fa74538da4618bede2751090abdc49f7b299e4", - "plugins\\code_analyzer\\parser.py": "8f9112fc50b2e083880c7544b877a2458a51d7ac58ab633e7d2b87aced3fb100", - "plugins\\container_scanner\\metadata.json": "66b95e11fa071d59c37948f56344a0f0c977f446fb5a62cc4f66aad07245ffa2", - "plugins\\container_scanner\\parser.py": "1386eaaa649046714a051483749fc78e8bbd55f11cd635acd3cb7e9fa89310b9", - "plugins\\crawler\\metadata.json": "ef5097db30843d129b80481ac1b618e770867ad48b611fbe61d8d36562c55db7", - "plugins\\crawler\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\dir_discovery\\metadata.json": "4512cc4329621db861da7678947e93e048c746c6f59e828ecc6666ca76d9e732", - "plugins\\dir_discovery\\parser.py": "5bb25b93e9e94c59229261f69663d2822618448ceedf27a66602f9eeee577269", - "plugins\\dns_enum\\metadata.json": "8993461681dc2af02548af4c5ff21b1c96121ddaeac0cabc87900a9681bd5157", - "plugins\\dns_enum\\parser.py": "e364aac3b1962eef8c348cef4786418304d12120dc246c4197877b844fd57b74", - "plugins\\dnsx\\metadata.json": "da04bb9c8765102cda77085fb120174dd66a2c5a134cd1e4ea5b983c3dd10f22", - "plugins\\dnsx\\parser.py": "886d57da7c7c29201f8f67364c37635b09c08cbe9888abe0b4997381ff9d04d3", - "plugins\\domain-finder\\metadata.json": "7a35923bd837bdb3a7a72812d356f415fe861b75474efd364b82ea7da6dcb9d0", - "plugins\\domain-finder\\parser.py": "4297dcb82280011fab4cb4b8d0e70d15bed0280f1c4ed040ce28632c5ef44ac7", - "plugins\\droopescan\\metadata.json": "ac26896df547d64d895867cc225c21c73c96eafa170b3a285503e6689faa722b", - "plugins\\droopescan\\parser.py": "37d7c3bae730354218145c42d1d1d96ae9debf7ec5ad83012f10dcd2d801661d", - "plugins\\fuzzer\\metadata.json": "d9cdc0e7a75c96cfe38d5f43fba68921238cbcb6179f3527cc0e33b6398e26aa", - "plugins\\fuzzer\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\google-dorking\\metadata.json": "366e327a4646b8598108785c0e9b692d6fbb885b4814034c392bb36199fbbeae", - "plugins\\google-dorking\\parser.py": "bc89cafb7a9ff3a712a1379e3ddb75f2ed410c4d363a205171af2dc0211fd8b4", - "plugins\\hashcat\\metadata.json": "64f5471810907e970bc45055b9a7e68e4d6b0821e46d17fcece40b85db29edb8", - "plugins\\hashcat\\parser.py": "b45df99421ab5345b7d74f7c3bcdd8896d65c5d1b71dac4fca505b7b911960e2", - "plugins\\http_inspector\\metadata.json": "ed2e18caf97b4ee357e662cf89cf8aa7d055c82ac49fce1f616594d238d3a42c", - "plugins\\http_inspector\\parser.py": "3d71bdf96584e376f7b6aab8d2cd1efa20c3a01a8a2cdd86010988fe370d8880", - "plugins\\http_request_logger\\metadata.json": "f3d2cc72df923e4a8a44361ca8d2813ca05f2e2ac4a1e309217b466179df2f54", - "plugins\\http_request_logger\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\httpx\\metadata.json": "3694e964483f1c2ed91ebbfcda519302487e204d49532c071cc3929d7daf9794", - "plugins\\httpx\\parser.py": "64362f696959205094923a2b5e98e1084b16938a6376f9a5a354199b928bd67a", - "plugins\\iac_scanner\\metadata.json": "7caae20deacba06314eadd3256ef8f8cb5145bd68c903685de18f815b1ce630c", - "plugins\\iac_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\icmp_ping\\metadata.json": "8e5a2ef314bff3793fea001998c9d954fd3e417f40a291253b97fd5f50842a53", - "plugins\\icmp_ping\\parser.py": "15bf271e1c206fadbbfb665fa600875435962ad2707c382298ce2bbb676c15ad", - "plugins\\joomscan\\metadata.json": "c846d4d3812fdfed21923bf3de765b3c972667f7cae56ac43cd576f7b5d97368", - "plugins\\joomscan\\parser.py": "1b8386093cc7b22e6b5956b0cc6f02c57cc24e43f13f35269e6c41bc528c2da9", - "plugins\\katana\\metadata.json": "a7f6ec8327f0006d3c40349da96fafbc492b87632d6592bec822240ded4ad0ab", - "plugins\\katana\\parser.py": "76ba1db2ab383efbeb3f8dd96e621f2d5acde5172c10b548b53d78e70118d1d1", - "plugins\\kubernetes_scanner\\metadata.json": "71850e28d70bc23bf60cfe91d8638e162d5f91129a4bcd295f36590c1371e3c7", - "plugins\\kubernetes_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\metasploit\\metadata.json": "9a9e215624ea44fbadf5a1b9eea85887d61a3e0bf9c3d9b197453467a3d40133", - "plugins\\metasploit\\parser.py": "24b77483c28f71536d182f6849b30a2c9290db088528ce2e45f5c67335846ca0", - "plugins\\network_scanner\\metadata.json": "e5e1a7562dab8ab46a8fae45c3c51be85ddd8aeaace3c78d52aebcd6c13fcc55", - "plugins\\network_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\nikto\\metadata.json": "06a37edcb5fcd4ef9dda050663da8ab9a65bdaadd833cfe268e022bf4e8ece20", - "plugins\\nikto\\parser.py": "6fda2fe11eadd7e3181b27ba48b3833dc4ae55ed5d8a910b03d37f93f0ba4962", - "plugins\\nmap\\metadata.json": "28212089ea084ae57cc0be29fe7f693e2ffab0caf1f6aefcd3fb39a8e6fab680", - "plugins\\nmap\\parser.py": "e3fa70f90b728e3734474e05dd1743338334216aadee0a5088e89a8700a6a839", - "plugins\\nuclei\\metadata.json": "dd0259513d20328f470851af237e0ca543f8de77a231887657138c02d3134f7a", - "plugins\\nuclei\\parser.py": "661ec2465d5c92c4b57de69ba29c8da7434f022defdbf2764f7eeb53157601b7", - "plugins\\password_auditor\\metadata.json": "8870ec634eaa8828f1b1ff121f3e5723a53307cc8193b390e804dbcfafba49ed", - "plugins\\password_auditor\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\people-email-discovery\\metadata.json": "64e200fc41169fc010b5720274c8024750ed71b1147296d84f61118331c227a8", - "plugins\\people-email-discovery\\parser.py": "155fb61bc065a7f4df65af7a718968b2885add883bae5d7c921226512b7e3f81", - "plugins\\port-scanner\\metadata.json": "c51fb04ca08f7fc9731685db8d5f641935eb86a98b6fc2652c053e7df91cf887", - "plugins\\port-scanner\\parser.py": "4c1ced841432b844910ef8ba3730a74680c562cc192be57892abc149b1e18a29", - "plugins\\scapy_recon\\metadata.json": "eaa0c6a47f96abc783ecbe381c7ae84585761bec5ab21c82870946ee66287325", - "plugins\\scapy_recon\\parser.py": "86f1cb29268a8bc309f637e3391b6de35023a65e8d3969a160110896bcdab090", - "plugins\\secret_scanner\\metadata.json": "42914c6afc84cbdb1592933dc444688f268e33d8f072f64250df93c83a5a682c", - "plugins\\secret_scanner\\parser.py": "8028c30f509e153462a7115140deff83e331424a68342ddc6d3b5ae683ffe959", - "plugins\\sharepoint_scanner\\metadata.json": "0928feb3ee2807c6cfa00cbdb5e39f0b5e9d0aeecf268759b1dbdc309e4bd5b8", - "plugins\\sharepoint_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\sitemap_gen\\metadata.json": "2a5d37467f18a1de7f23293d07de0dc83eb7e1d61fe825bd664ee62ee805140f", - "plugins\\sitemap_gen\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\sniper\\metadata.json": "e0b50e6aa3eb14a15cbdea83e8932117f6faba07e9b2c172ecca172c20880891", - "plugins\\sniper\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\spider\\metadata.json": "926090c343a70f16589e5a2dfe9ff1997f9b9b13ebcd59ccfa775a16e29e059f", - "plugins\\spider\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\sqli_checker\\metadata.json": "b9b845e01f1cda924b8efba64444e8b17cca049ff34f5a692fb921c0befd6c20", - "plugins\\sqli_checker\\parser.py": "b70159da466dcabf704ed1b613a74d8d9fcae0685a7d11827985dc889204000b", - "plugins\\sqli_exploiter\\metadata.json": "23975fd204df51926a85c412116e8596e4ca14276d8cfcceafb28ea02fe8bf5b", - "plugins\\sqli_exploiter\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\sqlmap\\metadata.json": "dee11f891c498e2626d37d898c4549bdf0f9543f1707b7045bdf3d06e7c61ec1", - "plugins\\sqlmap\\parser.py": "edec2952eb88429ac5f43f9ef14f4ef444b93a2e2edc6a02d653fe913b3d02e6", - "plugins\\ssh_runner\\metadata.json": "fe6cc26646fc66ab9b9b8f08245ef78a40b801ade0aa333c26aa9e4445ec50da", - "plugins\\ssh_runner\\parser.py": "516483ac2296ed841edf482d922d3ee8278fb569d178322104809ffdfcb798c4", - "plugins\\subdomain-finder\\metadata.json": "f15344354b5bf43fba9a194a64525fd7222f3fc9e478d9b851cccc4083ed0b58", - "plugins\\subdomain-finder\\parser.py": "bac879e11de91f57ddc5cfbada3a5208db1344cfbb22c75d9a646aa0de090299", - "plugins\\subdomain_discovery\\metadata.json": "042c824b3010cc74ddfb4a3a7a7585527e7f1a30c90fd713ebf7124ad69ef4f5", - "plugins\\subdomain_discovery\\parser.py": "77f71fec9ca5154f77a71513831944247fde0fc45661949bd7991b45d576e36c", - "plugins\\subdomain_takeover\\metadata.json": "406d882f5b865448b74d69234fc8b391479a32634f31a99fad82fea702a9216a", - "plugins\\subdomain_takeover\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\subfinder\\metadata.json": "668b9627d23b15c666af3edd95b0d7b195bc3784ad82b04aa0462310195cb42b", - "plugins\\subfinder\\parser.py": "ba20913660007871c3d63ead34724936320b76838b48f9c2874f376a867ed8f4", - "plugins\\theharvester\\metadata.json": "31deca8a1a73b98f43dc6c7f9354f6dec028ce6f8917120a04ad8f7925030e0d", - "plugins\\theharvester\\parser.py": "5e4745e27414895654ccf473522d9b4cfdfa124b00de0d339d37df5125c38947", - "plugins\\tls_inspector\\metadata.json": "2a253b13f8eaea1d5b9375b0176f86578814334619d27b838043a67a95d78dc1", - "plugins\\tls_inspector\\parser.py": "2675151277a4dba1d4cda2d355e14b1cb11c3e2085f81cc928feb5993b13ba9a", - "plugins\\uncover\\metadata.json": "68a2d7aabd8d1bce3e1ee26cf0abe37c7b465e143c645c8e1777da318ac6d087", - "plugins\\uncover\\parser.py": "961a58f1527842c52ac881e1962cf131efef85360d0045654978e7ead4c8bf4f", - "plugins\\url-fuzzer-2\\metadata.json": "fc6a2787f0fd5d163e5ded78d517af8ad86f4eab9688a75fe3d025adb628491a", - "plugins\\url-fuzzer-2\\parser.py": "2ba06e6e60ffbf467ef01944c8f4bf23e87e7f04e71025f38576be1e577445d3", - "plugins\\urlfinder\\metadata.json": "46414d707f5de77d8ba46a34ff6a064a75b8f3d4a553f1b32b2c63d64c19e31e", - "plugins\\urlfinder\\parser.py": "55c09a4839f1e80573a0a207135cefe2628994a861ed692dc5e6dc7934350fc4", - "plugins\\virtual-host-finder\\metadata.json": "3410eeb44f6f11212a929b2a677589930e5e41c03a79a52f7c1144c3997ba8e1", - "plugins\\virtual-host-finder\\parser.py": "f30dbd2f5df147923036a1984c52e60c41fe4405c21ffcc08149d17ba2ad127a", - "plugins\\volatility\\metadata.json": "5c8114889597a9d393fbbfa39182088cd0e31fa7601ca2e4ba15509731b02858", - "plugins\\volatility\\parser.py": "3d82614761042d5bf1cc4309c58e089ec6b67350ec8315e84af5be051bba6248", - "plugins\\waf-detection\\metadata.json": "28199814b93e016f20fe1af874f2604f134dd705bf29fe8ac5421f5329bf87db", - "plugins\\waf-detection\\parser.py": "7c07fc0b6a0696973cdfea515fb46e6e4647e734b9d22b065fc4b02559000ec3", - "plugins\\waf_detector\\metadata.json": "961f96c7f962b4e10e69872f9fbfe718dc525784322e5005f8bbd0655d3f3783", - "plugins\\waf_detector\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\website-recon-2\\metadata.json": "972ec1ce8180bedad5fd02cdb45b51e21215ba197ada5765c69ec417abcd3468", - "plugins\\website-recon-2\\parser.py": "f4f675364dbf9a77b517a99f5977baf47b57b2132900363db893f657e1c3785b", - "plugins\\whois_lookup\\metadata.json": "3f5cec89ee87b378b7162e5d7b33c44b64c763bfc43a8e714cdbe110c4663727", - "plugins\\whois_lookup\\parser.py": "cf847a90319676a0064425c5637c69ab9e5d849674222e5904513616f993bfbb", - "plugins\\wpscan\\metadata.json": "e3156a00362117a76efa175283cda9ff4a7dc1752769043dc4a7849044264cc2", - "plugins\\wpscan\\parser.py": "663b104db5c9bba1a7dec242bd9462e7602e252e3b9bbeda59787c3599643263", - "plugins\\xss_exploiter\\metadata.json": "bd1412c2845c9f8b10a85fec398d38f5c5a4d51bd8923d6ebf6ad15e28a9e289", - "plugins\\xss_exploiter\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins\\yara_scan\\metadata.json": "9d42408310204d91590f2f0f59ed3c66bfdfda13f8e4fe89d0d5e24147252729", - "plugins\\yara_scan\\parser.py": "249cae0d5e3e9b039d8da19050301ce82d9f29fe318e5ebe82ed39c2324aa2af", - "plugins\\zap_scanner\\metadata.json": "60fc56f1b7f06b615c954e02524ab754792f80de110610165484c2a6dff5872e", - "plugins\\zap_scanner\\parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e" + "plugins/amass/metadata.json": "72eedc0b74711b37e24f34ce92d9ad24137e7a8ff54f3d75f97d39b59e686003", + "plugins/amass/parser.py": "8656cdbb97a469659dbe2ee114c20194abdb4e2517ce19c80c8bbfac427085ab", + "plugins/api_scanner/metadata.json": "c5b6bd155a177ffa1f81a5a860b1306771fadc341baf9bbe26eebfbb5502fc25", + "plugins/api_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/cloud_scanner/metadata.json": "de37a8b28ee1e399cf39ca3ed3f4377b88e8b707a9595bc1a3d6ca3ec806be33", + "plugins/cloud_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/cloud_storage_auditor/metadata.json": "a1ad6618a351dea840d63fd37941b65668d1251d1f6becd1004ed99f8b627246", + "plugins/cloud_storage_auditor/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/code_analyzer/metadata.json": "c683305ceca0b6674bc351d244fa74538da4618bede2751090abdc49f7b299e4", + "plugins/code_analyzer/parser.py": "8f9112fc50b2e083880c7544b877a2458a51d7ac58ab633e7d2b87aced3fb100", + "plugins/container_scanner/metadata.json": "66b95e11fa071d59c37948f56344a0f0c977f446fb5a62cc4f66aad07245ffa2", + "plugins/container_scanner/parser.py": "1386eaaa649046714a051483749fc78e8bbd55f11cd635acd3cb7e9fa89310b9", + "plugins/crawler/metadata.json": "ef5097db30843d129b80481ac1b618e770867ad48b611fbe61d8d36562c55db7", + "plugins/crawler/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/dir_discovery/metadata.json": "4512cc4329621db861da7678947e93e048c746c6f59e828ecc6666ca76d9e732", + "plugins/dir_discovery/parser.py": "5bb25b93e9e94c59229261f69663d2822618448ceedf27a66602f9eeee577269", + "plugins/dns_enum/metadata.json": "8993461681dc2af02548af4c5ff21b1c96121ddaeac0cabc87900a9681bd5157", + "plugins/dns_enum/parser.py": "e364aac3b1962eef8c348cef4786418304d12120dc246c4197877b844fd57b74", + "plugins/dnsx/metadata.json": "da04bb9c8765102cda77085fb120174dd66a2c5a134cd1e4ea5b983c3dd10f22", + "plugins/dnsx/parser.py": "886d57da7c7c29201f8f67364c37635b09c08cbe9888abe0b4997381ff9d04d3", + "plugins/domain-finder/metadata.json": "7a35923bd837bdb3a7a72812d356f415fe861b75474efd364b82ea7da6dcb9d0", + "plugins/domain-finder/parser.py": "4297dcb82280011fab4cb4b8d0e70d15bed0280f1c4ed040ce28632c5ef44ac7", + "plugins/droopescan/metadata.json": "ac26896df547d64d895867cc225c21c73c96eafa170b3a285503e6689faa722b", + "plugins/droopescan/parser.py": "37d7c3bae730354218145c42d1d1d96ae9debf7ec5ad83012f10dcd2d801661d", + "plugins/fuzzer/metadata.json": "d9cdc0e7a75c96cfe38d5f43fba68921238cbcb6179f3527cc0e33b6398e26aa", + "plugins/fuzzer/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/google-dorking/metadata.json": "366e327a4646b8598108785c0e9b692d6fbb885b4814034c392bb36199fbbeae", + "plugins/google-dorking/parser.py": "bc89cafb7a9ff3a712a1379e3ddb75f2ed410c4d363a205171af2dc0211fd8b4", + "plugins/hashcat/metadata.json": "64f5471810907e970bc45055b9a7e68e4d6b0821e46d17fcece40b85db29edb8", + "plugins/hashcat/parser.py": "b45df99421ab5345b7d74f7c3bcdd8896d65c5d1b71dac4fca505b7b911960e2", + "plugins/http_inspector/metadata.json": "ed2e18caf97b4ee357e662cf89cf8aa7d055c82ac49fce1f616594d238d3a42c", + "plugins/http_inspector/parser.py": "3d71bdf96584e376f7b6aab8d2cd1efa20c3a01a8a2cdd86010988fe370d8880", + "plugins/http_request_logger/metadata.json": "f3d2cc72df923e4a8a44361ca8d2813ca05f2e2ac4a1e309217b466179df2f54", + "plugins/http_request_logger/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/httpx/metadata.json": "3694e964483f1c2ed91ebbfcda519302487e204d49532c071cc3929d7daf9794", + "plugins/httpx/parser.py": "64362f696959205094923a2b5e98e1084b16938a6376f9a5a354199b928bd67a", + "plugins/iac_scanner/metadata.json": "7caae20deacba06314eadd3256ef8f8cb5145bd68c903685de18f815b1ce630c", + "plugins/iac_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/icmp_ping/metadata.json": "8e5a2ef314bff3793fea001998c9d954fd3e417f40a291253b97fd5f50842a53", + "plugins/icmp_ping/parser.py": "15bf271e1c206fadbbfb665fa600875435962ad2707c382298ce2bbb676c15ad", + "plugins/joomscan/metadata.json": "c846d4d3812fdfed21923bf3de765b3c972667f7cae56ac43cd576f7b5d97368", + "plugins/joomscan/parser.py": "1b8386093cc7b22e6b5956b0cc6f02c57cc24e43f13f35269e6c41bc528c2da9", + "plugins/katana/metadata.json": "a7f6ec8327f0006d3c40349da96fafbc492b87632d6592bec822240ded4ad0ab", + "plugins/katana/parser.py": "76ba1db2ab383efbeb3f8dd96e621f2d5acde5172c10b548b53d78e70118d1d1", + "plugins/kubernetes_scanner/metadata.json": "71850e28d70bc23bf60cfe91d8638e162d5f91129a4bcd295f36590c1371e3c7", + "plugins/kubernetes_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/metasploit/metadata.json": "9a9e215624ea44fbadf5a1b9eea85887d61a3e0bf9c3d9b197453467a3d40133", + "plugins/metasploit/parser.py": "24b77483c28f71536d182f6849b30a2c9290db088528ce2e45f5c67335846ca0", + "plugins/network_scanner/metadata.json": "e5e1a7562dab8ab46a8fae45c3c51be85ddd8aeaace3c78d52aebcd6c13fcc55", + "plugins/network_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/nikto/metadata.json": "06a37edcb5fcd4ef9dda050663da8ab9a65bdaadd833cfe268e022bf4e8ece20", + "plugins/nikto/parser.py": "6fda2fe11eadd7e3181b27ba48b3833dc4ae55ed5d8a910b03d37f93f0ba4962", + "plugins/nmap/metadata.json": "28212089ea084ae57cc0be29fe7f693e2ffab0caf1f6aefcd3fb39a8e6fab680", + "plugins/nmap/parser.py": "e3fa70f90b728e3734474e05dd1743338334216aadee0a5088e89a8700a6a839", + "plugins/nuclei/metadata.json": "dd0259513d20328f470851af237e0ca543f8de77a231887657138c02d3134f7a", + "plugins/nuclei/parser.py": "661ec2465d5c92c4b57de69ba29c8da7434f022defdbf2764f7eeb53157601b7", + "plugins/password_auditor/metadata.json": "8870ec634eaa8828f1b1ff121f3e5723a53307cc8193b390e804dbcfafba49ed", + "plugins/password_auditor/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/people-email-discovery/metadata.json": "64e200fc41169fc010b5720274c8024750ed71b1147296d84f61118331c227a8", + "plugins/people-email-discovery/parser.py": "155fb61bc065a7f4df65af7a718968b2885add883bae5d7c921226512b7e3f81", + "plugins/port-scanner/metadata.json": "c51fb04ca08f7fc9731685db8d5f641935eb86a98b6fc2652c053e7df91cf887", + "plugins/port-scanner/parser.py": "4c1ced841432b844910ef8ba3730a74680c562cc192be57892abc149b1e18a29", + "plugins/scapy_recon/metadata.json": "eaa0c6a47f96abc783ecbe381c7ae84585761bec5ab21c82870946ee66287325", + "plugins/scapy_recon/parser.py": "86f1cb29268a8bc309f637e3391b6de35023a65e8d3969a160110896bcdab090", + "plugins/secret_scanner/metadata.json": "42914c6afc84cbdb1592933dc444688f268e33d8f072f64250df93c83a5a682c", + "plugins/secret_scanner/parser.py": "8028c30f509e153462a7115140deff83e331424a68342ddc6d3b5ae683ffe959", + "plugins/sharepoint_scanner/metadata.json": "0928feb3ee2807c6cfa00cbdb5e39f0b5e9d0aeecf268759b1dbdc309e4bd5b8", + "plugins/sharepoint_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/sitemap_gen/metadata.json": "2a5d37467f18a1de7f23293d07de0dc83eb7e1d61fe825bd664ee62ee805140f", + "plugins/sitemap_gen/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/sniper/metadata.json": "e0b50e6aa3eb14a15cbdea83e8932117f6faba07e9b2c172ecca172c20880891", + "plugins/sniper/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/spider/metadata.json": "926090c343a70f16589e5a2dfe9ff1997f9b9b13ebcd59ccfa775a16e29e059f", + "plugins/spider/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/sqli_checker/metadata.json": "b9b845e01f1cda924b8efba64444e8b17cca049ff34f5a692fb921c0befd6c20", + "plugins/sqli_checker/parser.py": "b70159da466dcabf704ed1b613a74d8d9fcae0685a7d11827985dc889204000b", + "plugins/sqli_exploiter/metadata.json": "23975fd204df51926a85c412116e8596e4ca14276d8cfcceafb28ea02fe8bf5b", + "plugins/sqli_exploiter/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/sqlmap/metadata.json": "dee11f891c498e2626d37d898c4549bdf0f9543f1707b7045bdf3d06e7c61ec1", + "plugins/sqlmap/parser.py": "edec2952eb88429ac5f43f9ef14f4ef444b93a2e2edc6a02d653fe913b3d02e6", + "plugins/ssh_runner/metadata.json": "fe6cc26646fc66ab9b9b8f08245ef78a40b801ade0aa333c26aa9e4445ec50da", + "plugins/ssh_runner/parser.py": "516483ac2296ed841edf482d922d3ee8278fb569d178322104809ffdfcb798c4", + "plugins/subdomain-finder/metadata.json": "f15344354b5bf43fba9a194a64525fd7222f3fc9e478d9b851cccc4083ed0b58", + "plugins/subdomain-finder/parser.py": "bac879e11de91f57ddc5cfbada3a5208db1344cfbb22c75d9a646aa0de090299", + "plugins/subdomain_discovery/metadata.json": "042c824b3010cc74ddfb4a3a7a7585527e7f1a30c90fd713ebf7124ad69ef4f5", + "plugins/subdomain_discovery/parser.py": "77f71fec9ca5154f77a71513831944247fde0fc45661949bd7991b45d576e36c", + "plugins/subdomain_takeover/metadata.json": "406d882f5b865448b74d69234fc8b391479a32634f31a99fad82fea702a9216a", + "plugins/subdomain_takeover/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/subfinder/metadata.json": "668b9627d23b15c666af3edd95b0d7b195bc3784ad82b04aa0462310195cb42b", + "plugins/subfinder/parser.py": "ba20913660007871c3d63ead34724936320b76838b48f9c2874f376a867ed8f4", + "plugins/theharvester/metadata.json": "31deca8a1a73b98f43dc6c7f9354f6dec028ce6f8917120a04ad8f7925030e0d", + "plugins/theharvester/parser.py": "5e4745e27414895654ccf473522d9b4cfdfa124b00de0d339d37df5125c38947", + "plugins/tls_inspector/metadata.json": "2a253b13f8eaea1d5b9375b0176f86578814334619d27b838043a67a95d78dc1", + "plugins/tls_inspector/parser.py": "2675151277a4dba1d4cda2d355e14b1cb11c3e2085f81cc928feb5993b13ba9a", + "plugins/uncover/metadata.json": "68a2d7aabd8d1bce3e1ee26cf0abe37c7b465e143c645c8e1777da318ac6d087", + "plugins/uncover/parser.py": "961a58f1527842c52ac881e1962cf131efef85360d0045654978e7ead4c8bf4f", + "plugins/url-fuzzer-2/metadata.json": "fc6a2787f0fd5d163e5ded78d517af8ad86f4eab9688a75fe3d025adb628491a", + "plugins/url-fuzzer-2/parser.py": "2ba06e6e60ffbf467ef01944c8f4bf23e87e7f04e71025f38576be1e577445d3", + "plugins/urlfinder/metadata.json": "46414d707f5de77d8ba46a34ff6a064a75b8f3d4a553f1b32b2c63d64c19e31e", + "plugins/urlfinder/parser.py": "55c09a4839f1e80573a0a207135cefe2628994a861ed692dc5e6dc7934350fc4", + "plugins/virtual-host-finder/metadata.json": "3410eeb44f6f11212a929b2a677589930e5e41c03a79a52f7c1144c3997ba8e1", + "plugins/virtual-host-finder/parser.py": "f30dbd2f5df147923036a1984c52e60c41fe4405c21ffcc08149d17ba2ad127a", + "plugins/volatility/metadata.json": "5c8114889597a9d393fbbfa39182088cd0e31fa7601ca2e4ba15509731b02858", + "plugins/volatility/parser.py": "3d82614761042d5bf1cc4309c58e089ec6b67350ec8315e84af5be051bba6248", + "plugins/waf-detection/metadata.json": "28199814b93e016f20fe1af874f2604f134dd705bf29fe8ac5421f5329bf87db", + "plugins/waf-detection/parser.py": "7c07fc0b6a0696973cdfea515fb46e6e4647e734b9d22b065fc4b02559000ec3", + "plugins/waf_detector/metadata.json": "961f96c7f962b4e10e69872f9fbfe718dc525784322e5005f8bbd0655d3f3783", + "plugins/waf_detector/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/website-recon-2/metadata.json": "972ec1ce8180bedad5fd02cdb45b51e21215ba197ada5765c69ec417abcd3468", + "plugins/website-recon-2/parser.py": "f4f675364dbf9a77b517a99f5977baf47b57b2132900363db893f657e1c3785b", + "plugins/whois_lookup/metadata.json": "3f5cec89ee87b378b7162e5d7b33c44b64c763bfc43a8e714cdbe110c4663727", + "plugins/whois_lookup/parser.py": "cf847a90319676a0064425c5637c69ab9e5d849674222e5904513616f993bfbb", + "plugins/wpscan/metadata.json": "e3156a00362117a76efa175283cda9ff4a7dc1752769043dc4a7849044264cc2", + "plugins/wpscan/parser.py": "663b104db5c9bba1a7dec242bd9462e7602e252e3b9bbeda59787c3599643263", + "plugins/xss_exploiter/metadata.json": "bd1412c2845c9f8b10a85fec398d38f5c5a4d51bd8923d6ebf6ad15e28a9e289", + "plugins/xss_exploiter/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", + "plugins/yara_scan/metadata.json": "9d42408310204d91590f2f0f59ed3c66bfdfda13f8e4fe89d0d5e24147252729", + "plugins/yara_scan/parser.py": "249cae0d5e3e9b039d8da19050301ce82d9f29fe318e5ebe82ed39c2324aa2af", + "plugins/zap_scanner/metadata.json": "60fc56f1b7f06b615c954e02524ab754792f80de110610165484c2a6dff5872e", + "plugins/zap_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e" } From bd00bf5eb7b3d803d343175504704c0e722d4141 Mon Sep 17 00:00:00 2001 From: siddiqui7864 Date: Sat, 6 Jun 2026 10:12:40 +0530 Subject: [PATCH 05/12] chore(ci): add workflow to regenerate checksum manifest on Linux --- .github/workflows/update-checksums.yml | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/update-checksums.yml diff --git a/.github/workflows/update-checksums.yml b/.github/workflows/update-checksums.yml new file mode 100644 index 000000000..e05be7f5a --- /dev/null +++ b/.github/workflows/update-checksums.yml @@ -0,0 +1,27 @@ +name: Update Plugin Checksum Manifest +on: + workflow_dispatch: + +jobs: + update-manifest: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + ref: fix/plugin-checksum-verification + token: ${{ secrets.GITHUB_TOKEN }} + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Regenerate manifest on Linux + run: python scripts/refresh_plugin_checksums.py + - name: Commit and push updated manifest + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add plugins/checksums.json + git diff --cached --quiet || git commit -m "chore(ci): regenerate checksum manifest with Linux line endings" + git push From f3d61e9d936e2d632424ab99fdd7967827990c31 Mon Sep 17 00:00:00 2001 From: siddiqui7864 Date: Sat, 6 Jun 2026 10:18:26 +0530 Subject: [PATCH 06/12] fix(ci): regenerate manifest on Linux runner before verifying --- .github/workflows/plugin-checksum.yml | 2 ++ .github/workflows/update-checksums.yml | 27 -------------------------- 2 files changed, 2 insertions(+), 27 deletions(-) delete mode 100644 .github/workflows/update-checksums.yml diff --git a/.github/workflows/plugin-checksum.yml b/.github/workflows/plugin-checksum.yml index cf9dcd8c2..4c297184f 100644 --- a/.github/workflows/plugin-checksum.yml +++ b/.github/workflows/plugin-checksum.yml @@ -20,5 +20,7 @@ jobs: run: sudo apt-get install -y libcairo2-dev pkg-config python3-dev - name: Install dependencies run: pip install -r backend/requirements.txt + - name: Regenerate manifest from Linux runner + run: python scripts/refresh_plugin_checksums.py - name: Verify plugin checksums run: python scripts/refresh_plugin_checksums.py --dry-run diff --git a/.github/workflows/update-checksums.yml b/.github/workflows/update-checksums.yml deleted file mode 100644 index e05be7f5a..000000000 --- a/.github/workflows/update-checksums.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Update Plugin Checksum Manifest -on: - workflow_dispatch: - -jobs: - update-manifest: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - with: - ref: fix/plugin-checksum-verification - token: ${{ secrets.GITHUB_TOKEN }} - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - name: Regenerate manifest on Linux - run: python scripts/refresh_plugin_checksums.py - - name: Commit and push updated manifest - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add plugins/checksums.json - git diff --cached --quiet || git commit -m "chore(ci): regenerate checksum manifest with Linux line endings" - git push From e048880a2bc62075c886c66e9a375ee2cc87fee5 Mon Sep 17 00:00:00 2001 From: Zeltarox Date: Sun, 7 Jun 2026 15:57:47 +0530 Subject: [PATCH 07/12] fix(ci): verify against committed manifest and add drift-detection smoke test --- .github/workflows/plugin-checksum.yml | 38 +++- plugins/checksums.json | 240 +++++++++++++------------- 2 files changed, 155 insertions(+), 123 deletions(-) diff --git a/.github/workflows/plugin-checksum.yml b/.github/workflows/plugin-checksum.yml index 4c297184f..2ec1c422b 100644 --- a/.github/workflows/plugin-checksum.yml +++ b/.github/workflows/plugin-checksum.yml @@ -20,7 +20,39 @@ jobs: run: sudo apt-get install -y libcairo2-dev pkg-config python3-dev - name: Install dependencies run: pip install -r backend/requirements.txt - - name: Regenerate manifest from Linux runner - run: python scripts/refresh_plugin_checksums.py - - name: Verify plugin checksums + - name: Verify plugin checksums match committed manifest run: python scripts/refresh_plugin_checksums.py --dry-run + + drift-detection-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Install system dependencies + run: sudo apt-get install -y libcairo2-dev pkg-config python3-dev + - name: Install dependencies + run: pip install -r backend/requirements.txt + - name: Seed manifest from current state + run: python scripts/refresh_plugin_checksums.py + - name: Simulate plugin drift + run: | + FIRST=$(python - <<'PYEOF' +import os, json +with open("plugins/checksums.json") as f: + data = json.load(f) +print(next(k for k in data if k.endswith("metadata.json"))) +PYEOF +) + echo "# drifted" >> "$FIRST" + echo "Mutated: $FIRST" + - name: Assert drift is detected (must exit 1) + run: | + if python scripts/refresh_plugin_checksums.py --dry-run; then + echo "ERROR: drift was not detected — script should have exited 1" + exit 1 + else + echo "OK: drift correctly detected" + fi diff --git a/plugins/checksums.json b/plugins/checksums.json index 8686d3913..7586f192e 100644 --- a/plugins/checksums.json +++ b/plugins/checksums.json @@ -1,122 +1,122 @@ { - "plugins/amass/metadata.json": "72eedc0b74711b37e24f34ce92d9ad24137e7a8ff54f3d75f97d39b59e686003", - "plugins/amass/parser.py": "8656cdbb97a469659dbe2ee114c20194abdb4e2517ce19c80c8bbfac427085ab", - "plugins/api_scanner/metadata.json": "c5b6bd155a177ffa1f81a5a860b1306771fadc341baf9bbe26eebfbb5502fc25", - "plugins/api_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/cloud_scanner/metadata.json": "de37a8b28ee1e399cf39ca3ed3f4377b88e8b707a9595bc1a3d6ca3ec806be33", - "plugins/cloud_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/cloud_storage_auditor/metadata.json": "a1ad6618a351dea840d63fd37941b65668d1251d1f6becd1004ed99f8b627246", - "plugins/cloud_storage_auditor/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/code_analyzer/metadata.json": "c683305ceca0b6674bc351d244fa74538da4618bede2751090abdc49f7b299e4", - "plugins/code_analyzer/parser.py": "8f9112fc50b2e083880c7544b877a2458a51d7ac58ab633e7d2b87aced3fb100", - "plugins/container_scanner/metadata.json": "66b95e11fa071d59c37948f56344a0f0c977f446fb5a62cc4f66aad07245ffa2", - "plugins/container_scanner/parser.py": "1386eaaa649046714a051483749fc78e8bbd55f11cd635acd3cb7e9fa89310b9", - "plugins/crawler/metadata.json": "ef5097db30843d129b80481ac1b618e770867ad48b611fbe61d8d36562c55db7", - "plugins/crawler/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/dir_discovery/metadata.json": "4512cc4329621db861da7678947e93e048c746c6f59e828ecc6666ca76d9e732", - "plugins/dir_discovery/parser.py": "5bb25b93e9e94c59229261f69663d2822618448ceedf27a66602f9eeee577269", - "plugins/dns_enum/metadata.json": "8993461681dc2af02548af4c5ff21b1c96121ddaeac0cabc87900a9681bd5157", - "plugins/dns_enum/parser.py": "e364aac3b1962eef8c348cef4786418304d12120dc246c4197877b844fd57b74", - "plugins/dnsx/metadata.json": "da04bb9c8765102cda77085fb120174dd66a2c5a134cd1e4ea5b983c3dd10f22", - "plugins/dnsx/parser.py": "886d57da7c7c29201f8f67364c37635b09c08cbe9888abe0b4997381ff9d04d3", - "plugins/domain-finder/metadata.json": "7a35923bd837bdb3a7a72812d356f415fe861b75474efd364b82ea7da6dcb9d0", - "plugins/domain-finder/parser.py": "4297dcb82280011fab4cb4b8d0e70d15bed0280f1c4ed040ce28632c5ef44ac7", - "plugins/droopescan/metadata.json": "ac26896df547d64d895867cc225c21c73c96eafa170b3a285503e6689faa722b", - "plugins/droopescan/parser.py": "37d7c3bae730354218145c42d1d1d96ae9debf7ec5ad83012f10dcd2d801661d", - "plugins/fuzzer/metadata.json": "d9cdc0e7a75c96cfe38d5f43fba68921238cbcb6179f3527cc0e33b6398e26aa", - "plugins/fuzzer/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/google-dorking/metadata.json": "366e327a4646b8598108785c0e9b692d6fbb885b4814034c392bb36199fbbeae", - "plugins/google-dorking/parser.py": "bc89cafb7a9ff3a712a1379e3ddb75f2ed410c4d363a205171af2dc0211fd8b4", - "plugins/hashcat/metadata.json": "64f5471810907e970bc45055b9a7e68e4d6b0821e46d17fcece40b85db29edb8", - "plugins/hashcat/parser.py": "b45df99421ab5345b7d74f7c3bcdd8896d65c5d1b71dac4fca505b7b911960e2", - "plugins/http_inspector/metadata.json": "ed2e18caf97b4ee357e662cf89cf8aa7d055c82ac49fce1f616594d238d3a42c", - "plugins/http_inspector/parser.py": "3d71bdf96584e376f7b6aab8d2cd1efa20c3a01a8a2cdd86010988fe370d8880", - "plugins/http_request_logger/metadata.json": "f3d2cc72df923e4a8a44361ca8d2813ca05f2e2ac4a1e309217b466179df2f54", - "plugins/http_request_logger/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/httpx/metadata.json": "3694e964483f1c2ed91ebbfcda519302487e204d49532c071cc3929d7daf9794", - "plugins/httpx/parser.py": "64362f696959205094923a2b5e98e1084b16938a6376f9a5a354199b928bd67a", - "plugins/iac_scanner/metadata.json": "7caae20deacba06314eadd3256ef8f8cb5145bd68c903685de18f815b1ce630c", - "plugins/iac_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/icmp_ping/metadata.json": "8e5a2ef314bff3793fea001998c9d954fd3e417f40a291253b97fd5f50842a53", - "plugins/icmp_ping/parser.py": "15bf271e1c206fadbbfb665fa600875435962ad2707c382298ce2bbb676c15ad", - "plugins/joomscan/metadata.json": "c846d4d3812fdfed21923bf3de765b3c972667f7cae56ac43cd576f7b5d97368", - "plugins/joomscan/parser.py": "1b8386093cc7b22e6b5956b0cc6f02c57cc24e43f13f35269e6c41bc528c2da9", - "plugins/katana/metadata.json": "a7f6ec8327f0006d3c40349da96fafbc492b87632d6592bec822240ded4ad0ab", - "plugins/katana/parser.py": "76ba1db2ab383efbeb3f8dd96e621f2d5acde5172c10b548b53d78e70118d1d1", - "plugins/kubernetes_scanner/metadata.json": "71850e28d70bc23bf60cfe91d8638e162d5f91129a4bcd295f36590c1371e3c7", - "plugins/kubernetes_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/metasploit/metadata.json": "9a9e215624ea44fbadf5a1b9eea85887d61a3e0bf9c3d9b197453467a3d40133", - "plugins/metasploit/parser.py": "24b77483c28f71536d182f6849b30a2c9290db088528ce2e45f5c67335846ca0", - "plugins/network_scanner/metadata.json": "e5e1a7562dab8ab46a8fae45c3c51be85ddd8aeaace3c78d52aebcd6c13fcc55", - "plugins/network_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/nikto/metadata.json": "06a37edcb5fcd4ef9dda050663da8ab9a65bdaadd833cfe268e022bf4e8ece20", - "plugins/nikto/parser.py": "6fda2fe11eadd7e3181b27ba48b3833dc4ae55ed5d8a910b03d37f93f0ba4962", - "plugins/nmap/metadata.json": "28212089ea084ae57cc0be29fe7f693e2ffab0caf1f6aefcd3fb39a8e6fab680", - "plugins/nmap/parser.py": "e3fa70f90b728e3734474e05dd1743338334216aadee0a5088e89a8700a6a839", - "plugins/nuclei/metadata.json": "dd0259513d20328f470851af237e0ca543f8de77a231887657138c02d3134f7a", - "plugins/nuclei/parser.py": "661ec2465d5c92c4b57de69ba29c8da7434f022defdbf2764f7eeb53157601b7", - "plugins/password_auditor/metadata.json": "8870ec634eaa8828f1b1ff121f3e5723a53307cc8193b390e804dbcfafba49ed", - "plugins/password_auditor/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/people-email-discovery/metadata.json": "64e200fc41169fc010b5720274c8024750ed71b1147296d84f61118331c227a8", - "plugins/people-email-discovery/parser.py": "155fb61bc065a7f4df65af7a718968b2885add883bae5d7c921226512b7e3f81", - "plugins/port-scanner/metadata.json": "c51fb04ca08f7fc9731685db8d5f641935eb86a98b6fc2652c053e7df91cf887", - "plugins/port-scanner/parser.py": "4c1ced841432b844910ef8ba3730a74680c562cc192be57892abc149b1e18a29", - "plugins/scapy_recon/metadata.json": "eaa0c6a47f96abc783ecbe381c7ae84585761bec5ab21c82870946ee66287325", - "plugins/scapy_recon/parser.py": "86f1cb29268a8bc309f637e3391b6de35023a65e8d3969a160110896bcdab090", - "plugins/secret_scanner/metadata.json": "42914c6afc84cbdb1592933dc444688f268e33d8f072f64250df93c83a5a682c", - "plugins/secret_scanner/parser.py": "8028c30f509e153462a7115140deff83e331424a68342ddc6d3b5ae683ffe959", - "plugins/sharepoint_scanner/metadata.json": "0928feb3ee2807c6cfa00cbdb5e39f0b5e9d0aeecf268759b1dbdc309e4bd5b8", - "plugins/sharepoint_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/sitemap_gen/metadata.json": "2a5d37467f18a1de7f23293d07de0dc83eb7e1d61fe825bd664ee62ee805140f", - "plugins/sitemap_gen/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/sniper/metadata.json": "e0b50e6aa3eb14a15cbdea83e8932117f6faba07e9b2c172ecca172c20880891", - "plugins/sniper/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/spider/metadata.json": "926090c343a70f16589e5a2dfe9ff1997f9b9b13ebcd59ccfa775a16e29e059f", - "plugins/spider/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/sqli_checker/metadata.json": "b9b845e01f1cda924b8efba64444e8b17cca049ff34f5a692fb921c0befd6c20", - "plugins/sqli_checker/parser.py": "b70159da466dcabf704ed1b613a74d8d9fcae0685a7d11827985dc889204000b", - "plugins/sqli_exploiter/metadata.json": "23975fd204df51926a85c412116e8596e4ca14276d8cfcceafb28ea02fe8bf5b", - "plugins/sqli_exploiter/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/sqlmap/metadata.json": "dee11f891c498e2626d37d898c4549bdf0f9543f1707b7045bdf3d06e7c61ec1", - "plugins/sqlmap/parser.py": "edec2952eb88429ac5f43f9ef14f4ef444b93a2e2edc6a02d653fe913b3d02e6", - "plugins/ssh_runner/metadata.json": "fe6cc26646fc66ab9b9b8f08245ef78a40b801ade0aa333c26aa9e4445ec50da", - "plugins/ssh_runner/parser.py": "516483ac2296ed841edf482d922d3ee8278fb569d178322104809ffdfcb798c4", - "plugins/subdomain-finder/metadata.json": "f15344354b5bf43fba9a194a64525fd7222f3fc9e478d9b851cccc4083ed0b58", - "plugins/subdomain-finder/parser.py": "bac879e11de91f57ddc5cfbada3a5208db1344cfbb22c75d9a646aa0de090299", - "plugins/subdomain_discovery/metadata.json": "042c824b3010cc74ddfb4a3a7a7585527e7f1a30c90fd713ebf7124ad69ef4f5", - "plugins/subdomain_discovery/parser.py": "77f71fec9ca5154f77a71513831944247fde0fc45661949bd7991b45d576e36c", - "plugins/subdomain_takeover/metadata.json": "406d882f5b865448b74d69234fc8b391479a32634f31a99fad82fea702a9216a", - "plugins/subdomain_takeover/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/subfinder/metadata.json": "668b9627d23b15c666af3edd95b0d7b195bc3784ad82b04aa0462310195cb42b", - "plugins/subfinder/parser.py": "ba20913660007871c3d63ead34724936320b76838b48f9c2874f376a867ed8f4", - "plugins/theharvester/metadata.json": "31deca8a1a73b98f43dc6c7f9354f6dec028ce6f8917120a04ad8f7925030e0d", - "plugins/theharvester/parser.py": "5e4745e27414895654ccf473522d9b4cfdfa124b00de0d339d37df5125c38947", - "plugins/tls_inspector/metadata.json": "2a253b13f8eaea1d5b9375b0176f86578814334619d27b838043a67a95d78dc1", - "plugins/tls_inspector/parser.py": "2675151277a4dba1d4cda2d355e14b1cb11c3e2085f81cc928feb5993b13ba9a", - "plugins/uncover/metadata.json": "68a2d7aabd8d1bce3e1ee26cf0abe37c7b465e143c645c8e1777da318ac6d087", - "plugins/uncover/parser.py": "961a58f1527842c52ac881e1962cf131efef85360d0045654978e7ead4c8bf4f", - "plugins/url-fuzzer-2/metadata.json": "fc6a2787f0fd5d163e5ded78d517af8ad86f4eab9688a75fe3d025adb628491a", - "plugins/url-fuzzer-2/parser.py": "2ba06e6e60ffbf467ef01944c8f4bf23e87e7f04e71025f38576be1e577445d3", - "plugins/urlfinder/metadata.json": "46414d707f5de77d8ba46a34ff6a064a75b8f3d4a553f1b32b2c63d64c19e31e", - "plugins/urlfinder/parser.py": "55c09a4839f1e80573a0a207135cefe2628994a861ed692dc5e6dc7934350fc4", - "plugins/virtual-host-finder/metadata.json": "3410eeb44f6f11212a929b2a677589930e5e41c03a79a52f7c1144c3997ba8e1", - "plugins/virtual-host-finder/parser.py": "f30dbd2f5df147923036a1984c52e60c41fe4405c21ffcc08149d17ba2ad127a", - "plugins/volatility/metadata.json": "5c8114889597a9d393fbbfa39182088cd0e31fa7601ca2e4ba15509731b02858", - "plugins/volatility/parser.py": "3d82614761042d5bf1cc4309c58e089ec6b67350ec8315e84af5be051bba6248", - "plugins/waf-detection/metadata.json": "28199814b93e016f20fe1af874f2604f134dd705bf29fe8ac5421f5329bf87db", - "plugins/waf-detection/parser.py": "7c07fc0b6a0696973cdfea515fb46e6e4647e734b9d22b065fc4b02559000ec3", - "plugins/waf_detector/metadata.json": "961f96c7f962b4e10e69872f9fbfe718dc525784322e5005f8bbd0655d3f3783", - "plugins/waf_detector/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/website-recon-2/metadata.json": "972ec1ce8180bedad5fd02cdb45b51e21215ba197ada5765c69ec417abcd3468", - "plugins/website-recon-2/parser.py": "f4f675364dbf9a77b517a99f5977baf47b57b2132900363db893f657e1c3785b", - "plugins/whois_lookup/metadata.json": "3f5cec89ee87b378b7162e5d7b33c44b64c763bfc43a8e714cdbe110c4663727", - "plugins/whois_lookup/parser.py": "cf847a90319676a0064425c5637c69ab9e5d849674222e5904513616f993bfbb", - "plugins/wpscan/metadata.json": "e3156a00362117a76efa175283cda9ff4a7dc1752769043dc4a7849044264cc2", - "plugins/wpscan/parser.py": "663b104db5c9bba1a7dec242bd9462e7602e252e3b9bbeda59787c3599643263", - "plugins/xss_exploiter/metadata.json": "bd1412c2845c9f8b10a85fec398d38f5c5a4d51bd8923d6ebf6ad15e28a9e289", - "plugins/xss_exploiter/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e", - "plugins/yara_scan/metadata.json": "9d42408310204d91590f2f0f59ed3c66bfdfda13f8e4fe89d0d5e24147252729", - "plugins/yara_scan/parser.py": "249cae0d5e3e9b039d8da19050301ce82d9f29fe318e5ebe82ed39c2324aa2af", - "plugins/zap_scanner/metadata.json": "60fc56f1b7f06b615c954e02524ab754792f80de110610165484c2a6dff5872e", - "plugins/zap_scanner/parser.py": "21dc981bbd93fe4554cb07bd55c051c51fd72134724bb4919ffc563211a1db2e" + "plugins/amass/metadata.json": "8085734cfcc202b31be62485c46a2d44fb10d1512122ca1dac8fbcdde4b5c8ba", + "plugins/amass/parser.py": "ca88eb90721c07d76f4400c7ce8339b71e95370324e2745a9039b728ff31d779", + "plugins/api_scanner/metadata.json": "801067e36219edbdd49beba7ad7c1e1fc37065e029e3c3056055cd7d2e9d220a", + "plugins/api_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/cloud_scanner/metadata.json": "fb162eb75202aa5d31a4bf4d2a77960d785d799553e86b5cef4e48506f6e8a83", + "plugins/cloud_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/cloud_storage_auditor/metadata.json": "0ab003f019bbf8960f12dc30edb213643d2eaf99e269ec9996229f01507cf1ab", + "plugins/cloud_storage_auditor/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/code_analyzer/metadata.json": "59f7002ba019b404a3c90de217c3bec0bf6c579e440366c3ba8654a0aa5295c0", + "plugins/code_analyzer/parser.py": "530bbd8495860a2d1f697794bf494b2a4c96ffa0b7c608d13bb50e6cba0a4db0", + "plugins/container_scanner/metadata.json": "aae07275e1246ff7c37a858a44c4b43d27e4c2b630973a5273fb36a95f530ce4", + "plugins/container_scanner/parser.py": "2d0b0064c9a67f9b7c93c9e1720ce5600ebfccc1d80de7a78e143278e5f1f4b3", + "plugins/crawler/metadata.json": "10697988271fd9cc5293b8fa089cc2dbd9fb3f6c7da5f177fec99899cdfa419c", + "plugins/crawler/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/dir_discovery/metadata.json": "f75d2a2ac05b89ae4daf3067e0f54927e490eede0dccf758b4101457670db5fb", + "plugins/dir_discovery/parser.py": "1fa39d0be591b51c6fcc9bcbac4c4956e4f800ffbaeeb592358dfb027b20ea1a", + "plugins/dns_enum/metadata.json": "baab6e4557d4039936e795188509b5472da6a347569d0bd0594a6013fa979c01", + "plugins/dns_enum/parser.py": "55be96b7e341e5695d67e6e3de8835f9748c09b67f92b83f5631f5a075746fbc", + "plugins/dnsx/metadata.json": "8f04e3c6c39608749c912c96667e37fde00586f51cad59b6df61a4c25096ef7c", + "plugins/dnsx/parser.py": "7969b7c9e40f320131a5ed25d3fef57caea7aeb54b0137d1a9c266f1453e7fbf", + "plugins/domain-finder/metadata.json": "70a2ab85ba98d52ec95dcc56a2e90d7a9b9b3fe39d957fb145d954b42826581e", + "plugins/domain-finder/parser.py": "4f37f7a15a373988cc24c8ed4ce0b864005eb6b596d3f6f35d30775416204ad5", + "plugins/droopescan/metadata.json": "efdc435519c336d4e1b29c7ad8b35147187a3fcf3d10784e310944ffa168ac00", + "plugins/droopescan/parser.py": "b8a768265c36fcfb44c93bbea5c7a9773250e328ca046b0c5de703369544eea2", + "plugins/fuzzer/metadata.json": "383f54f4ea9379fc57d96daa4b3648651c319bf44b70b1d89998e71939f6a4ca", + "plugins/fuzzer/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/google-dorking/metadata.json": "0af27fcea2d78b40e2e542b0f729c77775491a59113879e151726457bbe9f1a5", + "plugins/google-dorking/parser.py": "9a9f3de81a2d0b7539ed2004777b3a5a6d88d738ec1437b3851c60bf817ec395", + "plugins/hashcat/metadata.json": "c011eea3eac3caa8385a5e66bcd701f01da32ffd2c151163a27ba97dcec6b64f", + "plugins/hashcat/parser.py": "64f279f0299b9be3f8270ba5a7e0be4ba64bb58ff3f9b1f3fde776bcfe8ae40f", + "plugins/http_inspector/metadata.json": "263c540c98172bd15a6b0b587b94c6e60543745ca2a6e281179cc948729e831b", + "plugins/http_inspector/parser.py": "9af42c29cff674f680d5cda9e64037ae112a39dfc0d7f07f40a0221a023a1158", + "plugins/http_request_logger/metadata.json": "cac0de30f7060986b3e0668f99215442e2f0283c989e3928867f67c6a21416c7", + "plugins/http_request_logger/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/httpx/metadata.json": "177c75192c1073ad7cf3b8730b03761fc76d7d8dca0c6e711c6dfccb7d1b35a1", + "plugins/httpx/parser.py": "057758ed06775f76de0acc0e56785ffb7ed42394c02c127ea61e778b215a4a4e", + "plugins/iac_scanner/metadata.json": "1c1d8c2f5317fde03750b0b8d1599de51f234da5b0f196a3adec584b27969f8c", + "plugins/iac_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/icmp_ping/metadata.json": "7ce790d9ed733f2b34c5b5d2a56e04678eb1737c07d533d7d2ba20c06b34bba8", + "plugins/icmp_ping/parser.py": "e4956cd48975815054d3fab679d84f9dbe7390b99fc5d97c04d5f26ef6c78abb", + "plugins/joomscan/metadata.json": "9678199a89b791ef033b2e367e78c4c60f9b2218867e8fc5365500f7fc464996", + "plugins/joomscan/parser.py": "80c63c94b4b4b35c9ab7602b7cffa42078a7f81aa34382b02c9266c3b234a16f", + "plugins/katana/metadata.json": "e35a3b4a48c34151f5bc8fd5a2d67cafeec9daf9c05ecc57f907438a7344149e", + "plugins/katana/parser.py": "48bd827701b9822904bada9e9a028388f419007c27710683b0b0325b2d2ac2e3", + "plugins/kubernetes_scanner/metadata.json": "b062d38c01765863067f000513c73392e8503417fa47a74830db82ad2cc1baa7", + "plugins/kubernetes_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/metasploit/metadata.json": "fcc5518fbcda29e4bd3c719deab41cf8634d80cfeff1ecb0641d2e3e5fce2601", + "plugins/metasploit/parser.py": "8d0968d75137126b41fede3353bb08f748975e810e3b3f0aee7212801b8503ce", + "plugins/network_scanner/metadata.json": "6be07009c352e52be3ac4d3c9e587c23c4410cd3be98c602e097e842017ddf62", + "plugins/network_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/nikto/metadata.json": "38a76b78446fa5680aa6b4713e8f5e3b43bdf4e0e64dc67c838287af743f64c0", + "plugins/nikto/parser.py": "5453c51abb5d81d8667154780a63d25c785cf48c86f886444aa39aec7aae39f4", + "plugins/nmap/metadata.json": "b953f82a9c0821fd1342c1777190ee281b700ae27b350d16e7d048fe732a345d", + "plugins/nmap/parser.py": "ec7c67e22cd90ce7d5365685307d8981840942821605950e8560afe628086b8c", + "plugins/nuclei/metadata.json": "eb9c715f2e5d789a1490afb82f82778f600ba81447afb278494bdec7327f5a81", + "plugins/nuclei/parser.py": "7708cec4fea3e2192dd999d787f0e48393a21c9a524000cfbcec7049396ade5e", + "plugins/password_auditor/metadata.json": "c7c5bc540991554832868cc14091b7d6a87ae0ff6bd39063572aa7ea8ab36bb8", + "plugins/password_auditor/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/people-email-discovery/metadata.json": "968007741260b33c9cf3a0911937184e33f79e57ddd5b81230ea97e24817053d", + "plugins/people-email-discovery/parser.py": "728ef3c1abbb6e69116cd7df19cbc80507c8750a29061e22bb441dbab50b9359", + "plugins/port-scanner/metadata.json": "2f40fb011f6aef4b21e9b0571d08369be40f34fe0b08d6da999530aaf1c635a2", + "plugins/port-scanner/parser.py": "a30afe8ca794def4f04a42e81ce1d594a1cd9ebebafba584b7ce3779aa36826c", + "plugins/scapy_recon/metadata.json": "c2be7fa7b456f11403a4af30a338e19f662714b00a9705f0f92a1519f311f0dc", + "plugins/scapy_recon/parser.py": "b9c1fba6ff58aedb4584de9e3814d5b5ca0f8d44df0f3b1ee526f276a1c7bb8b", + "plugins/secret_scanner/metadata.json": "8d5c6852a06a437d34824a73665141b486c076ff776e39108879835d77777f3a", + "plugins/secret_scanner/parser.py": "d4ebdbaabb6cb58be578a67d920fb67618dd750543829d2178b886446d7664f2", + "plugins/sharepoint_scanner/metadata.json": "bea08eb80d31d5145c2af0daeb6d1d7471661e008fcd7a83619bc90611c8ab0f", + "plugins/sharepoint_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/sitemap_gen/metadata.json": "1a38185a5cef3d2aa57034a711a01beecb2a829b08c28966d5a08d28192fa828", + "plugins/sitemap_gen/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/sniper/metadata.json": "8c559de6326e6e91d3f226811578b1f37f8163ab8bfe62a31b05c183b9d65e01", + "plugins/sniper/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/spider/metadata.json": "0bfb464554774f112d3a123179d4a7d5affbc13cd18759aade49e1bfea565f53", + "plugins/spider/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/sqli_checker/metadata.json": "f114cb73e245e5724985ca2f705f6a0b0901e0686fc3c55ad35fa1443d8633ce", + "plugins/sqli_checker/parser.py": "3b31a6e20eabe567165569f0e42841ecf4a991d220f55721b71ec1567e949475", + "plugins/sqli_exploiter/metadata.json": "0e2f24a009b725b4f76d11b0e6cd11e7b60f20a4e0b62e29694e65e08c5c0b86", + "plugins/sqli_exploiter/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/sqlmap/metadata.json": "f458f73dc5edadf66ed42438339e042b7566db666859e5382d4cbc72d5027d3e", + "plugins/sqlmap/parser.py": "1708299ab47f76de69131a8074672f4aad69c1a6b8a1c6955866e1fdfef976b2", + "plugins/ssh_runner/metadata.json": "a2fed56519bea9e9e9bd886e0b0f99cf1f012258d4604a41908c1de35bd5d070", + "plugins/ssh_runner/parser.py": "bbc0ca00f62dc7a92c6d890b9a72dd8cdabb7ceb6b9ee2c3c944e52c2d42deb3", + "plugins/subdomain-finder/metadata.json": "df1721bb6167335756d65670519c0d341ae9f3e96e49974303b397f6b65a5e3c", + "plugins/subdomain-finder/parser.py": "97438107ca6b8cae404c594479bf48f7bd0978f50ed8227a9b2132f2217f39bf", + "plugins/subdomain_discovery/metadata.json": "ec966633d2cd9913c11a8766b049d8edfcdbd35e84e7758b63c99b06c91fb699", + "plugins/subdomain_discovery/parser.py": "f83d3aa18e52b223d597eb5c8b41effa1110abce71153aa127db8c275a6d9850", + "plugins/subdomain_takeover/metadata.json": "18bc52f5c05a23912b21db6ab048ffd2b91f3d59dab3a1b456f302f5670587cd", + "plugins/subdomain_takeover/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/subfinder/metadata.json": "3970de33a910ace4f5e6fb58f1593776f90c0dd7dc999690c115273815cd90a5", + "plugins/subfinder/parser.py": "f0b836dd87292b1d5d433b3584a4d0158e1b485ade1339255838c6c7e6261d0a", + "plugins/theharvester/metadata.json": "8019c0e33b363297d44e2f68c270ef3f4beaf72bcafe55a7d7c7b4d0ab40a7d4", + "plugins/theharvester/parser.py": "54dc7c5716e26c822438f5cd7251c01ec6b10ca9754b6bf1d7c4a56bd7ae5dab", + "plugins/tls_inspector/metadata.json": "bedc851d7af86760c3a2e2e6396af851e0d13474df0520c20976d768298c9280", + "plugins/tls_inspector/parser.py": "f7aa4a6255570c3a8ce9558873d88f8f05bbd1b4668c91293ac6564d54716ffb", + "plugins/uncover/metadata.json": "a7d15fc8592aede8c5edd27c42ac20fccb40b6100037b473d46924469f06bc83", + "plugins/uncover/parser.py": "8239043efa625e99d98a8f337cfb62055b93751eb22a7d1c6e2ec20236222f9a", + "plugins/url-fuzzer-2/metadata.json": "725b9faf5ec78ad2c8baf2d87b76df9abad33966e95da83ebf8ded977988ea0d", + "plugins/url-fuzzer-2/parser.py": "13bc1f8f3867f7f10f9d93e59851e604cba4b2142034501f066139ccdfd58ea7", + "plugins/urlfinder/metadata.json": "bf081ddafd73c6100205eae62a58c06ccf80bc46dc04cb5f144173858875587f", + "plugins/urlfinder/parser.py": "aac61d1d1b3418f3af994901b8b66c5e9e646eb94c864713c8ce2618873678f2", + "plugins/virtual-host-finder/metadata.json": "06a787da633e19c0c5305bdad02bd2fc06934255d87bed57828b636f18893a3a", + "plugins/virtual-host-finder/parser.py": "05b16d0b35a8ee12af2d527873a6ce974f4c25d8d5ff318775a7d3543d5f1d73", + "plugins/volatility/metadata.json": "dc2afa1d33f684692883a1a734b32676a76b829cec6a6bdab01b3b12bdd1c1ec", + "plugins/volatility/parser.py": "429ab2231a2637e507b1ac45f24e9c3b838b285e3e72fc015dd80a5eea55b8d5", + "plugins/waf-detection/metadata.json": "74d1e7afe057a46c2a2f5d4e17fbdfd9d814ca0126c57b787bd35187ed109edf", + "plugins/waf-detection/parser.py": "c84ae8bfa33ad245f6c8854706bdd0e1298f403e1ec24e90d064755635c652ce", + "plugins/waf_detector/metadata.json": "8bb39e6feedcd27f1122171c338eea0d6513acd971e10937e5dc946b76e05073", + "plugins/waf_detector/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/website-recon-2/metadata.json": "f0801b4dc542fede228d3e75136e3952ebe131b4e1708421790c3b1f3ad05083", + "plugins/website-recon-2/parser.py": "3d05ce7fde793eb8799a7389817d2f4ae172ce5ce49cb0a38845ab011cfd17da", + "plugins/whois_lookup/metadata.json": "d301ed91aea79a0a25e9c0ef8cec53df69d8d6a48df79f3bf43df210831da7c5", + "plugins/whois_lookup/parser.py": "4ad33292ee128c93a3d567ff44b1c51439e3bb80d2bec82f4ca8d7164406bdd3", + "plugins/wpscan/metadata.json": "41dc2174689da0f66045601fb457f420e3a8cd45486c99062461ac8a07b69fbc", + "plugins/wpscan/parser.py": "12ce514688de66240156e0058502a336fefa655cdd7595b6e1c9b281cb2d316d", + "plugins/xss_exploiter/metadata.json": "73cf1111cf40acd6ffd3ecbaa109080d5c95610a5d8ec89156adb58a87f5bc1d", + "plugins/xss_exploiter/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", + "plugins/yara_scan/metadata.json": "4ec5275b93803aa117c09f92a914ab9c96e120eb59e7af4362e9c82aae8fde5d", + "plugins/yara_scan/parser.py": "9209f5cf6191b384790f2663e1824b02d5470c26268b8668c710ace7ac8ed80e", + "plugins/zap_scanner/metadata.json": "1061ea0ec48c370fb3cbfccea0b27cc05ab62ae3ef9a2805ccdd05014d596aa1", + "plugins/zap_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d" } From 0ddaad127dbba43a7c46690c551a5e2f7a5f1675 Mon Sep 17 00:00:00 2001 From: Zeltarox Date: Sun, 7 Jun 2026 19:20:07 +0530 Subject: [PATCH 08/12] fix(ci): replace heredoc with inline python3 -c in drift-detection step --- .github/workflows/plugin-checksum.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/plugin-checksum.yml b/.github/workflows/plugin-checksum.yml index 2ec1c422b..3f7e638cc 100644 --- a/.github/workflows/plugin-checksum.yml +++ b/.github/workflows/plugin-checksum.yml @@ -39,13 +39,7 @@ jobs: run: python scripts/refresh_plugin_checksums.py - name: Simulate plugin drift run: | - FIRST=$(python - <<'PYEOF' -import os, json -with open("plugins/checksums.json") as f: - data = json.load(f) -print(next(k for k in data if k.endswith("metadata.json"))) -PYEOF -) + FIRST=$(python3 -c "import json; d=json.load(open('plugins/checksums.json')); print(next(k for k in d if k.endswith('metadata.json')))") echo "# drifted" >> "$FIRST" echo "Mutated: $FIRST" - name: Assert drift is detected (must exit 1) From 7d11a89d4fa5dfa7e4c1715c58e671c01a246ee0 Mon Sep 17 00:00:00 2001 From: Zeltarox Date: Sun, 7 Jun 2026 19:24:18 +0530 Subject: [PATCH 09/12] chore(ci): regenerate manifest against upstream main plugin state --- plugins/checksums.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/checksums.json b/plugins/checksums.json index 7586f192e..ff68f065d 100644 --- a/plugins/checksums.json +++ b/plugins/checksums.json @@ -1,7 +1,7 @@ { "plugins/amass/metadata.json": "8085734cfcc202b31be62485c46a2d44fb10d1512122ca1dac8fbcdde4b5c8ba", "plugins/amass/parser.py": "ca88eb90721c07d76f4400c7ce8339b71e95370324e2745a9039b728ff31d779", - "plugins/api_scanner/metadata.json": "801067e36219edbdd49beba7ad7c1e1fc37065e029e3c3056055cd7d2e9d220a", + "plugins/api_scanner/metadata.json": "9e2f6962632ade784bc547b9c4a802f3eac1e6109a73dda519bb41b23449049f", "plugins/api_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", "plugins/cloud_scanner/metadata.json": "fb162eb75202aa5d31a4bf4d2a77960d785d799553e86b5cef4e48506f6e8a83", "plugins/cloud_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", @@ -47,13 +47,13 @@ "plugins/kubernetes_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", "plugins/metasploit/metadata.json": "fcc5518fbcda29e4bd3c719deab41cf8634d80cfeff1ecb0641d2e3e5fce2601", "plugins/metasploit/parser.py": "8d0968d75137126b41fede3353bb08f748975e810e3b3f0aee7212801b8503ce", - "plugins/network_scanner/metadata.json": "6be07009c352e52be3ac4d3c9e587c23c4410cd3be98c602e097e842017ddf62", + "plugins/network_scanner/metadata.json": "5721417097f65400c007ed1039690ce69665a71ddfa0cfe18d695230216d6337", "plugins/network_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", "plugins/nikto/metadata.json": "38a76b78446fa5680aa6b4713e8f5e3b43bdf4e0e64dc67c838287af743f64c0", "plugins/nikto/parser.py": "5453c51abb5d81d8667154780a63d25c785cf48c86f886444aa39aec7aae39f4", "plugins/nmap/metadata.json": "b953f82a9c0821fd1342c1777190ee281b700ae27b350d16e7d048fe732a345d", "plugins/nmap/parser.py": "ec7c67e22cd90ce7d5365685307d8981840942821605950e8560afe628086b8c", - "plugins/nuclei/metadata.json": "eb9c715f2e5d789a1490afb82f82778f600ba81447afb278494bdec7327f5a81", + "plugins/nuclei/metadata.json": "ec9abb4c639f3aec744988fe0bb6d3d22a9d83bda5760a98639a71f7061f568a", "plugins/nuclei/parser.py": "7708cec4fea3e2192dd999d787f0e48393a21c9a524000cfbcec7049396ade5e", "plugins/password_auditor/metadata.json": "c7c5bc540991554832868cc14091b7d6a87ae0ff6bd39063572aa7ea8ab36bb8", "plugins/password_auditor/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", @@ -69,7 +69,7 @@ "plugins/sharepoint_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", "plugins/sitemap_gen/metadata.json": "1a38185a5cef3d2aa57034a711a01beecb2a829b08c28966d5a08d28192fa828", "plugins/sitemap_gen/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/sniper/metadata.json": "8c559de6326e6e91d3f226811578b1f37f8163ab8bfe62a31b05c183b9d65e01", + "plugins/sniper/metadata.json": "d1a3c177c8c586510804601c479ba28becc790b0a921fe6a3df50926b5f5eb0f", "plugins/sniper/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", "plugins/spider/metadata.json": "0bfb464554774f112d3a123179d4a7d5affbc13cd18759aade49e1bfea565f53", "plugins/spider/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", @@ -77,7 +77,7 @@ "plugins/sqli_checker/parser.py": "3b31a6e20eabe567165569f0e42841ecf4a991d220f55721b71ec1567e949475", "plugins/sqli_exploiter/metadata.json": "0e2f24a009b725b4f76d11b0e6cd11e7b60f20a4e0b62e29694e65e08c5c0b86", "plugins/sqli_exploiter/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/sqlmap/metadata.json": "f458f73dc5edadf66ed42438339e042b7566db666859e5382d4cbc72d5027d3e", + "plugins/sqlmap/metadata.json": "512a7c6dc14eabdf473fb9866c57df30a0982180f86169b74c9fdf6ce4f542b2", "plugins/sqlmap/parser.py": "1708299ab47f76de69131a8074672f4aad69c1a6b8a1c6955866e1fdfef976b2", "plugins/ssh_runner/metadata.json": "a2fed56519bea9e9e9bd886e0b0f99cf1f012258d4604a41908c1de35bd5d070", "plugins/ssh_runner/parser.py": "bbc0ca00f62dc7a92c6d890b9a72dd8cdabb7ceb6b9ee2c3c944e52c2d42deb3", @@ -93,7 +93,7 @@ "plugins/theharvester/parser.py": "54dc7c5716e26c822438f5cd7251c01ec6b10ca9754b6bf1d7c4a56bd7ae5dab", "plugins/tls_inspector/metadata.json": "bedc851d7af86760c3a2e2e6396af851e0d13474df0520c20976d768298c9280", "plugins/tls_inspector/parser.py": "f7aa4a6255570c3a8ce9558873d88f8f05bbd1b4668c91293ac6564d54716ffb", - "plugins/uncover/metadata.json": "a7d15fc8592aede8c5edd27c42ac20fccb40b6100037b473d46924469f06bc83", + "plugins/uncover/metadata.json": "9604f94d15abf0074af9ba92e9c3d902d1d5a9529fe64fa718872d28a277b4ed", "plugins/uncover/parser.py": "8239043efa625e99d98a8f337cfb62055b93751eb22a7d1c6e2ec20236222f9a", "plugins/url-fuzzer-2/metadata.json": "725b9faf5ec78ad2c8baf2d87b76df9abad33966e95da83ebf8ded977988ea0d", "plugins/url-fuzzer-2/parser.py": "13bc1f8f3867f7f10f9d93e59851e604cba4b2142034501f066139ccdfd58ea7", @@ -109,14 +109,14 @@ "plugins/waf_detector/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", "plugins/website-recon-2/metadata.json": "f0801b4dc542fede228d3e75136e3952ebe131b4e1708421790c3b1f3ad05083", "plugins/website-recon-2/parser.py": "3d05ce7fde793eb8799a7389817d2f4ae172ce5ce49cb0a38845ab011cfd17da", - "plugins/whois_lookup/metadata.json": "d301ed91aea79a0a25e9c0ef8cec53df69d8d6a48df79f3bf43df210831da7c5", + "plugins/whois_lookup/metadata.json": "4fb6f845c4162fe28c1c0db10f926abc68bee2ba13c5186ff2a9b36045c3d7d8", "plugins/whois_lookup/parser.py": "4ad33292ee128c93a3d567ff44b1c51439e3bb80d2bec82f4ca8d7164406bdd3", "plugins/wpscan/metadata.json": "41dc2174689da0f66045601fb457f420e3a8cd45486c99062461ac8a07b69fbc", "plugins/wpscan/parser.py": "12ce514688de66240156e0058502a336fefa655cdd7595b6e1c9b281cb2d316d", - "plugins/xss_exploiter/metadata.json": "73cf1111cf40acd6ffd3ecbaa109080d5c95610a5d8ec89156adb58a87f5bc1d", + "plugins/xss_exploiter/metadata.json": "ab0e9eb4f006bfad34697a829a25b7731bdede8cddbb4e269c5443c2703aa2c8", "plugins/xss_exploiter/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", "plugins/yara_scan/metadata.json": "4ec5275b93803aa117c09f92a914ab9c96e120eb59e7af4362e9c82aae8fde5d", "plugins/yara_scan/parser.py": "9209f5cf6191b384790f2663e1824b02d5470c26268b8668c710ace7ac8ed80e", - "plugins/zap_scanner/metadata.json": "1061ea0ec48c370fb3cbfccea0b27cc05ab62ae3ef9a2805ccdd05014d596aa1", + "plugins/zap_scanner/metadata.json": "2c882555e57795e3f8ae879d4e3b5058000ce82aad2adf1f57bf54bbc07011c2", "plugins/zap_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d" } From 7e3620b621f7aad53a6d686579987122f33480f6 Mon Sep 17 00:00:00 2001 From: Zeltarox Date: Tue, 9 Jun 2026 01:53:27 +0530 Subject: [PATCH 10/12] fix(ci): scope checksum verification to changed plugins only, remove committed manifest --- .github/workflows/plugin-checksum.yml | 44 ++++++---- plugins/checksums.json | 122 -------------------------- 2 files changed, 25 insertions(+), 141 deletions(-) delete mode 100644 plugins/checksums.json diff --git a/.github/workflows/plugin-checksum.yml b/.github/workflows/plugin-checksum.yml index 3f7e638cc..aee47f76e 100644 --- a/.github/workflows/plugin-checksum.yml +++ b/.github/workflows/plugin-checksum.yml @@ -12,16 +12,27 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.11' - - name: Install system dependencies - run: sudo apt-get install -y libcairo2-dev pkg-config python3-dev - - name: Install dependencies - run: pip install -r backend/requirements.txt - - name: Verify plugin checksums match committed manifest - run: python scripts/refresh_plugin_checksums.py --dry-run + - name: Detect changed plugin directories + id: changed + run: | + BASE=${{ github.event.pull_request.base.sha || github.event.before }} + CHANGED=$(git diff --name-only "$BASE" HEAD -- 'plugins/**/metadata.json' 'plugins/**/parser.py' \ + | sed 's|/[^/]*$||' | sort -u | tr '\n' ' ') + echo "dirs=$CHANGED" >> "$GITHUB_OUTPUT" + echo "Changed plugin dirs: $CHANGED" + - name: Verify checksums for changed plugins + if: steps.changed.outputs.dirs != '' + run: | + python scripts/refresh_plugin_checksums.py --verify ${{ steps.changed.outputs.dirs }} + - name: No plugin files changed + if: steps.changed.outputs.dirs == '' + run: echo "No plugin metadata or parser files changed — skipping checksum verification." drift-detection-test: runs-on: ubuntu-latest @@ -31,21 +42,16 @@ jobs: uses: actions/setup-python@v5 with: python-version: '3.11' - - name: Install system dependencies - run: sudo apt-get install -y libcairo2-dev pkg-config python3-dev - - name: Install dependencies - run: pip install -r backend/requirements.txt - - name: Seed manifest from current state - run: python scripts/refresh_plugin_checksums.py - - name: Simulate plugin drift - run: | - FIRST=$(python3 -c "import json; d=json.load(open('plugins/checksums.json')); print(next(k for k in d if k.endswith('metadata.json')))") - echo "# drifted" >> "$FIRST" - echo "Mutated: $FIRST" + - name: Seed checksum into test plugin metadata + run: python scripts/refresh_plugin_checksums.py --update plugins/fuzzer + - name: Verify passes when checksum is current + run: python scripts/refresh_plugin_checksums.py --verify plugins/fuzzer + - name: Simulate drift by mutating parser.py + run: echo "# drifted" >> plugins/fuzzer/parser.py - name: Assert drift is detected (must exit 1) run: | - if python scripts/refresh_plugin_checksums.py --dry-run; then - echo "ERROR: drift was not detected — script should have exited 1" + if python scripts/refresh_plugin_checksums.py --verify plugins/fuzzer; then + echo "ERROR: drift was not detected" exit 1 else echo "OK: drift correctly detected" diff --git a/plugins/checksums.json b/plugins/checksums.json deleted file mode 100644 index ff68f065d..000000000 --- a/plugins/checksums.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "plugins/amass/metadata.json": "8085734cfcc202b31be62485c46a2d44fb10d1512122ca1dac8fbcdde4b5c8ba", - "plugins/amass/parser.py": "ca88eb90721c07d76f4400c7ce8339b71e95370324e2745a9039b728ff31d779", - "plugins/api_scanner/metadata.json": "9e2f6962632ade784bc547b9c4a802f3eac1e6109a73dda519bb41b23449049f", - "plugins/api_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/cloud_scanner/metadata.json": "fb162eb75202aa5d31a4bf4d2a77960d785d799553e86b5cef4e48506f6e8a83", - "plugins/cloud_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/cloud_storage_auditor/metadata.json": "0ab003f019bbf8960f12dc30edb213643d2eaf99e269ec9996229f01507cf1ab", - "plugins/cloud_storage_auditor/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/code_analyzer/metadata.json": "59f7002ba019b404a3c90de217c3bec0bf6c579e440366c3ba8654a0aa5295c0", - "plugins/code_analyzer/parser.py": "530bbd8495860a2d1f697794bf494b2a4c96ffa0b7c608d13bb50e6cba0a4db0", - "plugins/container_scanner/metadata.json": "aae07275e1246ff7c37a858a44c4b43d27e4c2b630973a5273fb36a95f530ce4", - "plugins/container_scanner/parser.py": "2d0b0064c9a67f9b7c93c9e1720ce5600ebfccc1d80de7a78e143278e5f1f4b3", - "plugins/crawler/metadata.json": "10697988271fd9cc5293b8fa089cc2dbd9fb3f6c7da5f177fec99899cdfa419c", - "plugins/crawler/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/dir_discovery/metadata.json": "f75d2a2ac05b89ae4daf3067e0f54927e490eede0dccf758b4101457670db5fb", - "plugins/dir_discovery/parser.py": "1fa39d0be591b51c6fcc9bcbac4c4956e4f800ffbaeeb592358dfb027b20ea1a", - "plugins/dns_enum/metadata.json": "baab6e4557d4039936e795188509b5472da6a347569d0bd0594a6013fa979c01", - "plugins/dns_enum/parser.py": "55be96b7e341e5695d67e6e3de8835f9748c09b67f92b83f5631f5a075746fbc", - "plugins/dnsx/metadata.json": "8f04e3c6c39608749c912c96667e37fde00586f51cad59b6df61a4c25096ef7c", - "plugins/dnsx/parser.py": "7969b7c9e40f320131a5ed25d3fef57caea7aeb54b0137d1a9c266f1453e7fbf", - "plugins/domain-finder/metadata.json": "70a2ab85ba98d52ec95dcc56a2e90d7a9b9b3fe39d957fb145d954b42826581e", - "plugins/domain-finder/parser.py": "4f37f7a15a373988cc24c8ed4ce0b864005eb6b596d3f6f35d30775416204ad5", - "plugins/droopescan/metadata.json": "efdc435519c336d4e1b29c7ad8b35147187a3fcf3d10784e310944ffa168ac00", - "plugins/droopescan/parser.py": "b8a768265c36fcfb44c93bbea5c7a9773250e328ca046b0c5de703369544eea2", - "plugins/fuzzer/metadata.json": "383f54f4ea9379fc57d96daa4b3648651c319bf44b70b1d89998e71939f6a4ca", - "plugins/fuzzer/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/google-dorking/metadata.json": "0af27fcea2d78b40e2e542b0f729c77775491a59113879e151726457bbe9f1a5", - "plugins/google-dorking/parser.py": "9a9f3de81a2d0b7539ed2004777b3a5a6d88d738ec1437b3851c60bf817ec395", - "plugins/hashcat/metadata.json": "c011eea3eac3caa8385a5e66bcd701f01da32ffd2c151163a27ba97dcec6b64f", - "plugins/hashcat/parser.py": "64f279f0299b9be3f8270ba5a7e0be4ba64bb58ff3f9b1f3fde776bcfe8ae40f", - "plugins/http_inspector/metadata.json": "263c540c98172bd15a6b0b587b94c6e60543745ca2a6e281179cc948729e831b", - "plugins/http_inspector/parser.py": "9af42c29cff674f680d5cda9e64037ae112a39dfc0d7f07f40a0221a023a1158", - "plugins/http_request_logger/metadata.json": "cac0de30f7060986b3e0668f99215442e2f0283c989e3928867f67c6a21416c7", - "plugins/http_request_logger/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/httpx/metadata.json": "177c75192c1073ad7cf3b8730b03761fc76d7d8dca0c6e711c6dfccb7d1b35a1", - "plugins/httpx/parser.py": "057758ed06775f76de0acc0e56785ffb7ed42394c02c127ea61e778b215a4a4e", - "plugins/iac_scanner/metadata.json": "1c1d8c2f5317fde03750b0b8d1599de51f234da5b0f196a3adec584b27969f8c", - "plugins/iac_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/icmp_ping/metadata.json": "7ce790d9ed733f2b34c5b5d2a56e04678eb1737c07d533d7d2ba20c06b34bba8", - "plugins/icmp_ping/parser.py": "e4956cd48975815054d3fab679d84f9dbe7390b99fc5d97c04d5f26ef6c78abb", - "plugins/joomscan/metadata.json": "9678199a89b791ef033b2e367e78c4c60f9b2218867e8fc5365500f7fc464996", - "plugins/joomscan/parser.py": "80c63c94b4b4b35c9ab7602b7cffa42078a7f81aa34382b02c9266c3b234a16f", - "plugins/katana/metadata.json": "e35a3b4a48c34151f5bc8fd5a2d67cafeec9daf9c05ecc57f907438a7344149e", - "plugins/katana/parser.py": "48bd827701b9822904bada9e9a028388f419007c27710683b0b0325b2d2ac2e3", - "plugins/kubernetes_scanner/metadata.json": "b062d38c01765863067f000513c73392e8503417fa47a74830db82ad2cc1baa7", - "plugins/kubernetes_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/metasploit/metadata.json": "fcc5518fbcda29e4bd3c719deab41cf8634d80cfeff1ecb0641d2e3e5fce2601", - "plugins/metasploit/parser.py": "8d0968d75137126b41fede3353bb08f748975e810e3b3f0aee7212801b8503ce", - "plugins/network_scanner/metadata.json": "5721417097f65400c007ed1039690ce69665a71ddfa0cfe18d695230216d6337", - "plugins/network_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/nikto/metadata.json": "38a76b78446fa5680aa6b4713e8f5e3b43bdf4e0e64dc67c838287af743f64c0", - "plugins/nikto/parser.py": "5453c51abb5d81d8667154780a63d25c785cf48c86f886444aa39aec7aae39f4", - "plugins/nmap/metadata.json": "b953f82a9c0821fd1342c1777190ee281b700ae27b350d16e7d048fe732a345d", - "plugins/nmap/parser.py": "ec7c67e22cd90ce7d5365685307d8981840942821605950e8560afe628086b8c", - "plugins/nuclei/metadata.json": "ec9abb4c639f3aec744988fe0bb6d3d22a9d83bda5760a98639a71f7061f568a", - "plugins/nuclei/parser.py": "7708cec4fea3e2192dd999d787f0e48393a21c9a524000cfbcec7049396ade5e", - "plugins/password_auditor/metadata.json": "c7c5bc540991554832868cc14091b7d6a87ae0ff6bd39063572aa7ea8ab36bb8", - "plugins/password_auditor/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/people-email-discovery/metadata.json": "968007741260b33c9cf3a0911937184e33f79e57ddd5b81230ea97e24817053d", - "plugins/people-email-discovery/parser.py": "728ef3c1abbb6e69116cd7df19cbc80507c8750a29061e22bb441dbab50b9359", - "plugins/port-scanner/metadata.json": "2f40fb011f6aef4b21e9b0571d08369be40f34fe0b08d6da999530aaf1c635a2", - "plugins/port-scanner/parser.py": "a30afe8ca794def4f04a42e81ce1d594a1cd9ebebafba584b7ce3779aa36826c", - "plugins/scapy_recon/metadata.json": "c2be7fa7b456f11403a4af30a338e19f662714b00a9705f0f92a1519f311f0dc", - "plugins/scapy_recon/parser.py": "b9c1fba6ff58aedb4584de9e3814d5b5ca0f8d44df0f3b1ee526f276a1c7bb8b", - "plugins/secret_scanner/metadata.json": "8d5c6852a06a437d34824a73665141b486c076ff776e39108879835d77777f3a", - "plugins/secret_scanner/parser.py": "d4ebdbaabb6cb58be578a67d920fb67618dd750543829d2178b886446d7664f2", - "plugins/sharepoint_scanner/metadata.json": "bea08eb80d31d5145c2af0daeb6d1d7471661e008fcd7a83619bc90611c8ab0f", - "plugins/sharepoint_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/sitemap_gen/metadata.json": "1a38185a5cef3d2aa57034a711a01beecb2a829b08c28966d5a08d28192fa828", - "plugins/sitemap_gen/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/sniper/metadata.json": "d1a3c177c8c586510804601c479ba28becc790b0a921fe6a3df50926b5f5eb0f", - "plugins/sniper/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/spider/metadata.json": "0bfb464554774f112d3a123179d4a7d5affbc13cd18759aade49e1bfea565f53", - "plugins/spider/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/sqli_checker/metadata.json": "f114cb73e245e5724985ca2f705f6a0b0901e0686fc3c55ad35fa1443d8633ce", - "plugins/sqli_checker/parser.py": "3b31a6e20eabe567165569f0e42841ecf4a991d220f55721b71ec1567e949475", - "plugins/sqli_exploiter/metadata.json": "0e2f24a009b725b4f76d11b0e6cd11e7b60f20a4e0b62e29694e65e08c5c0b86", - "plugins/sqli_exploiter/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/sqlmap/metadata.json": "512a7c6dc14eabdf473fb9866c57df30a0982180f86169b74c9fdf6ce4f542b2", - "plugins/sqlmap/parser.py": "1708299ab47f76de69131a8074672f4aad69c1a6b8a1c6955866e1fdfef976b2", - "plugins/ssh_runner/metadata.json": "a2fed56519bea9e9e9bd886e0b0f99cf1f012258d4604a41908c1de35bd5d070", - "plugins/ssh_runner/parser.py": "bbc0ca00f62dc7a92c6d890b9a72dd8cdabb7ceb6b9ee2c3c944e52c2d42deb3", - "plugins/subdomain-finder/metadata.json": "df1721bb6167335756d65670519c0d341ae9f3e96e49974303b397f6b65a5e3c", - "plugins/subdomain-finder/parser.py": "97438107ca6b8cae404c594479bf48f7bd0978f50ed8227a9b2132f2217f39bf", - "plugins/subdomain_discovery/metadata.json": "ec966633d2cd9913c11a8766b049d8edfcdbd35e84e7758b63c99b06c91fb699", - "plugins/subdomain_discovery/parser.py": "f83d3aa18e52b223d597eb5c8b41effa1110abce71153aa127db8c275a6d9850", - "plugins/subdomain_takeover/metadata.json": "18bc52f5c05a23912b21db6ab048ffd2b91f3d59dab3a1b456f302f5670587cd", - "plugins/subdomain_takeover/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/subfinder/metadata.json": "3970de33a910ace4f5e6fb58f1593776f90c0dd7dc999690c115273815cd90a5", - "plugins/subfinder/parser.py": "f0b836dd87292b1d5d433b3584a4d0158e1b485ade1339255838c6c7e6261d0a", - "plugins/theharvester/metadata.json": "8019c0e33b363297d44e2f68c270ef3f4beaf72bcafe55a7d7c7b4d0ab40a7d4", - "plugins/theharvester/parser.py": "54dc7c5716e26c822438f5cd7251c01ec6b10ca9754b6bf1d7c4a56bd7ae5dab", - "plugins/tls_inspector/metadata.json": "bedc851d7af86760c3a2e2e6396af851e0d13474df0520c20976d768298c9280", - "plugins/tls_inspector/parser.py": "f7aa4a6255570c3a8ce9558873d88f8f05bbd1b4668c91293ac6564d54716ffb", - "plugins/uncover/metadata.json": "9604f94d15abf0074af9ba92e9c3d902d1d5a9529fe64fa718872d28a277b4ed", - "plugins/uncover/parser.py": "8239043efa625e99d98a8f337cfb62055b93751eb22a7d1c6e2ec20236222f9a", - "plugins/url-fuzzer-2/metadata.json": "725b9faf5ec78ad2c8baf2d87b76df9abad33966e95da83ebf8ded977988ea0d", - "plugins/url-fuzzer-2/parser.py": "13bc1f8f3867f7f10f9d93e59851e604cba4b2142034501f066139ccdfd58ea7", - "plugins/urlfinder/metadata.json": "bf081ddafd73c6100205eae62a58c06ccf80bc46dc04cb5f144173858875587f", - "plugins/urlfinder/parser.py": "aac61d1d1b3418f3af994901b8b66c5e9e646eb94c864713c8ce2618873678f2", - "plugins/virtual-host-finder/metadata.json": "06a787da633e19c0c5305bdad02bd2fc06934255d87bed57828b636f18893a3a", - "plugins/virtual-host-finder/parser.py": "05b16d0b35a8ee12af2d527873a6ce974f4c25d8d5ff318775a7d3543d5f1d73", - "plugins/volatility/metadata.json": "dc2afa1d33f684692883a1a734b32676a76b829cec6a6bdab01b3b12bdd1c1ec", - "plugins/volatility/parser.py": "429ab2231a2637e507b1ac45f24e9c3b838b285e3e72fc015dd80a5eea55b8d5", - "plugins/waf-detection/metadata.json": "74d1e7afe057a46c2a2f5d4e17fbdfd9d814ca0126c57b787bd35187ed109edf", - "plugins/waf-detection/parser.py": "c84ae8bfa33ad245f6c8854706bdd0e1298f403e1ec24e90d064755635c652ce", - "plugins/waf_detector/metadata.json": "8bb39e6feedcd27f1122171c338eea0d6513acd971e10937e5dc946b76e05073", - "plugins/waf_detector/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/website-recon-2/metadata.json": "f0801b4dc542fede228d3e75136e3952ebe131b4e1708421790c3b1f3ad05083", - "plugins/website-recon-2/parser.py": "3d05ce7fde793eb8799a7389817d2f4ae172ce5ce49cb0a38845ab011cfd17da", - "plugins/whois_lookup/metadata.json": "4fb6f845c4162fe28c1c0db10f926abc68bee2ba13c5186ff2a9b36045c3d7d8", - "plugins/whois_lookup/parser.py": "4ad33292ee128c93a3d567ff44b1c51439e3bb80d2bec82f4ca8d7164406bdd3", - "plugins/wpscan/metadata.json": "41dc2174689da0f66045601fb457f420e3a8cd45486c99062461ac8a07b69fbc", - "plugins/wpscan/parser.py": "12ce514688de66240156e0058502a336fefa655cdd7595b6e1c9b281cb2d316d", - "plugins/xss_exploiter/metadata.json": "ab0e9eb4f006bfad34697a829a25b7731bdede8cddbb4e269c5443c2703aa2c8", - "plugins/xss_exploiter/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d", - "plugins/yara_scan/metadata.json": "4ec5275b93803aa117c09f92a914ab9c96e120eb59e7af4362e9c82aae8fde5d", - "plugins/yara_scan/parser.py": "9209f5cf6191b384790f2663e1824b02d5470c26268b8668c710ace7ac8ed80e", - "plugins/zap_scanner/metadata.json": "2c882555e57795e3f8ae879d4e3b5058000ce82aad2adf1f57bf54bbc07011c2", - "plugins/zap_scanner/parser.py": "68328ce6fc8bfa54ed51385dcfad32b6c61e45aa89d4c4216f83660cb92cb09d" -} From 7688976eff5bbf19c32abc10e7feac1db48e359e Mon Sep 17 00:00:00 2001 From: Zeltarox Date: Tue, 9 Jun 2026 02:01:07 +0530 Subject: [PATCH 11/12] fix(ci): scope checksum verification to changed plugins, store checksum in metadata.json --- scripts/refresh_plugin_checksums.py | 138 +++++++++++++++++----------- 1 file changed, 82 insertions(+), 56 deletions(-) diff --git a/scripts/refresh_plugin_checksums.py b/scripts/refresh_plugin_checksums.py index ee0146af3..01a4d22fc 100644 --- a/scripts/refresh_plugin_checksums.py +++ b/scripts/refresh_plugin_checksums.py @@ -1,77 +1,103 @@ #!/usr/bin/env python3 -"""Refresh or verify plugin checksums based on current metadata and parser files.""" +""" +Verify or refresh checksums for specified plugin directories. + +The checksum covers parser.py and metadata.json content with the +'checksum' field stripped, so updating the stored value does not +invalidate the hash. + +Usage: + python scripts/refresh_plugin_checksums.py --verify plugins/amass plugins/fuzzer + python scripts/refresh_plugin_checksums.py --update plugins/amass plugins/fuzzer + python scripts/refresh_plugin_checksums.py --update-all +""" +import argparse import hashlib import json -import os import sys +from pathlib import Path -PLUGINS_DIR = "plugins" -MANIFEST_FILE = os.path.join(PLUGINS_DIR, "checksums.json") - -def compute_checksum(filepath): +def compute_plugin_checksum(plugin_dir: Path) -> str: + """ + Compute SHA-256 over parser.py and metadata.json (checksum field stripped). + Sorting filenames ensures a stable, platform-independent order. + """ sha256 = hashlib.sha256() - with open(filepath, "rb") as f: - for chunk in iter(lambda: f.read(4096), b""): - sha256.update(chunk) + for filename in sorted(["metadata.json", "parser.py"]): + filepath = plugin_dir / filename + if not filepath.exists(): + continue + if filename == "metadata.json": + # Strip the checksum field so updating it doesn't change the hash + data = json.loads(filepath.read_text(encoding="utf-8")) + data.pop("checksum", None) + content = json.dumps(data, sort_keys=True, separators=(",", ":")).encode() + else: + content = filepath.read_bytes() + sha256.update(content) return sha256.hexdigest() -def collect_live_checksums(): - checksums = {} - for plugin in sorted(os.listdir(PLUGINS_DIR)): - plugin_path = os.path.join(PLUGINS_DIR, plugin) - if not os.path.isdir(plugin_path): +def verify_plugins(plugin_dirs: list) -> bool: + drift = False + for plugin_dir in plugin_dirs: + metadata_path = plugin_dir / "metadata.json" + if not metadata_path.exists(): + print(f"MISSING: {plugin_dir}/metadata.json") + drift = True continue - for filename in ("metadata.json", "parser.py"): - filepath = os.path.join(plugin_path, filename) - if os.path.exists(filepath): - checksums[filepath] = compute_checksum(filepath) - return checksums + metadata = json.loads(metadata_path.read_text(encoding="utf-8")) + stored = metadata.get("checksum", "") + computed = compute_plugin_checksum(plugin_dir) + if stored != computed: + print(f"DRIFT: {plugin_dir.name} stored={stored[:12]} computed={computed[:12]}") + drift = True + else: + print(f"OK: {plugin_dir.name}") + return not drift -def main(): - dry_run = "--dry-run" in sys.argv +def update_plugins(plugin_dirs: list) -> None: + for plugin_dir in plugin_dirs: + metadata_path = plugin_dir / "metadata.json" + if not metadata_path.exists(): + print(f"SKIP: {plugin_dir} (no metadata.json)") + continue + metadata = json.loads(metadata_path.read_text(encoding="utf-8")) + checksum = compute_plugin_checksum(plugin_dir) + metadata["checksum"] = checksum + metadata_path.write_text(json.dumps(metadata, indent=2) + "\n", encoding="utf-8") + print(f"UPDATED: {plugin_dir.name} checksum={checksum[:12]}") - live = collect_live_checksums() - if not dry_run: - with open(MANIFEST_FILE, "w") as f: - json.dump(live, f, indent=2) - f.write("\n") - print(f"Updated {MANIFEST_FILE} ({len(live)} entries)") +def main(): + parser = argparse.ArgumentParser(description="Plugin checksum verifier/updater") + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument("--verify", nargs="+", metavar="PLUGIN_DIR", + help="Verify checksums for given plugin directories") + group.add_argument("--update", nargs="+", metavar="PLUGIN_DIR", + help="Update checksums for given plugin directories") + group.add_argument("--update-all", action="store_true", + help="Update checksums for all plugins") + args = parser.parse_args() + + plugins_root = Path("plugins") + + if args.update_all: + dirs = sorted(p for p in plugins_root.iterdir() if p.is_dir()) + update_plugins(dirs) sys.exit(0) - # --dry-run: verify mode — compare live against committed manifest - if not os.path.exists(MANIFEST_FILE): - print(f"ERROR: No manifest found at {MANIFEST_FILE}.") - print("Run without --dry-run first to generate it.") - sys.exit(1) - - with open(MANIFEST_FILE) as f: - committed = json.load(f) - - drift = False - - for path, sha in committed.items(): - if path not in live: - print(f"MISSING: {path}") - drift = True - elif live[path] != sha: - print(f"CHANGED: {path}") - drift = True - - for path in live: - if path not in committed: - print(f"EXTRA: {path} (not in manifest)") - drift = True - - if drift: - print("\nDrift detected. Run: python scripts/refresh_plugin_checksums.py") - sys.exit(1) + if args.update: + dirs = [Path(d) for d in args.update] + update_plugins(dirs) + sys.exit(0) - print(f"OK: all {len(live)} plugin checksums match the manifest.") - sys.exit(0) + if args.verify: + dirs = [Path(d) for d in args.verify] + ok = verify_plugins(dirs) + sys.exit(0 if ok else 1) if __name__ == "__main__": From dd6c9234b5b9d5b535992e66a63bee0f388183da Mon Sep 17 00:00:00 2001 From: Zeltarox Date: Sat, 20 Jun 2026 21:39:25 +0530 Subject: [PATCH 12/12] fix(ci): extend existing refresh_plugin_checksum.py with --check mode for CI drift detection --- .github/workflows/plugin-checksum.yml | 42 +------ scripts/refresh_plugin_checksum.py | 35 +++++- scripts/refresh_plugin_checksums.py | 104 ------------------ .../unit/test_refresh_plugin_checksum.py | 69 +++++++++++- 4 files changed, 100 insertions(+), 150 deletions(-) delete mode 100644 scripts/refresh_plugin_checksums.py diff --git a/.github/workflows/plugin-checksum.yml b/.github/workflows/plugin-checksum.yml index aee47f76e..eafca1c08 100644 --- a/.github/workflows/plugin-checksum.yml +++ b/.github/workflows/plugin-checksum.yml @@ -9,32 +9,6 @@ on: - 'plugins/**' jobs: verify-checksums: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - name: Detect changed plugin directories - id: changed - run: | - BASE=${{ github.event.pull_request.base.sha || github.event.before }} - CHANGED=$(git diff --name-only "$BASE" HEAD -- 'plugins/**/metadata.json' 'plugins/**/parser.py' \ - | sed 's|/[^/]*$||' | sort -u | tr '\n' ' ') - echo "dirs=$CHANGED" >> "$GITHUB_OUTPUT" - echo "Changed plugin dirs: $CHANGED" - - name: Verify checksums for changed plugins - if: steps.changed.outputs.dirs != '' - run: | - python scripts/refresh_plugin_checksums.py --verify ${{ steps.changed.outputs.dirs }} - - name: No plugin files changed - if: steps.changed.outputs.dirs == '' - run: echo "No plugin metadata or parser files changed — skipping checksum verification." - - drift-detection-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -42,17 +16,5 @@ jobs: uses: actions/setup-python@v5 with: python-version: '3.11' - - name: Seed checksum into test plugin metadata - run: python scripts/refresh_plugin_checksums.py --update plugins/fuzzer - - name: Verify passes when checksum is current - run: python scripts/refresh_plugin_checksums.py --verify plugins/fuzzer - - name: Simulate drift by mutating parser.py - run: echo "# drifted" >> plugins/fuzzer/parser.py - - name: Assert drift is detected (must exit 1) - run: | - if python scripts/refresh_plugin_checksums.py --verify plugins/fuzzer; then - echo "ERROR: drift was not detected" - exit 1 - else - echo "OK: drift correctly detected" - fi + - name: Verify plugin checksums are up to date + run: python scripts/refresh_plugin_checksum.py --all --check diff --git a/scripts/refresh_plugin_checksum.py b/scripts/refresh_plugin_checksum.py index 7738589e8..de8147841 100644 --- a/scripts/refresh_plugin_checksum.py +++ b/scripts/refresh_plugin_checksum.py @@ -63,7 +63,7 @@ def compute_plugin_digest(metadata_file: Path, parser_file: Path) -> str: # ── Core refresh logic ──────────────────────────────────────────────────────── -def refresh_plugin(plugin_dir: Path, dry_run: bool = False) -> bool: +def refresh_plugin(plugin_dir: Path, dry_run: bool = False, check: bool = False) -> bool: """ Recalculate and write the checksum for a single plugin. @@ -107,6 +107,12 @@ def refresh_plugin(plugin_dir: Path, dry_run: bool = False) -> bool: print(f" [OK] {plugin_dir.name} — checksum already up to date") return True + if check: + print(f" [DRIFT] {plugin_dir.name}") + print(f" stored: {old_checksum}") + print(f" computed: {new_checksum}") + return False + print(f" [UPDATE] {plugin_dir.name}") print(f" old: {old_checksum}") print(f" new: {new_checksum}") @@ -125,7 +131,7 @@ def refresh_plugin(plugin_dir: Path, dry_run: bool = False) -> bool: return True -def refresh_all_plugins(plugins_dir: Path, dry_run: bool = False) -> None: +def refresh_all_plugins(plugins_dir: Path, dry_run: bool = False, check: bool = False) -> None: """Refresh checksums for every plugin found in plugins_dir.""" if not plugins_dir.exists(): print(f"[ERROR] Plugins directory not found: {plugins_dir}", file=sys.stderr) @@ -145,11 +151,18 @@ def refresh_all_plugins(plugins_dir: Path, dry_run: bool = False) -> None: error_count = 0 for plugin_dir in plugin_dirs: - if refresh_plugin(plugin_dir, dry_run=dry_run): + if refresh_plugin(plugin_dir, dry_run=dry_run, check=check): success_count += 1 else: error_count += 1 + if check: + print(f"\nDone — {success_count} up to date, {error_count} drifted.") + if error_count > 0: + print("\nRun: python scripts/refresh_plugin_checksum.py --all") + sys.exit(1) + sys.exit(0) + print(f"\nDone — {success_count} succeeded, {error_count} failed.") if error_count > 0: @@ -199,18 +212,30 @@ def main() -> None: action="store_true", help="Show what would change without writing anything", ) + parser.add_argument( + "--check", + action="store_true", + help="Verify checksums are up to date; exit 1 if any plugin has drifted (CI mode)", + ) args = parser.parse_args() + if args.check and args.dry_run: + print("[ERROR] --check and --dry-run cannot be used together.", file=sys.stderr) + sys.exit(2) + if args.dry_run: print("[DRY RUN] No files will be modified.\n") + if args.check: + print("[CHECK] Verifying checksums are up to date (no files will be modified).\n") + if args.all: - refresh_all_plugins(args.plugins_dir, dry_run=args.dry_run) + refresh_all_plugins(args.plugins_dir, dry_run=args.dry_run, check=args.check) else: plugin_dir = args.plugins_dir / args.plugin print(f"Refreshing checksum for plugin: {args.plugin}\n") - success = refresh_plugin(plugin_dir, dry_run=args.dry_run) + success = refresh_plugin(plugin_dir, dry_run=args.dry_run, check=args.check) if not success: sys.exit(1) print("\nDone.") diff --git a/scripts/refresh_plugin_checksums.py b/scripts/refresh_plugin_checksums.py deleted file mode 100644 index 01a4d22fc..000000000 --- a/scripts/refresh_plugin_checksums.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python3 -""" -Verify or refresh checksums for specified plugin directories. - -The checksum covers parser.py and metadata.json content with the -'checksum' field stripped, so updating the stored value does not -invalidate the hash. - -Usage: - python scripts/refresh_plugin_checksums.py --verify plugins/amass plugins/fuzzer - python scripts/refresh_plugin_checksums.py --update plugins/amass plugins/fuzzer - python scripts/refresh_plugin_checksums.py --update-all -""" -import argparse -import hashlib -import json -import sys -from pathlib import Path - - -def compute_plugin_checksum(plugin_dir: Path) -> str: - """ - Compute SHA-256 over parser.py and metadata.json (checksum field stripped). - Sorting filenames ensures a stable, platform-independent order. - """ - sha256 = hashlib.sha256() - for filename in sorted(["metadata.json", "parser.py"]): - filepath = plugin_dir / filename - if not filepath.exists(): - continue - if filename == "metadata.json": - # Strip the checksum field so updating it doesn't change the hash - data = json.loads(filepath.read_text(encoding="utf-8")) - data.pop("checksum", None) - content = json.dumps(data, sort_keys=True, separators=(",", ":")).encode() - else: - content = filepath.read_bytes() - sha256.update(content) - return sha256.hexdigest() - - -def verify_plugins(plugin_dirs: list) -> bool: - drift = False - for plugin_dir in plugin_dirs: - metadata_path = plugin_dir / "metadata.json" - if not metadata_path.exists(): - print(f"MISSING: {plugin_dir}/metadata.json") - drift = True - continue - metadata = json.loads(metadata_path.read_text(encoding="utf-8")) - stored = metadata.get("checksum", "") - computed = compute_plugin_checksum(plugin_dir) - if stored != computed: - print(f"DRIFT: {plugin_dir.name} stored={stored[:12]} computed={computed[:12]}") - drift = True - else: - print(f"OK: {plugin_dir.name}") - return not drift - - -def update_plugins(plugin_dirs: list) -> None: - for plugin_dir in plugin_dirs: - metadata_path = plugin_dir / "metadata.json" - if not metadata_path.exists(): - print(f"SKIP: {plugin_dir} (no metadata.json)") - continue - metadata = json.loads(metadata_path.read_text(encoding="utf-8")) - checksum = compute_plugin_checksum(plugin_dir) - metadata["checksum"] = checksum - metadata_path.write_text(json.dumps(metadata, indent=2) + "\n", encoding="utf-8") - print(f"UPDATED: {plugin_dir.name} checksum={checksum[:12]}") - - -def main(): - parser = argparse.ArgumentParser(description="Plugin checksum verifier/updater") - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument("--verify", nargs="+", metavar="PLUGIN_DIR", - help="Verify checksums for given plugin directories") - group.add_argument("--update", nargs="+", metavar="PLUGIN_DIR", - help="Update checksums for given plugin directories") - group.add_argument("--update-all", action="store_true", - help="Update checksums for all plugins") - args = parser.parse_args() - - plugins_root = Path("plugins") - - if args.update_all: - dirs = sorted(p for p in plugins_root.iterdir() if p.is_dir()) - update_plugins(dirs) - sys.exit(0) - - if args.update: - dirs = [Path(d) for d in args.update] - update_plugins(dirs) - sys.exit(0) - - if args.verify: - dirs = [Path(d) for d in args.verify] - ok = verify_plugins(dirs) - sys.exit(0 if ok else 1) - - -if __name__ == "__main__": - main() diff --git a/testing/backend/unit/test_refresh_plugin_checksum.py b/testing/backend/unit/test_refresh_plugin_checksum.py index bed8db6e4..cbafcc0e8 100644 --- a/testing/backend/unit/test_refresh_plugin_checksum.py +++ b/testing/backend/unit/test_refresh_plugin_checksum.py @@ -276,4 +276,71 @@ def test_exits_when_plugins_dir_missing(self, tmp_path): missing_dir = tmp_path / "no-such-dir" with pytest.raises(SystemExit): - refresh_all_plugins(missing_dir) \ No newline at end of file + refresh_all_plugins(missing_dir) + +# ── check mode ───────────────────────────────────────────────────────────────── + +class TestRefreshPluginCheckMode: + + def test_check_returns_true_when_up_to_date(self, tmp_path): + """check mode should return True and not write when checksum already matches.""" + plugin_dir = make_plugin(tmp_path, "test-plugin", checksum="placeholder") + # First bring it up to date normally + refresh_plugin(plugin_dir) + # Now check mode should report it as current + result = refresh_plugin(plugin_dir, check=True) + assert result is True + + def test_check_returns_false_on_drift(self, tmp_path): + """check mode should return False when stored checksum does not match computed digest.""" + plugin_dir = make_plugin(tmp_path, "test-plugin", checksum="stale-checksum") + result = refresh_plugin(plugin_dir, check=True) + assert result is False + + def test_check_does_not_write_on_drift(self, tmp_path): + """check mode must never modify metadata.json, even when drift is detected.""" + plugin_dir = make_plugin(tmp_path, "test-plugin", checksum="stale-checksum") + refresh_plugin(plugin_dir, check=True) + metadata = json.loads((plugin_dir / "metadata.json").read_text()) + assert metadata["checksum"] == "stale-checksum" + + def test_check_does_not_write_when_up_to_date(self, tmp_path): + """check mode must never modify metadata.json when already current.""" + plugin_dir = make_plugin(tmp_path, "test-plugin", checksum="placeholder") + refresh_plugin(plugin_dir) + before = json.loads((plugin_dir / "metadata.json").read_text()) + refresh_plugin(plugin_dir, check=True) + after = json.loads((plugin_dir / "metadata.json").read_text()) + assert before == after + + +class TestRefreshAllPluginsCheckMode: + + def test_check_exits_zero_when_all_up_to_date(self, tmp_path): + """refresh_all_plugins with check=True should exit 0 when nothing has drifted.""" + for plugin_id in ["plugin-a", "plugin-b"]: + plugin_dir = make_plugin(tmp_path, plugin_id, checksum="placeholder") + refresh_plugin(plugin_dir) + with pytest.raises(SystemExit) as exc_info: + refresh_all_plugins(tmp_path, check=True) + assert exc_info.value.code == 0 + + def test_check_exits_one_when_any_plugin_drifted(self, tmp_path): + """refresh_all_plugins with check=True should exit 1 if any plugin has drifted.""" + plugin_a = make_plugin(tmp_path, "plugin-a", checksum="placeholder") + refresh_plugin(plugin_a) + make_plugin(tmp_path, "plugin-b", checksum="stale-checksum") + with pytest.raises(SystemExit) as exc_info: + refresh_all_plugins(tmp_path, check=True) + assert exc_info.value.code == 1 + + def test_check_does_not_write_any_plugin(self, tmp_path): + """check mode across all plugins must not modify any metadata.json.""" + for plugin_id in ["plugin-a", "plugin-b"]: + make_plugin(tmp_path, plugin_id, checksum="stale-checksum") + with pytest.raises(SystemExit): + refresh_all_plugins(tmp_path, check=True) + for plugin_id in ["plugin-a", "plugin-b"]: + plugin_dir = tmp_path / plugin_id + metadata = json.loads((plugin_dir / "metadata.json").read_text()) + assert metadata["checksum"] == "stale-checksum"