diff --git a/QUICKSTART.md b/QUICKSTART.md index 14411ab..30b3c21 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -119,7 +119,7 @@ docker compose -f docker-compose.sentinelguard.yml up --build # Start OpenAI-compatible LLM gateway from generated config export OPENAI_API_KEY="sk-..." -export SENTINELGUARD_GATEWAY_API_KEY="local-gateway-token" +export SENTINELGUARD_GATEWAY_API_KEY="replace-with-a-random-local-token" sentinelguard gateway \ --config sentinelguard.yaml \ --gateway-config sentinelguard-gateway.yaml \ @@ -134,8 +134,16 @@ sentinelguard gateway --provider anthropic --port 8080 export GEMINI_API_KEY="..." sentinelguard gateway --provider gemini --port 8080 + +export MOONSHOT_API_KEY="..." +sentinelguard gateway --provider kimi --port 8080 ``` +`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, and +`MOONSHOT_API_KEY` are upstream provider keys. `SENTINELGUARD_GATEWAY_API_KEY` +is a client-facing token you choose for apps and IDEs that call the +SentinelGuard gateway. + Point OpenAI-compatible apps or IDEs to: ```text diff --git a/README.md b/README.md index 5910bd0..cf8889d 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,7 @@ response, and returns the safe response. pip install "sentinelguard[gateway,monitoring]" export OPENAI_API_KEY="sk-..." -export SENTINELGUARD_GATEWAY_API_KEY="local-gateway-token" +export SENTINELGUARD_GATEWAY_API_KEY="replace-with-a-random-local-token" sentinelguard init sentinelguard gateway \ --config sentinelguard.yaml \ @@ -204,6 +204,10 @@ sentinelguard gateway \ --port 8080 ``` +`OPENAI_API_KEY` is the upstream provider key. `SENTINELGUARD_GATEWAY_API_KEY` +is a client-facing token that you choose; apps, SDKs, and IDEs use it when they +call SentinelGuard at `http://localhost:8080/v1`. + For a quick single-provider run without generated files: ```bash @@ -230,7 +234,7 @@ docker build -t sentinelguard-gateway . docker run --rm -p 8080:8080 \ -e OPENAI_API_KEY="$OPENAI_API_KEY" \ - -e SENTINELGUARD_GATEWAY_API_KEY="local-gateway-token" \ + -e SENTINELGUARD_GATEWAY_API_KEY="replace-with-a-random-local-token" \ sentinelguard-gateway \ gateway --provider openai --client-api-key-env SENTINELGUARD_GATEWAY_API_KEY ``` @@ -242,7 +246,7 @@ sentinelguard init cp .env.example .env # Edit .env and set at least one upstream provider key. export OPENAI_API_KEY="sk-..." -export SENTINELGUARD_GATEWAY_API_KEY="local-gateway-token" +export SENTINELGUARD_GATEWAY_API_KEY="replace-with-a-random-local-token" docker compose -f docker-compose.sentinelguard.yml up --build ``` @@ -280,6 +284,10 @@ sentinelguard gateway --provider anthropic --port 8080 # Google Gemini export GEMINI_API_KEY="..." sentinelguard gateway --provider gemini --port 8080 + +# Kimi / Moonshot +export MOONSHOT_API_KEY="..." +sentinelguard gateway --provider kimi --port 8080 ``` OpenAI-compatible providers can use the same gateway API shape. SentinelGuard @@ -306,13 +314,17 @@ export HF_TOKEN="..." sentinelguard gateway --provider huggingface --port 8080 ``` +SentinelGuard also supports private OpenAI-compatible model gateways, vLLM, TGI, +llama.cpp servers, local Ollama, and provider pools that route across multiple +models with failover. + Then point an OpenAI-compatible client at the gateway: ```python from openai import OpenAI client = OpenAI( - api_key="local-gateway-token", + api_key="replace-with-a-random-local-token", base_url="http://localhost:8080/v1", ) @@ -328,7 +340,7 @@ client-facing base URL and client-facing API key: ```bash # In the app container or app runtime: export OPENAI_BASE_URL="http://localhost:8080/v1" -export OPENAI_API_KEY="local-gateway-token" +export OPENAI_API_KEY="replace-with-a-random-local-token" ``` Keep the real upstream provider key on the SentinelGuard gateway process or @@ -511,13 +523,15 @@ Provider defaults: | `openai` | `https://api.openai.com/v1` | `OPENAI_API_KEY` | | `anthropic` | `https://api.anthropic.com/v1` | `ANTHROPIC_API_KEY` | | `gemini` | `https://generativelanguage.googleapis.com/v1beta` | `GEMINI_API_KEY` | +| `kimi` | `https://api.moonshot.ai/v1` | `MOONSHOT_API_KEY` | | `deepseek` | `https://api.deepseek.com` | `DEEPSEEK_API_KEY` | | `mistral` | `https://api.mistral.ai/v1` | `MISTRAL_API_KEY` | | `minimax` | `https://api.minimaxi.com/v1` | `MINIMAX_API_KEY` | | `ollama` | `http://localhost:11434/v1` | `OLLAMA_API_KEY` optional | | `huggingface` | `https://router.huggingface.co/v1` | `HF_TOKEN` | -Gemini also checks `GOOGLE_API_KEY` when `GEMINI_API_KEY` is not set. +Gemini also checks `GOOGLE_API_KEY` when `GEMINI_API_KEY` is not set. Kimi also +checks `KIMI_API_KEY` when `MOONSHOT_API_KEY` is not set. For custom OpenAI-compatible servers such as vLLM, TGI, llama.cpp servers, or private model gateways, set `provider: openai-compatible` and provide `upstream_url`. diff --git a/docs/assets/css/style.scss b/docs/assets/css/style.scss index 634a9fa..ddbf9de 100644 --- a/docs/assets/css/style.scss +++ b/docs/assets/css/style.scss @@ -175,6 +175,22 @@ padding: 0.3rem 0.58rem; } +.sg-provider-row { + display: flex; + flex-wrap: wrap; + gap: 0.45rem; + margin-top: 1rem; +} + +.sg-provider-row span { + border-left: 3px solid var(--sg-teal); + color: var(--sg-muted); + font-size: 0.72rem; + font-weight: 750; + line-height: 1.2; + padding: 0.12rem 0 0.12rem 0.45rem; +} + .sg-terminal { background: var(--sg-code-bg); border: 1px solid rgba(255, 255, 255, 0.14); diff --git a/docs/gateway-api.md b/docs/gateway-api.md index 7e1a6b2..a3836aa 100644 --- a/docs/gateway-api.md +++ b/docs/gateway-api.md @@ -64,6 +64,8 @@ GET /gateway/provider-health ## Authentication Runtime traffic and usage endpoints use the gateway client key when configured. +This is the token you set with `SENTINELGUARD_GATEWAY_API_KEY`; it is separate +from upstream provider keys such as `OPENAI_API_KEY` or `ANTHROPIC_API_KEY`. Supported client headers: ```text diff --git a/docs/gateway.md b/docs/gateway.md index f791a63..9a5a131 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -7,15 +7,22 @@ SentinelGuard first. ```text Application or IDE -> SentinelGuard /v1/chat/completions - -> OpenAI, Anthropic, Gemini, Ollama, Mistral, DeepSeek, or another provider + -> OpenAI, Anthropic, Gemini, Kimi, Ollama, Mistral, DeepSeek, or another provider ``` ## Start Locally +The example below uses two different keys: + +- `OPENAI_API_KEY` is the upstream provider key used by SentinelGuard to call OpenAI. +- `SENTINELGUARD_GATEWAY_API_KEY` is a client-facing token that you choose. Your + apps, IDEs, and SDKs use this token when calling SentinelGuard at + `http://localhost:8080/v1`. + ```bash pip install "sentinelguard[gateway,monitoring]" export OPENAI_API_KEY="sk-..." -export SENTINELGUARD_GATEWAY_API_KEY="local-gateway-token" +export SENTINELGUARD_GATEWAY_API_KEY="replace-with-a-random-local-token" sentinelguard init sentinelguard gateway \ @@ -24,6 +31,40 @@ sentinelguard gateway \ --port 8080 ``` +For local testing, the gateway token can be any random string. In shared or +production deployments, use a generated secret and keep it out of source code. + +## Supported Providers + +SentinelGuard can run as one gateway in front of public, private, and local +model providers: + +| Provider | CLI shortcut | Key environment variable | +| --- | --- | --- | +| OpenAI | `--provider openai` | `OPENAI_API_KEY` | +| Anthropic Claude | `--provider anthropic` | `ANTHROPIC_API_KEY` | +| Google Gemini | `--provider gemini` | `GEMINI_API_KEY` or `GOOGLE_API_KEY` | +| Kimi / Moonshot | `--provider kimi` | `MOONSHOT_API_KEY` or `KIMI_API_KEY` | +| DeepSeek | `--provider deepseek` | `DEEPSEEK_API_KEY` | +| Mistral | `--provider mistral` | `MISTRAL_API_KEY` | +| MiniMax | `--provider minimax` | `MINIMAX_API_KEY` | +| Ollama | `--provider ollama` | optional `OLLAMA_API_KEY` | +| Hugging Face router | `--provider huggingface` | `HF_TOKEN` or `HUGGINGFACE_API_KEY` | +| vLLM, TGI, llama.cpp, private gateways | `--provider openai-compatible` | your configured key env | + +Examples: + +```bash +export ANTHROPIC_API_KEY="sk-ant-..." +sentinelguard gateway --provider anthropic --port 8080 + +export GEMINI_API_KEY="..." +sentinelguard gateway --provider gemini --port 8080 + +export MOONSHOT_API_KEY="..." +sentinelguard gateway --provider kimi --port 8080 +``` + ## Configure Apps And IDEs Use this OpenAI-compatible base URL: @@ -33,7 +74,8 @@ http://localhost:8080/v1 ``` If gateway client authentication is enabled, use the configured gateway token as -the client API key. +the client API key. That value is your `SENTINELGUARD_GATEWAY_API_KEY`, not the +upstream provider key. ## Change Gateway Settings diff --git a/docs/getting-started.md b/docs/getting-started.md index d8dfbcd..f86cb9e 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -60,6 +60,28 @@ This creates: Use `--profile library` when you only want package-mode scanner configuration. +## Gateway Keys + +Gateway mode usually has two kinds of keys: + +- An upstream provider key, such as `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, + `GEMINI_API_KEY`, or `MOONSHOT_API_KEY`. SentinelGuard uses this to call the + model provider. +- `SENTINELGUARD_GATEWAY_API_KEY`, a client-facing token that you choose. + Applications and IDEs use this token when they call SentinelGuard at + `http://localhost:8080/v1`. + +For local testing, this gateway token can be any random string: + +```bash +export SENTINELGUARD_GATEWAY_API_KEY="replace-with-a-random-local-token" +``` + +Supported gateway providers include OpenAI, Anthropic Claude, Google Gemini, +Kimi / Moonshot, DeepSeek, Mistral, MiniMax, Ollama, Hugging Face, and custom +OpenAI-compatible providers such as vLLM, TGI, llama.cpp, or private model +gateways. + ## Change Configuration From The CLI Scanner settings can be updated without opening the YAML file: diff --git a/docs/index.md b/docs/index.md index f45a7be..a4f5d90 100644 --- a/docs/index.md +++ b/docs/index.md @@ -42,6 +42,17 @@ description: Security-first LLM gateway and guardrails framework for AI applicat Prometheus metrics Docker and Kubernetes ready +
+ OpenAI + Anthropic Claude + Google Gemini + Kimi / Moonshot + DeepSeek + Mistral + MiniMax + Ollama + Hugging Face +
@@ -52,6 +63,8 @@ description: Security-first LLM gateway and guardrails framework for AI applicat

