Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.git
.github
.pytest_cache
.ruff_cache
.mypy_cache
.coverage
.venv
__pycache__
*.py[cod]
*.egg-info
build
dist
htmlcov
research_paper
tmp
tools
23 changes: 23 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM python:3.11-slim

ARG SENTINELGUARD_EXTRAS=gateway,monitoring

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1

WORKDIR /app

COPY pyproject.toml README.md ./
COPY sentinelguard ./sentinelguard

RUN python -m pip install --upgrade pip \
&& python -m pip install ".[${SENTINELGUARD_EXTRAS}]"

EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/gateway/health', timeout=3)"

ENTRYPOINT ["sentinelguard"]
CMD ["gateway", "--host", "0.0.0.0", "--port", "8080"]
58 changes: 56 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ print(report.summary())
pip install sentinelguard
```

For model-backed prompt injection, jailbreak, toxicity, and bias scanners,
install the optional model extra:
For model-backed prompt injection, jailbreak, secrets, toxicity, and bias
scanners, install the optional model extra:

```bash
pip install "sentinelguard[models]"
Expand All @@ -67,6 +67,18 @@ scores are used automatically once the models are ready. The optional models
can require more than 2 GB of local cache space depending on platform and
Hugging Face cache state.

The secrets scanner remains hybrid: deterministic detectors catch known API
keys, tokens, private keys, and explicit password disclosure, while the local
Hugging Face model adds a second signal for ambiguous credential-sharing
language. No prompt text is sent to a remote LLM for this model-backed secret
detection.

```python
from sentinelguard.scanners.prompt import SecretsScanner

scanner = SecretsScanner(use_model="auto") # local model when warmed and ready
```

You can disable background warmup if needed:

```python
Expand Down Expand Up @@ -114,6 +126,42 @@ export OPENAI_API_KEY="sk-..."
sentinelguard gateway --provider openai --port 8080
```

Or run the gateway as a standalone Docker proxy:

```bash
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" \
sentinelguard-gateway \
gateway --provider openai --client-api-key-env SENTINELGUARD_GATEWAY_API_KEY
```

With Docker Compose:

```bash
export OPENAI_API_KEY="sk-..."
export SENTINELGUARD_GATEWAY_API_KEY="local-gateway-token"
docker compose up --build
```

For local Hugging Face model-backed detection inside the image:

```bash
SENTINELGUARD_EXTRAS=gateway,monitoring,models docker compose up --build
```

Kubernetes manifests are available for running the gateway as a cluster service:

```bash
kubectl apply -k examples/kubernetes
kubectl -n sentinelguard port-forward svc/sentinelguard-gateway 8080:8080
```

See `examples/kubernetes/README.md` for image publishing, Secrets, Ingress,
and IDE/app configuration.

Native provider adapters are also available:

```bash
Expand Down Expand Up @@ -149,6 +197,11 @@ custom provider endpoint to use the gateway:
http://localhost:8080/v1
```

If gateway client auth is enabled, use the configured gateway token as the
client API key. Multiple apps, users, and AI IDEs can use the same gateway URL
as long as they route OpenAI-compatible traffic through it. Tools that do not
support a custom OpenAI-compatible endpoint cannot be intercepted automatically.

When traffic is routed through this URL, SentinelGuard scans prompts before
they reach the upstream LLM and scans model responses before they are returned.
Registering SentinelGuard only as an MCP server gives the IDE optional scanning
Expand All @@ -167,6 +220,7 @@ gateway:
provider: openai
upstream_url: https://api.openai.com/v1
api_key_env: OPENAI_API_KEY
client_api_key_env: SENTINELGUARD_GATEWAY_API_KEY
default_max_tokens: 1024
streaming_mode: buffered
metrics_enabled: true
Expand Down
30 changes: 30 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
services:
sentinelguard-gateway:
build:
context: .
args:
SENTINELGUARD_EXTRAS: ${SENTINELGUARD_EXTRAS:-gateway,monitoring}
image: sentinelguard-gateway:local
ports:
- "${SENTINELGUARD_GATEWAY_PORT:-8080}:8080"
environment:
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
GEMINI_API_KEY: ${GEMINI_API_KEY:-}
GOOGLE_API_KEY: ${GOOGLE_API_KEY:-}
SENTINELGUARD_GATEWAY_API_KEY: ${SENTINELGUARD_GATEWAY_API_KEY:-}
SENTINELGUARD_AUDIT_SALT: ${SENTINELGUARD_AUDIT_SALT:-local-dev-salt}
volumes:
- ./examples/gateway/gateway.yaml:/app/gateway.yaml:ro
- sentinelguard-hf-cache:/root/.cache/huggingface
command:
- gateway
- --host
- 0.0.0.0
- --port
- "8080"
- --gateway-config
- /app/gateway.yaml

