Merge branch 'main' into litellm_fix_httpx_transport

This commit is contained in:
Krish Dholakia 2024-07-02 17:17:43 -07:00 committed by GitHub
commit d38f01e956
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
189 changed files with 8377 additions and 1087 deletions

View file

@ -66,7 +66,7 @@ jobs:
pip install "pydantic==2.7.1"
pip install "diskcache==5.6.1"
pip install "Pillow==10.3.0"
pip install "ijson==3.2.3"
pip install "jsonschema==4.22.0"
- save_cache:
paths:
- ./venv
@ -128,7 +128,7 @@ jobs:
pip install jinja2
pip install tokenizers
pip install openai
pip install ijson
pip install jsonschema
- run:
name: Run tests
command: |
@ -183,7 +183,7 @@ jobs:
pip install numpydoc
pip install prisma
pip install fastapi
pip install ijson
pip install jsonschema
pip install "httpx==0.24.1"
pip install "gunicorn==21.2.0"
pip install "anyio==3.7.1"
@ -212,6 +212,7 @@ jobs:
-e AWS_REGION_NAME=$AWS_REGION_NAME \
-e AUTO_INFER_REGION=True \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
-e LITELLM_LICENSE=$LITELLM_LICENSE \
-e LANGFUSE_PROJECT1_PUBLIC=$LANGFUSE_PROJECT1_PUBLIC \
-e LANGFUSE_PROJECT2_PUBLIC=$LANGFUSE_PROJECT2_PUBLIC \
-e LANGFUSE_PROJECT1_SECRET=$LANGFUSE_PROJECT1_SECRET \

View file

@ -50,7 +50,7 @@ Use `litellm.get_supported_openai_params()` for an updated list of params for ea
|Huggingface| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | |
|Openrouter| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | | | ✅ | | | | |
|AI21| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | |
|VertexAI| ✅ | ✅ | | ✅ | ✅ | | | | | | | | | | ✅ | | |
|VertexAI| ✅ | ✅ | | ✅ | ✅ | | | | | | | | | | ✅ | | |
|Bedrock| ✅ | ✅ | ✅ | ✅ | ✅ | | | | | | | | | | ✅ (for anthropic) | |
|Sagemaker| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | |
|TogetherAI| ✅ | ✅ | ✅ | ✅ | ✅ | | | | | | ✅ |

View file