Install and start the gateway

pip install "sentinelguard[gateway,monitoring]"
+export OPENAI_API_KEY="sk-..."
+export SENTINELGUARD_GATEWAY_API_KEY="your-gateway-token"
 sentinelguard init
 sentinelguard gateway \
   --config sentinelguard.yaml \
diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css
index e574130..7c1174b 100644
--- a/docs/stylesheets/extra.css
+++ b/docs/stylesheets/extra.css
@@ -176,6 +176,22 @@
   padding: 0.3rem 0.58rem;
 }
 
+.sg-provider-row {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 0.45rem;
+  margin-top: 1rem;
+}
+
+.sg-provider-row span {
+  border-left: 3px solid var(--sg-teal);
+  color: var(--sg-muted);
+  font-size: 0.72rem;
+  font-weight: 750;
+  line-height: 1.2;
+  padding: 0.12rem 0 0.12rem 0.45rem;
+}
+
 .sg-terminal {
   background: var(--sg-code-bg);
   border: 1px solid rgba(255, 255, 255, 0.14);
diff --git a/examples/helm/sentinelguard/values.yaml b/examples/helm/sentinelguard/values.yaml
index d3182ad..3ed7efc 100644
--- a/examples/helm/sentinelguard/values.yaml
+++ b/examples/helm/sentinelguard/values.yaml
@@ -27,6 +27,15 @@ env:
   OPENAI_API_KEY: ""
   ANTHROPIC_API_KEY: ""
   GEMINI_API_KEY: ""
+  GOOGLE_API_KEY: ""
+  MOONSHOT_API_KEY: ""
+  KIMI_API_KEY: ""
+  DEEPSEEK_API_KEY: ""
+  MISTRAL_API_KEY: ""
+  MINIMAX_API_KEY: ""
+  HF_TOKEN: ""
+  HUGGINGFACE_API_KEY: ""
+  OLLAMA_API_KEY: ""
   SENTINELGUARD_GATEWAY_API_KEY: ""
   SENTINELGUARD_AUDIT_SALT: ""
 
diff --git a/examples/kubernetes/README.md b/examples/kubernetes/README.md
index e715d32..0aff775 100644
--- a/examples/kubernetes/README.md
+++ b/examples/kubernetes/README.md
@@ -38,16 +38,17 @@ Create the gateway Secret:
 kubectl create secret generic sentinelguard-gateway-secrets \
   -n sentinelguard \
   --from-literal=OPENAI_API_KEY="$OPENAI_API_KEY" \
-  --from-literal=SENTINELGUARD_GATEWAY_API_KEY="shared-gateway-token" \
+  --from-literal=SENTINELGUARD_GATEWAY_API_KEY="replace-with-shared-gateway-token" \
   --from-literal=SENTINELGUARD_AUDIT_SALT="$(openssl rand -hex 32)"
 ```
 
-For Anthropic, Gemini, DeepSeek, Mistral, MiniMax, or Hugging Face, add the
-matching key:
+For Anthropic, Gemini, Kimi/Moonshot, DeepSeek, Mistral, MiniMax, or Hugging
+Face, add the matching key:
 
 ```bash
 --from-literal=ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY"
 --from-literal=GEMINI_API_KEY="$GEMINI_API_KEY"
+--from-literal=MOONSHOT_API_KEY="$MOONSHOT_API_KEY"
 --from-literal=DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY"
 --from-literal=MISTRAL_API_KEY="$MISTRAL_API_KEY"
 --from-literal=MINIMAX_API_KEY="$MINIMAX_API_KEY"
@@ -87,8 +88,8 @@ the OpenAI-compatible base URL to:
 http://localhost:8080/v1
 ```
 
-Use `shared-gateway-token` as the client API key when gateway client auth is
-enabled.
+Use your `SENTINELGUARD_GATEWAY_API_KEY` value as the client API key when
+gateway client auth is enabled.
 
 ## Optional Ingress
 
diff --git a/examples/kubernetes/deployment.yaml b/examples/kubernetes/deployment.yaml
index abe4246..5432247 100644
--- a/examples/kubernetes/deployment.yaml
+++ b/examples/kubernetes/deployment.yaml
@@ -63,6 +63,18 @@ spec:
                   name: sentinelguard-gateway-secrets
                   key: DEEPSEEK_API_KEY
                   optional: true
+            - name: MOONSHOT_API_KEY
+              valueFrom:
+                secretKeyRef:
+                  name: sentinelguard-gateway-secrets
+                  key: MOONSHOT_API_KEY
+                  optional: true
+            - name: KIMI_API_KEY
+              valueFrom:
+                secretKeyRef:
+                  name: sentinelguard-gateway-secrets
+                  key: KIMI_API_KEY
+                  optional: true
             - name: MISTRAL_API_KEY
               valueFrom:
                 secretKeyRef:
diff --git a/examples/kubernetes/secret.example.yaml b/examples/kubernetes/secret.example.yaml
index e3d45c7..ca1e89e 100644
--- a/examples/kubernetes/secret.example.yaml
+++ b/examples/kubernetes/secret.example.yaml
@@ -11,6 +11,8 @@ stringData:
   ANTHROPIC_API_KEY: ""
   GEMINI_API_KEY: ""
   GOOGLE_API_KEY: ""
+  MOONSHOT_API_KEY: ""
+  KIMI_API_KEY: ""
   DEEPSEEK_API_KEY: ""
   MISTRAL_API_KEY: ""
   MINIMAX_API_KEY: ""
diff --git a/examples/terraform/kubernetes/README.md b/examples/terraform/kubernetes/README.md
index 098fca3..8ab2e92 100644
--- a/examples/terraform/kubernetes/README.md
+++ b/examples/terraform/kubernetes/README.md
@@ -6,7 +6,7 @@ This example deploys the SentinelGuard Helm chart with Terraform.
 terraform init
 terraform apply \
   -var='openai_api_key=sk-...' \
-  -var='gateway_api_key=local-gateway-token'
+  -var='gateway_api_key=replace-with-a-random-local-token'
 ```
 
 The example assumes your local Kubernetes context already points at the target
diff --git a/examples/test_apps/README.md b/examples/test_apps/README.md
index a77065a..1e2a9c7 100644
--- a/examples/test_apps/README.md
+++ b/examples/test_apps/README.md
@@ -108,7 +108,7 @@ Or run the same gateway as a Docker proxy:
 
 ```bash
 export OPENAI_API_KEY="sk-..."
-export SENTINELGUARD_GATEWAY_API_KEY="local-gateway-token"
+export SENTINELGUARD_GATEWAY_API_KEY="replace-with-a-random-local-token"
 docker compose up --build
 ```
 
@@ -183,6 +183,10 @@ sentinelguard gateway --provider anthropic --port 8080
 export GEMINI_API_KEY="..."
 sentinelguard gateway --provider gemini --port 8080
 
+# Kimi / Moonshot
+export MOONSHOT_API_KEY="..."
+sentinelguard gateway --provider kimi --port 8080
+
 # DeepSeek
 export DEEPSEEK_API_KEY="..."
 sentinelguard gateway --provider deepseek --port 8080
@@ -229,7 +233,7 @@ base URL and app-facing API key to the gateway:
 
 ```bash
 export OPENAI_BASE_URL="http://localhost:8080/v1"
-export OPENAI_API_KEY="local-gateway-token"
+export OPENAI_API_KEY="replace-with-a-random-local-token"
 ```
 
 The gateway container keeps the real upstream provider API key. The app only
diff --git a/sentinelguard/cli/__init__.py b/sentinelguard/cli/__init__.py
index 70c622d..2a7b638 100644
--- a/sentinelguard/cli/__init__.py
+++ b/sentinelguard/cli/__init__.py
@@ -104,7 +104,7 @@ def main(argv: Optional[List[str]] = None) -> int:
         "--provider",
         default=None,
         help=(
-            "Gateway provider: openai, anthropic, gemini, deepseek, mistral, "
+            "Gateway provider: openai, anthropic, gemini, kimi, deepseek, mistral, "
             "minimax, ollama, huggingface, or openai-compatible"
         ),
     )
