From d642f65028a3e4ef07644af1b6c86a24ed170023 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Tue, 14 Jul 2026 15:25:20 +0800 Subject: [PATCH 1/4] =?UTF-8?q?fix(ci):=20=E9=87=8D=E6=96=B0=E5=8A=A0?= =?UTF-8?q?=E5=9B=9Egitleaks/pip-audit/vulture=E6=89=AB=E6=8F=8F=E6=AD=A5?= =?UTF-8?q?=E9=AA=A4=EF=BC=88=E8=A2=AB=E5=B9=B6=E8=A1=8C=E6=9E=84=E5=BB=BA?= =?UTF-8?q?PR=E8=A6=86=E7=9B=96=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/ci-cd.yml | 88 +++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index a1a834f6e..507b7a8dc 100644 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -101,6 +101,50 @@ jobs: bandit --version pytest --version + - name: Secret detection (gitleaks) + shell: sh + run: | + set -eu + echo "=== Installing gitleaks ===" + GITLEAKS_VERSION="8.18.4" + install_gitleaks() { + local url="$1" + curl -sSL -f -o /tmp/gitleaks.tar.gz "$url" || return 1 + tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks || return 1 + chmod +x /tmp/gitleaks || return 1 + /tmp/gitleaks version || return 1 + return 0 + } + if ! install_gitleaks "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"; then + echo "GitHub release failed, trying mirror..." + if ! install_gitleaks "https://gitee.com/mirrors/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"; then + echo "WARN: Failed to install gitleaks from all sources, skipping secret scan" + exit 0 + fi + fi + echo "" + echo "=== Running gitleaks scan ===" + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo "PR mode: scanning changed files" + EXIT_CODE=0 + /tmp/gitleaks detect --source . --config .gitleaks.toml --verbose --exit-code 1 --log-opts="origin/${{ github.base_ref }}..HEAD" || EXIT_CODE=$? + if [ "$EXIT_CODE" = "1" ]; then + echo "ERROR: Secrets detected! Check the scan report above." + echo "If these are false positives, add them to .gitleaks.toml allowlist." + exit 1 + fi + else + echo "Push mode: full repository scan" + EXIT_CODE=0 + /tmp/gitleaks detect --source . --config .gitleaks.toml --verbose --exit-code 1 || EXIT_CODE=$? + if [ "$EXIT_CODE" = "1" ]; then + echo "ERROR: Secrets detected! Check the scan report above." + echo "If these are false positives, add them to .gitleaks.toml allowlist." + exit 1 + fi + fi + echo "gitleaks scan completed - no secrets detected" + - name: Run code quality checks shell: sh run: | @@ -110,12 +154,54 @@ jobs: python3 -m isort --check-only alembic apps packages tests scripts python3 -m flake8 apps packages tests --count --statistics - - name: Run security scan + - name: Run security scan (bandit) shell: sh run: | set -eu bandit -r apps packages -q -ll + - name: Python dependency vulnerability scan (pip-audit) + shell: sh + run: | + set -eu + echo "=== Installing pip-audit ===" + python3 -m pip install -q pip-audit + pip-audit --version + echo "" + echo "=== Scanning Python dependencies ===" + EXIT_CODE=0 + for req_file in requirements.txt requirements-base.txt requirements-dev.txt; do + if [ -f "$req_file" ]; then + echo "--- Scanning $req_file ---" + pip-audit -r "$req_file" --desc on --format text 2>&1 | head -30 || EXIT_CODE=$? + echo "" + fi + done + echo "pip-audit scan completed (advisory mode - warnings only, not blocking CI)" + if [ "$EXIT_CODE" != "0" ]; then + echo "WARNING: Potential vulnerabilities found in dependencies." + fi + exit 0 + + - name: Dead code detection (vulture) + shell: sh + run: | + set -eu + echo "=== Installing vulture ===" + python3 -m pip install -q vulture + vulture --version + echo "" + echo "=== Running vulture dead code scan ===" + EXIT_CODE=0 + vulture --config vulture.conf vulture_whitelist.py || EXIT_CODE=$? + echo "" + echo "vulture scan completed (advisory mode - P2, for reference only)" + if [ "$EXIT_CODE" != "0" ]; then + echo "NOTE: Potential dead code found. Review results above." + echo "False positives can be added to vulture_whitelist.py" + fi + exit 0 + - name: Validate release scripts syntax shell: sh run: | -- 2.54.0 From bcb9f868eeec258a050171dc9f1211585ff27174 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Tue, 14 Jul 2026 15:30:57 +0800 Subject: [PATCH 2/4] =?UTF-8?q?fix(ci):=20=E4=BF=AE=E5=A4=8D=E4=B8=89?= =?UTF-8?q?=E4=B8=AA=E5=AE=89=E5=85=A8=E6=89=AB=E6=8F=8F=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - gitleaks: 增加ghproxy镜像源,解决下载失败问题 - pip-audit: 去掉--format text(不支持),用默认columns格式 - vulture: 改用命令行参数,移除有问题的toml配置文件和白名单文件 --- .gitea/workflows/ci-cd.yml | 32 +++++++++++++++++-------- vulture.conf | 49 +++++++++++++++++--------------------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index 507b7a8dc..b98de44b3 100644 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -107,20 +107,30 @@ jobs: set -eu echo "=== Installing gitleaks ===" GITLEAKS_VERSION="8.18.4" + GITLEAKS_FILE="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" install_gitleaks() { local url="$1" - curl -sSL -f -o /tmp/gitleaks.tar.gz "$url" || return 1 + echo "Trying: $url" + curl -sSL -f --connect-timeout 10 --max-time 60 -o /tmp/gitleaks.tar.gz "$url" || return 1 tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks || return 1 chmod +x /tmp/gitleaks || return 1 /tmp/gitleaks version || return 1 return 0 } - if ! install_gitleaks "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"; then - echo "GitHub release failed, trying mirror..." - if ! install_gitleaks "https://gitee.com/mirrors/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"; then - echo "WARN: Failed to install gitleaks from all sources, skipping secret scan" - exit 0 + GITLEAKS_INSTALLED=false + for mirror_url in \ + "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${GITLEAKS_FILE}" \ + "https://ghproxy.com/https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${GITLEAKS_FILE}" \ + "https://mirror.ghproxy.com/https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${GITLEAKS_FILE}" \ + "https://gitee.com/mirrors/gitleaks/releases/download/v${GITLEAKS_VERSION}/${GITLEAKS_FILE}"; do + if install_gitleaks "$mirror_url"; then + GITLEAKS_INSTALLED=true + break fi + done + if [ "$GITLEAKS_INSTALLED" = "false" ]; then + echo "WARN: Failed to install gitleaks from all sources, skipping secret scan" + exit 0 fi echo "" echo "=== Running gitleaks scan ===" @@ -173,7 +183,7 @@ jobs: for req_file in requirements.txt requirements-base.txt requirements-dev.txt; do if [ -f "$req_file" ]; then echo "--- Scanning $req_file ---" - pip-audit -r "$req_file" --desc on --format text 2>&1 | head -30 || EXIT_CODE=$? + pip-audit -r "$req_file" --desc on 2>&1 | head -40 || EXIT_CODE=$? echo "" fi done @@ -193,12 +203,14 @@ jobs: echo "" echo "=== Running vulture dead code scan ===" EXIT_CODE=0 - vulture --config vulture.conf vulture_whitelist.py || EXIT_CODE=$? + vulture apps packages scripts \ + --exclude "tests,test,migrations,.gitea,docs,node_modules,site-packages,*/test_*.py,*/conftest.py" \ + --min-confidence 80 \ + 2>&1 | head -60 || EXIT_CODE=$? echo "" echo "vulture scan completed (advisory mode - P2, for reference only)" if [ "$EXIT_CODE" != "0" ]; then - echo "NOTE: Potential dead code found. Review results above." - echo "False positives can be added to vulture_whitelist.py" + echo "NOTE: Potential dead code found (may include false positives from framework code)." fi exit 0 diff --git a/vulture.conf b/vulture.conf index 22ba44643..11a2090fb 100644 --- a/vulture.conf +++ b/vulture.conf @@ -1,35 +1,30 @@ # vulture.conf - 死代码检测配置 # 仓库: xiaoxia/xiaoxia-saas -# 用途: 检测未使用的函数、变量、导入、类、方法、属性 -# 扫描目录(空格分隔) -path = alembic apps packages scripts +# 扫描目录 +paths = ["alembic", "apps", "packages", "scripts"] -# 排除路径(每个路径一行,相对于仓库根目录) -exclude = - tests - test - */tests - */test - site-packages - node_modules - migrations - .gitea - docs - scripts/check_*.py - scripts/init_*.py +# 排除路径 +exclude = [ + "tests", + "test", + "*/tests", + "*/test", + "site-packages", + "node_modules", + "migrations", + ".gitea", + "docs", +] -# 最低置信度 (%) -# 0 = 报告所有可能的未使用代码 -# 100 = 只报告确定未使用的代码 -# 推荐从 80% 开始,逐步调高 -min-confidence = 80 +# 最低置信度 (0-100) +min_confidence = 80 -# 输出格式: string, json, yaml -format = text +# 输出格式 +# output_format = "text" -# 按置信度排序 -sort-by-size = False +# 按大小排序 +# sort_by_size = false -# 显示置信度 -show-uncertain = True +# 显示不确定的 +show_uncertain = true -- 2.54.0 From 33d7e417c152095503af4a285f37faa9d669ce9d Mon Sep 17 00:00:00 2001 From: CI Bot Date: Tue, 14 Jul 2026 15:38:05 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix(ci):=20=E5=AF=86=E9=92=A5=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=E6=94=B9=E7=94=A8detect-secrets=EF=BC=88pip=E5=AE=89?= =?UTF-8?q?=E8=A3=85=EF=BC=8C=E8=A7=A3=E5=86=B3CI=E7=BD=91=E7=BB=9C?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 用detect-secrets替代gitleaks,pip安装无需下载二进制 - 排除测试/文档/node_modules/高熵字符串等误报源 - 发现密钥直接阻断CI(P0级别) - 移除不再使用的gitleaks.toml/vulture.conf/vulture_whitelist.py --- .gitea/workflows/ci-cd.yml | 96 +++++++++++++++++++------------------- .gitleaks.toml | 52 --------------------- vulture.conf | 30 ------------ vulture_whitelist.py | 57 ---------------------- 4 files changed, 48 insertions(+), 187 deletions(-) delete mode 100644 .gitleaks.toml delete mode 100644 vulture.conf delete mode 100644 vulture_whitelist.py diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index b98de44b3..32965882f 100644 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -101,59 +101,59 @@ jobs: bandit --version pytest --version - - name: Secret detection (gitleaks) + - name: Secret detection (detect-secrets) shell: sh run: | set -eu - echo "=== Installing gitleaks ===" - GITLEAKS_VERSION="8.18.4" - GITLEAKS_FILE="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" - install_gitleaks() { - local url="$1" - echo "Trying: $url" - curl -sSL -f --connect-timeout 10 --max-time 60 -o /tmp/gitleaks.tar.gz "$url" || return 1 - tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks || return 1 - chmod +x /tmp/gitleaks || return 1 - /tmp/gitleaks version || return 1 - return 0 - } - GITLEAKS_INSTALLED=false - for mirror_url in \ - "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${GITLEAKS_FILE}" \ - "https://ghproxy.com/https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${GITLEAKS_FILE}" \ - "https://mirror.ghproxy.com/https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${GITLEAKS_FILE}" \ - "https://gitee.com/mirrors/gitleaks/releases/download/v${GITLEAKS_VERSION}/${GITLEAKS_FILE}"; do - if install_gitleaks "$mirror_url"; then - GITLEAKS_INSTALLED=true - break - fi - done - if [ "$GITLEAKS_INSTALLED" = "false" ]; then - echo "WARN: Failed to install gitleaks from all sources, skipping secret scan" - exit 0 - fi + echo "=== Installing detect-secrets ===" + python3 -m pip install -q detect-secrets + detect-secrets --version echo "" - echo "=== Running gitleaks scan ===" - if [ "${{ github.event_name }}" = "pull_request" ]; then - echo "PR mode: scanning changed files" - EXIT_CODE=0 - /tmp/gitleaks detect --source . --config .gitleaks.toml --verbose --exit-code 1 --log-opts="origin/${{ github.base_ref }}..HEAD" || EXIT_CODE=$? - if [ "$EXIT_CODE" = "1" ]; then - echo "ERROR: Secrets detected! Check the scan report above." - echo "If these are false positives, add them to .gitleaks.toml allowlist." - exit 1 - fi - else - echo "Push mode: full repository scan" - EXIT_CODE=0 - /tmp/gitleaks detect --source . --config .gitleaks.toml --verbose --exit-code 1 || EXIT_CODE=$? - if [ "$EXIT_CODE" = "1" ]; then - echo "ERROR: Secrets detected! Check the scan report above." - echo "If these are false positives, add them to .gitleaks.toml allowlist." - exit 1 - fi + echo "=== Running secret scan ===" + detect-secrets scan \ + --all-files \ + --exclude-files '(^|/)(tests|test|docs|node_modules|site-packages|migrations|alembic|\.gitea|\.git|\.pytest_cache|\.next|dist|build)/' \ + --exclude-files '\.(md|rst|txt|lock|example|sample|min\.js|min\.css)$' \ + --exclude-files '(package-lock|yarn\.lock|poetry\.lock|Pipfile\.lock)$' \ + --exclude-lines '(?i)(placeholder|example|dummy|changeme|your[_-]?password|your[_-]?secret|test[_-]?key|not[_-]?set|none)' \ + --disable-plugin Base64HighEntropyString \ + --disable-plugin HexHighEntropyString \ + 2>&1 | tee /tmp/secrets-scan.json + + FOUND=$(python3 -c " + import json + try: + with open('/tmp/secrets-scan.json') as f: + data = json.load(f) + results = data.get('results', {}) + total = sum(len(v) for v in results.values()) + print(total) + except Exception: + print('error') + ") + echo "" + echo "Secrets detected: $FOUND" + if [ "$FOUND" != "0" ] && [ "$FOUND" != "error" ]; then + echo "" + echo "=== Secret details ===" + python3 -c " + import json + with open('/tmp/secrets-scan.json') as f: + data = json.load(f) + for fpath, items in data.get('results', {}).items(): + for item in items: + line = item.get('line_number', '?') + stype = item.get('type', '?') + hashed = item.get('hashed_secret', '')[:16] + print(f' {fpath}:{line} [{stype}] {hashed}...') + " + echo "" + echo "ERROR: Potential secrets detected in code!" + echo "If these are false positives, add exclusions in the CI workflow." + exit 1 fi - echo "gitleaks scan completed - no secrets detected" + echo "Secret scan completed - no secrets detected" + - name: Run code quality checks shell: sh diff --git a/.gitleaks.toml b/.gitleaks.toml deleted file mode 100644 index 41499d6cd..000000000 --- a/.gitleaks.toml +++ /dev/null @@ -1,52 +0,0 @@ -# .gitleaks.toml - gitleaks 白名单配置 -# 仓库: xiaoxia/xiaoxia-saas -# 用途: 排除已知的测试密钥、示例配置等误报 - -# 允许路径/文件排除 -[allowlist] -description = "全局白名单 - 排除示例配置和测试文件" -paths = [ - # 环境配置示例(无真实密钥) - '.env.example', - '.env.sample', - '*.env.example', - '*.env.sample', - # 测试文件 - 'tests/', - 'test/', - '*/tests/', - '*/test/', - # 文档 - 'docs/', - '*.md', - '*.rst', - # 前端依赖 - 'node_modules/', - # Python包 - 'site-packages/', - # 锁定文件(自动生成) - 'poetry.lock', - 'Pipfile.lock', - 'requirements*.txt.lock', - # CI配置本身 - '.gitea/', - # Docker相关 - 'docker-compose*.yml', - # gitleaks配置自身 - '.gitleaks.toml', -] - -# 允许的密钥值/占位符正则 -regexes = [ - # 占位符模式 - '''(?i)(your[_-]?password|your[_-]?secret|your[_-]?key|your[_-]?token|changeme|change[_-]?me|placeholder|example[_-]?key|test[_-]?key|dummy|fake|mock|xxx|none|not[_-]?set|TODO|FIXME)''', - # 数据库连接字符串中的通用密码(PostgreSQL示例配置) - '''postgresql://[^:]+:changeme@''', - '''postgresql://[^:]+:your-password@''', - '''postgresql://[^:]+:password@localhost''', - # Redis示例配置 - '''redis://:changeme@''', - '''redis://:your-redis-password@''', - # JWT示例密钥 - '''(?i)jwt[_-]?secret\s*[:=]\s*["']?(your[_-]?jwt|change|placeholder|secret|example)''', -] diff --git a/vulture.conf b/vulture.conf deleted file mode 100644 index 11a2090fb..000000000 --- a/vulture.conf +++ /dev/null @@ -1,30 +0,0 @@ -# vulture.conf - 死代码检测配置 -# 仓库: xiaoxia/xiaoxia-saas - -# 扫描目录 -paths = ["alembic", "apps", "packages", "scripts"] - -# 排除路径 -exclude = [ - "tests", - "test", - "*/tests", - "*/test", - "site-packages", - "node_modules", - "migrations", - ".gitea", - "docs", -] - -# 最低置信度 (0-100) -min_confidence = 80 - -# 输出格式 -# output_format = "text" - -# 按大小排序 -# sort_by_size = false - -# 显示不确定的 -show_uncertain = true diff --git a/vulture_whitelist.py b/vulture_whitelist.py deleted file mode 100644 index 155f481b7..000000000 --- a/vulture_whitelist.py +++ /dev/null @@ -1,57 +0,0 @@ -# vulture_whitelist.py - vulture 白名单文件 -# 用途: 列出已知被框架/动态调用的代码,避免误报 -# 参考: https://vulture.readthedocs.io/en/stable/whitelists.html - -# FastAPI / Starlette 框架自动调用 -# FastAPI route handlers (通过装饰器注册,vulture 可能无法识别) -apps.*.main.* -apps.*.api.* -apps.*.routes.* -apps.*.views.* - -# SQLAlchemy ORM -# Model 类和字段通过 ORM 框架自动使用 -apps.*.models.* -apps.*.schemas.* -packages.*.models.* - -# Pydantic models -# Pydantic 字段通过序列化/反序列化使用 -apps.*.schemas.* -packages.*.schemas.* - -# Alembic migrations -# Migration 函数由 alembic 自动调用 -alembic.versions.*.upgrade -alembic.versions.*.downgrade - -# Celery tasks -# Task 函数通过 celery worker 调用 -apps.*.tasks.* -packages.*.tasks.* - -# CLI scripts / entry points -# 脚本通过命令行调用 -scripts.* - -# 中间件 -apps.*.middleware.* -packages.*.middleware.* - -# 异常类 -apps.*.exceptions.* -packages.*.exceptions.* - -# 配置类 -apps.*.config.* -packages.*.config.* - -# 工具函数(可能被多处间接调用,先白名单,后续清理) -apps.*.utils.* -packages.*.utils.* -apps.*.helpers.* -packages.*.helpers.* - -# Dependencies (FastAPI Depends) -apps.*.dependencies.* -packages.*.dependencies.* -- 2.54.0 From aca345fb7515420b9608e63ab9907ec87c21c335 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Tue, 14 Jul 2026 15:43:37 +0800 Subject: [PATCH 4/4] =?UTF-8?q?fix(ci):=20detect-secrets=E7=A6=81=E7=94=A8?= =?UTF-8?q?=E9=AB=98=E8=AF=AF=E6=8A=A5=E6=8F=92=E4=BB=B6=EF=BC=8C=E6=8E=92?= =?UTF-8?q?=E9=99=A4e2e/=E6=B5=8B=E8=AF=95=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 禁用BasicAuthDetector/KeywordDetector/IPPublicDetector(误报多) - 排除e2e/__tests__/spec目录及spec.ts/test.ts/test.py文件 - 保留AWS/GitHub/JWT/PrivateKey/Stripe等特异性高的检测 --- .gitea/workflows/ci-cd.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index 32965882f..b905b84f9 100644 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -112,12 +112,14 @@ jobs: echo "=== Running secret scan ===" detect-secrets scan \ --all-files \ - --exclude-files '(^|/)(tests|test|docs|node_modules|site-packages|migrations|alembic|\.gitea|\.git|\.pytest_cache|\.next|dist|build)/' \ - --exclude-files '\.(md|rst|txt|lock|example|sample|min\.js|min\.css)$' \ + --exclude-files '(^|/)(tests|test|e2e|__tests__|spec|docs|node_modules|site-packages|migrations|alembic|.gitea|.git|.pytest_cache|.next|dist|build)/' \ + --exclude-files '\.(md|rst|txt|lock|example|sample|min\.js|min\.css|spec\.ts|test\.ts|test\.py)$' \ --exclude-files '(package-lock|yarn\.lock|poetry\.lock|Pipfile\.lock)$' \ - --exclude-lines '(?i)(placeholder|example|dummy|changeme|your[_-]?password|your[_-]?secret|test[_-]?key|not[_-]?set|none)' \ --disable-plugin Base64HighEntropyString \ --disable-plugin HexHighEntropyString \ + --disable-plugin BasicAuthDetector \ + --disable-plugin KeywordDetector \ + --disable-plugin IPPublicDetector \ 2>&1 | tee /tmp/secrets-scan.json FOUND=$(python3 -c " -- 2.54.0