secator 0.16.5__tar.gz → 0.18.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.16.5 → secator-0.18.0}/.docker/build_all.sh +13 -1
- secator-0.18.0/.dockerignore +4 -0
- {secator-0.16.5 → secator-0.18.0}/.gitignore +3 -0
- {secator-0.16.5 → secator-0.18.0}/CHANGELOG.md +31 -0
- {secator-0.16.5 → secator-0.18.0}/PKG-INFO +1 -1
- {secator-0.16.5 → secator-0.18.0}/helm/templates/redis-service.yaml +0 -1
- {secator-0.16.5 → secator-0.18.0}/helm/templates/redis.yaml +6 -2
- secator-0.18.0/helm/templates/secator-manager.yaml +22 -0
- {secator-0.16.5 → secator-0.18.0}/helm/templates/secator-worker.yaml +8 -3
- secator-0.18.0/helm/values.yaml +58 -0
- {secator-0.16.5 → secator-0.18.0}/pyproject.toml +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/celery.py +75 -9
- {secator-0.16.5 → secator-0.18.0}/secator/celery_signals.py +2 -1
- {secator-0.16.5 → secator-0.18.0}/secator/cli.py +7 -1
- {secator-0.16.5 → secator-0.18.0}/secator/config.py +2 -1
- secator-0.18.0/secator/configs/workflows/user_hunt.yaml +24 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/wordpress.yaml +13 -0
- {secator-0.16.5 → secator-0.18.0}/secator/hooks/gcs.py +11 -1
- {secator-0.16.5 → secator-0.18.0}/secator/hooks/mongodb.py +71 -66
- {secator-0.16.5 → secator-0.18.0}/secator/installer.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/certificate.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/exploit.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/ip.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/progress.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/record.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/stat.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/state.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/subdomain.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/tag.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/target.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/user_account.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/vulnerability.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/runners/_base.py +8 -8
- {secator-0.16.5 → secator-0.18.0}/secator/runners/command.py +29 -11
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/bup.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/cariddi.py +37 -1
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/dalfox.py +2 -2
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/dirsearch.py +0 -1
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/feroxbuster.py +0 -1
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/ffuf.py +0 -1
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/fping.py +24 -7
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/katana.py +3 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/maigret.py +7 -2
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/naabu.py +1 -2
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/nuclei.py +4 -1
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/wpscan.py +15 -4
- {secator-0.16.5 → secator-0.18.0}/secator/utils.py +9 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/inputs.py +1 -1
- {secator-0.16.5 → secator-0.18.0}/tests/integration/outputs.py +3 -3
- {secator-0.16.5 → secator-0.18.0}/tests/integration/test_tasks_categories.py +10 -1
- secator-0.16.5/.dockerignore +0 -1
- secator-0.16.5/helm/templates/secator-manager.yaml +0 -18
- secator-0.16.5/helm/values.yaml +0 -34
- secator-0.16.5/secator/configs/workflows/user_hunt.yaml +0 -12
- {secator-0.16.5 → secator-0.18.0}/.coderabbit.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/.docker/Dockerfile.alpine +0 -0
- {secator-0.16.5 → secator-0.18.0}/.docker/Dockerfile.arch +0 -0
- {secator-0.16.5 → secator-0.18.0}/.docker/Dockerfile.debian +0 -0
- {secator-0.16.5 → secator-0.18.0}/.docker/Dockerfile.kali +0 -0
- {secator-0.16.5 → secator-0.18.0}/.docker/Dockerfile.osx +0 -0
- {secator-0.16.5 → secator-0.18.0}/.docker/Dockerfile.ubuntu +0 -0
- {secator-0.16.5 → secator-0.18.0}/.flake8 +0 -0
- {secator-0.16.5 → secator-0.18.0}/CONTRIBUTING.md +0 -0
- {secator-0.16.5 → secator-0.18.0}/Dockerfile +0 -0
- {secator-0.16.5 → secator-0.18.0}/LICENSE +0 -0
- {secator-0.16.5 → secator-0.18.0}/README.md +0 -0
- {secator-0.16.5 → secator-0.18.0}/SECURITY.md +0 -0
- {secator-0.16.5 → secator-0.18.0}/cloudbuild.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/helm/.helmignore +0 -0
- {secator-0.16.5 → secator-0.18.0}/helm/Chart.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/download_cves.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/generate_tools_md_table.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/install.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/install_asciinema.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/install_go.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/install_ruby.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/msf/exploit_cve.rc +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/msf/ftp_anonymous.rc +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/msf/ftp_version.rc +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/msf/ftp_vsftpd_234_backdoor.rc +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/msf/redis.rc +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/stories/STORY.md +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/stories/aliases.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/stories/demo.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/stories/fmt.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/stories/input.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/stories/pipe.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/stories/short_demo.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/scripts/update_tools.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/.gitignore +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/celery_utils.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/cli_helper.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/click.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/aggressive.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/http_headless.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/http_record.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/insane.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/paranoid.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/polite.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/sneaky.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/tor.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/scans/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/scans/domain.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/scans/host.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/scans/network.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/scans/subdomain.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/scans/url.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/cidr_recon.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/code_scan.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/host_recon.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/subdomain_recon.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/url_bypass.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/url_crawl.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/url_dirsearch.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/url_fuzz.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/url_params_fuzz.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/url_vuln.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/cve.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/decorators.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/definitions.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/exporters/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/exporters/_base.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/exporters/console.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/exporters/csv.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/exporters/gdrive.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/exporters/json.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/exporters/table.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/exporters/txt.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/hooks/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/loader.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/_base.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/error.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/info.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/port.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/url.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/output_types/warning.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/report.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/rich.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/runners/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/runners/_helpers.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/runners/celery.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/runners/scan.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/runners/task.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/runners/workflow.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/scans/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/serializers/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/serializers/dataclass.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/serializers/json.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/serializers/regex.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/_categories.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/arjun.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/bbot.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/dnsx.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/gau.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/gf.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/gitleaks.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/gospider.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/grype.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/h8mail.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/httpx.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/mapcidr.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/msfconsole.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/nmap.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/searchsploit.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/subfinder.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/testssl.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/trivy.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/wafw00f.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tasks/wpprobe.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/template.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/thread.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/tree.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/utils_test.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/secator/workflows/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/fixtures/h8mail_breach.txt +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/fixtures/ls.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/fixtures/msfconsole_input.rc +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/fixtures/nmap_output.xml +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/all.yaml +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/setup.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/teardown.sh +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/test_addons.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/test_celery.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/test_scans.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/test_tasks.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/test_worker.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/test_workflows.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/wordlist.txt +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/wordlist_dns.txt +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/wordpress_toolbox/Dockerfile +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/integration/wordpress_toolbox/Makefile +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/performance/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/performance/loadtester.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/performance/test_worker.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/template/test_templates.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/__init__.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/test_celery.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/test_cli.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/test_command.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/test_config.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/test_offline.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/test_runners.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/test_runners_helpers.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/test_scans.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/test_serializers.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/test_tasks.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/test_tasks_categories.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/test_template.py +0 -0
- {secator-0.16.5 → secator-0.18.0}/tests/unit/test_utils.py +0 -0
|
@@ -2,16 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
# Define an array of distributions
|
|
4
4
|
DISTROS=("alpine" "arch" "debian" "kali" "osx" "ubuntu")
|
|
5
|
+
BUILDER=$(which docker || which podman || which buildah)
|
|
6
|
+
|
|
7
|
+
if [ -z "$BUILDER" ]; then
|
|
8
|
+
echo "Error: No container builder found (docker, podman, or buildah required)"
|
|
9
|
+
exit 1
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
echo "Using builder: $BUILDER"
|
|
13
|
+
|
|
14
|
+
mkdir -p .docker/logs/
|
|
5
15
|
|
|
6
16
|
# Function to build an image
|
|
7
17
|
build_image() {
|
|
8
18
|
local DISTRO=$1
|
|
9
19
|
local DOCKERFILE=".docker/Dockerfile.${DISTRO}"
|
|
20
|
+
local STDOUT_LOG=".docker/logs/${DISTRO}.stdout"
|
|
21
|
+
local STDERR_LOG=".docker/logs/${DISTRO}.stderr"
|
|
10
22
|
local IMAGE_NAME="secator-${DISTRO}"
|
|
11
23
|
|
|
12
24
|
if [ -f "$DOCKERFILE" ]; then
|
|
13
25
|
echo "🚀 Building $IMAGE_NAME using $DOCKERFILE..."
|
|
14
|
-
|
|
26
|
+
$BUILDER build -t "$IMAGE_NAME" -f "$DOCKERFILE" . > $STDOUT_LOG 2> $STDERR_LOG && \
|
|
15
27
|
echo "✅ Successfully built $IMAGE_NAME" || \
|
|
16
28
|
echo "❌ Failed to build $IMAGE_NAME"
|
|
17
29
|
else
|
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.18.0](https://github.com/freelabz/secator/compare/v0.17.0...v0.18.0) (2025-10-22)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **workflow:** update user hunt ([#688](https://github.com/freelabz/secator/issues/688)) ([e4f3e29](https://github.com/freelabz/secator/commit/e4f3e294c1668c66ed893305b0147df37cb4453a))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* broken sudo prompt because of os.setsid ([#722](https://github.com/freelabz/secator/issues/722)) ([5c77957](https://github.com/freelabz/secator/commit/5c77957cb78533b7e819c01c19de6e46eae0d2af))
|
|
14
|
+
* bugs and warnings in task data ([#714](https://github.com/freelabz/secator/issues/714)) ([845415b](https://github.com/freelabz/secator/commit/845415bb337f77867d49be66bbd23eaf307e5848))
|
|
15
|
+
* bup file flag ([#725](https://github.com/freelabz/secator/issues/725)) ([0622ef5](https://github.com/freelabz/secator/commit/0622ef509b1dc33996dd5e89aea5cd802160744d))
|
|
16
|
+
* context propagation for subtasks ([#720](https://github.com/freelabz/secator/issues/720)) ([d636aa6](https://github.com/freelabz/secator/commit/d636aa66562fd030299fce20f3abaeca283eaf74))
|
|
17
|
+
* **fping:** remove bad options, add new ones ([#713](https://github.com/freelabz/secator/issues/713)) ([4356b4f](https://github.com/freelabz/secator/commit/4356b4f120043e2f94973a9c0061345a06efaeda))
|
|
18
|
+
* maigret version pin ([#721](https://github.com/freelabz/secator/issues/721)) ([488b5a1](https://github.com/freelabz/secator/commit/488b5a1b994e6d3dfadc409d09aaaeb93ff60fb4))
|
|
19
|
+
* subfinder integration tests ([#724](https://github.com/freelabz/secator/issues/724)) ([8163152](https://github.com/freelabz/secator/commit/8163152efb09f3854ec9fa7125b16084eda4c98f))
|
|
20
|
+
* wpscan errors and wordpress workflow ([#723](https://github.com/freelabz/secator/issues/723)) ([8ee32aa](https://github.com/freelabz/secator/commit/8ee32aacb1310cfb833bdcf696477ae29eb271c7))
|
|
21
|
+
|
|
22
|
+
## [0.17.0](https://github.com/freelabz/secator/compare/v0.16.5...v0.17.0) (2025-09-06)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
* enforceable memory limits ([#710](https://github.com/freelabz/secator/issues/710)) ([eaefa1f](https://github.com/freelabz/secator/commit/eaefa1f5497af4d6a6020e09d5f954ae4639f20c))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Bug Fixes
|
|
31
|
+
|
|
32
|
+
* prod optimizations ([#708](https://github.com/freelabz/secator/issues/708)) ([efb5d3c](https://github.com/freelabz/secator/commit/efb5d3ce637a5de6e23ed157fd85d2a39bef360d))
|
|
33
|
+
|
|
3
34
|
## [0.16.5](https://github.com/freelabz/secator/compare/v0.16.4...v0.16.5) (2025-06-25)
|
|
4
35
|
|
|
5
36
|
|
|
@@ -2,7 +2,6 @@ apiVersion: apps/v1
|
|
|
2
2
|
kind: StatefulSet
|
|
3
3
|
metadata:
|
|
4
4
|
name: {{ .Values.redis.name }}
|
|
5
|
-
namespace: {{ .Values.namespace }}
|
|
6
5
|
spec:
|
|
7
6
|
selector:
|
|
8
7
|
matchLabels:
|
|
@@ -13,10 +12,15 @@ spec:
|
|
|
13
12
|
metadata:
|
|
14
13
|
labels:
|
|
15
14
|
app: redis
|
|
16
|
-
spec:
|
|
15
|
+
spec:
|
|
16
|
+
automountServiceAccountToken: {{ .Values.automountServiceAccountToken }}
|
|
17
17
|
containers:
|
|
18
18
|
- name: {{ .Values.redis.name }}
|
|
19
19
|
image: {{ .Values.redis.image }}
|
|
20
|
+
securityContext:
|
|
21
|
+
{{- toYaml .Values.redis.securityContext | nindent 10 }}
|
|
22
|
+
resources:
|
|
23
|
+
{{- toYaml .Values.redis.resources | nindent 10 }}
|
|
20
24
|
ports:
|
|
21
25
|
- containerPort: {{ .Values.redis.port }}
|
|
22
26
|
name: client
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
apiVersion: v1
|
|
2
|
+
kind: Pod
|
|
3
|
+
metadata:
|
|
4
|
+
name: {{ .Values.secatorManager.name }}
|
|
5
|
+
labels:
|
|
6
|
+
name: secator-manager
|
|
7
|
+
spec:
|
|
8
|
+
automountServiceAccountToken: {{ .Values.automountServiceAccountToken }}
|
|
9
|
+
containers:
|
|
10
|
+
- name: secator-manager
|
|
11
|
+
image: {{ .Values.secatorManager.image }}
|
|
12
|
+
securityContext:
|
|
13
|
+
{{- toYaml .Values.secatorManager.securityContext | nindent 6 }}
|
|
14
|
+
resources:
|
|
15
|
+
{{- toYaml .Values.secatorManager.resources | nindent 6 }}
|
|
16
|
+
command: ["sleep"]
|
|
17
|
+
args: ["infinity"]
|
|
18
|
+
env:
|
|
19
|
+
- name: SECATOR_CELERY_BROKER_URL
|
|
20
|
+
value: "redis://{{ .Values.redis.name }}:{{ .Values.redis.port }}/0"
|
|
21
|
+
- name: SECATOR_CELERY_RESULT_BACKEND
|
|
22
|
+
value: "redis://{{ .Values.redis.name }}:{{ .Values.redis.port }}/0"
|
|
@@ -2,8 +2,8 @@ apiVersion: apps/v1
|
|
|
2
2
|
kind: Deployment
|
|
3
3
|
metadata:
|
|
4
4
|
name: {{ .Values.secatorWorker.name }}
|
|
5
|
-
namespace: {{ .Values.namespace }}
|
|
6
5
|
spec:
|
|
6
|
+
replicas: {{ .Values.secatorWorker.replicas }}
|
|
7
7
|
selector:
|
|
8
8
|
matchLabels:
|
|
9
9
|
app: secator-worker
|
|
@@ -12,13 +12,18 @@ spec:
|
|
|
12
12
|
labels:
|
|
13
13
|
app: secator-worker
|
|
14
14
|
spec:
|
|
15
|
+
automountServiceAccountToken: {{ .Values.automountServiceAccountToken }}
|
|
15
16
|
containers:
|
|
16
17
|
- name: {{ .Values.secatorWorker.name }}
|
|
17
18
|
image: {{ .Values.secatorWorker.image }}
|
|
19
|
+
securityContext:
|
|
20
|
+
{{- toYaml .Values.secatorWorker.securityContext | nindent 10 }}
|
|
21
|
+
resources:
|
|
22
|
+
{{- toYaml .Values.secatorWorker.resources | nindent 10 }}
|
|
18
23
|
command: ["secator"]
|
|
19
24
|
args: ["worker"]
|
|
20
25
|
env:
|
|
21
26
|
- name: SECATOR_CELERY_BROKER_URL
|
|
22
|
-
value: "redis://{{ .Values.redis.name }}:
|
|
27
|
+
value: "redis://{{ .Values.redis.name }}:{{ .Values.redis.port }}/0"
|
|
23
28
|
- name: SECATOR_CELERY_RESULT_BACKEND
|
|
24
|
-
value: "redis://{{ .Values.redis.name }}:
|
|
29
|
+
value: "redis://{{ .Values.redis.name }}:{{ .Values.redis.port }}/0"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Default values for Secator
|
|
2
|
+
# This is a YAML-formatted file.
|
|
3
|
+
# Declare variables to be passed into your templates.
|
|
4
|
+
|
|
5
|
+
# TODO: Create service accounts instead. Assess for RBAC. Add tooling for kubernetes to image, or side-car.
|
|
6
|
+
# For instance, the secator Manager pod could have sufficient access to list/get/set worker replicas for scaling from
|
|
7
|
+
# from the pod itself. Perhaps another add-on?
|
|
8
|
+
automountServiceAccountToken: false
|
|
9
|
+
|
|
10
|
+
secatorManager:
|
|
11
|
+
name: secator-manager
|
|
12
|
+
image: "freelabz/secator"
|
|
13
|
+
securityContext: {}
|
|
14
|
+
|
|
15
|
+
# resources: cpu/memory requests and limits for managers
|
|
16
|
+
resources: {}
|
|
17
|
+
|
|
18
|
+
# Empty if using default repository
|
|
19
|
+
repository:
|
|
20
|
+
# Empty if using tag "latest"
|
|
21
|
+
tag:
|
|
22
|
+
|
|
23
|
+
secatorWorker:
|
|
24
|
+
name: secator-worker
|
|
25
|
+
image: "freelabz/secator"
|
|
26
|
+
securityContext: {}
|
|
27
|
+
|
|
28
|
+
# resources: cpu/memory requests and limits for workers
|
|
29
|
+
resources: {}
|
|
30
|
+
replicas: 1
|
|
31
|
+
|
|
32
|
+
# Empty if using default repository
|
|
33
|
+
repository:
|
|
34
|
+
# Empty if using tag "latest"
|
|
35
|
+
tag:
|
|
36
|
+
|
|
37
|
+
redis:
|
|
38
|
+
name: redis
|
|
39
|
+
image: "redis:alpine"
|
|
40
|
+
# Run redis with least privilege.
|
|
41
|
+
securityContext:
|
|
42
|
+
runAsUser: 999
|
|
43
|
+
runAsGroup: 1000
|
|
44
|
+
runAsNonRoot: true
|
|
45
|
+
allowPrivilegeEscalation: false
|
|
46
|
+
readOnlyRootFilesystem: true
|
|
47
|
+
capabilities:
|
|
48
|
+
drop:
|
|
49
|
+
- ALL
|
|
50
|
+
# resources: cpu/memory requests and limits for redis
|
|
51
|
+
resources: {}
|
|
52
|
+
|
|
53
|
+
# Empty if using default repository
|
|
54
|
+
repository:
|
|
55
|
+
# Empty if using tag "latest"
|
|
56
|
+
tag:
|
|
57
|
+
replicas: 1
|
|
58
|
+
port: 6379
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import gc
|
|
1
2
|
import json
|
|
2
3
|
import logging
|
|
3
4
|
import os
|
|
@@ -5,6 +6,7 @@ import os
|
|
|
5
6
|
from time import time
|
|
6
7
|
|
|
7
8
|
from celery import Celery, chord
|
|
9
|
+
from celery.canvas import signature
|
|
8
10
|
from celery.app import trace
|
|
9
11
|
|
|
10
12
|
from rich.logging import RichHandler
|
|
@@ -61,9 +63,10 @@ app.conf.update({
|
|
|
61
63
|
'result_backend': CONFIG.celery.result_backend,
|
|
62
64
|
'result_expires': CONFIG.celery.result_expires,
|
|
63
65
|
'result_backend_transport_options': json.loads(CONFIG.celery.result_backend_transport_options) if CONFIG.celery.result_backend_transport_options else {}, # noqa: E501
|
|
64
|
-
'result_extended':
|
|
66
|
+
'result_extended': not CONFIG.addons.mongodb.enabled,
|
|
65
67
|
'result_backend_thread_safe': True,
|
|
66
68
|
'result_serializer': 'pickle',
|
|
69
|
+
'result_accept_content': ['application/x-python-serialize'],
|
|
67
70
|
|
|
68
71
|
# Task config
|
|
69
72
|
'task_acks_late': CONFIG.celery.task_acks_late,
|
|
@@ -81,6 +84,11 @@ app.conf.update({
|
|
|
81
84
|
'task_store_eager_result': True,
|
|
82
85
|
'task_send_sent_event': CONFIG.celery.task_send_sent_event,
|
|
83
86
|
'task_serializer': 'pickle',
|
|
87
|
+
'task_accept_content': ['application/x-python-serialize'],
|
|
88
|
+
|
|
89
|
+
# Event config
|
|
90
|
+
'event_serializer': 'pickle',
|
|
91
|
+
'event_accept_content': ['application/x-python-serialize'],
|
|
84
92
|
|
|
85
93
|
# Worker config
|
|
86
94
|
# 'worker_direct': True, # TODO: consider enabling this to allow routing to specific workers
|
|
@@ -168,6 +176,12 @@ def run_scan(self, args=[], kwargs={}):
|
|
|
168
176
|
|
|
169
177
|
@app.task(bind=True)
|
|
170
178
|
def run_command(self, results, name, targets, opts={}):
|
|
179
|
+
# Set Celery request id in context
|
|
180
|
+
context = opts.get('context', {})
|
|
181
|
+
context['celery_id'] = self.request.id
|
|
182
|
+
context['worker_name'] = os.environ.get('WORKER_NAME', 'unknown')
|
|
183
|
+
|
|
184
|
+
# Set routing key in context
|
|
171
185
|
if IN_CELERY_WORKER_PROCESS:
|
|
172
186
|
quiet = not CONFIG.cli.worker_command_verbose
|
|
173
187
|
opts.update({
|
|
@@ -179,15 +193,13 @@ def run_command(self, results, name, targets, opts={}):
|
|
|
179
193
|
'quiet': quiet
|
|
180
194
|
})
|
|
181
195
|
routing_key = self.request.delivery_info['routing_key']
|
|
196
|
+
context['routing_key'] = routing_key
|
|
182
197
|
debug(f'Task "{name}" running with routing key "{routing_key}"', sub='celery.state')
|
|
183
198
|
|
|
184
199
|
# Flatten + dedupe + filter results
|
|
185
200
|
results = forward_results(results)
|
|
186
201
|
|
|
187
|
-
# Set
|
|
188
|
-
context = opts.get('context', {})
|
|
189
|
-
context['celery_id'] = self.request.id
|
|
190
|
-
context['worker_name'] = os.environ.get('WORKER_NAME', 'unknown')
|
|
202
|
+
# Set task opts
|
|
191
203
|
opts['context'] = context
|
|
192
204
|
opts['results'] = results
|
|
193
205
|
opts['sync'] = True
|
|
@@ -204,10 +216,13 @@ def run_command(self, results, name, targets, opts={}):
|
|
|
204
216
|
# Chunk task if needed
|
|
205
217
|
if chunk_it:
|
|
206
218
|
if IN_CELERY_WORKER_PROCESS:
|
|
207
|
-
console.print(Info(message=f'Task {name} requires chunking
|
|
208
|
-
|
|
219
|
+
console.print(Info(message=f'Task {name} requires chunking'))
|
|
220
|
+
workflow = break_task(task, opts, results=results)
|
|
221
|
+
if IN_CELERY_WORKER_PROCESS:
|
|
222
|
+
console.print(Info(message=f'Task {name} successfully broken into {len(workflow)} chunks'))
|
|
209
223
|
update_state(self, task, force=True)
|
|
210
|
-
|
|
224
|
+
console.print(Info(message=f'Task {name} updated state, replacing task with Celery chord workflow'))
|
|
225
|
+
return replace(self, workflow)
|
|
211
226
|
|
|
212
227
|
# Update state live
|
|
213
228
|
for _ in task:
|
|
@@ -327,6 +342,52 @@ def is_celery_worker_alive():
|
|
|
327
342
|
return result
|
|
328
343
|
|
|
329
344
|
|
|
345
|
+
def replace(task_instance, sig):
|
|
346
|
+
"""Replace this task, with a new task inheriting the task id.
|
|
347
|
+
|
|
348
|
+
Execution of the host task ends immediately and no subsequent statements
|
|
349
|
+
will be run.
|
|
350
|
+
|
|
351
|
+
.. versionadded:: 4.0
|
|
352
|
+
|
|
353
|
+
Arguments:
|
|
354
|
+
sig (Signature): signature to replace with.
|
|
355
|
+
visitor (StampingVisitor): Visitor API object.
|
|
356
|
+
|
|
357
|
+
Raises:
|
|
358
|
+
~@Ignore: This is always raised when called in asynchronous context.
|
|
359
|
+
It is best to always use ``return self.replace(...)`` to convey
|
|
360
|
+
to the reader that the task won't continue after being replaced.
|
|
361
|
+
"""
|
|
362
|
+
console.print('Replacing task')
|
|
363
|
+
chord = task_instance.request.chord
|
|
364
|
+
sig.freeze(task_instance.request.id)
|
|
365
|
+
replaced_task_nesting = task_instance.request.get('replaced_task_nesting', 0) + 1
|
|
366
|
+
sig.set(
|
|
367
|
+
chord=chord,
|
|
368
|
+
group_id=task_instance.request.group,
|
|
369
|
+
group_index=task_instance.request.group_index,
|
|
370
|
+
root_id=task_instance.request.root_id,
|
|
371
|
+
replaced_task_nesting=replaced_task_nesting
|
|
372
|
+
)
|
|
373
|
+
import psutil
|
|
374
|
+
import os
|
|
375
|
+
process = psutil.Process(os.getpid())
|
|
376
|
+
length = len(task_instance.request.chain) if task_instance.request.chain else 0
|
|
377
|
+
console.print(f'Adding {length} chain tasks from request chain')
|
|
378
|
+
for ix, t in enumerate(reversed(task_instance.request.chain or [])):
|
|
379
|
+
console.print(f'Adding chain task {t.name} from request chain ({ix + 1}/{length})')
|
|
380
|
+
chain_task = signature(t, app=task_instance.app)
|
|
381
|
+
chain_task.set(replaced_task_nesting=replaced_task_nesting)
|
|
382
|
+
sig |= chain_task
|
|
383
|
+
del chain_task
|
|
384
|
+
del t
|
|
385
|
+
memory_bytes = process.memory_info().rss
|
|
386
|
+
console.print(f'Memory usage: {memory_bytes / 1024 / 1024:.2f} MB (chain task {ix + 1}/{length})')
|
|
387
|
+
gc.collect()
|
|
388
|
+
return task_instance.on_replace(sig)
|
|
389
|
+
|
|
390
|
+
|
|
330
391
|
def break_task(task, task_opts, results=[]):
|
|
331
392
|
"""Break a task into multiple of the same type."""
|
|
332
393
|
chunks = task.inputs
|
|
@@ -370,16 +431,21 @@ def break_task(task, task_opts, results=[]):
|
|
|
370
431
|
task_id = sig.freeze().task_id
|
|
371
432
|
full_name = f'{task.name}_{ix + 1}'
|
|
372
433
|
task.add_subtask(task_id, task.name, full_name)
|
|
373
|
-
info = Info(message=f'Celery chunked task created: {task_id}')
|
|
434
|
+
info = Info(message=f'Celery chunked task created ({ix + 1} / {len(chunks)}): {task_id}')
|
|
374
435
|
task.add_result(info)
|
|
375
436
|
sigs.append(sig)
|
|
376
437
|
|
|
377
438
|
# Mark main task as async since it's being chunked
|
|
378
439
|
task.sync = False
|
|
440
|
+
task.results = []
|
|
441
|
+
task.uuids = set()
|
|
442
|
+
console.print(Info(message=f'Task {task.unique_name} is now async, building chord with{len(sigs)} chunks'))
|
|
443
|
+
console.print(Info(message=f'Results: {results}'))
|
|
379
444
|
|
|
380
445
|
# Build Celery workflow
|
|
381
446
|
workflow = chord(
|
|
382
447
|
tuple(sigs),
|
|
383
448
|
mark_runner_completed.s(runner=task).set(queue='results')
|
|
384
449
|
)
|
|
450
|
+
console.print(Info(message=f'Task {task.unique_name} chord built with {len(sigs)} chunks, returning workflow'))
|
|
385
451
|
return workflow
|
|
@@ -92,8 +92,9 @@ def task_postrun_handler(**kwargs):
|
|
|
92
92
|
|
|
93
93
|
# Get sender name from kwargs
|
|
94
94
|
sender_name = kwargs['sender'].name
|
|
95
|
+
# console.print(Info(message=f'Task postrun handler --> Sender name: {sender_name}'))
|
|
95
96
|
|
|
96
|
-
if CONFIG.celery.worker_kill_after_task and sender_name.startswith('secator.'):
|
|
97
|
+
if CONFIG.celery.worker_kill_after_task and (sender_name.startswith('secator.') or sender_name.startswith('api.')):
|
|
97
98
|
worker_name = os.environ.get('WORKER_NAME', 'unknown')
|
|
98
99
|
console.print(Info(message=f'Shutdown worker {worker_name} since config celery.worker_kill_after_task is set.'))
|
|
99
100
|
kill_worker(parent=True)
|
|
@@ -134,7 +134,10 @@ for config in SCANS:
|
|
|
134
134
|
@click.option('--stop', is_flag=True, help='Stop a worker in dev mode (celery multi).')
|
|
135
135
|
@click.option('--show', is_flag=True, help='Show command (celery multi).')
|
|
136
136
|
@click.option('--use-command-runner', is_flag=True, default=False, help='Use command runner to run the command.')
|
|
137
|
-
|
|
137
|
+
@click.option('--without-gossip', is_flag=True)
|
|
138
|
+
@click.option('--without-mingle', is_flag=True)
|
|
139
|
+
@click.option('--without-heartbeat', is_flag=True)
|
|
140
|
+
def worker(hostname, concurrency, reload, queue, pool, quiet, loglevel, check, dev, stop, show, use_command_runner, without_gossip, without_mingle, without_heartbeat): # noqa: E501
|
|
138
141
|
"""Run a worker."""
|
|
139
142
|
|
|
140
143
|
# Check Celery addon is installed
|
|
@@ -182,6 +185,9 @@ def worker(hostname, concurrency, reload, queue, pool, quiet, loglevel, check, d
|
|
|
182
185
|
cmd += f' -P {pool}' if pool else ''
|
|
183
186
|
cmd += f' -c {concurrency}' if concurrency else ''
|
|
184
187
|
cmd += f' -l {loglevel}' if loglevel else ''
|
|
188
|
+
cmd += ' --without-mingle' if without_mingle else ''
|
|
189
|
+
cmd += ' --without-gossip' if without_gossip else ''
|
|
190
|
+
cmd += ' --without-heartbeat' if without_heartbeat else ''
|
|
185
191
|
|
|
186
192
|
if reload:
|
|
187
193
|
patterns = "celery.py;tasks/*.py;runners/*.py;serializers/*.py;output_types/*.py;hooks/*.py;exporters/*.py"
|
|
@@ -100,6 +100,7 @@ class Security(StrictModel):
|
|
|
100
100
|
allow_local_file_access: bool = True
|
|
101
101
|
auto_install_commands: bool = True
|
|
102
102
|
force_source_install: bool = False
|
|
103
|
+
memory_limit_mb: int = -1
|
|
103
104
|
|
|
104
105
|
|
|
105
106
|
class HTTP(StrictModel):
|
|
@@ -144,7 +145,7 @@ class Wordlists(StrictModel):
|
|
|
144
145
|
templates: Dict[str, str] = {
|
|
145
146
|
'bo0m_fuzz': 'https://raw.githubusercontent.com/Bo0oM/fuzz.txt/master/fuzz.txt',
|
|
146
147
|
'combined_subdomains': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/combined_subdomains.txt', # noqa: E501
|
|
147
|
-
'directory_list_small': 'https://
|
|
148
|
+
'directory_list_small': 'https://gist.githubusercontent.com/sl4v/c087e36164e74233514b/raw/c51a811c70bbdd87f4725521420cc30e7232b36d/directory-list-2.3-small.txt', # noqa: E501
|
|
148
149
|
}
|
|
149
150
|
lists: Dict[str, List[str]] = {}
|
|
150
151
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type: workflow
|
|
2
|
+
name: user_hunt
|
|
3
|
+
alias: userhunt
|
|
4
|
+
description: User account search
|
|
5
|
+
tags: [user_account]
|
|
6
|
+
input_types:
|
|
7
|
+
- slug
|
|
8
|
+
- string
|
|
9
|
+
- email
|
|
10
|
+
|
|
11
|
+
tasks:
|
|
12
|
+
_group/hunt_users:
|
|
13
|
+
maigret:
|
|
14
|
+
description: Hunt user accounts
|
|
15
|
+
targets_:
|
|
16
|
+
- type: target
|
|
17
|
+
field: name
|
|
18
|
+
condition: target.type != 'email'
|
|
19
|
+
h8mail:
|
|
20
|
+
description: Find password leaks
|
|
21
|
+
targets_:
|
|
22
|
+
- type: target
|
|
23
|
+
field: name
|
|
24
|
+
condition: target.type == 'email'
|
|
@@ -5,15 +5,28 @@ description: Wordpress vulnerability scan
|
|
|
5
5
|
tags: [http, wordpress, vulnerability]
|
|
6
6
|
input_types:
|
|
7
7
|
- url
|
|
8
|
+
- ip
|
|
9
|
+
- host
|
|
10
|
+
- host:port
|
|
8
11
|
|
|
9
12
|
tasks:
|
|
13
|
+
httpx:
|
|
14
|
+
description: URL probe
|
|
15
|
+
tech_detect: True
|
|
16
|
+
|
|
10
17
|
_group/hunt_wordpress:
|
|
11
18
|
nuclei:
|
|
12
19
|
description: Nuclei Wordpress scan
|
|
13
20
|
tags: [wordpress]
|
|
21
|
+
targets_:
|
|
22
|
+
- url.url
|
|
14
23
|
|
|
15
24
|
wpscan:
|
|
16
25
|
description: WPScan
|
|
26
|
+
targets_:
|
|
27
|
+
- url.url
|
|
17
28
|
|
|
18
29
|
wpprobe:
|
|
19
30
|
description: WPProbe
|
|
31
|
+
targets_:
|
|
32
|
+
- url.url
|
|
@@ -14,6 +14,16 @@ ITEMS_TO_SEND = {
|
|
|
14
14
|
'url': ['screenshot_path', 'stored_response_path']
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
_gcs_client = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_gcs_client():
|
|
21
|
+
"""Get or create GCS client"""
|
|
22
|
+
global _gcs_client
|
|
23
|
+
if _gcs_client is None:
|
|
24
|
+
_gcs_client = storage.Client()
|
|
25
|
+
return _gcs_client
|
|
26
|
+
|
|
17
27
|
|
|
18
28
|
def process_item(self, item):
|
|
19
29
|
if item._type not in ITEMS_TO_SEND.keys():
|
|
@@ -39,7 +49,7 @@ def process_item(self, item):
|
|
|
39
49
|
def upload_blob(bucket_name, source_file_name, destination_blob_name):
|
|
40
50
|
"""Uploads a file to the bucket."""
|
|
41
51
|
start_time = time()
|
|
42
|
-
storage_client =
|
|
52
|
+
storage_client = get_gcs_client()
|
|
43
53
|
bucket = storage_client.bucket(bucket_name)
|
|
44
54
|
blob = bucket.blob(destination_blob_name)
|
|
45
55
|
with open(source_file_name, 'rb') as f:
|