diff --git a/sentinelguard/cli/bootstrap.py b/sentinelguard/cli/bootstrap.py
index 6c804fe..21ad1ca 100644
--- a/sentinelguard/cli/bootstrap.py
+++ b/sentinelguard/cli/bootstrap.py
@@ -200,7 +200,7 @@ def _env_example() -> str:
         SENTINELGUARD_VERSION={__version__}
         SENTINELGUARD_EXTRAS=gateway,monitoring
         SENTINELGUARD_IMAGE=sentinelguard-gateway:local
-        SENTINELGUARD_GATEWAY_API_KEY=change-me-local-gateway-token
+        SENTINELGUARD_GATEWAY_API_KEY=replace-with-a-random-local-token
         SENTINELGUARD_AUDIT_SALT=change-me-random-audit-salt
         SENTINELGUARD_GATEWAY_PORT=8080
 
@@ -209,6 +209,8 @@ def _env_example() -> str:
         GEMINI_API_KEY=
         GOOGLE_API_KEY=
         DEEPSEEK_API_KEY=
+        MOONSHOT_API_KEY=
+        KIMI_API_KEY=
         MISTRAL_API_KEY=
         MINIMAX_API_KEY=
         HF_TOKEN=
@@ -266,6 +268,8 @@ def _docker_compose(docker_image: str) -> str:
               GEMINI_API_KEY: ${{GEMINI_API_KEY:-}}
               GOOGLE_API_KEY: ${{GOOGLE_API_KEY:-}}
               DEEPSEEK_API_KEY: ${{DEEPSEEK_API_KEY:-}}