volumes:
sentinelguard-hf-cache:
16 changes: 16 additions & 0 deletions examples/gateway/gateway.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
gateway:
enabled: true
provider: openai
upstream_url: https://api.openai.com/v1
api_key_env: OPENAI_API_KEY
client_api_key_env: SENTINELGUARD_GATEWAY_API_KEY
forward_authorization: true
block_on_prompt_fail: true
block_on_output_fail: true
sanitize: true
timeout_seconds: 60
default_max_tokens: 1024
streaming_mode: buffered
metrics_enabled: true
audit_enabled: true
audit_hash_salt_env: SENTINELGUARD_AUDIT_SALT
104 changes: 104 additions & 0 deletions examples/kubernetes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# SentinelGuard Gateway on Kubernetes

Run SentinelGuard as an OpenAI-compatible LLM gateway service in Kubernetes.
Apps, users, and AI IDEs can point their OpenAI-compatible base URL to this
gateway so prompts and model responses are scanned centrally.

## Build and publish the image

Build the default gateway image:

```bash
docker build -t registry.example.com/sentinelguard-gateway:0.0.8 .
docker push registry.example.com/sentinelguard-gateway:0.0.8
```

For local Hugging Face model-backed detection inside the gateway image:

```bash
docker build \
--build-arg SENTINELGUARD_EXTRAS=gateway,monitoring,models \
-t registry.example.com/sentinelguard-gateway:0.0.8-models .
docker push registry.example.com/sentinelguard-gateway:0.0.8-models
```

Update `deployment.yaml` to use your pushed image.

## Create secrets

Create the namespace first:

```bash
kubectl apply -f examples/kubernetes/namespace.yaml
```

Create the gateway Secret:

```bash
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_AUDIT_SALT="$(openssl rand -hex 32)"
```

For Anthropic or Gemini, add the matching key:

```bash
--from-literal=ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY"
--from-literal=GEMINI_API_KEY="$GEMINI_API_KEY"
```

You can also copy `secret.example.yaml`, replace the placeholder values, and
apply it. Do not commit real secret values.

## Deploy

```bash
kubectl apply -k examples/kubernetes
kubectl -n sentinelguard rollout status deployment/sentinelguard-gateway
```

Check health:

```bash
kubectl -n sentinelguard port-forward svc/sentinelguard-gateway 8080:8080
curl http://localhost:8080/gateway/health
```

## Configure apps and IDEs

For in-cluster apps:

```text
http://sentinelguard-gateway.sentinelguard.svc.cluster.local:8080/v1
```

For local IDEs such as Cursor, VS Code extensions, Kiro, or Codex-compatible
OpenAI clients, use port-forwarding or an internal Ingress/LoadBalancer and set
the OpenAI-compatible base URL to:

```text
http://localhost:8080/v1
```

Use `shared-gateway-token` as the client API key when gateway client auth is
enabled.

## Optional Ingress

Edit `ingress.example.yaml` for your ingress class, hostname, and TLS setup,
then apply it:

```bash
kubectl apply -f examples/kubernetes/ingress.example.yaml
```

Keep this endpoint private to your network, VPN, or internal platform controls.
The gateway may hold upstream LLM API keys.

## Model cache note

The default deployment uses an ephemeral Hugging Face cache. If you run the
`models` image in production, replace the `emptyDir` cache volume with a
PersistentVolumeClaim so model downloads survive pod restarts.
25 changes: 25 additions & 0 deletions examples/kubernetes/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: sentinelguard-gateway-config
namespace: sentinelguard
labels:
app.kubernetes.io/name: sentinelguard-gateway
data:
gateway.yaml: |
gateway:
enabled: true
provider: openai
upstream_url: https://api.openai.com/v1
api_key_env: OPENAI_API_KEY
client_api_key_env: SENTINELGUARD_GATEWAY_API_KEY
forward_authorization: true
block_on_prompt_fail: true
block_on_output_fail: true
sanitize: true
timeout_seconds: 60
default_max_tokens: 1024
streaming_mode: buffered
metrics_enabled: true
audit_enabled: true
audit_hash_salt_env: SENTINELGUARD_AUDIT_SALT
Loading
Loading