secator 0.6.0__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of secator might be problematic. Click here for more details.
- {secator-0.6.0 → secator-0.7.0}/CHANGELOG.md +47 -0
- {secator-0.6.0 → secator-0.7.0}/Dockerfile +2 -1
- {secator-0.6.0 → secator-0.7.0}/PKG-INFO +11 -5
- secator-0.7.0/pyproject.toml +97 -0
- secator-0.7.0/secator/celery.py +344 -0
- secator-0.7.0/secator/celery_utils.py +268 -0
- {secator-0.6.0 → secator-0.7.0}/secator/cli.py +327 -106
- {secator-0.6.0 → secator-0.7.0}/secator/config.py +27 -11
- {secator-0.6.0 → secator-0.7.0}/secator/configs/workflows/host_recon.yaml +5 -3
- {secator-0.6.0 → secator-0.7.0}/secator/configs/workflows/port_scan.yaml +7 -3
- secator-0.7.0/secator/configs/workflows/url_bypass.yaml +10 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/workflows/url_vuln.yaml +1 -1
- {secator-0.6.0 → secator-0.7.0}/secator/decorators.py +169 -92
- {secator-0.6.0 → secator-0.7.0}/secator/definitions.py +10 -3
- {secator-0.6.0 → secator-0.7.0}/secator/exporters/__init__.py +7 -5
- secator-0.7.0/secator/exporters/console.py +10 -0
- secator-0.7.0/secator/exporters/csv.py +37 -0
- {secator-0.6.0 → secator-0.7.0}/secator/exporters/gdrive.py +16 -11
- {secator-0.6.0 → secator-0.7.0}/secator/exporters/json.py +3 -1
- secator-0.7.0/secator/exporters/table.py +35 -0
- secator-0.7.0/secator/exporters/txt.py +28 -0
- secator-0.7.0/secator/hooks/gcs.py +53 -0
- {secator-0.6.0 → secator-0.7.0}/secator/hooks/mongodb.py +53 -27
- secator-0.7.0/secator/output_types/__init__.py +42 -0
- {secator-0.6.0 → secator-0.7.0}/secator/output_types/_base.py +11 -1
- secator-0.7.0/secator/output_types/error.py +36 -0
- {secator-0.6.0 → secator-0.7.0}/secator/output_types/exploit.py +1 -1
- secator-0.7.0/secator/output_types/info.py +24 -0
- {secator-0.6.0 → secator-0.7.0}/secator/output_types/ip.py +7 -0
- {secator-0.6.0 → secator-0.7.0}/secator/output_types/port.py +8 -1
- {secator-0.6.0 → secator-0.7.0}/secator/output_types/progress.py +5 -0
- {secator-0.6.0 → secator-0.7.0}/secator/output_types/record.py +3 -1
- secator-0.7.0/secator/output_types/stat.py +33 -0
- {secator-0.6.0 → secator-0.7.0}/secator/output_types/tag.py +6 -4
- {secator-0.6.0 → secator-0.7.0}/secator/output_types/url.py +6 -3
- {secator-0.6.0 → secator-0.7.0}/secator/output_types/vulnerability.py +3 -2
- secator-0.7.0/secator/output_types/warning.py +24 -0
- secator-0.7.0/secator/report.py +127 -0
- {secator-0.6.0 → secator-0.7.0}/secator/rich.py +44 -39
- secator-0.7.0/secator/runners/_base.py +897 -0
- secator-0.7.0/secator/runners/_helpers.py +86 -0
- secator-0.7.0/secator/runners/celery.py +18 -0
- {secator-0.6.0 → secator-0.7.0}/secator/runners/command.py +364 -211
- {secator-0.6.0 → secator-0.7.0}/secator/runners/scan.py +8 -24
- secator-0.7.0/secator/runners/task.py +74 -0
- {secator-0.6.0 → secator-0.7.0}/secator/runners/workflow.py +41 -40
- secator-0.7.0/secator/scans/__init__.py +28 -0
- {secator-0.6.0 → secator-0.7.0}/secator/serializers/dataclass.py +6 -0
- secator-0.7.0/secator/serializers/json.py +20 -0
- secator-0.7.0/secator/serializers/regex.py +25 -0
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/_categories.py +5 -2
- secator-0.7.0/secator/tasks/bbot.py +293 -0
- secator-0.7.0/secator/tasks/bup.py +98 -0
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/cariddi.py +38 -49
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/dalfox.py +3 -0
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/dirsearch.py +12 -23
- secator-0.7.0/secator/tasks/dnsx.py +76 -0
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/dnsxbrute.py +2 -0
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/feroxbuster.py +8 -17
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/ffuf.py +3 -2
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/fping.py +3 -3
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/gau.py +5 -0
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/gf.py +2 -2
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/gospider.py +4 -0
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/grype.py +9 -9
- secator-0.7.0/secator/tasks/h8mail.py +70 -0
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/httpx.py +58 -21
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/katana.py +18 -22
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/maigret.py +26 -24
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/mapcidr.py +2 -3
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/msfconsole.py +4 -16
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/naabu.py +3 -1
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/nmap.py +50 -35
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/nuclei.py +9 -2
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/searchsploit.py +17 -9
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/subfinder.py +5 -1
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/wpscan.py +79 -93
- {secator-0.6.0 → secator-0.7.0}/secator/template.py +61 -45
- secator-0.7.0/secator/thread.py +24 -0
- secator-0.7.0/secator/utils.py +691 -0
- {secator-0.6.0 → secator-0.7.0}/secator/utils_test.py +48 -23
- secator-0.7.0/secator/workflows/__init__.py +28 -0
- {secator-0.6.0 → secator-0.7.0}/tests/fixtures/ls.py +1 -1
- {secator-0.6.0 → secator-0.7.0}/tests/integration/inputs.py +5 -4
- {secator-0.6.0 → secator-0.7.0}/tests/integration/outputs.py +38 -21
- {secator-0.6.0 → secator-0.7.0}/tests/integration/setup.sh +1 -0
- secator-0.7.0/tests/integration/test_addons.py +23 -0
- secator-0.7.0/tests/integration/test_celery.py +195 -0
- {secator-0.6.0 → secator-0.7.0}/tests/integration/test_scans.py +5 -26
- {secator-0.6.0 → secator-0.7.0}/tests/integration/test_tasks.py +11 -40
- {secator-0.6.0 → secator-0.7.0}/tests/integration/test_worker.py +20 -10
- {secator-0.6.0 → secator-0.7.0}/tests/integration/test_workflows.py +24 -29
- {secator-0.6.0 → secator-0.7.0}/tests/integration/wordlist.txt +2 -1
- secator-0.7.0/tests/performance/loadtester.py +77 -0
- secator-0.7.0/tests/performance/test_worker.py +31 -0
- secator-0.7.0/tests/unit/test_celery.py +117 -0
- secator-0.7.0/tests/unit/test_config.py +156 -0
- {secator-0.6.0 → secator-0.7.0}/tests/unit/test_offline.py +18 -10
- secator-0.7.0/tests/unit/test_runners.py +435 -0
- {secator-0.6.0 → secator-0.7.0}/tests/unit/test_tasks.py +68 -113
- secator-0.7.0/tests/unit/test_template.py +126 -0
- secator-0.7.0/tests/unit/test_utils.py +40 -0
- secator-0.6.0/pyproject.toml +0 -89
- secator-0.6.0/secator/celery.py +0 -369
- secator-0.6.0/secator/exporters/csv.py +0 -29
- secator-0.6.0/secator/exporters/table.py +0 -7
- secator-0.6.0/secator/exporters/txt.py +0 -24
- secator-0.6.0/secator/output_types/__init__.py +0 -24
- secator-0.6.0/secator/report.py +0 -95
- secator-0.6.0/secator/runners/_base.py +0 -910
- secator-0.6.0/secator/runners/_helpers.py +0 -172
- secator-0.6.0/secator/runners/task.py +0 -108
- secator-0.6.0/secator/serializers/json.py +0 -15
- secator-0.6.0/secator/serializers/regex.py +0 -17
- secator-0.6.0/secator/tasks/dnsx.py +0 -57
- secator-0.6.0/secator/tasks/h8mail.py +0 -80
- secator-0.6.0/secator/utils.py +0 -441
- secator-0.6.0/tests/performance/loadtester.py +0 -55
- secator-0.6.0/tests/unit/test_celery.py +0 -39
- secator-0.6.0/tests/unit/test_config.py +0 -71
- secator-0.6.0/tests/unit/test_template.py +0 -53
- secator-0.6.0/tests/unit/test_workflows.py +0 -75
- {secator-0.6.0 → secator-0.7.0}/.flake8 +0 -0
- {secator-0.6.0 → secator-0.7.0}/.gitignore +0 -0
- {secator-0.6.0 → secator-0.7.0}/CONTRIBUTING.md +0 -0
- {secator-0.6.0 → secator-0.7.0}/LICENSE +0 -0
- {secator-0.6.0 → secator-0.7.0}/README.md +0 -0
- {secator-0.6.0 → secator-0.7.0}/SECURITY.md +0 -0
- {secator-0.6.0 → secator-0.7.0}/cloudbuild.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/helm/.helmignore +0 -0
- {secator-0.6.0 → secator-0.7.0}/helm/Chart.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/helm/templates/redis-service.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/helm/templates/redis.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/helm/templates/secator-manager.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/helm/templates/secator-worker.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/helm/values.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/images/aliases.cast +0 -0
- {secator-0.6.0 → secator-0.7.0}/images/aliases.gif +0 -0
- {secator-0.6.0 → secator-0.7.0}/images/demo.gif +0 -0
- {secator-0.6.0 → secator-0.7.0}/images/demo.tap +0 -0
- {secator-0.6.0 → secator-0.7.0}/images/fmt.cast +0 -0
- {secator-0.6.0 → secator-0.7.0}/images/fmt.gif +0 -0
- {secator-0.6.0 → secator-0.7.0}/images/help.png +0 -0
- {secator-0.6.0 → secator-0.7.0}/images/input.cast +0 -0
- {secator-0.6.0 → secator-0.7.0}/images/input.gif +0 -0
- {secator-0.6.0 → secator-0.7.0}/images/pipe.cast +0 -0
- {secator-0.6.0 → secator-0.7.0}/images/pipe.gif +0 -0
- {secator-0.6.0 → secator-0.7.0}/images/short_demo.cast +0 -0
- {secator-0.6.0 → secator-0.7.0}/images/short_demo.gif +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/download_cves.sh +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/install.sh +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/install_asciinema.sh +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/install_go.sh +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/install_ruby.sh +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/msf/exploit_cve.rc +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/msf/ftp_anonymous.rc +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/msf/ftp_version.rc +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/msf/ftp_vsftpd_234_backdoor.rc +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/msf/redis.rc +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/msfinstall.sh +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/stories/STORY.md +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/stories/aliases.sh +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/stories/demo.sh +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/stories/fmt.sh +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/stories/input.sh +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/stories/pipe.sh +0 -0
- {secator-0.6.0 → secator-0.7.0}/scripts/stories/short_demo.sh +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/.gitignore +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/__init__.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/__init__.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/profiles/__init__.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/profiles/aggressive.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/profiles/default.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/profiles/stealth.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/scans/__init__.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/scans/domain.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/scans/host.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/scans/network.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/scans/subdomain.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/scans/url.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/workflows/__init__.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/workflows/cidr_recon.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/workflows/code_scan.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/workflows/subdomain_recon.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/workflows/url_crawl.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/workflows/url_dirsearch.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/workflows/url_fuzz.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/workflows/url_nuclei.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/workflows/user_hunt.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/configs/workflows/wordpress.yaml +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/exporters/_base.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/hooks/__init__.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/installer.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/output_types/subdomain.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/output_types/target.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/output_types/user_account.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/runners/__init__.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/serializers/__init__.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/secator/tasks/__init__.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/tests/__init__.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/tests/fixtures/h8mail_breach.txt +0 -0
- {secator-0.6.0 → secator-0.7.0}/tests/fixtures/msfconsole_input.rc +0 -0
- {secator-0.6.0 → secator-0.7.0}/tests/fixtures/nmap_output.xml +0 -0
- {secator-0.6.0 → secator-0.7.0}/tests/integration/__init__.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/tests/integration/teardown.sh +0 -0
- {secator-0.6.0 → secator-0.7.0}/tests/integration/wordlist_dns.txt +0 -0
- {secator-0.6.0 → secator-0.7.0}/tests/integration/wordpress_toolbox/Dockerfile +0 -0
- {secator-0.6.0 → secator-0.7.0}/tests/integration/wordpress_toolbox/Makefile +0 -0
- {secator-0.6.0 → secator-0.7.0}/tests/performance/__init__.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/tests/unit/__init__.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/tests/unit/test_scans.py +0 -0
- {secator-0.6.0 → secator-0.7.0}/tests/unit/test_serializers.py +0 -0
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.0](https://github.com/freelabz/secator/compare/v0.6.0...v0.7.0) (2024-11-13)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **`bup`:** add proxy option and progress indicator ([#444](https://github.com/freelabz/secator/issues/444)) ([d5c63c8](https://github.com/freelabz/secator/commit/d5c63c81c6465a142ce70e4800effc02d526a243))
|
|
9
|
+
* **`dnsx`:** add IP output type on dnsx A record ([#426](https://github.com/freelabz/secator/issues/426)) ([629439e](https://github.com/freelabz/secator/commit/629439e459a6eefd5cbe68e9fc3a317371ba7987))
|
|
10
|
+
* **`naabu`/`nmap`:** help for defaults and change workflow opts ([#438](https://github.com/freelabz/secator/issues/438)) ([4dd0055](https://github.com/freelabz/secator/commit/4dd00556648e691a093887d294325b00409ac04a))
|
|
11
|
+
* **`nmap`:** add udp scan (`-sU`) and change default scan opts ([#418](https://github.com/freelabz/secator/issues/418)) ([36c6ff3](https://github.com/freelabz/secator/commit/36c6ff3766f88ac311c1bfea86a1b5e8686dd94e))
|
|
12
|
+
* add url_bypass workflow based on bup ([e96b1bc](https://github.com/freelabz/secator/commit/e96b1bc9906cd2f9aa3eb5b3770594811f242abd))
|
|
13
|
+
* chunk dalfox input by 1 ([#443](https://github.com/freelabz/secator/issues/443)) ([26c38d7](https://github.com/freelabz/secator/commit/26c38d79e89be3d35f464e89c6973b7beadb6ac4))
|
|
14
|
+
* **cli:** misc bug fixes and features ([#445](https://github.com/freelabz/secator/issues/445)) ([fccfdb8](https://github.com/freelabz/secator/commit/fccfdb8ca38dcd3a2c559429a7d58d46ecac49a6))
|
|
15
|
+
* **hooks:** explicit output type yield in static hooks ([#439](https://github.com/freelabz/secator/issues/439)) ([2d1f8e6](https://github.com/freelabz/secator/commit/2d1f8e6b7b77210028efe2c2c56866efbd6b0152))
|
|
16
|
+
* **katana:** add form_fill option ([#419](https://github.com/freelabz/secator/issues/419)) ([bebddb1](https://github.com/freelabz/secator/commit/bebddb1e2fae460403adda2d84b9ae515ca977aa))
|
|
17
|
+
* **refactor:** improve performance, add on_interval hook, rework CLI opts ([#473](https://github.com/freelabz/secator/issues/473)) ([4a22a70](https://github.com/freelabz/secator/commit/4a22a7082fe1edf50644034cfc54b11653b47aa4))
|
|
18
|
+
* **runner:** add GCS driver and secator threads ([#476](https://github.com/freelabz/secator/issues/476)) ([cae475a](https://github.com/freelabz/secator/commit/cae475a2fe15742ccd80d40c28ad41aa1ffc5348))
|
|
19
|
+
* **runner:** add skip_if_no_inputs to workflows ([#482](https://github.com/freelabz/secator/issues/482)) ([5546b82](https://github.com/freelabz/secator/commit/5546b82756d6aad0d227072d5a3b1149c44306e8))
|
|
20
|
+
* **runner:** on serialized hooks ([#424](https://github.com/freelabz/secator/issues/424)) ([fde6cd7](https://github.com/freelabz/secator/commit/fde6cd7f6cba015b08b370bfd14b0aca3f4a4018))
|
|
21
|
+
* **runner:** rework Celery core and mix fixes ([#450](https://github.com/freelabz/secator/issues/450)) ([b72f152](https://github.com/freelabz/secator/commit/b72f15286bb29ae60568309907d4dad41d4fbacb))
|
|
22
|
+
* sudo prompt check test ([#432](https://github.com/freelabz/secator/issues/432)) ([f45b123](https://github.com/freelabz/secator/commit/f45b1230fd6313342ebdda5a359c1285f2d80aa8))
|
|
23
|
+
* sudo prompts in non-tty mode ([#431](https://github.com/freelabz/secator/issues/431)) ([0e26b55](https://github.com/freelabz/secator/commit/0e26b55c168bfd69c212bc7667ef1b97e89e6bd5))
|
|
24
|
+
* **tasks:** bbot integration ([#375](https://github.com/freelabz/secator/issues/375)) ([2f0dea4](https://github.com/freelabz/secator/commit/2f0dea4f4cac3370129d0adf0000c8d0efa54361))
|
|
25
|
+
* **tasks:** bup integration ([#398](https://github.com/freelabz/secator/issues/398)) ([ed636aa](https://github.com/freelabz/secator/commit/ed636aad7d90baa7b3b73baebc8f5be002dd796a))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Bug Fixes
|
|
29
|
+
|
|
30
|
+
* **cli:** proper opts override for workflows ([#436](https://github.com/freelabz/secator/issues/436)) ([1d1eaa3](https://github.com/freelabz/secator/commit/1d1eaa3283b3d5e9650b452e3865476e6a60a086))
|
|
31
|
+
* **dalfox:** restore input_chunk_size to default ([8f0a3b4](https://github.com/freelabz/secator/commit/8f0a3b4976e20afc2fb708483c7f8885b2b9f3d9))
|
|
32
|
+
* dnsx parsing output loading error ([#422](https://github.com/freelabz/secator/issues/422)) ([b9e98da](https://github.com/freelabz/secator/commit/b9e98da2b5378957076e1d8f0afd3948d5bcb5f6))
|
|
33
|
+
* empty CVE should pass ([#478](https://github.com/freelabz/secator/issues/478)) ([0644d68](https://github.com/freelabz/secator/commit/0644d68ccb92a4c38e8210e39f14f0850d84348d))
|
|
34
|
+
* gcs bug with empty paths ([549ac4c](https://github.com/freelabz/secator/commit/549ac4c8e7391a829cf1a6c5a43ad291bec1b34a))
|
|
35
|
+
* gcs bug with empty paths ([2d57e1a](https://github.com/freelabz/secator/commit/2d57e1ad4669587cf0abb0a59b0918cf72107d72))
|
|
36
|
+
* get_opt_value default value and reorg hooks ([#429](https://github.com/freelabz/secator/issues/429)) ([a44a36d](https://github.com/freelabz/secator/commit/a44a36d37f888787927ec6dfc891e86dab071aa4))
|
|
37
|
+
* mix bugfixes for stable release ([b743925](https://github.com/freelabz/secator/commit/b7439258c9cdadc7bd14a0a0b49e2db2d0f5b537))
|
|
38
|
+
* nmap defaults ([396f68a](https://github.com/freelabz/secator/commit/396f68a325a5a8f1a9379d314979dbf85a9c95c7))
|
|
39
|
+
* **nmap:** undefined service name ([#437](https://github.com/freelabz/secator/issues/437)) ([596f1af](https://github.com/freelabz/secator/commit/596f1aff53e9add73e1587497aee82465d212300))
|
|
40
|
+
* runner opts processing ([#477](https://github.com/freelabz/secator/issues/477)) ([d788e9d](https://github.com/freelabz/secator/commit/d788e9d3e508a849119d418bcc5ce371c6c53c6c))
|
|
41
|
+
* runner toDict() errors ([#475](https://github.com/freelabz/secator/issues/475)) ([b43c866](https://github.com/freelabz/secator/commit/b43c8669808651368536fa121be2ce79de7556aa))
|
|
42
|
+
* **runner:** bug with no inputs ([#483](https://github.com/freelabz/secator/issues/483)) ([4db7b46](https://github.com/freelabz/secator/commit/4db7b460a949e6b74b5837f0f1e3b5ca51b39094))
|
|
43
|
+
* **url_vuln:** repair bad condition ([214c8ab](https://github.com/freelabz/secator/commit/214c8abf7cad4916c8301ff056d894cc0bc26b28))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
### Documentation
|
|
47
|
+
|
|
48
|
+
* add package json ([#415](https://github.com/freelabz/secator/issues/415)) ([f9a7c2f](https://github.com/freelabz/secator/commit/f9a7c2fc5df11506cce0d81babf1f7790b80465a))
|
|
49
|
+
|
|
3
50
|
## [0.6.0](https://github.com/freelabz/secator/compare/v0.5.2...v0.6.0) (2024-07-25)
|
|
4
51
|
|
|
5
52
|
|
|
@@ -37,7 +37,8 @@ COPY . /code/
|
|
|
37
37
|
RUN pipx install .
|
|
38
38
|
RUN secator install tools
|
|
39
39
|
RUN secator install addons worker
|
|
40
|
-
RUN secator install addons
|
|
40
|
+
RUN secator install addons gdrive
|
|
41
|
+
RUN secator install addons gcs
|
|
41
42
|
RUN secator install addons mongodb
|
|
42
43
|
RUN secator install addons redis
|
|
43
44
|
RUN secator install addons dev
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: secator
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: The pentester's swiss knife.
|
|
5
5
|
Project-URL: Homepage, https://github.com/freelabz/secator
|
|
6
6
|
Project-URL: Issues, https://github.com/freelabz/secator/issues
|
|
7
7
|
Author-email: FreeLabz <sales@freelabz.com>
|
|
8
|
-
License-File: LICENSE
|
|
9
8
|
Keywords: automation,cybersecurity,pentest,recon,vulnerability
|
|
10
9
|
Classifier: Development Status :: 3 - Alpha
|
|
11
10
|
Classifier: Intended Audience :: Developers
|
|
@@ -25,16 +24,20 @@ Requires-Dist: cpe<2
|
|
|
25
24
|
Requires-Dist: dotmap<2
|
|
26
25
|
Requires-Dist: free-proxy<2
|
|
27
26
|
Requires-Dist: furl<3
|
|
27
|
+
Requires-Dist: greenlet<4
|
|
28
28
|
Requires-Dist: humanize<5
|
|
29
29
|
Requires-Dist: ifaddr<1
|
|
30
30
|
Requires-Dist: jinja2<4
|
|
31
31
|
Requires-Dist: packaging<25
|
|
32
|
+
Requires-Dist: psutil<7
|
|
32
33
|
Requires-Dist: pydantic<3
|
|
33
34
|
Requires-Dist: python-dotenv<2
|
|
34
35
|
Requires-Dist: pyyaml<7
|
|
35
36
|
Requires-Dist: requests<3
|
|
37
|
+
Requires-Dist: retry<1
|
|
36
38
|
Requires-Dist: rich-click<1.7
|
|
37
39
|
Requires-Dist: rich<14
|
|
40
|
+
Requires-Dist: tldextract<6
|
|
38
41
|
Requires-Dist: typing-extensions<5
|
|
39
42
|
Requires-Dist: validators<1
|
|
40
43
|
Requires-Dist: xmltodict<1
|
|
@@ -44,10 +47,13 @@ Provides-Extra: dev
|
|
|
44
47
|
Requires-Dist: asciinema-automation<1; extra == 'dev'
|
|
45
48
|
Requires-Dist: coverage<8; extra == 'dev'
|
|
46
49
|
Requires-Dist: flake8<8; extra == 'dev'
|
|
50
|
+
Requires-Dist: pytest<9; extra == 'dev'
|
|
47
51
|
Requires-Dist: watchdog<3; extra == 'dev'
|
|
48
|
-
Provides-Extra:
|
|
49
|
-
Requires-Dist: google-
|
|
50
|
-
|
|
52
|
+
Provides-Extra: gcs
|
|
53
|
+
Requires-Dist: google-cloud-storage<3; extra == 'gcs'
|
|
54
|
+
Provides-Extra: gdrive
|
|
55
|
+
Requires-Dist: google-api-python-client<3; extra == 'gdrive'
|
|
56
|
+
Requires-Dist: gspread<7; extra == 'gdrive'
|
|
51
57
|
Provides-Extra: mongodb
|
|
52
58
|
Requires-Dist: pymongo<5; extra == 'mongodb'
|
|
53
59
|
Provides-Extra: redis
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ['hatchling']
|
|
3
|
+
build-backend = 'hatchling.build'
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = 'secator'
|
|
7
|
+
version = "0.7.0"
|
|
8
|
+
authors = [{ name = 'FreeLabz', email = 'sales@freelabz.com' }]
|
|
9
|
+
readme = 'README.md'
|
|
10
|
+
description = "The pentester's swiss knife."
|
|
11
|
+
requires-python = '>=3.8'
|
|
12
|
+
keywords = [
|
|
13
|
+
'cybersecurity',
|
|
14
|
+
'recon',
|
|
15
|
+
'vulnerability',
|
|
16
|
+
'pentest',
|
|
17
|
+
'automation'
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
'Development Status :: 3 - Alpha',
|
|
21
|
+
'Intended Audience :: Developers',
|
|
22
|
+
'Intended Audience :: Information Technology',
|
|
23
|
+
'License :: Free for non-commercial use',
|
|
24
|
+
'Operating System :: Unix',
|
|
25
|
+
'Programming Language :: Python',
|
|
26
|
+
'Programming Language :: Python :: 3',
|
|
27
|
+
'Programming Language :: Python :: 3.8',
|
|
28
|
+
'Programming Language :: Python :: 3.9',
|
|
29
|
+
'Programming Language :: Python :: 3.10',
|
|
30
|
+
'Programming Language :: Python :: 3.11',
|
|
31
|
+
]
|
|
32
|
+
dependencies = [
|
|
33
|
+
'beautifulsoup4 <= 5',
|
|
34
|
+
'celery < 6',
|
|
35
|
+
'cpe < 2',
|
|
36
|
+
'dotmap < 2',
|
|
37
|
+
'free-proxy < 2',
|
|
38
|
+
'furl < 3',
|
|
39
|
+
'greenlet < 4',
|
|
40
|
+
'humanize < 5',
|
|
41
|
+
'ifaddr < 1',
|
|
42
|
+
'jinja2 < 4',
|
|
43
|
+
'packaging < 25',
|
|
44
|
+
'python-dotenv < 2',
|
|
45
|
+
'pyyaml < 7',
|
|
46
|
+
'pydantic < 3',
|
|
47
|
+
'requests < 3',
|
|
48
|
+
'rich < 14',
|
|
49
|
+
'rich-click < 1.7',
|
|
50
|
+
'psutil < 7',
|
|
51
|
+
'retry < 1',
|
|
52
|
+
'tldextract < 6',
|
|
53
|
+
'typing_extensions < 5',
|
|
54
|
+
'validators < 1',
|
|
55
|
+
'xmltodict < 1'
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[project.optional-dependencies]
|
|
59
|
+
dev = [
|
|
60
|
+
'coverage < 8',
|
|
61
|
+
'flake8 < 8',
|
|
62
|
+
'pytest < 9',
|
|
63
|
+
'watchdog < 3',
|
|
64
|
+
'asciinema-automation < 1',
|
|
65
|
+
]
|
|
66
|
+
build = [
|
|
67
|
+
'hatch < 2',
|
|
68
|
+
]
|
|
69
|
+
trace = [
|
|
70
|
+
'memray < 2',
|
|
71
|
+
'pyinstrument < 5',
|
|
72
|
+
]
|
|
73
|
+
worker = [
|
|
74
|
+
'gevent < 25',
|
|
75
|
+
'eventlet < 1',
|
|
76
|
+
'flower < 3',
|
|
77
|
+
]
|
|
78
|
+
redis = [
|
|
79
|
+
'redis < 6',
|
|
80
|
+
]
|
|
81
|
+
mongodb = [
|
|
82
|
+
'pymongo < 5',
|
|
83
|
+
]
|
|
84
|
+
gdrive = [
|
|
85
|
+
'google-api-python-client < 3',
|
|
86
|
+
'gspread < 7'
|
|
87
|
+
]
|
|
88
|
+
gcs = [
|
|
89
|
+
'google-cloud-storage < 3'
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
[project.scripts]
|
|
93
|
+
secator = 'secator.cli:cli'
|
|
94
|
+
|
|
95
|
+
[project.urls]
|
|
96
|
+
Homepage = 'https://github.com/freelabz/secator'
|
|
97
|
+
Issues = 'https://github.com/freelabz/secator/issues'
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import gc
|
|
2
|
+
import logging
|
|
3
|
+
import sys
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
from time import time
|
|
7
|
+
|
|
8
|
+
from celery import Celery, chain, chord, signals
|
|
9
|
+
from celery.app import trace
|
|
10
|
+
|
|
11
|
+
from rich.logging import RichHandler
|
|
12
|
+
from retry import retry
|
|
13
|
+
|
|
14
|
+
from secator.config import CONFIG
|
|
15
|
+
from secator.output_types import Info, Warning, Error
|
|
16
|
+
from secator.rich import console
|
|
17
|
+
from secator.runners import Scan, Task, Workflow
|
|
18
|
+
from secator.runners._helpers import run_extractors
|
|
19
|
+
from secator.utils import (debug, deduplicate, flatten, should_update)
|
|
20
|
+
|
|
21
|
+
IN_CELERY_WORKER_PROCESS = sys.argv and ('secator.celery.app' in sys.argv or 'worker' in sys.argv)
|
|
22
|
+
|
|
23
|
+
#---------#
|
|
24
|
+
# Logging #
|
|
25
|
+
#---------#
|
|
26
|
+
|
|
27
|
+
rich_handler = RichHandler(rich_tracebacks=True)
|
|
28
|
+
rich_handler.setLevel(logging.INFO)
|
|
29
|
+
logging.basicConfig(
|
|
30
|
+
level='NOTSET',
|
|
31
|
+
format="%(threadName)s:%(message)s",
|
|
32
|
+
datefmt="[%X]",
|
|
33
|
+
handlers=[rich_handler],
|
|
34
|
+
force=True)
|
|
35
|
+
logging.getLogger('kombu').setLevel(logging.ERROR)
|
|
36
|
+
logging.getLogger('celery').setLevel(logging.INFO if CONFIG.debug.level > 6 else logging.WARNING)
|
|
37
|
+
logger = logging.getLogger(__name__)
|
|
38
|
+
trace.LOG_SUCCESS = "Task %(name)s[%(id)s] succeeded in %(runtime)ss"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
#------------#
|
|
42
|
+
# Celery app #
|
|
43
|
+
#------------#
|
|
44
|
+
|
|
45
|
+
app = Celery(__name__)
|
|
46
|
+
app.conf.update({
|
|
47
|
+
# Content types
|
|
48
|
+
'accept_content': ['application/x-python-serialize', 'application/json'],
|
|
49
|
+
|
|
50
|
+
# Broker config
|
|
51
|
+
'broker_url': CONFIG.celery.broker_url,
|
|
52
|
+
'broker_transport_options': {
|
|
53
|
+
'data_folder_in': CONFIG.dirs.celery_data,
|
|
54
|
+
'data_folder_out': CONFIG.dirs.celery_data,
|
|
55
|
+
'control_folder': CONFIG.dirs.celery_data,
|
|
56
|
+
'visibility_timeout': CONFIG.celery.broker_visibility_timeout,
|
|
57
|
+
},
|
|
58
|
+
'broker_connection_retry_on_startup': True,
|
|
59
|
+
'broker_pool_limit': CONFIG.celery.broker_pool_limit,
|
|
60
|
+
'broker_connection_timeout': CONFIG.celery.broker_connection_timeout,
|
|
61
|
+
|
|
62
|
+
# Result backend config
|
|
63
|
+
'result_backend': CONFIG.celery.result_backend,
|
|
64
|
+
'result_expires': CONFIG.celery.result_expires,
|
|
65
|
+
'result_extended': True,
|
|
66
|
+
'result_backend_thread_safe': True,
|
|
67
|
+
'result_serializer': 'pickle',
|
|
68
|
+
# 'result_backend_transport_options': {'master_name': 'mymaster'}, # for Redis HA backend
|
|
69
|
+
|
|
70
|
+
# Task config
|
|
71
|
+
'task_acks_late': False,
|
|
72
|
+
'task_compression': 'gzip',
|
|
73
|
+
'task_create_missing_queues': True,
|
|
74
|
+
'task_eager_propagates': False,
|
|
75
|
+
'task_reject_on_worker_lost': False,
|
|
76
|
+
'task_routes': {
|
|
77
|
+
'secator.celery.run_workflow': {'queue': 'celery'},
|
|
78
|
+
'secator.celery.run_scan': {'queue': 'celery'},
|
|
79
|
+
'secator.celery.run_task': {'queue': 'celery'},
|
|
80
|
+
'secator.hooks.mongodb.tag_duplicates': {'queue': 'mongodb'}
|
|
81
|
+
},
|
|
82
|
+
'task_store_eager_result': True,
|
|
83
|
+
# 'task_send_sent_event': True, # TODO: consider enabling this for Flower monitoring
|
|
84
|
+
'task_serializer': 'pickle',
|
|
85
|
+
|
|
86
|
+
# Worker config
|
|
87
|
+
# 'worker_direct': True, # TODO: consider enabling this to allow routing to specific workers
|
|
88
|
+
'worker_max_tasks_per_child': 10,
|
|
89
|
+
# 'worker_max_memory_per_child': 100000 # TODO: consider enabling this
|
|
90
|
+
'worker_pool_restarts': True,
|
|
91
|
+
'worker_prefetch_multiplier': 1,
|
|
92
|
+
# 'worker_send_task_events': True, # TODO: consider enabling this for Flower monitoring
|
|
93
|
+
})
|
|
94
|
+
app.autodiscover_tasks(['secator.hooks.mongodb'], related_name=None)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def maybe_override_logging():
|
|
98
|
+
def decorator(func):
|
|
99
|
+
if CONFIG.celery.override_default_logging:
|
|
100
|
+
return signals.setup_logging.connect(func)
|
|
101
|
+
else:
|
|
102
|
+
return func
|
|
103
|
+
return decorator
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@maybe_override_logging()
|
|
107
|
+
def void(*args, **kwargs):
|
|
108
|
+
"""Override celery's logging setup to prevent it from altering our settings.
|
|
109
|
+
github.com/celery/celery/issues/1867
|
|
110
|
+
"""
|
|
111
|
+
pass
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@retry(Exception, tries=3, delay=2)
|
|
115
|
+
def update_state(celery_task, task, force=False):
|
|
116
|
+
"""Update task state to add metadata information."""
|
|
117
|
+
if task.sync:
|
|
118
|
+
return
|
|
119
|
+
if not force and not should_update(CONFIG.runners.backend_update_frequency, task.last_updated_celery):
|
|
120
|
+
return
|
|
121
|
+
task.last_updated_celery = time()
|
|
122
|
+
debug(
|
|
123
|
+
'',
|
|
124
|
+
sub='celery.state',
|
|
125
|
+
id=celery_task.request.id,
|
|
126
|
+
obj={task.unique_name: task.status, 'count': task.self_findings_count},
|
|
127
|
+
obj_after=False,
|
|
128
|
+
verbose=True
|
|
129
|
+
)
|
|
130
|
+
return celery_task.update_state(
|
|
131
|
+
state='RUNNING',
|
|
132
|
+
meta=task.celery_state
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def revoke_task(task_id, task_name=None):
|
|
137
|
+
message = f'Revoked task {task_id}'
|
|
138
|
+
if task_name:
|
|
139
|
+
message += f' ({task_name})'
|
|
140
|
+
app.control.revoke(task_id, terminate=True)
|
|
141
|
+
console.print(Info(message=message))
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
#--------------#
|
|
145
|
+
# Celery tasks #
|
|
146
|
+
#--------------#
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def chunker(seq, size):
|
|
150
|
+
return (seq[pos:pos + size] for pos in range(0, len(seq), size))
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def break_task(task, task_opts, targets, results=[], chunk_size=1):
|
|
154
|
+
"""Break a task into multiple of the same type."""
|
|
155
|
+
chunks = targets
|
|
156
|
+
if chunk_size > 1:
|
|
157
|
+
chunks = list(chunker(targets, chunk_size))
|
|
158
|
+
debug(
|
|
159
|
+
'',
|
|
160
|
+
obj={task.unique_name: 'CHUNKED', 'chunk_size': chunk_size, 'chunks': len(chunks), 'target_count': len(targets)},
|
|
161
|
+
obj_after=False,
|
|
162
|
+
sub='celery.state',
|
|
163
|
+
verbose=True
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
# Clone opts
|
|
167
|
+
opts = task_opts.copy()
|
|
168
|
+
|
|
169
|
+
# Build signatures
|
|
170
|
+
sigs = []
|
|
171
|
+
task.ids_map = {}
|
|
172
|
+
for ix, chunk in enumerate(chunks):
|
|
173
|
+
if not isinstance(chunk, list):
|
|
174
|
+
chunk = [chunk]
|
|
175
|
+
if len(chunks) > 0: # add chunk to task opts for tracking chunks exec
|
|
176
|
+
opts['chunk'] = ix + 1
|
|
177
|
+
opts['chunk_count'] = len(chunks)
|
|
178
|
+
task_id = str(uuid.uuid4())
|
|
179
|
+
opts['has_parent'] = True
|
|
180
|
+
opts['enable_duplicate_check'] = False
|
|
181
|
+
sig = type(task).s(chunk, **opts).set(queue=type(task).profile, task_id=task_id)
|
|
182
|
+
full_name = f'{task.name}_{ix + 1}'
|
|
183
|
+
task.add_subtask(task_id, task.name, f'{task.name}_{ix + 1}')
|
|
184
|
+
info = Info(message=f'Celery chunked task created: {task_id}', _source=full_name, _uuid=str(uuid.uuid4()))
|
|
185
|
+
task.add_result(info)
|
|
186
|
+
sigs.append(sig)
|
|
187
|
+
|
|
188
|
+
# Build Celery workflow
|
|
189
|
+
workflow = chain(
|
|
190
|
+
forward_results.s(results).set(queue='io'),
|
|
191
|
+
chord(
|
|
192
|
+
tuple(sigs),
|
|
193
|
+
forward_results.s().set(queue='io'),
|
|
194
|
+
)
|
|
195
|
+
)
|
|
196
|
+
if task.sync:
|
|
197
|
+
task.print_item = False
|
|
198
|
+
task.results = workflow.apply().get()
|
|
199
|
+
else:
|
|
200
|
+
result = workflow.apply_async()
|
|
201
|
+
task.celery_result = result
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@app.task(bind=True)
|
|
205
|
+
def run_task(self, args=[], kwargs={}):
|
|
206
|
+
kwargs['context']['celery_id'] = self.request.id
|
|
207
|
+
task = Task(*args, **kwargs)
|
|
208
|
+
task.run()
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@app.task(bind=True)
|
|
212
|
+
def run_workflow(self, args=[], kwargs={}):
|
|
213
|
+
kwargs['context']['celery_id'] = self.request.id
|
|
214
|
+
workflow = Workflow(*args, **kwargs)
|
|
215
|
+
workflow.run()
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@app.task(bind=True)
|
|
219
|
+
def run_scan(self, args=[], kwargs={}):
|
|
220
|
+
if 'context' not in kwargs:
|
|
221
|
+
kwargs['context'] = {}
|
|
222
|
+
kwargs['context']['celery_id'] = self.request.id
|
|
223
|
+
scan = Scan(*args, **kwargs)
|
|
224
|
+
scan.run()
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
@app.task(bind=True)
|
|
228
|
+
def run_command(self, results, name, targets, opts={}):
|
|
229
|
+
chunk = opts.get('chunk')
|
|
230
|
+
sync = opts.get('sync', True)
|
|
231
|
+
|
|
232
|
+
# Set Celery request id in context
|
|
233
|
+
context = opts.get('context', {})
|
|
234
|
+
context['celery_id'] = self.request.id
|
|
235
|
+
opts['context'] = context
|
|
236
|
+
opts['print_remote_info'] = False
|
|
237
|
+
opts['results'] = results
|
|
238
|
+
|
|
239
|
+
# If we are in a Celery worker, print everything, always
|
|
240
|
+
if IN_CELERY_WORKER_PROCESS:
|
|
241
|
+
opts.update({
|
|
242
|
+
'print_item': True,
|
|
243
|
+
'print_line': True,
|
|
244
|
+
'print_cmd': True
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
# Flatten + dedupe results
|
|
248
|
+
results = flatten(results)
|
|
249
|
+
results = deduplicate(results, attr='_uuid')
|
|
250
|
+
|
|
251
|
+
# Get expanded targets
|
|
252
|
+
if not chunk and results:
|
|
253
|
+
targets, opts = run_extractors(results, opts, targets)
|
|
254
|
+
debug('after extractors', obj={'targets': targets, 'opts': opts}, sub='celery.state')
|
|
255
|
+
|
|
256
|
+
try:
|
|
257
|
+
# Get task class
|
|
258
|
+
task_cls = Task.get_task_class(name)
|
|
259
|
+
|
|
260
|
+
# Check if chunkable
|
|
261
|
+
many_targets = len(targets) > 1
|
|
262
|
+
targets_over_chunk_size = task_cls.input_chunk_size and len(targets) > task_cls.input_chunk_size
|
|
263
|
+
has_file_flag = task_cls.file_flag is not None
|
|
264
|
+
chunk_it = (sync and many_targets and not has_file_flag) or (not sync and many_targets and targets_over_chunk_size)
|
|
265
|
+
task_opts = opts.copy()
|
|
266
|
+
task_opts.update({
|
|
267
|
+
'print_remote_info': False,
|
|
268
|
+
'has_children': chunk_it,
|
|
269
|
+
})
|
|
270
|
+
if chunk_it:
|
|
271
|
+
task_opts['print_cmd'] = False
|
|
272
|
+
task = task_cls(targets, **task_opts)
|
|
273
|
+
debug(
|
|
274
|
+
'',
|
|
275
|
+
obj={
|
|
276
|
+
f'{task.unique_name}': 'CHUNK STATUS',
|
|
277
|
+
'chunk_it': chunk_it,
|
|
278
|
+
'sync': task.sync,
|
|
279
|
+
'many_targets': many_targets,
|
|
280
|
+
'targets_over_chunk_size': targets_over_chunk_size,
|
|
281
|
+
},
|
|
282
|
+
obj_after=False,
|
|
283
|
+
id=self.request.id,
|
|
284
|
+
sub='celery.state',
|
|
285
|
+
verbose=True
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
# Chunk task if needed
|
|
289
|
+
if chunk_it:
|
|
290
|
+
chunk_size = task_cls.input_chunk_size if has_file_flag else 1
|
|
291
|
+
break_task(
|
|
292
|
+
task,
|
|
293
|
+
opts,
|
|
294
|
+
targets,
|
|
295
|
+
results=results,
|
|
296
|
+
chunk_size=chunk_size)
|
|
297
|
+
|
|
298
|
+
# Update state before starting
|
|
299
|
+
update_state(self, task)
|
|
300
|
+
|
|
301
|
+
# Update state for each item found
|
|
302
|
+
for _ in task:
|
|
303
|
+
update_state(self, task)
|
|
304
|
+
|
|
305
|
+
except BaseException as e:
|
|
306
|
+
error = Error.from_exception(e)
|
|
307
|
+
error._source = task.unique_name
|
|
308
|
+
error._uuid = str(uuid.uuid4())
|
|
309
|
+
task.add_result(error, print=True)
|
|
310
|
+
task.stop_celery_tasks()
|
|
311
|
+
|
|
312
|
+
finally:
|
|
313
|
+
update_state(self, task, force=True)
|
|
314
|
+
gc.collect()
|
|
315
|
+
debug('', obj={task.unique_name: task.status, 'results': task.results}, sub='celery.results', verbose=True)
|
|
316
|
+
return task.results
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
@app.task
|
|
320
|
+
def forward_results(results):
|
|
321
|
+
if isinstance(results, list):
|
|
322
|
+
for ix, item in enumerate(results):
|
|
323
|
+
if isinstance(item, dict) and 'results' in item:
|
|
324
|
+
results[ix] = item['results']
|
|
325
|
+
elif 'results' in results:
|
|
326
|
+
results = results['results']
|
|
327
|
+
results = flatten(results)
|
|
328
|
+
results = deduplicate(results, attr='_uuid')
|
|
329
|
+
return results
|
|
330
|
+
|
|
331
|
+
#--------------#
|
|
332
|
+
# Celery utils #
|
|
333
|
+
#--------------#
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def is_celery_worker_alive():
|
|
337
|
+
"""Check if a Celery worker is available."""
|
|
338
|
+
result = app.control.broadcast('ping', reply=True, limit=1, timeout=1)
|
|
339
|
+
result = bool(result)
|
|
340
|
+
if result:
|
|
341
|
+
console.print(Info(message='Celery worker is alive !'))
|
|
342
|
+
else:
|
|
343
|
+
console.print(Warning(message='No Celery worker alive.'))
|
|
344
|
+
return result
|