+              MOONSHOT_API_KEY: ${{MOONSHOT_API_KEY:-}}
+              KIMI_API_KEY: ${{KIMI_API_KEY:-}}
               MISTRAL_API_KEY: ${{MISTRAL_API_KEY:-}}
               MINIMAX_API_KEY: ${{MINIMAX_API_KEY:-}}
               HF_TOKEN: ${{HF_TOKEN:-}}
@@ -333,7 +337,7 @@ def _readme(profile: str) -> str:
 
         ```bash
         python -m pip install "sentinelguard[gateway,monitoring]"
-        export SENTINELGUARD_GATEWAY_API_KEY="change-me-local-gateway-token"
+        export SENTINELGUARD_GATEWAY_API_KEY="replace-with-a-random-local-token"
         export SENTINELGUARD_AUDIT_SALT="change-me-random-audit-salt"
         export OPENAI_API_KEY="your-provider-key"
         sentinelguard gateway \\
@@ -342,6 +346,10 @@ def _readme(profile: str) -> str:
           --port 8080
         ```
 
+        `OPENAI_API_KEY` is the upstream provider key. The
+        `SENTINELGUARD_GATEWAY_API_KEY` value is a client-facing token that you
+        choose for apps and IDEs calling SentinelGuard.
+
         ## Run With Docker Compose
 
         ```bash
@@ -363,7 +371,9 @@ def _readme(profile: str) -> str:
         ```
 
         Use `fast-chat` for OpenAI, `smart-chat` for Anthropic, and