@ -1,7 +1,21 @@
# Completion Token Usage & Cost
By default LiteLLM returns token usage in all completion requests ([See here](https://litellm.readthedocs.io/en/latest/output/))
However, we also expose some helper functions + **[NEW]** an API to calculate token usage across providers:
LiteLLM returns `response_cost` in all calls.
```python
from litellm import completion
response = litellm.completion(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "Hey, how's it going?"}],
mock_response="Hello world",
)
print(response._hidden_params["response_cost"])
```
LiteLLM also exposes some helper functions:
- `encode`: This encodes the text passed in, using the model-specific tokenizer. [**Jump to code**](#1-encode)
@ -23,7 +37,7 @@ However, we also expose some helper functions + **[NEW]** an API to calculate to
- `api.litellm.ai`: Live token + price count across [all supported models](https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json). [**Jump to code**](#10-apilitellmai)
📣 This is a community maintained list. Contributions are welcome! ❤️
📣 [This is a community maintained list](https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json). Contributions are welcome! ❤️
## Example Usage

View file

@ -2,26 +2,39 @@
For companies that need SSO, user management and professional support for LiteLLM Proxy
:::info
Interested in Enterprise? Schedule a meeting with us here 👉
[Talk to founders](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
:::
This covers:
- ✅ **Features under the [LiteLLM Commercial License (Content Mod, Custom Tags, etc.)](https://docs.litellm.ai/docs/proxy/enterprise)**
- ✅ [**Secure UI access with Single Sign-On**](../docs/proxy/ui.md#setup-ssoauth-for-ui)
- ✅ [**Audit Logs with retention policy**](../docs/proxy/enterprise.md#audit-logs)
- ✅ [**JWT-Auth**](../docs/proxy/token_auth.md)
- ✅ [**Control available public, private routes**](../docs/proxy/enterprise.md#control-available-public-private-routes)
- ✅ [**Guardrails, Content Moderation, PII Masking, Secret/API Key Masking**](../docs/proxy/enterprise.md#prompt-injection-detection---lakeraai)
- ✅ [**Prompt Injection Detection**](../docs/proxy/enterprise.md#prompt-injection-detection---lakeraai)
- ✅ [**Invite Team Members to access `/spend` Routes**](../docs/proxy/cost_tracking#allowing-non-proxy-admins-to-access-spend-endpoints)
- **Enterprise Features**
- **Security**
- ✅ [SSO for Admin UI](./proxy/ui#✨-enterprise-features)
- ✅ [Audit Logs with retention policy](./proxy/enterprise#audit-logs)
- ✅ [JWT-Auth](../docs/proxy/token_auth.md)
- ✅ [Control available public, private routes](./proxy/enterprise#control-available-public-private-routes)
- ✅ [[BETA] AWS Key Manager v2 - Key Decryption](./proxy/enterprise#beta-aws-key-manager---key-decryption)
- ✅ [Use LiteLLM keys/authentication on Pass Through Endpoints](./proxy/pass_through#✨-enterprise---use-litellm-keysauthentication-on-pass-through-endpoints)
- ✅ [Enforce Required Params for LLM Requests (ex. Reject requests missing ["metadata"]["generation_name"])](./proxy/enterprise#enforce-required-params-for-llm-requests)
- **Spend Tracking**
- ✅ [Tracking Spend for Custom Tags](./proxy/enterprise#tracking-spend-for-custom-tags)
- ✅ [API Endpoints to get Spend Reports per Team, API Key, Customer](./proxy/cost_tracking.md#✨-enterprise-api-endpoints-to-get-spend)
- **Advanced Metrics**
- ✅ [`x-ratelimit-remaining-requests`, `x-ratelimit-remaining-tokens` for LLM APIs on Prometheus](./proxy/prometheus#✨-enterprise-llm-remaining-requests-and-remaining-tokens)
- **Guardrails, PII Masking, Content Moderation**
- ✅ [Content Moderation with LLM Guard, LlamaGuard, Secret Detection, Google Text Moderations](./proxy/enterprise#content-moderation)
- ✅ [Prompt Injection Detection (with LakeraAI API)](./proxy/enterprise#prompt-injection-detection---lakeraai)
- ✅ Reject calls from Blocked User list
- ✅ Reject calls (incoming / outgoing) with Banned Keywords (e.g. competitors)
- **Custom Branding**
- ✅ [Custom Branding + Routes on Swagger Docs](./proxy/enterprise#swagger-docs---custom-routes--branding)
- ✅ [Public Model Hub](../docs/proxy/enterprise.md#public-model-hub)
- ✅ [Custom Email Branding](../docs/proxy/email.md#customizing-email-branding)
- ✅ **Feature Prioritization**
- ✅ **Custom Integrations**
- ✅ **Professional Support - Dedicated discord + slack**
- ✅ [**Custom Swagger**](../docs/proxy/enterprise.md#swagger-docs---custom-routes--branding)
- ✅ [**Public Model Hub**](../docs/proxy/enterprise.md#public-model-hub)
- ✅ [**Custom Email Branding**](../docs/proxy/email.md#customizing-email-branding)

View file

@ -168,11 +168,15 @@ print(response)
## Supported Models
`Model Name` 👉 Human-friendly name.
`Function Call` 👉 How to call the model in LiteLLM.
| Model Name | Function Call |
|------------------|--------------------------------------------|
| claude-3-5-sonnet | `completion('claude-3-5-sonnet-20240620', messages)` | `os.environ['ANTHROPIC_API_KEY']` |
| claude-3-haiku | `completion('claude-3-haiku-20240307', messages)` | `os.environ['ANTHROPIC_API_KEY']` |
| claude-3-opus | `completion('claude-3-opus-20240229', messages)` | `os.environ['ANTHROPIC_API_KEY']` |
| claude-3-5-sonnet | `completion('claude-3-5-sonnet-20240620', messages)` | `os.environ['ANTHROPIC_API_KEY']` |
| claude-3-5-sonnet-20240620 | `completion('claude-3-5-sonnet-20240620', messages)` | `os.environ['ANTHROPIC_API_KEY']` |
| claude-3-sonnet | `completion('claude-3-sonnet-20240229', messages)` | `os.environ['ANTHROPIC_API_KEY']` |
| claude-2.1 | `completion('claude-2.1', messages)` | `os.environ['ANTHROPIC_API_KEY']` |
| claude-2 | `completion('claude-2', messages)` | `os.environ['ANTHROPIC_API_KEY']` |

View file

@ -14,7 +14,7 @@ LiteLLM supports all models on Azure AI Studio
### ENV VAR
```python
import os
os.environ["AZURE_API_API_KEY"] = ""
os.environ["AZURE_AI_API_KEY"] = ""
os.environ["AZURE_AI_API_BASE"] = ""
```
@ -24,7 +24,7 @@ os.environ["AZURE_AI_API_BASE"] = ""
from litellm import completion
import os
## set ENV variables
os.environ["AZURE_API_API_KEY"] = "azure ai key"
os.environ["AZURE_AI_API_KEY"] = "azure ai key"
os.environ["AZURE_AI_API_BASE"] = "azure ai base url" # e.g.: https://Mistral-large-dfgfj-serverless.eastus2.inference.ai.azure.com/
# predibase llama-3 call

View file

@ -549,6 +549,10 @@ response = completion(
This is a deprecated flow. Boto3 is not async. And boto3.client does not let us make the http call through httpx. Pass in your aws params through the method above 👆. [See Auth Code](https://github.com/BerriAI/litellm/blob/55a20c7cce99a93d36a82bf3ae90ba3baf9a7f89/litellm/llms/bedrock_httpx.py#L284) [Add new auth flow](https://github.com/BerriAI/litellm/issues)
Experimental - 2024-Jun-23:
`aws_access_key_id`, `aws_secret_access_key`, and `aws_session_token` will be extracted from boto3.client and be passed into the httpx client
:::
Pass an external BedrockRuntime.Client object as a parameter to litellm.completion. Useful when using an AWS credentials profile, SSO session, assumed role session, or if environment variables are not available for auth.

View file

@ -27,7 +27,7 @@ import os
os.environ["DATABRICKS_API_KEY"] = "databricks key"
os.environ["DATABRICKS_API_BASE"] = "databricks base url" # e.g.: https://adb-3064715882934586.6.azuredatabricks.net/serving-endpoints
# predibase llama-3 call
# Databricks dbrx-instruct call
response = completion(
model="databricks/databricks-dbrx-instruct",
messages = [{ "content": "Hello, how are you?","role": "user"}]
@ -143,13 +143,13 @@ response = completion(
model_list:
- model_name: llama-3
litellm_params:
model: predibase/llama-3-8b-instruct
api_key: os.environ/PREDIBASE_API_KEY
model: databricks/databricks-meta-llama-3-70b-instruct
api_key: os.environ/DATABRICKS_API_KEY
max_tokens: 20
temperature: 0.5
```
## Passings Database specific params - 'instruction'
## Passings Databricks specific params - 'instruction'
For embedding models, databricks lets you pass in an additional param 'instruction'. [Full Spec](https://github.com/BerriAI/litellm/blob/43353c28b341df0d9992b45c6ce464222ebd7984/litellm/llms/databricks.py#L164)
@ -162,7 +162,7 @@ import os
os.environ["DATABRICKS_API_KEY"] = "databricks key"
os.environ["DATABRICKS_API_BASE"] = "databricks url"
# predibase llama3 call
# Databricks bge-large-en call
response = litellm.embedding(
model="databricks/databricks-bge-large-en",
input=["good morning from litellm"],
@ -184,7 +184,6 @@ response = litellm.embedding(
## Supported Databricks Chat Completion Models
Here's an example of using a Databricks models with LiteLLM
| Model Name | Command |
|----------------------------|------------------------------------------------------------------|
@ -196,8 +195,8 @@ Here's an example of using a Databricks models with LiteLLM
| databricks-mpt-7b-instruct | `completion(model='databricks/databricks-mpt-7b-instruct', messages=messages)` |
## Supported Databricks Embedding Models
Here's an example of using a databricks models with LiteLLM
| Model Name | Command |
|----------------------------|------------------------------------------------------------------|
| databricks-bge-large-en | `completion(model='databricks/databricks-bge-large-en', messages=messages)` |
| databricks-bge-large-en | `embedding(model='databricks/databricks-bge-large-en', messages=messages)` |
| databricks-gte-large-en | `embedding(model='databricks/databricks-gte-large-en', messages=messages)` |

View file

@ -18,7 +18,7 @@ import litellm
import os
response = litellm.completion(
model="openai/mistral, # add `openai/` prefix to model so litellm knows to route to OpenAI
model="openai/mistral", # add `openai/` prefix to model so litellm knows to route to OpenAI
api_key="sk-1234", # api key to your openai compatible endpoint
api_base="http://0.0.0.0:4000", # set API Base of your Custom OpenAI Endpoint
messages=[
@ -115,3 +115,18 @@ Here's how to call an OpenAI-Compatible Endpoint with the LiteLLM Proxy Server
</TabItem>
</Tabs>
### Advanced - Disable System Messages
Some VLLM models (e.g. gemma) don't support system messages. To map those requests to 'user' messages, use the `supports_system_message` flag.
```yaml
model_list:
- model_name: my-custom-model
litellm_params:
model: openai/google/gemma
api_base: http://my-custom-base
api_key: ""
supports_system_message: False # 👈 KEY CHANGE
```

View file

@ -123,6 +123,182 @@ print(completion(**data))
### **JSON Schema**
From v`1.40.1+` LiteLLM supports sending `response_schema` as a param for Gemini-1.5-Pro on Vertex AI. For other models (e.g. `gemini-1.5-flash` or `claude-3-5-sonnet`), LiteLLM adds the schema to the message list with a user-controlled prompt.
**Response Schema**
<Tabs>
<TabItem value="sdk" label="SDK">
```python
from litellm import completion
import json
## SETUP ENVIRONMENT
# !gcloud auth application-default login - run this to add vertex credentials to your env
messages = [
{
"role": "user",
"content": "List 5 popular cookie recipes."
}
]
response_schema = {
"type": "array",
"items": {
"type": "object",
"properties": {
"recipe_name": {
"type": "string",
},
},
"required": ["recipe_name"],
},
}
completion(
model="vertex_ai_beta/gemini-1.5-pro",
messages=messages,
response_format={"type": "json_object", "response_schema": response_schema} # 👈 KEY CHANGE
)
print(json.loads(completion.choices[0].message.content))
```
</TabItem>
<TabItem value="proxy" label="PROXY">
1. Add model to config.yaml
```yaml
model_list:
- model_name: gemini-pro
litellm_params:
model: vertex_ai_beta/gemini-1.5-pro
vertex_project: "project-id"
vertex_location: "us-central1"
vertex_credentials: "/path/to/service_account.json" # [OPTIONAL] Do this OR `!gcloud auth application-default login` - run this to add vertex credentials to your env
```
2. Start Proxy
```
$ litellm --config /path/to/config.yaml
```
3. Make Request!
```bash
curl -X POST 'http://0.0.0.0:4000/chat/completions' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer sk-1234' \
-D '{
"model": "gemini-pro",
"messages": [
{"role": "user", "content": "List 5 popular cookie recipes."}
],
"response_format": {"type": "json_object", "response_schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"recipe_name": {
"type": "string",
},
},
"required": ["recipe_name"],
},
}}
}
'
```
</TabItem>
</Tabs>
**Validate Schema**
To validate the response_schema, set `enforce_validation: true`.
<Tabs>
<TabItem value="sdk" label="SDK">
```python
from litellm import completion, JSONSchemaValidationError
try:
completion(
model="vertex_ai_beta/gemini-1.5-pro",
messages=messages,
response_format={
"type": "json_object",
"response_schema": response_schema,
"enforce_validation": true # 👈 KEY CHANGE
}
)
except JSONSchemaValidationError as e:
print("Raw Response: {}".format(e.raw_response))
raise e
```
</TabItem>
<TabItem value="proxy" label="PROXY">
1. Add model to config.yaml
```yaml
model_list:
- model_name: gemini-pro
litellm_params:
model: vertex_ai_beta/gemini-1.5-pro
vertex_project: "project-id"
vertex_location: "us-central1"
vertex_credentials: "/path/to/service_account.json" # [OPTIONAL] Do this OR `!gcloud auth application-default login` - run this to add vertex credentials to your env
```
2. Start Proxy
```
$ litellm --config /path/to/config.yaml
```
3. Make Request!
```bash
curl -X POST 'http://0.0.0.0:4000/chat/completions' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer sk-1234' \
-D '{
"model": "gemini-pro",
"messages": [
{"role": "user", "content": "List 5 popular cookie recipes."}
],
"response_format": {"type": "json_object", "response_schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"recipe_name": {
"type": "string",
},
},
"required": ["recipe_name"],
},
},
"enforce_validation": true
}
}
'
```
</TabItem>
</Tabs>
LiteLLM will validate the response against the schema, and raise a `JSONSchemaValidationError` if the response does not match the schema.
JSONSchemaValidationError inherits from `openai.APIError`
Access the raw response with `e.raw_response`
**Add to prompt yourself**
```python
from litellm import completion
@ -645,6 +821,86 @@ assert isinstance(
```
## Usage - PDF / Videos / etc. Files
Pass any file supported by Vertex AI, through LiteLLM.
<Tabs>
<TabItem value="sdk" label="SDK">
```python
from litellm import completion
response = completion(
model="vertex_ai/gemini-1.5-flash",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "You are a very professional document summarization specialist. Please summarize the given document."},
{
"type": "image_url",
"image_url": "gs://cloud-samples-data/generative-ai/pdf/2403.05530.pdf",
},
],
}
],
max_tokens=300,
)
print(response.choices[0])
```
</TabItem>
<TabItem value="proxy" lable="PROXY">
1. Add model to config
```yaml
- model_name: gemini-1.5-flash
litellm_params:
model: vertex_ai/gemini-1.5-flash
vertex_credentials: "/path/to/service_account.json"
```
2. Start Proxy
```
litellm --config /path/to/config.yaml
```
3. Test it!
```bash
curl http://0.0.0.0:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR-LITELLM-KEY>" \
-d '{
"model": "gemini-1.5-flash",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "You are a very professional document summarization specialist. Please summarize the given document"
},
{
"type": "image_url",
"image_url": "gs://cloud-samples-data/generative-ai/pdf/2403.05530.pdf",
},
}
]
}
],
"max_tokens": 300
}'
```
</TabItem>
</Tabs>
## Chat Models
| Model Name | Function Call |
|------------------|--------------------------------------|

View file

@ -0,0 +1,98 @@
# Volcano Engine (Volcengine)
https://www.volcengine.com/docs/82379/1263482
:::tip
**We support ALL Volcengine NIM models, just set `model=volcengine/<any-model-on-volcengine>` as a prefix when sending litellm requests**
:::
## API Key
```python
# env variable
os.environ['VOLCENGINE_API_KEY']
```
## Sample Usage
```python
from litellm import completion
import os
os.environ['VOLCENGINE_API_KEY'] = ""
response = completion(
model="volcengine/<OUR_ENDPOINT_ID>",
messages=[
{
"role": "user",
"content": "What's the weather like in Boston today in Fahrenheit?",
}
],
temperature=0.2, # optional
top_p=0.9, # optional
frequency_penalty=0.1, # optional
presence_penalty=0.1, # optional
max_tokens=10, # optional
stop=["\n\n"], # optional
)
print(response)
```
## Sample Usage - Streaming
```python
from litellm import completion
import os
os.environ['VOLCENGINE_API_KEY'] = ""
response = completion(
model="volcengine/<OUR_ENDPOINT_ID>",
messages=[
{
"role": "user",
"content": "What's the weather like in Boston today in Fahrenheit?",
}
],
stream=True,
temperature=0.2, # optional
top_p=0.9, # optional
frequency_penalty=0.1, # optional
presence_penalty=0.1, # optional
max_tokens=10, # optional
stop=["\n\n"], # optional
)
for chunk in response:
print(chunk)
```
## Supported Models - 💥 ALL Volcengine NIM Models Supported!
We support ALL `volcengine` models, just set `volcengine/<OUR_ENDPOINT_ID>` as a prefix when sending completion requests
## Sample Usage - LiteLLM Proxy
### Config.yaml setting
```yaml
model_list:
- model_name: volcengine-model
litellm_params:
model: volcengine/<OUR_ENDPOINT_ID>
api_key: os.environ/VOLCENGINE_API_KEY
```
### Send Request
```shell
curl --location 'http://localhost:4000/chat/completions' \
--header 'Authorization: Bearer sk-1234' \
--header 'Content-Type: application/json' \
--data '{
"model": "volcengine-model",
"messages": [
{
"role": "user",
"content": "here is my api key. openai_api_key=sk-1234"
}
]
}'
```

View file

@ -277,17 +277,65 @@ curl --location 'http://0.0.0.0:4000/v1/model/info' \
--data ''
```
## Wildcard Model Name (Add ALL MODELS from env)
Dynamically call any model from any given provider without the need to predefine it in the config YAML file. As long as the relevant keys are in the environment (see [providers list](../providers/)), LiteLLM will make the call correctly.
1. Setup config.yaml
```
model_list:
- model_name: "*" # all requests where model not in your config go to this deployment
litellm_params:
model: "openai/*" # passes our validation check that a real provider is given
```
2. Start LiteLLM proxy
```
litellm --config /path/to/config.yaml
```
3. Try claude 3-5 sonnet from anthropic
```bash
curl -X POST 'http://0.0.0.0:4000/chat/completions' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer sk-1234' \
-D '{
"model": "claude-3-5-sonnet-20240620",
"messages": [
{"role": "user", "content": "Hey, how'\''s it going?"},
{
"role": "assistant",
"content": "I'\''m doing well. Would like to hear the rest of the story?"
},
{"role": "user", "content": "Na"},
{
"role": "assistant",
"content": "No problem, is there anything else i can help you with today?"
},
{
"role": "user",
"content": "I think you'\''re getting cut off sometimes"
}
]
}
'
```
## Load Balancing
:::info
For more on this, go to [this page](./load_balancing.md)
For more on this, go to [this page](https://docs.litellm.ai/docs/proxy/load_balancing)
:::
Use this to call multiple instances of the same model and configure things like [routing strategy](../routing.md#advanced).
Use this to call multiple instances of the same model and configure things like [routing strategy](https://docs.litellm.ai/docs/routing#advanced).
For optimal performance:
- Set `tpm/rpm` per model deployment. Weighted picks are then based on the established tpm/rpm.
- Select your optimal routing strategy in `router_settings:routing_strategy`.
- Select your optimal routing strategy in `router_settings:routing_strategy`.
LiteLLM supports
```python
@ -427,7 +475,7 @@ model_list:
```shell
$ litellm --config /path/to/config.yaml
```
```
## Setting Embedding Models

View file

@ -114,6 +114,16 @@ print(response)
**Step3 - Verify Spend Tracked**
That's IT. Now Verify your spend was tracked
<Tabs>
<TabItem value="curl" label="Response Headers">
Expect to see `x-litellm-response-cost` in the response headers with calculated cost
<Image img={require('../../img/response_cost_img.png')} />
</TabItem>
<TabItem value="db" label="DB + UI">
The following spend gets tracked in Table `LiteLLM_SpendLogs`
```json
@ -137,12 +147,16 @@ Navigate to the Usage Tab on the LiteLLM UI (found on https://your-proxy-endpoin
<Image img={require('../../img/admin_ui_spend.png')} />
## API Endpoints to get Spend
</TabItem>
</Tabs>
## ✨ (Enterprise) API Endpoints to get Spend
#### Getting Spend Reports - To Charge Other Teams, Customers
Use the `/global/spend/report` endpoint to get daily spend report per
- team
- customer [this is `user` passed to `/chat/completions` request](#how-to-track-spend-with-litellm)
- Team
- Customer [this is `user` passed to `/chat/completions` request](#how-to-track-spend-with-litellm)
- [LiteLLM API key](virtual_keys.md)
<Tabs>
@ -325,6 +339,61 @@ curl -X GET 'http://localhost:4000/global/spend/report?start_date=2024-04-01&end
```
</TabItem>
<TabItem value="per key" label="Spend Per API Key">
👉 Key Change: Specify `group_by=api_key`
```shell
curl -X GET 'http://localhost:4000/global/spend/report?start_date=2024-04-01&end_date=2024-06-30&group_by=api_key' \
-H 'Authorization: Bearer sk-1234'
```
##### Example Response
```shell
[
{
"api_key": "ad64768847d05d978d62f623d872bff0f9616cc14b9c1e651c84d14fe3b9f539",
"total_cost": 0.0002157,
"total_input_tokens": 45.0,
"total_output_tokens": 1375.0,
"model_details": [
{
"model": "gpt-3.5-turbo",
"total_cost": 0.0001095,
"total_input_tokens": 9,
"total_output_tokens": 70
},
{
"model": "llama3-8b-8192",
"total_cost": 0.0001062,
"total_input_tokens": 36,
"total_output_tokens": 1305
}
]
},
{
"api_key": "88dc28d0f030c55ed4ab77ed8faf098196cb1c05df778539800c9f1243fe6b4b",
"total_cost": 0.00012924,
"total_input_tokens": 36.0,
"total_output_tokens": 1593.0,
"model_details": [
{
"model": "llama3-8b-8192",
"total_cost": 0.00012924,
"total_input_tokens": 36,
"total_output_tokens": 1593
}
]
}
]
```
</TabItem>
</Tabs>

View file

@ -88,4 +88,31 @@ Expected Output:
```bash
# no info statements
```
```
## Common Errors
1. "No available deployments..."
```
No deployments available for selected model, Try again in 60 seconds. Passed model=claude-3-5-sonnet. pre-call-checks=False, allowed_model_region=n/a.
```
This can be caused due to all your models hitting rate limit errors, causing the cooldown to kick in.
How to control this?
- Adjust the cooldown time
```yaml
router_settings:
cooldown_time: 0 # 👈 KEY CHANGE
```
- Disable Cooldowns [NOT RECOMMENDED]
```yaml
router_settings:
disable_cooldowns: True
```
This is not recommended, as it will lead to requests being routed to deployments over their tpm/rpm limit.

View file

@ -6,21 +6,34 @@ import TabItem from '@theme/TabItem';
:::tip
Get in touch with us [here](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
To get a license, get in touch with us [here](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat)
:::
Features:
- ✅ [SSO for Admin UI](./ui.md#✨-enterprise-features)
- ✅ [Audit Logs](#audit-logs)
- ✅ [Tracking Spend for Custom Tags](#tracking-spend-for-custom-tags)
- ✅ [Control available public, private routes](#control-available-public-private-routes)
- ✅ [Content Moderation with LLM Guard, LlamaGuard, Secret Detection, Google Text Moderations](#content-moderation)
- ✅ [Prompt Injection Detection (with LakeraAI API)](#prompt-injection-detection---lakeraai)
- ✅ [Custom Branding + Routes on Swagger Docs](#swagger-docs---custom-routes--branding)
- ✅ [Enforce Required Params for LLM Requests (ex. Reject requests missing ["metadata"]["generation_name"])](#enforce-required-params-for-llm-requests)
- ✅ Reject calls from Blocked User list
- ✅ Reject calls (incoming / outgoing) with Banned Keywords (e.g. competitors)
- **Security**
- ✅ [SSO for Admin UI](./ui.md#✨-enterprise-features)
- ✅ [Audit Logs with retention policy](#audit-logs)
- ✅ [JWT-Auth](../docs/proxy/token_auth.md)
- ✅ [Control available public, private routes](#control-available-public-private-routes)
- ✅ [[BETA] AWS Key Manager v2 - Key Decryption](#beta-aws-key-manager---key-decryption)
- ✅ [Use LiteLLM keys/authentication on Pass Through Endpoints](pass_through#✨-enterprise---use-litellm-keysauthentication-on-pass-through-endpoints)
- ✅ [Enforce Required Params for LLM Requests (ex. Reject requests missing ["metadata"]["generation_name"])](#enforce-required-params-for-llm-requests)
- **Spend Tracking**
- ✅ [Tracking Spend for Custom Tags](#tracking-spend-for-custom-tags)
- ✅ [API Endpoints to get Spend Reports per Team, API Key, Customer](cost_tracking.md#✨-enterprise-api-endpoints-to-get-spend)
- **Advanced Metrics**
- ✅ [`x-ratelimit-remaining-requests`, `x-ratelimit-remaining-tokens` for LLM APIs on Prometheus](prometheus#✨-enterprise-llm-remaining-requests-and-remaining-tokens)
- **Guardrails, PII Masking, Content Moderation**
- ✅ [Content Moderation with LLM Guard, LlamaGuard, Secret Detection, Google Text Moderations](#content-moderation)
- ✅ [Prompt Injection Detection (with LakeraAI API)](#prompt-injection-detection---lakeraai)
- ✅ Reject calls from Blocked User list
- ✅ Reject calls (incoming / outgoing) with Banned Keywords (e.g. competitors)
- **Custom Branding**
- ✅ [Custom Branding + Routes on Swagger Docs](#swagger-docs---custom-routes--branding)
- ✅ [Public Model Hub](../docs/proxy/enterprise.md#public-model-hub)
- ✅ [Custom Email Branding](../docs/proxy/email.md#customizing-email-branding)
## Audit Logs
@ -1019,4 +1032,35 @@ curl --location 'http://0.0.0.0:4000/chat/completions' \
Share a public page of available models for users
<Image img={require('../../img/model_hub.png')} style={{ width: '900px', height: 'auto' }}/>
<Image img={require('../../img/model_hub.png')} style={{ width: '900px', height: 'auto' }}/>
## [BETA] AWS Key Manager - Key Decryption
This is a beta feature, and subject to changes.
**Step 1.** Add `USE_AWS_KMS` to env
```env
USE_AWS_KMS="True"
```
**Step 2.** Add `aws_kms/` to encrypted keys in env
```env
DATABASE_URL="aws_kms/AQICAH.."
```
**Step 3.** Start proxy
```
$ litellm
```
How it works?
- Key Decryption runs before server starts up. [**Code**](https://github.com/BerriAI/litellm/blob/8571cb45e80cc561dc34bc6aa89611eb96b9fe3e/litellm/proxy/proxy_cli.py#L445)
- It adds the decrypted value to the `os.environ` for the python process.
**Note:** Setting an environment variable within a Python script using os.environ will not make that variable accessible via SSH sessions or any other new processes that are started independently of the Python script. Environment variables set this way only affect the current process and its child processes.

View file

@ -1188,6 +1188,7 @@ litellm_settings:
s3_region_name: us-west-2 # AWS Region Name for S3
s3_aws_access_key_id: os.environ/AWS_ACCESS_KEY_ID # us os.environ/<variable name> to pass environment variables. This is AWS Access Key ID for S3
s3_aws_secret_access_key: os.environ/AWS_SECRET_ACCESS_KEY # AWS Secret Access Key for S3
s3_path: my-test-path # [OPTIONAL] set path in bucket you want to write logs to
s3_endpoint_url: https://s3.amazonaws.com # [OPTIONAL] S3 endpoint URL, if you want to use Backblaze/cloudflare s3 buckets
```

View file

@ -0,0 +1,220 @@
import Image from '@theme/IdealImage';
# ➡️ Create Pass Through Endpoints
Add pass through routes to LiteLLM Proxy
**Example:** Add a route `/v1/rerank` that forwards requests to `https://api.cohere.com/v1/rerank` through LiteLLM Proxy
💡 This allows making the following Request to LiteLLM Proxy
```shell
curl --request POST \
--url http://localhost:4000/v1/rerank \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"model": "rerank-english-v3.0",
"query": "What is the capital of the United States?",
"top_n": 3,
"documents": ["Carson City is the capital city of the American state of Nevada."]
}'
```
## Tutorial - Pass through Cohere Re-Rank Endpoint
**Step 1** Define pass through routes on [litellm config.yaml](configs.md)
```yaml
general_settings:
master_key: sk-1234
pass_through_endpoints:
- path: "/v1/rerank" # route you want to add to LiteLLM Proxy Server
target: "https://api.cohere.com/v1/rerank" # URL this route should forward requests to
headers: # headers to forward to this URL
Authorization: "bearer os.environ/COHERE_API_KEY" # (Optional) Auth Header to forward to your Endpoint
content-type: application/json # (Optional) Extra Headers to pass to this endpoint
accept: application/json
```
**Step 2** Start Proxy Server in detailed_debug mode
```shell
litellm --config config.yaml --detailed_debug
```
**Step 3** Make Request to pass through endpoint
Here `http://localhost:4000` is your litellm proxy endpoint
```shell
curl --request POST \
--url http://localhost:4000/v1/rerank \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"model": "rerank-english-v3.0",
"query": "What is the capital of the United States?",
"top_n": 3,
"documents": ["Carson City is the capital city of the American state of Nevada.",
"The Commonwealth of the Northern Mariana Islands is a group of islands in the Pacific Ocean. Its capital is Saipan.",
"Washington, D.C. (also known as simply Washington or D.C., and officially as the District of Columbia) is the capital of the United States. It is a federal district.",
"Capitalization or capitalisation in English grammar is the use of a capital letter at the start of a word. English usage varies from capitalization in other languages.",
"Capital punishment (the death penalty) has existed in the United States since beforethe United States was a country. As of 2017, capital punishment is legal in 30 of the 50 states."]
}'
```
🎉 **Expected Response**
This request got forwarded from LiteLLM Proxy -> Defined Target URL (with headers)
```shell
{
"id": "37103a5b-8cfb-48d3-87c7-da288bedd429",
"results": [
{
"index": 2,
"relevance_score": 0.999071
},
{
"index": 4,
"relevance_score": 0.7867867
},
{
"index": 0,
"relevance_score": 0.32713068
}
],
"meta": {
"api_version": {
"version": "1"
},
"billed_units": {
"search_units": 1
}
}
}
```
## Tutorial - Pass Through Langfuse Requests
**Step 1** Define pass through routes on [litellm config.yaml](configs.md)
```yaml
general_settings:
master_key: sk-1234
pass_through_endpoints:
- path: "/api/public/ingestion" # route you want to add to LiteLLM Proxy Server
target: "https://us.cloud.langfuse.com/api/public/ingestion" # URL this route should forward
headers:
LANGFUSE_PUBLIC_KEY: "os.environ/LANGFUSE_DEV_PUBLIC_KEY" # your langfuse account public key
LANGFUSE_SECRET_KEY: "os.environ/LANGFUSE_DEV_SK_KEY" # your langfuse account secret key
```
**Step 2** Start Proxy Server in detailed_debug mode
```shell
litellm --config config.yaml --detailed_debug
```
**Step 3** Make Request to pass through endpoint
Run this code to make a sample trace
```python
from langfuse import Langfuse
langfuse = Langfuse(
host="http://localhost:4000", # your litellm proxy endpoint
public_key="anything", # no key required since this is a pass through
secret_key="anything", # no key required since this is a pass through
)
print("sending langfuse trace request")
trace = langfuse.trace(name="test-trace-litellm-proxy-passthrough")
print("flushing langfuse request")
langfuse.flush()
print("flushed langfuse request")
```
🎉 **Expected Response**
On success
Expect to see the following Trace Generated on your Langfuse Dashboard
<Image img={require('../../img/proxy_langfuse.png')} />
You will see the following endpoint called on your litellm proxy server logs
```shell
POST /api/public/ingestion HTTP/1.1" 207 Multi-Status
```
## ✨ [Enterprise] - Use LiteLLM keys/authentication on Pass Through Endpoints
Use this if you want the pass through endpoint to honour LiteLLM keys/authentication
Usage - set `auth: true` on the config
```yaml
general_settings:
master_key: sk-1234
pass_through_endpoints:
- path: "/v1/rerank"
target: "https://api.cohere.com/v1/rerank"
auth: true # 👈 Key change to use LiteLLM Auth / Keys
headers:
Authorization: "bearer os.environ/COHERE_API_KEY"
content-type: application/json
accept: application/json
```
Test Request with LiteLLM Key
```shell
curl --request POST \
--url http://localhost:4000/v1/rerank \
--header 'accept: application/json' \
--header 'Authorization: Bearer sk-1234'\
--header 'content-type: application/json' \
--data '{
"model": "rerank-english-v3.0",
"query": "What is the capital of the United States?",
"top_n": 3,
"documents": ["Carson City is the capital city of the American state of Nevada.",
"The Commonwealth of the Northern Mariana Islands is a group of islands in the Pacific Ocean. Its capital is Saipan.",
"Washington, D.C. (also known as simply Washington or D.C., and officially as the District of Columbia) is the capital of the United States. It is a federal district.",
"Capitalization or capitalisation in English grammar is the use of a capital letter at the start of a word. English usage varies from capitalization in other languages.",
"Capital punishment (the death penalty) has existed in the United States since beforethe United States was a country. As of 2017, capital punishment is legal in 30 of the 50 states."]
}'
```
## `pass_through_endpoints` Spec on config.yaml
All possible values for `pass_through_endpoints` and what they mean
**Example config**
```yaml
general_settings:
pass_through_endpoints:
- path: "/v1/rerank" # route you want to add to LiteLLM Proxy Server
target: "https://api.cohere.com/v1/rerank" # URL this route should forward requests to
headers: # headers to forward to this URL
Authorization: "bearer os.environ/COHERE_API_KEY" # (Optional) Auth Header to forward to your Endpoint
content-type: application/json # (Optional) Extra Headers to pass to this endpoint
accept: application/json
```
**Spec**
* `pass_through_endpoints` *list*: A collection of endpoint configurations for request forwarding.
* `path` *string*: The route to be added to the LiteLLM Proxy Server.
* `target` *string*: The URL to which requests for this path should be forwarded.
* `headers` *object*: Key-value pairs of headers to be forwarded with the request. You can set any key value pair here and it will be forwarded to your target endpoint
* `Authorization` *string*: The authentication header for the target API.
* `content-type` *string*: The format specification for the request body.
* `accept` *string*: The expected response format from the server.
* `LANGFUSE_PUBLIC_KEY` *string*: Your Langfuse account public key - only set this when forwarding to Langfuse.
* `LANGFUSE_SECRET_KEY` *string*: Your Langfuse account secret key - only set this when forwarding to Langfuse.
* `<your-custom-header>` *string*: Pass any custom header key/value pair

View file

@ -1,3 +1,6 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# 📈 Prometheus metrics [BETA]
LiteLLM Exposes a `/metrics` endpoint for Prometheus to Poll
@ -61,6 +64,56 @@ http://localhost:4000/metrics
| `litellm_remaining_api_key_budget_metric` | Remaining Budget for API Key (A key Created on LiteLLM)|
### ✨ (Enterprise) LLM Remaining Requests and Remaining Tokens
Set this on your config.yaml to allow you to track how close you are to hitting your TPM / RPM limits on each model group
```yaml
litellm_settings:
success_callback: ["prometheus"]
failure_callback: ["prometheus"]
return_response_headers: true # ensures the LLM API calls track the response headers
```
| Metric Name | Description |
|----------------------|--------------------------------------|
| `litellm_remaining_requests_metric` | Track `x-ratelimit-remaining-requests` returned from LLM API Deployment |
| `litellm_remaining_tokens` | Track `x-ratelimit-remaining-tokens` return from LLM API Deployment |
Example Metric
<Tabs>
<TabItem value="Remaining Requests" label="Remaining Requests">
```shell
litellm_remaining_requests
{
api_base="https://api.openai.com/v1",
api_provider="openai",
litellm_model_name="gpt-3.5-turbo",
model_group="gpt-3.5-turbo"
}
8998.0
```
</TabItem>
<TabItem value="Requests" label="Remaining Tokens">
```shell
litellm_remaining_tokens
{
api_base="https://api.openai.com/v1",
api_provider="openai",
litellm_model_name="gpt-3.5-turbo",
model_group="gpt-3.5-turbo"
}
999981.0
```
</TabItem>
</Tabs>
## Monitor System Health
To monitor the health of litellm adjacent services (redis / postgres), do:

View file

@ -4,7 +4,7 @@ import TabItem from '@theme/TabItem';
# 🤗 UI - Self-Serve
Allow users to creat their own keys on [Proxy UI](./ui.md).
Allow users to create their own keys on [Proxy UI](./ui.md).
1. Add user with permissions to a team on proxy

View file

@ -152,6 +152,27 @@ response = chat(messages)
print(response)
```
</TabItem>
<TabItem value="langchain js" label="Langchain JS">
```js
import { ChatOpenAI } from "@langchain/openai";
const model = new ChatOpenAI({
modelName: "gpt-4",
openAIApiKey: "sk-1234",
modelKwargs: {"metadata": "hello world"} // 👈 PASS Additional params here
}, {
basePath: "http://0.0.0.0:4000",
});
const message = await model.invoke("Hi there!");
console.log(message);
```
</TabItem>
</Tabs>

View file

@ -815,6 +815,35 @@ model_list:
</TabItem>
</Tabs>
**Expected Response**
```
No deployments available for selected model, Try again in 60 seconds. Passed model=claude-3-5-sonnet. pre-call-checks=False, allowed_model_region=n/a.
```
#### **Disable cooldowns**
<Tabs>
<TabItem value="sdk" label="SDK">
```python
from litellm import Router
router = Router(..., disable_cooldowns=True)
```
</TabItem>
<TabItem value="proxy" label="PROXY">
```yaml
router_settings:
disable_cooldowns: True
```
</TabItem>
</Tabs>
### Retries
For both async + sync functions, we support retrying failed requests.

View file

@ -8,7 +8,13 @@ LiteLLM supports reading secrets from Azure Key Vault and Infisical
- [Infisical Secret Manager](#infisical-secret-manager)
- [.env Files](#env-files)
## AWS Key Management Service
## AWS Key Management V1
:::tip
[BETA] AWS Key Management v2 is on the enterprise tier. Go [here for docs](./proxy/enterprise.md#beta-aws-key-manager---key-decryption)
:::
Use AWS KMS to storing a hashed copy of your Proxy Master Key in the environment.

View file

@ -14,14 +14,6 @@ response = speech(
model="openai/tts-1",
voice="alloy",
input="the quick brown fox jumped over the lazy dogs",
api_base=None,
api_key=None,
organization=None,
project=None,
max_retries=1,
timeout=600,
client=None,
optional_params={},
)
response.stream_to_file(speech_file_path)
```
@ -84,4 +76,37 @@ curl http://0.0.0.0:4000/v1/audio/speech \
litellm --config /path/to/config.yaml
# RUNNING on http://0.0.0.0:4000
```
## Azure Usage
**PROXY**
```yaml
- model_name: azure/tts-1
litellm_params:
model: azure/tts-1
api_base: "os.environ/AZURE_API_BASE_TTS"
api_key: "os.environ/AZURE_API_KEY_TTS"
api_version: "os.environ/AZURE_API_VERSION"
```
**SDK**
```python
from litellm import completion
## set ENV variables
os.environ["AZURE_API_KEY"] = ""
os.environ["AZURE_API_BASE"] = ""
os.environ["AZURE_API_VERSION"] = ""
# azure call
speech_file_path = Path(__file__).parent / "speech.mp3"
response = speech(
model="azure/<your-deployment-name",
voice="alloy",
input="the quick brown fox jumped over the lazy dogs",
)
response.stream_to_file(speech_file_path)
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

View file

@ -48,6 +48,7 @@ const sidebars = {
"proxy/billing",
"proxy/user_keys",
"proxy/virtual_keys",
"proxy/token_auth",
"proxy/alerting",
{
type: "category",
@ -56,11 +57,11 @@ const sidebars = {
},
"proxy/ui",
"proxy/prometheus",
"proxy/pass_through",
"proxy/email",
"proxy/multiple_admins",
"proxy/team_based_routing",
"proxy/customer_routing",
"proxy/token_auth",
{
type: "category",
label: "Extra Load Balancing",
@ -147,6 +148,7 @@ const sidebars = {
"providers/watsonx",
"providers/predibase",
"providers/nvidia_nim",
"providers/volcano",
"providers/triton-inference-server",
"providers/ollama",
"providers/perplexity",

View file

@ -114,7 +114,11 @@ class _ENTERPRISE_lakeraAI_Moderation(CustomLogger):
if flagged == True:
raise HTTPException(
status_code=400, detail={"error": "Violated content safety policy"}
status_code=400,
detail={
"error": "Violated content safety policy",
"lakera_ai_response": _json_response,
},
)
pass

View file

@ -33,27 +33,429 @@ from litellm._logging import verbose_proxy_logger
litellm.set_verbose = True
_custom_plugins_path = "file://" + os.path.join(
os.path.dirname(os.path.abspath(__file__)), "secrets_plugins"
)
print("custom plugins path", _custom_plugins_path)
_default_detect_secrets_config = {
"plugins_used": [
{"name": "SoftlayerDetector"},
{"name": "StripeDetector"},
{"name": "NpmDetector"},
{"name": "IbmCosHmacDetector"},
{"name": "DiscordBotTokenDetector"},
{"name": "BasicAuthDetector"},
{"name": "AzureStorageKeyDetector"},
{"name": "ArtifactoryDetector"},
{"name": "AWSKeyDetector"},
{"name": "CloudantDetector"},
{"name": "IbmCloudIamDetector"},
{"name": "JwtTokenDetector"},
{"name": "MailchimpDetector"},
{"name": "SquareOAuthDetector"},
{"name": "PrivateKeyDetector"},
{"name": "TwilioKeyDetector"},
{
"name": "AdafruitKeyDetector",
"path": _custom_plugins_path + "/adafruit.py",
},
{
"name": "AdobeSecretDetector",
"path": _custom_plugins_path + "/adobe.py",
},
{
"name": "AgeSecretKeyDetector",
"path": _custom_plugins_path + "/age_secret_key.py",
},
{
"name": "AirtableApiKeyDetector",
"path": _custom_plugins_path + "/airtable_api_key.py",
},
{
"name": "AlgoliaApiKeyDetector",
"path": _custom_plugins_path + "/algolia_api_key.py",
},
{
"name": "AlibabaSecretDetector",
"path": _custom_plugins_path + "/alibaba.py",
},
{
"name": "AsanaSecretDetector",
"path": _custom_plugins_path + "/asana.py",
},
{
"name": "AtlassianApiTokenDetector",
"path": _custom_plugins_path + "/atlassian_api_token.py",
},
{
"name": "AuthressAccessKeyDetector",
"path": _custom_plugins_path + "/authress_access_key.py",
},
{
"name": "BittrexDetector",
"path": _custom_plugins_path + "/beamer_api_token.py",
},
{
"name": "BitbucketDetector",
"path": _custom_plugins_path + "/bitbucket.py",
},
{
"name": "BeamerApiTokenDetector",
"path": _custom_plugins_path + "/bittrex.py",
},
{
"name": "ClojarsApiTokenDetector",
"path": _custom_plugins_path + "/clojars_api_token.py",
},
{
"name": "CodecovAccessTokenDetector",
"path": _custom_plugins_path + "/codecov_access_token.py",
},
{
"name": "CoinbaseAccessTokenDetector",
"path": _custom_plugins_path + "/coinbase_access_token.py",
},
{
"name": "ConfluentDetector",
"path": _custom_plugins_path + "/confluent.py",
},
{
"name": "ContentfulApiTokenDetector",
"path": _custom_plugins_path + "/contentful_api_token.py",
},
{
"name": "DatabricksApiTokenDetector",
"path": _custom_plugins_path + "/databricks_api_token.py",
},
{
"name": "DatadogAccessTokenDetector",
"path": _custom_plugins_path + "/datadog_access_token.py",
},
{
"name": "DefinedNetworkingApiTokenDetector",
"path": _custom_plugins_path + "/defined_networking_api_token.py",
},
{
"name": "DigitaloceanDetector",
"path": _custom_plugins_path + "/digitalocean.py",
},
{
"name": "DopplerApiTokenDetector",
"path": _custom_plugins_path + "/doppler_api_token.py",
},
{
"name": "DroneciAccessTokenDetector",
"path": _custom_plugins_path + "/droneci_access_token.py",
},
{
"name": "DuffelApiTokenDetector",
"path": _custom_plugins_path + "/duffel_api_token.py",
},
{
"name": "DynatraceApiTokenDetector",
"path": _custom_plugins_path + "/dynatrace_api_token.py",
},
{
"name": "DiscordDetector",
"path": _custom_plugins_path + "/discord.py",
},
{
"name": "DropboxDetector",
"path": _custom_plugins_path + "/dropbox.py",
},
{
"name": "EasyPostDetector",
"path": _custom_plugins_path + "/easypost.py",
},
{
"name": "EtsyAccessTokenDetector",
"path": _custom_plugins_path + "/etsy_access_token.py",
},
{
"name": "FacebookAccessTokenDetector",
"path": _custom_plugins_path + "/facebook_access_token.py",
},
{
"name": "FastlyApiKeyDetector",
"path": _custom_plugins_path + "/fastly_api_token.py",
},
{
"name": "FinicityDetector",
"path": _custom_plugins_path + "/finicity.py",
},
{
"name": "FinnhubAccessTokenDetector",
"path": _custom_plugins_path + "/finnhub_access_token.py",
},
{
"name": "FlickrAccessTokenDetector",
"path": _custom_plugins_path + "/flickr_access_token.py",
},
{
"name": "FlutterwaveDetector",
"path": _custom_plugins_path + "/flutterwave.py",
},
{
"name": "FrameIoApiTokenDetector",
"path": _custom_plugins_path + "/frameio_api_token.py",
},
{
"name": "FreshbooksAccessTokenDetector",
"path": _custom_plugins_path + "/freshbooks_access_token.py",
},
{
"name": "GCPApiKeyDetector",
"path": _custom_plugins_path + "/gcp_api_key.py",
},
{
"name": "GitHubTokenCustomDetector",
"path": _custom_plugins_path + "/github_token.py",
},
{
"name": "GitLabDetector",
"path": _custom_plugins_path + "/gitlab.py",
},
{
"name": "GitterAccessTokenDetector",
"path": _custom_plugins_path + "/gitter_access_token.py",
},
{
"name": "GoCardlessApiTokenDetector",
"path": _custom_plugins_path + "/gocardless_api_token.py",
},
{
"name": "GrafanaDetector",
"path": _custom_plugins_path + "/grafana.py",
},
{
"name": "HashiCorpTFApiTokenDetector",
"path": _custom_plugins_path + "/hashicorp_tf_api_token.py",
},
{
"name": "HerokuApiKeyDetector",
"path": _custom_plugins_path + "/heroku_api_key.py",
},
{
"name": "HubSpotApiTokenDetector",
"path": _custom_plugins_path + "/hubspot_api_key.py",
},
{
"name": "HuggingFaceDetector",
"path": _custom_plugins_path + "/huggingface.py",
},
{
"name": "IntercomApiTokenDetector",
"path": _custom_plugins_path + "/intercom_api_key.py",
},
{
"name": "JFrogDetector",
"path": _custom_plugins_path + "/jfrog.py",
},
{
"name": "JWTBase64Detector",
"path": _custom_plugins_path + "/jwt.py",
},
{
"name": "KrakenAccessTokenDetector",
"path": _custom_plugins_path + "/kraken_access_token.py",
},
{
"name": "KucoinDetector",
"path": _custom_plugins_path + "/kucoin.py",
},
{
"name": "LaunchdarklyAccessTokenDetector",
"path": _custom_plugins_path + "/launchdarkly_access_token.py",
},
{
"name": "LinearDetector",
"path": _custom_plugins_path + "/linear.py",
},
{
"name": "LinkedInDetector",
"path": _custom_plugins_path + "/linkedin.py",
},
{
"name": "LobDetector",
"path": _custom_plugins_path + "/lob.py",
},
{
"name": "MailgunDetector",
"path": _custom_plugins_path + "/mailgun.py",
},
{
"name": "MapBoxApiTokenDetector",
"path": _custom_plugins_path + "/mapbox_api_token.py",
},
{
"name": "MattermostAccessTokenDetector",
"path": _custom_plugins_path + "/mattermost_access_token.py",
},
{
"name": "MessageBirdDetector",
"path": _custom_plugins_path + "/messagebird.py",
},
{
"name": "MicrosoftTeamsWebhookDetector",
"path": _custom_plugins_path + "/microsoft_teams_webhook.py",
},
{
"name": "NetlifyAccessTokenDetector",
"path": _custom_plugins_path + "/netlify_access_token.py",
},
{
"name": "NewRelicDetector",
"path": _custom_plugins_path + "/new_relic.py",
},
{
"name": "NYTimesAccessTokenDetector",
"path": _custom_plugins_path + "/nytimes_access_token.py",
},
{
"name": "OktaAccessTokenDetector",
"path": _custom_plugins_path + "/okta_access_token.py",
},
{
"name": "OpenAIApiKeyDetector",
"path": _custom_plugins_path + "/openai_api_key.py",
},
{
"name": "PlanetScaleDetector",
"path": _custom_plugins_path + "/planetscale.py",
},
{
"name": "PostmanApiTokenDetector",
"path": _custom_plugins_path + "/postman_api_token.py",
},
{
"name": "PrefectApiTokenDetector",
"path": _custom_plugins_path + "/prefect_api_token.py",
},
{
"name": "PulumiApiTokenDetector",
"path": _custom_plugins_path + "/pulumi_api_token.py",
},
{
"name": "PyPiUploadTokenDetector",
"path": _custom_plugins_path + "/pypi_upload_token.py",
},
{
"name": "RapidApiAccessTokenDetector",
"path": _custom_plugins_path + "/rapidapi_access_token.py",
},
{
"name": "ReadmeApiTokenDetector",
"path": _custom_plugins_path + "/readme_api_token.py",
},
{
"name": "RubygemsApiTokenDetector",
"path": _custom_plugins_path + "/rubygems_api_token.py",
},
{
"name": "ScalingoApiTokenDetector",
"path": _custom_plugins_path + "/scalingo_api_token.py",
},
{
"name": "SendbirdDetector",
"path": _custom_plugins_path + "/sendbird.py",
},
{
"name": "SendGridApiTokenDetector",
"path": _custom_plugins_path + "/sendgrid_api_token.py",
},
{
"name": "SendinBlueApiTokenDetector",
"path": _custom_plugins_path + "/sendinblue_api_token.py",
},
{
"name": "SentryAccessTokenDetector",
"path": _custom_plugins_path + "/sentry_access_token.py",
},
{
"name": "ShippoApiTokenDetector",
"path": _custom_plugins_path + "/shippo_api_token.py",
},
{
"name": "ShopifyDetector",
"path": _custom_plugins_path + "/shopify.py",
},
{
"name": "SlackDetector",
"path": _custom_plugins_path + "/slack.py",
},
{
"name": "SnykApiTokenDetector",
"path": _custom_plugins_path + "/snyk_api_token.py",
},
{
"name": "SquarespaceAccessTokenDetector",
"path": _custom_plugins_path + "/squarespace_access_token.py",
},
{
"name": "SumoLogicDetector",
"path": _custom_plugins_path + "/sumologic.py",
},
{
"name": "TelegramBotApiTokenDetector",
"path": _custom_plugins_path + "/telegram_bot_api_token.py",
},
{
"name": "TravisCiAccessTokenDetector",
"path": _custom_plugins_path + "/travisci_access_token.py",
},
{
"name": "TwitchApiTokenDetector",
"path": _custom_plugins_path + "/twitch_api_token.py",
},
{
"name": "TwitterDetector",
"path": _custom_plugins_path + "/twitter.py",
},
{
"name": "TypeformApiTokenDetector",
"path": _custom_plugins_path + "/typeform_api_token.py",
},
{
"name": "VaultDetector",
"path": _custom_plugins_path + "/vault.py",
},
{
"name": "YandexDetector",
"path": _custom_plugins_path + "/yandex.py",
},
{
"name": "ZendeskSecretKeyDetector",
"path": _custom_plugins_path + "/zendesk_secret_key.py",
},
{"name": "Base64HighEntropyString", "limit": 3.0},
{"name": "HexHighEntropyString", "limit": 3.0},
]
}
class _ENTERPRISE_SecretDetection(CustomLogger):
def __init__(self):
pass
def scan_message_for_secrets(self, message_content: str):
from detect_secrets import SecretsCollection
from detect_secrets.settings import default_settings
from detect_secrets.settings import transient_settings
temp_file = tempfile.NamedTemporaryFile(delete=False)
temp_file.write(message_content.encode("utf-8"))
temp_file.close()
secrets = SecretsCollection()
with default_settings():
with transient_settings(_default_detect_secrets_config):
secrets.scan_file(temp_file.name)
os.remove(temp_file.name)
detected_secrets = []
for file in secrets.files:
for found_secret in secrets[file]:
if found_secret.secret_value is None:
continue
detected_secrets.append(
@ -76,6 +478,7 @@ class _ENTERPRISE_SecretDetection(CustomLogger):
if "messages" in data and isinstance(data["messages"], list):
for message in data["messages"]:
if "content" in message and isinstance(message["content"], str):
detected_secrets = self.scan_message_for_secrets(message["content"])
for secret in detected_secrets:

View file

@ -0,0 +1,23 @@
"""
This plugin searches for Adafruit keys
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class AdafruitKeyDetector(RegexBasedDetector):
"""Scans for Adafruit keys."""
@property
def secret_type(self) -> str:
return "Adafruit API Key"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(
r"""(?i)(?:adafruit)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
)
]

View file

@ -0,0 +1,26 @@
"""
This plugin searches for Adobe keys
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class AdobeSecretDetector(RegexBasedDetector):
"""Scans for Adobe client keys."""
@property
def secret_type(self) -> str:
return "Adobe Client Keys"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Adobe Client ID (OAuth Web)
re.compile(
r"""(?i)(?:adobe)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# Adobe Client Secret
re.compile(r"(?i)\b((p8e-)[a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"),
]

View file

@ -0,0 +1,21 @@
"""
This plugin searches for Age secret keys
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class AgeSecretKeyDetector(RegexBasedDetector):
"""Scans for Age secret keys."""
@property
def secret_type(self) -> str:
return "Age Secret Key"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(r"""AGE-SECRET-KEY-1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{58}"""),
]

View file

@ -0,0 +1,23 @@
"""
This plugin searches for Airtable API keys
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class AirtableApiKeyDetector(RegexBasedDetector):
"""Scans for Airtable API keys."""
@property
def secret_type(self) -> str:
return "Airtable API Key"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(
r"""(?i)(?:airtable)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{17})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,21 @@
"""
This plugin searches for Algolia API keys
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class AlgoliaApiKeyDetector(RegexBasedDetector):
"""Scans for Algolia API keys."""
@property
def secret_type(self) -> str:
return "Algolia API Key"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(r"""(?i)\b((LTAI)[a-z0-9]{20})(?:['|\"|\n|\r|\s|\x60|;]|$)"""),
]

View file

@ -0,0 +1,26 @@
"""
This plugin searches for Alibaba secrets
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class AlibabaSecretDetector(RegexBasedDetector):
"""Scans for Alibaba AccessKey IDs and Secret Keys."""
@property
def secret_type(self) -> str:
return "Alibaba Secrets"
@property
def denylist(self) -> list[re.Pattern]:
return [
# For Alibaba AccessKey ID
re.compile(r"""(?i)\b((LTAI)[a-z0-9]{20})(?:['|\"|\n|\r|\s|\x60|;]|$)"""),
# For Alibaba Secret Key
re.compile(
r"""(?i)(?:alibaba)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{30})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,28 @@
"""
This plugin searches for Asana secrets
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class AsanaSecretDetector(RegexBasedDetector):
"""Scans for Asana Client IDs and Client Secrets."""
@property
def secret_type(self) -> str:
return "Asana Secrets"
@property
def denylist(self) -> list[re.Pattern]:
return [
# For Asana Client ID
re.compile(
r"""(?i)(?:asana)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9]{16})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# For Asana Client Secret
re.compile(
r"""(?i)(?:asana)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Atlassian API tokens
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class AtlassianApiTokenDetector(RegexBasedDetector):
"""Scans for Atlassian API tokens."""
@property
def secret_type(self) -> str:
return "Atlassian API token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# For Atlassian API token
re.compile(
r"""(?i)(?:atlassian|confluence|jira)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{24})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Authress Service Client Access Keys
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class AuthressAccessKeyDetector(RegexBasedDetector):
"""Scans for Authress Service Client Access Keys."""
@property
def secret_type(self) -> str:
return "Authress Service Client Access Key"
@property
def denylist(self) -> list[re.Pattern]:
return [
# For Authress Service Client Access Key
re.compile(
r"""(?i)\b((?:sc|ext|scauth|authress)_[a-z0-9]{5,30}\.[a-z0-9]{4,6}\.acc[_-][a-z0-9-]{10,32}\.[a-z0-9+/_=-]{30,120})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Beamer API tokens
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class BeamerApiTokenDetector(RegexBasedDetector):
"""Scans for Beamer API tokens."""
@property
def secret_type(self) -> str:
return "Beamer API token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# For Beamer API token
re.compile(
r"""(?i)(?:beamer)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(b_[a-z0-9=_\-]{44})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,28 @@
"""
This plugin searches for Bitbucket Client ID and Client Secret
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class BitbucketDetector(RegexBasedDetector):
"""Scans for Bitbucket Client ID and Client Secret."""
@property
def secret_type(self) -> str:
return "Bitbucket Secrets"
@property
def denylist(self) -> list[re.Pattern]:
return [
# For Bitbucket Client ID
re.compile(
r"""(?i)(?:bitbucket)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# For Bitbucket Client Secret
re.compile(
r"""(?i)(?:bitbucket)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,28 @@
"""
This plugin searches for Bittrex Access Key and Secret Key
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class BittrexDetector(RegexBasedDetector):
"""Scans for Bittrex Access Key and Secret Key."""
@property
def secret_type(self) -> str:
return "Bittrex Secrets"
@property
def denylist(self) -> list[re.Pattern]:
return [
# For Bittrex Access Key
re.compile(
r"""(?i)(?:bittrex)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# For Bittrex Secret Key
re.compile(
r"""(?i)(?:bittrex)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,22 @@
"""
This plugin searches for Clojars API tokens
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class ClojarsApiTokenDetector(RegexBasedDetector):
"""Scans for Clojars API tokens."""
@property
def secret_type(self) -> str:
return "Clojars API token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# For Clojars API token
re.compile(r"(?i)(CLOJARS_)[a-z0-9]{60}"),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Codecov Access Token
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class CodecovAccessTokenDetector(RegexBasedDetector):
"""Scans for Codecov Access Token."""
@property
def secret_type(self) -> str:
return "Codecov Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# For Codecov Access Token
re.compile(
r"""(?i)(?:codecov)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Coinbase Access Token
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class CoinbaseAccessTokenDetector(RegexBasedDetector):
"""Scans for Coinbase Access Token."""
@property
def secret_type(self) -> str:
return "Coinbase Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# For Coinbase Access Token
re.compile(
r"""(?i)(?:coinbase)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_-]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,28 @@
"""
This plugin searches for Confluent Access Token and Confluent Secret Key
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class ConfluentDetector(RegexBasedDetector):
"""Scans for Confluent Access Token and Confluent Secret Key."""
@property
def secret_type(self) -> str:
return "Confluent Secret"
@property
def denylist(self) -> list[re.Pattern]:
return [
# For Confluent Access Token
re.compile(
r"""(?i)(?:confluent)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{16})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# For Confluent Secret Key
re.compile(
r"""(?i)(?:confluent)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,23 @@
"""
This plugin searches for Contentful delivery API token.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class ContentfulApiTokenDetector(RegexBasedDetector):
"""Scans for Contentful delivery API token."""
@property
def secret_type(self) -> str:
return "Contentful API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(
r"""(?i)(?:contentful)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{43})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,21 @@
"""
This plugin searches for Databricks API token.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class DatabricksApiTokenDetector(RegexBasedDetector):
"""Scans for Databricks API token."""
@property
def secret_type(self) -> str:
return "Databricks API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(r"""(?i)\b(dapi[a-h0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""),
]

View file

@ -0,0 +1,23 @@
"""
This plugin searches for Datadog Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class DatadogAccessTokenDetector(RegexBasedDetector):
"""Scans for Datadog Access Tokens."""
@property
def secret_type(self) -> str:
return "Datadog Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(
r"""(?i)(?:datadog)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,23 @@
"""
This plugin searches for Defined Networking API Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class DefinedNetworkingApiTokenDetector(RegexBasedDetector):
"""Scans for Defined Networking API Tokens."""
@property
def secret_type(self) -> str:
return "Defined Networking API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(
r"""(?i)(?:dnkey)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(dnkey-[a-z0-9=_\-]{26}-[a-z0-9=_\-]{52})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,26 @@
"""
This plugin searches for DigitalOcean tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class DigitaloceanDetector(RegexBasedDetector):
"""Scans for various DigitalOcean Tokens."""
@property
def secret_type(self) -> str:
return "DigitalOcean Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# OAuth Access Token
re.compile(r"""(?i)\b(doo_v1_[a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)"""),
# Personal Access Token
re.compile(r"""(?i)\b(dop_v1_[a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)"""),
# OAuth Refresh Token
re.compile(r"""(?i)\b(dor_v1_[a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)"""),
]

View file

@ -0,0 +1,32 @@
"""
This plugin searches for Discord Client tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class DiscordDetector(RegexBasedDetector):
"""Scans for various Discord Client Tokens."""
@property
def secret_type(self) -> str:
return "Discord Client Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Discord API key
re.compile(
r"""(?i)(?:discord)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# Discord client ID
re.compile(
r"""(?i)(?:discord)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9]{18})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# Discord client secret
re.compile(
r"""(?i)(?:discord)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,22 @@
"""
This plugin searches for Doppler API tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class DopplerApiTokenDetector(RegexBasedDetector):
"""Scans for Doppler API Tokens."""
@property
def secret_type(self) -> str:
return "Doppler API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Doppler API token
re.compile(r"""(?i)dp\.pt\.[a-z0-9]{43}"""),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Droneci Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class DroneciAccessTokenDetector(RegexBasedDetector):
"""Scans for Droneci Access Tokens."""
@property
def secret_type(self) -> str:
return "Droneci Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Droneci Access Token
re.compile(
r"""(?i)(?:droneci)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,32 @@
"""
This plugin searches for Dropbox tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class DropboxDetector(RegexBasedDetector):
"""Scans for various Dropbox Tokens."""
@property
def secret_type(self) -> str:
return "Dropbox Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Dropbox API secret
re.compile(
r"""(?i)(?:dropbox)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{15})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# Dropbox long-lived API token
re.compile(
r"""(?i)(?:dropbox)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{11}(AAAAAAAAAA)[a-z0-9\-_=]{43})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# Dropbox short-lived API token
re.compile(
r"""(?i)(?:dropbox)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(sl\.[a-z0-9\-=_]{135})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,22 @@
"""
This plugin searches for Duffel API Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class DuffelApiTokenDetector(RegexBasedDetector):
"""Scans for Duffel API Tokens."""
@property
def secret_type(self) -> str:
return "Duffel API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Duffel API Token
re.compile(r"""(?i)duffel_(test|live)_[a-z0-9_\-=]{43}"""),
]

View file

@ -0,0 +1,22 @@
"""
This plugin searches for Dynatrace API Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class DynatraceApiTokenDetector(RegexBasedDetector):
"""Scans for Dynatrace API Tokens."""
@property
def secret_type(self) -> str:
return "Dynatrace API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Dynatrace API Token
re.compile(r"""(?i)dt0c01\.[a-z0-9]{24}\.[a-z0-9]{64}"""),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for EasyPost tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class EasyPostDetector(RegexBasedDetector):
"""Scans for various EasyPost Tokens."""
@property
def secret_type(self) -> str:
return "EasyPost Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# EasyPost API token
re.compile(r"""(?i)\bEZAK[a-z0-9]{54}"""),
# EasyPost test API token
re.compile(r"""(?i)\bEZTK[a-z0-9]{54}"""),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Etsy Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class EtsyAccessTokenDetector(RegexBasedDetector):
"""Scans for Etsy Access Tokens."""
@property
def secret_type(self) -> str:
return "Etsy Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Etsy Access Token
re.compile(
r"""(?i)(?:etsy)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{24})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Facebook Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class FacebookAccessTokenDetector(RegexBasedDetector):
"""Scans for Facebook Access Tokens."""
@property
def secret_type(self) -> str:
return "Facebook Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Facebook Access Token
re.compile(
r"""(?i)(?:facebook)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Fastly API keys.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class FastlyApiKeyDetector(RegexBasedDetector):
"""Scans for Fastly API keys."""
@property
def secret_type(self) -> str:
return "Fastly API Key"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Fastly API key
re.compile(
r"""(?i)(?:fastly)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,28 @@
"""
This plugin searches for Finicity API tokens and Client Secrets.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class FinicityDetector(RegexBasedDetector):
"""Scans for Finicity API tokens and Client Secrets."""
@property
def secret_type(self) -> str:
return "Finicity Credentials"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Finicity API token
re.compile(
r"""(?i)(?:finicity)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# Finicity Client Secret
re.compile(
r"""(?i)(?:finicity)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{20})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Finnhub Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class FinnhubAccessTokenDetector(RegexBasedDetector):
"""Scans for Finnhub Access Tokens."""
@property
def secret_type(self) -> str:
return "Finnhub Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Finnhub Access Token
re.compile(
r"""(?i)(?:finnhub)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{20})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Flickr Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class FlickrAccessTokenDetector(RegexBasedDetector):
"""Scans for Flickr Access Tokens."""
@property
def secret_type(self) -> str:
return "Flickr Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Flickr Access Token
re.compile(
r"""(?i)(?:flickr)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,26 @@
"""
This plugin searches for Flutterwave API keys.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class FlutterwaveDetector(RegexBasedDetector):
"""Scans for Flutterwave API Keys."""
@property
def secret_type(self) -> str:
return "Flutterwave API Key"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Flutterwave Encryption Key
re.compile(r"""(?i)FLWSECK_TEST-[a-h0-9]{12}"""),
# Flutterwave Public Key
re.compile(r"""(?i)FLWPUBK_TEST-[a-h0-9]{32}-X"""),
# Flutterwave Secret Key
re.compile(r"""(?i)FLWSECK_TEST-[a-h0-9]{32}-X"""),
]

View file

@ -0,0 +1,22 @@
"""
This plugin searches for Frame.io API tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class FrameIoApiTokenDetector(RegexBasedDetector):
"""Scans for Frame.io API Tokens."""
@property
def secret_type(self) -> str:
return "Frame.io API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Frame.io API token
re.compile(r"""(?i)fio-u-[a-z0-9\-_=]{64}"""),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Freshbooks Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class FreshbooksAccessTokenDetector(RegexBasedDetector):
"""Scans for Freshbooks Access Tokens."""
@property
def secret_type(self) -> str:
return "Freshbooks Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Freshbooks Access Token
re.compile(
r"""(?i)(?:freshbooks)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for GCP API keys.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class GCPApiKeyDetector(RegexBasedDetector):
"""Scans for GCP API keys."""
@property
def secret_type(self) -> str:
return "GCP API Key"
@property
def denylist(self) -> list[re.Pattern]:
return [
# GCP API Key
re.compile(
r"""(?i)\b(AIza[0-9A-Za-z\\-_]{35})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,26 @@
"""
This plugin searches for GitHub tokens
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class GitHubTokenCustomDetector(RegexBasedDetector):
"""Scans for GitHub tokens."""
@property
def secret_type(self) -> str:
return "GitHub Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# GitHub App/Personal Access/OAuth Access/Refresh Token
# ref. https://github.blog/2021-04-05-behind-githubs-new-authentication-token-formats/
re.compile(r"(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36}"),
# GitHub Fine-Grained Personal Access Token
re.compile(r"github_pat_[0-9a-zA-Z_]{82}"),
re.compile(r"gho_[0-9a-zA-Z]{36}"),
]

View file

@ -0,0 +1,26 @@
"""
This plugin searches for GitLab secrets.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class GitLabDetector(RegexBasedDetector):
"""Scans for GitLab Secrets."""
@property
def secret_type(self) -> str:
return "GitLab Secret"
@property
def denylist(self) -> list[re.Pattern]:
return [
# GitLab Personal Access Token
re.compile(r"""glpat-[0-9a-zA-Z\-\_]{20}"""),
# GitLab Pipeline Trigger Token
re.compile(r"""glptt-[0-9a-f]{40}"""),
# GitLab Runner Registration Token
re.compile(r"""GR1348941[0-9a-zA-Z\-\_]{20}"""),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Gitter Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class GitterAccessTokenDetector(RegexBasedDetector):
"""Scans for Gitter Access Tokens."""
@property
def secret_type(self) -> str:
return "Gitter Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Gitter Access Token
re.compile(
r"""(?i)(?:gitter)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_-]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,25 @@
"""
This plugin searches for GoCardless API tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class GoCardlessApiTokenDetector(RegexBasedDetector):
"""Scans for GoCardless API Tokens."""
@property
def secret_type(self) -> str:
return "GoCardless API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# GoCardless API token
re.compile(
r"""(?:gocardless)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(live_[a-z0-9\-_=]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)""",
re.IGNORECASE,
),
]

View file

@ -0,0 +1,32 @@
"""
This plugin searches for Grafana secrets.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class GrafanaDetector(RegexBasedDetector):
"""Scans for Grafana Secrets."""
@property
def secret_type(self) -> str:
return "Grafana Secret"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Grafana API key or Grafana Cloud API key
re.compile(
r"""(?i)\b(eyJrIjoi[A-Za-z0-9]{70,400}={0,2})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# Grafana Cloud API token
re.compile(
r"""(?i)\b(glc_[A-Za-z0-9+/]{32,400}={0,2})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# Grafana Service Account token
re.compile(
r"""(?i)\b(glsa_[A-Za-z0-9]{32}_[A-Fa-f0-9]{8})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,22 @@
"""
This plugin searches for HashiCorp Terraform user/org API tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class HashiCorpTFApiTokenDetector(RegexBasedDetector):
"""Scans for HashiCorp Terraform User/Org API Tokens."""
@property
def secret_type(self) -> str:
return "HashiCorp Terraform API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# HashiCorp Terraform user/org API token
re.compile(r"""(?i)[a-z0-9]{14}\.atlasv1\.[a-z0-9\-_=]{60,70}"""),
]

View file

@ -0,0 +1,23 @@
"""
This plugin searches for Heroku API Keys.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class HerokuApiKeyDetector(RegexBasedDetector):
"""Scans for Heroku API Keys."""
@property
def secret_type(self) -> str:
return "Heroku API Key"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(
r"""(?i)(?:heroku)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for HubSpot API Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class HubSpotApiTokenDetector(RegexBasedDetector):
"""Scans for HubSpot API Tokens."""
@property
def secret_type(self) -> str:
return "HubSpot API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# HubSpot API Token
re.compile(
r"""(?i)(?:hubspot)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,26 @@
"""
This plugin searches for Hugging Face Access and Organization API Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class HuggingFaceDetector(RegexBasedDetector):
"""Scans for Hugging Face Tokens."""
@property
def secret_type(self) -> str:
return "Hugging Face Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Hugging Face Access token
re.compile(r"""(?:^|[\\'"` >=:])(hf_[a-zA-Z]{34})(?:$|[\\'"` <])"""),
# Hugging Face Organization API token
re.compile(
r"""(?:^|[\\'"` >=:\(,)])(api_org_[a-zA-Z]{34})(?:$|[\\'"` <\),])"""
),
]

View file

@ -0,0 +1,23 @@
"""
This plugin searches for Intercom API Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class IntercomApiTokenDetector(RegexBasedDetector):
"""Scans for Intercom API Tokens."""
@property
def secret_type(self) -> str:
return "Intercom API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(
r"""(?i)(?:intercom)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{60})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,28 @@
"""
This plugin searches for JFrog-related secrets like API Key and Identity Token.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class JFrogDetector(RegexBasedDetector):
"""Scans for JFrog-related secrets."""
@property
def secret_type(self) -> str:
return "JFrog Secrets"
@property
def denylist(self) -> list[re.Pattern]:
return [
# JFrog API Key
re.compile(
r"""(?i)(?:jfrog|artifactory|bintray|xray)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{73})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# JFrog Identity Token
re.compile(
r"""(?i)(?:jfrog|artifactory|bintray|xray)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Base64-encoded JSON Web Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class JWTBase64Detector(RegexBasedDetector):
"""Scans for Base64-encoded JSON Web Tokens."""
@property
def secret_type(self) -> str:
return "Base64-encoded JSON Web Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Base64-encoded JSON Web Token
re.compile(
r"""\bZXlK(?:(?P<alg>aGJHY2lPaU)|(?P<apu>aGNIVWlPaU)|(?P<apv>aGNIWWlPaU)|(?P<aud>aGRXUWlPaU)|(?P<b64>aU5qUWlP)|(?P<crit>amNtbDBJanBi)|(?P<cty>amRIa2lPaU)|(?P<epk>bGNHc2lPbn)|(?P<enc>bGJtTWlPaU)|(?P<jku>cWEzVWlPaU)|(?P<jwk>cWQyc2lPb)|(?P<iss>cGMzTWlPaU)|(?P<iv>cGRpSTZJ)|(?P<kid>cmFXUWlP)|(?P<key_ops>clpYbGZiM0J6SWpwY)|(?P<kty>cmRIa2lPaUp)|(?P<nonce>dWIyNWpaU0k2)|(?P<p2c>d01tTWlP)|(?P<p2s>d01uTWlPaU)|(?P<ppt>d2NIUWlPaU)|(?P<sub>emRXSWlPaU)|(?P<svt>emRuUWlP)|(?P<tag>MFlXY2lPaU)|(?P<typ>MGVYQWlPaUp)|(?P<url>MWNtd2l)|(?P<use>MWMyVWlPaUp)|(?P<ver>MlpYSWlPaU)|(?P<version>MlpYSnphVzl1SWpv)|(?P<x>NElqb2)|(?P<x5c>NE5XTWlP)|(?P<x5t>NE5YUWlPaU)|(?P<x5ts256>NE5YUWpVekkxTmlJNkl)|(?P<x5u>NE5YVWlPaU)|(?P<zip>NmFYQWlPaU))[a-zA-Z0-9\/\\_+\-\r\n]{40,}={0,2}"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Kraken Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class KrakenAccessTokenDetector(RegexBasedDetector):
"""Scans for Kraken Access Tokens."""
@property
def secret_type(self) -> str:
return "Kraken Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Kraken Access Token
re.compile(
r"""(?i)(?:kraken)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9\/=_\+\-]{80,90})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,28 @@
"""
This plugin searches for Kucoin Access Tokens and Secret Keys.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class KucoinDetector(RegexBasedDetector):
"""Scans for Kucoin Access Tokens and Secret Keys."""
@property
def secret_type(self) -> str:
return "Kucoin Secret"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Kucoin Access Token
re.compile(
r"""(?i)(?:kucoin)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{24})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# Kucoin Secret Key
re.compile(
r"""(?i)(?:kucoin)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,23 @@
"""
This plugin searches for Launchdarkly Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class LaunchdarklyAccessTokenDetector(RegexBasedDetector):
"""Scans for Launchdarkly Access Tokens."""
@property
def secret_type(self) -> str:
return "Launchdarkly Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(
r"""(?i)(?:launchdarkly)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
)
]

View file

@ -0,0 +1,26 @@
"""
This plugin searches for Linear API Tokens and Linear Client Secrets.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class LinearDetector(RegexBasedDetector):
"""Scans for Linear secrets."""
@property
def secret_type(self) -> str:
return "Linear Secret"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Linear API Token
re.compile(r"""(?i)lin_api_[a-z0-9]{40}"""),
# Linear Client Secret
re.compile(
r"""(?i)(?:linear)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,28 @@
"""
This plugin searches for LinkedIn Client IDs and LinkedIn Client secrets.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class LinkedInDetector(RegexBasedDetector):
"""Scans for LinkedIn secrets."""
@property
def secret_type(self) -> str:
return "LinkedIn Secret"
@property
def denylist(self) -> list[re.Pattern]:
return [
# LinkedIn Client ID
re.compile(
r"""(?i)(?:linkedin|linked-in)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{14})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# LinkedIn Client secret
re.compile(
r"""(?i)(?:linkedin|linked-in)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{16})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,28 @@
"""
This plugin searches for Lob API secrets and Lob Publishable API keys.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class LobDetector(RegexBasedDetector):
"""Scans for Lob secrets."""
@property
def secret_type(self) -> str:
return "Lob Secret"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Lob API Key
re.compile(
r"""(?i)(?:lob)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}((live|test)_[a-f0-9]{35})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# Lob Publishable API Key
re.compile(
r"""(?i)(?:lob)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}((test|live)_pub_[a-f0-9]{31})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,32 @@
"""
This plugin searches for Mailgun API secrets, public validation keys, and webhook signing keys.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class MailgunDetector(RegexBasedDetector):
"""Scans for Mailgun secrets."""
@property
def secret_type(self) -> str:
return "Mailgun Secret"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Mailgun Private API Token
re.compile(
r"""(?i)(?:mailgun)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(key-[a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# Mailgun Public Validation Key
re.compile(
r"""(?i)(?:mailgun)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(pubkey-[a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# Mailgun Webhook Signing Key
re.compile(
r"""(?i)(?:mailgun)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-h0-9]{32}-[a-h0-9]{8}-[a-h0-9]{8})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for MapBox API tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class MapBoxApiTokenDetector(RegexBasedDetector):
"""Scans for MapBox API tokens."""
@property
def secret_type(self) -> str:
return "MapBox API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# MapBox API Token
re.compile(
r"""(?i)(?:mapbox)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(pk\.[a-z0-9]{60}\.[a-z0-9]{22})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Mattermost Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class MattermostAccessTokenDetector(RegexBasedDetector):
"""Scans for Mattermost Access Tokens."""
@property
def secret_type(self) -> str:
return "Mattermost Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Mattermost Access Token
re.compile(
r"""(?i)(?:mattermost)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{26})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,28 @@
"""
This plugin searches for MessageBird API tokens and client IDs.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class MessageBirdDetector(RegexBasedDetector):
"""Scans for MessageBird secrets."""
@property
def secret_type(self) -> str:
return "MessageBird Secret"
@property
def denylist(self) -> list[re.Pattern]:
return [
# MessageBird API Token
re.compile(
r"""(?i)(?:messagebird|message-bird|message_bird)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{25})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# MessageBird Client ID
re.compile(
r"""(?i)(?:messagebird|message-bird|message_bird)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Microsoft Teams Webhook URLs.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class MicrosoftTeamsWebhookDetector(RegexBasedDetector):
"""Scans for Microsoft Teams Webhook URLs."""
@property
def secret_type(self) -> str:
return "Microsoft Teams Webhook"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Microsoft Teams Webhook
re.compile(
r"""https:\/\/[a-z0-9]+\.webhook\.office\.com\/webhookb2\/[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}@[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}\/IncomingWebhook\/[a-z0-9]{32}\/[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}"""
),
]

View file

@ -0,0 +1,24 @@
"""
This plugin searches for Netlify Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class NetlifyAccessTokenDetector(RegexBasedDetector):
"""Scans for Netlify Access Tokens."""
@property
def secret_type(self) -> str:
return "Netlify Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# Netlify Access Token
re.compile(
r"""(?i)(?:netlify)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{40,46})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,32 @@
"""
This plugin searches for New Relic API tokens and keys.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class NewRelicDetector(RegexBasedDetector):
"""Scans for New Relic API tokens and keys."""
@property
def secret_type(self) -> str:
return "New Relic API Secrets"
@property
def denylist(self) -> list[re.Pattern]:
return [
# New Relic ingest browser API token
re.compile(
r"""(?i)(?:new-relic|newrelic|new_relic)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(NRJS-[a-f0-9]{19})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# New Relic user API ID
re.compile(
r"""(?i)(?:new-relic|newrelic|new_relic)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# New Relic user API Key
re.compile(
r"""(?i)(?:new-relic|newrelic|new_relic)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(NRAK-[a-z0-9]{27})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,23 @@
"""
This plugin searches for New York Times Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class NYTimesAccessTokenDetector(RegexBasedDetector):
"""Scans for New York Times Access Tokens."""
@property
def secret_type(self) -> str:
return "New York Times Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(
r"""(?i)(?:nytimes|new-york-times,|newyorktimes)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
)
]

View file

@ -0,0 +1,23 @@
"""
This plugin searches for Okta Access Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class OktaAccessTokenDetector(RegexBasedDetector):
"""Scans for Okta Access Tokens."""
@property
def secret_type(self) -> str:
return "Okta Access Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(
r"""(?i)(?:okta)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{42})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
)
]

View file

@ -0,0 +1,19 @@
"""
This plugin searches for OpenAI API Keys.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class OpenAIApiKeyDetector(RegexBasedDetector):
"""Scans for OpenAI API Keys."""
@property
def secret_type(self) -> str:
return "Strict OpenAI API Key"
@property
def denylist(self) -> list[re.Pattern]:
return [re.compile(r"""(sk-[a-zA-Z0-9]{5,})""")]

View file

@ -0,0 +1,32 @@
"""
This plugin searches for PlanetScale API tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class PlanetScaleDetector(RegexBasedDetector):
"""Scans for PlanetScale API Tokens."""
@property
def secret_type(self) -> str:
return "PlanetScale API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
# the PlanetScale API token
re.compile(
r"""(?i)\b(pscale_tkn_[a-z0-9=\-_\.]{32,64})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# the PlanetScale OAuth token
re.compile(
r"""(?i)\b(pscale_oauth_[a-z0-9=\-_\.]{32,64})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
# the PlanetScale password
re.compile(
r"""(?i)\b(pscale_pw_[a-z0-9=\-_\.]{32,64})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
),
]

View file

@ -0,0 +1,23 @@
"""
This plugin searches for Postman API Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class PostmanApiTokenDetector(RegexBasedDetector):
"""Scans for Postman API Tokens."""
@property
def secret_type(self) -> str:
return "Postman API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [
re.compile(
r"""(?i)\b(PMAK-[a-f0-9]{24}-[a-f0-9]{34})(?:['|\"|\n|\r|\s|\x60|;]|$)"""
)
]

View file

@ -0,0 +1,19 @@
"""
This plugin searches for Prefect API Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class PrefectApiTokenDetector(RegexBasedDetector):
"""Scans for Prefect API Tokens."""
@property
def secret_type(self) -> str:
return "Prefect API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [re.compile(r"""(?i)\b(pnu_[a-z0-9]{36})(?:['|\"|\n|\r|\s|\x60|;]|$)""")]

View file

@ -0,0 +1,19 @@
"""
This plugin searches for Pulumi API Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class PulumiApiTokenDetector(RegexBasedDetector):
"""Scans for Pulumi API Tokens."""
@property
def secret_type(self) -> str:
return "Pulumi API Token"
@property
def denylist(self) -> list[re.Pattern]:
return [re.compile(r"""(?i)\b(pul-[a-f0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)""")]

View file

@ -0,0 +1,19 @@
"""
This plugin searches for PyPI Upload Tokens.
"""
import re
from detect_secrets.plugins.base import RegexBasedDetector
class PyPiUploadTokenDetector(RegexBasedDetector):
"""Scans for PyPI Upload Tokens."""
@property
def secret_type(self) -> str:
return "PyPI Upload Token"
@property
def denylist(self) -> list[re.Pattern]:
return [re.compile(r"""pypi-AgEIcHlwaS5vcmc[A-Za-z0-9\-_]{50,1000}""")]

Some files were not shown because too many files have changed in this diff Show more