mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-08 22:21:35 +00:00
test(ci): add secret scan test and CI job to prevent hardcoded credentials
- Add unit test that scans Python source for Base64 Basic Auth patterns that would be flagged by secret scanners like GitGuardian/ggshield - Add secret-scan job to the linting CI workflow that runs the test on every PR and optionally runs ggshield if GITGUARDIAN_API_KEY is set Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
283a978575
commit
b667d79e01
2 changed files with 101 additions and 0 deletions
27
.github/workflows/test-linting.yml
vendored
27
.github/workflows/test-linting.yml
vendored
|
|
@ -74,3 +74,30 @@ jobs:
|
|||
- name: Check import safety
|
||||
run: |
|
||||
poetry run python -c "from litellm import *" || (echo '🚨 import failed, this means you introduced unprotected imports! 🚨'; exit 1)
|
||||
|
||||
secret-scan:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Run secret scan test
|
||||
run: |
|
||||
pip install pytest
|
||||
pytest tests/litellm/test_no_hardcoded_secrets.py -v
|
||||
|
||||
- name: Run ggshield secret scan
|
||||
if: env.GITGUARDIAN_API_KEY != ''
|
||||
env:
|
||||
GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }}
|
||||
run: |
|
||||
pip install ggshield
|
||||
ggshield secret scan repo .
|
||||
|
|
|
|||
74
tests/litellm/test_no_hardcoded_secrets.py
Normal file
74
tests/litellm/test_no_hardcoded_secrets.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
"""
|
||||
Test to ensure no hardcoded secrets exist in the codebase.
|
||||
|
||||
This catches Base64 Basic Authentication strings and other secret patterns
|
||||
that would be flagged by secret scanners like GitGuardian/ggshield.
|
||||
"""
|
||||
|
||||
import base64
|
||||
import os
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
# Root of the litellm package
|
||||
LITELLM_ROOT = os.path.join(os.path.dirname(__file__), "..", "..", "litellm")
|
||||
|
||||
# Regex for Base64 Basic Auth patterns: 'Basic <base64string>'
|
||||
# Matches strings like: Basic YW55dGhpbmc6YW55dGhpbmc=
|
||||
BASIC_AUTH_PATTERN = re.compile(
|
||||
r"""['"]Basic\s+([A-Za-z0-9+/]{16,}={0,2})['"]"""
|
||||
)
|
||||
|
||||
# Directories/files to skip
|
||||
SKIP_DIRS = {"__pycache__", ".git", "node_modules", ".mypy_cache", ".ruff_cache"}
|
||||
|
||||
|
||||
def _is_real_base64_credentials(match_str: str) -> bool:
|
||||
"""Check if a Base64 string decodes to something that looks like credentials (user:pass)."""
|
||||
try:
|
||||
# Add padding if needed - Base64 strings may omit trailing '='
|
||||
padded = match_str + "=" * (-len(match_str) % 4)
|
||||
decoded = base64.b64decode(padded).decode("utf-8", errors="ignore")
|
||||
return ":" in decoded
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def _collect_python_files():
|
||||
"""Collect all Python files under the litellm package."""
|
||||
python_files = []
|
||||
for root, dirs, files in os.walk(LITELLM_ROOT):
|
||||
dirs[:] = [d for d in dirs if d not in SKIP_DIRS]
|
||||
for f in files:
|
||||
if f.endswith(".py"):
|
||||
python_files.append(os.path.join(root, f))
|
||||
return python_files
|
||||
|
||||
|
||||
def test_no_hardcoded_basic_auth_secrets():
|
||||
"""Ensure no hardcoded Base64 Basic Authentication credentials exist in source code.
|
||||
|
||||
This test prevents regressions like the one caught by T-Mobile's GitGuardian
|
||||
container scan, where a docstring contained a literal Base64-encoded
|
||||
'Basic YW55dGhpbmc6YW55dGhpbmc' string (anything:anything).
|
||||
"""
|
||||
violations = []
|
||||
|
||||
for filepath in _collect_python_files():
|
||||
with open(filepath, "r", errors="ignore") as f:
|
||||
for line_num, line in enumerate(f, start=1):
|
||||
for match in BASIC_AUTH_PATTERN.finditer(line):
|
||||
b64_value = match.group(1)
|
||||
if _is_real_base64_credentials(b64_value):
|
||||
rel_path = os.path.relpath(filepath, LITELLM_ROOT)
|
||||
violations.append(
|
||||
f" {rel_path}:{line_num}: {match.group(0)}"
|
||||
)
|
||||
|
||||
assert not violations, (
|
||||
"Found hardcoded Base64 Basic Auth credentials that will be flagged by "
|
||||
"secret scanners (e.g. GitGuardian/ggshield):\n"
|
||||
+ "\n".join(violations)
|
||||
+ "\n\nUse placeholders like '<base64(username:password)>' in comments/docs instead."
|
||||
)
|
||||
Loading…
Add table
Reference in a new issue