-        `private-chat` for local Ollama. Remove provider routes you do not use.
+        `private-chat` for local Ollama. SentinelGuard also supports Gemini,
+        Kimi/Moonshot, DeepSeek, Mistral, MiniMax, Hugging Face, and custom
+        OpenAI-compatible providers. Remove provider routes you do not use.
 
         Useful checks:
 
diff --git a/sentinelguard/gateway/providers.py b/sentinelguard/gateway/providers.py
index 730e516..820338c 100644
--- a/sentinelguard/gateway/providers.py
+++ b/sentinelguard/gateway/providers.py
@@ -23,6 +23,10 @@
         "https://router.huggingface.co/v1",
         ["HF_TOKEN", "HUGGINGFACE_API_KEY", "OPENAI_API_KEY"],
     ),
+    "kimi": (
+        "https://api.moonshot.ai/v1",
+        ["MOONSHOT_API_KEY", "KIMI_API_KEY", "OPENAI_API_KEY"],
+    ),
     "minimax": ("https://api.minimaxi.com/v1", ["MINIMAX_API_KEY", "OPENAI_API_KEY"]),
     "mistral": ("https://api.mistral.ai/v1", ["MISTRAL_API_KEY", "OPENAI_API_KEY"]),
     "ollama": ("http://localhost:11434/v1", ["OLLAMA_API_KEY"]),
@@ -39,6 +43,9 @@
     "hf": "huggingface",
     "hugging-face": "huggingface",
     "huggingface": "huggingface",
+    "kimi": "kimi",
+    "moonshot": "kimi",
+    "moonshot-ai": "kimi",
     "minimax": "minimax",
     "mini-max": "minimax",
     "minimaxi": "minimax",
diff --git a/tests/test_gateway.py b/tests/test_gateway.py
index e7ae633..4df90db 100644
--- a/tests/test_gateway.py
+++ b/tests/test_gateway.py
@@ -203,6 +203,15 @@ def test_provider_defaults_are_effective_without_overwriting_config(self):
         assert effective_upstream_url(huggingface) == "https://router.huggingface.co/v1"
         assert effective_api_key_env(huggingface) == "HF_TOKEN"
 
+        kimi = GatewayConfig(provider="kimi")
+        assert effective_provider(kimi) == "kimi"
+        assert effective_upstream_url(kimi) == "https://api.moonshot.ai/v1"
+        assert effective_api_key_env(kimi) == "MOONSHOT_API_KEY"
+
+        moonshot = GatewayConfig(provider="moonshot")
+        assert effective_provider(moonshot) == "kimi"
+        assert effective_upstream_url(moonshot) == "https://api.moonshot.ai/v1"
+
         custom = GatewayConfig(provider="my-openai-compatible-api")
         assert effective_provider(custom) == "openai-compatible"
         assert effective_upstream_url(custom) == "https://api.openai.com/v1"