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
52 changes: 29 additions & 23 deletions Dockerfile.server
Original file line number Diff line number Diff line change
@@ -1,38 +1,44 @@
FROM python:3.11-slim

# System dependencies
RUN apt-get update && apt-get install -y gcc g++ git curl \
&& rm -rf /var/lib/apt/lists/*
FROM registry.access.redhat.com/ubi9/python-312 as build

USER 0
WORKDIR /app

# Install Poetry
RUN pip install --no-cache-dir poetry
RUN dnf install -y gcc gcc-c++ git && \
pip install --no-cache-dir poetry==1.8.2 pyyaml==6.0.2 && \
dnf clean all && \
rm -rf /var/cache/dnf

# Copy project files
COPY pyproject.toml poetry.lock* README.md ./
COPY nemoguardrails/ ./nemoguardrails/
COPY examples/ ./examples/
COPY chat-ui/ ./chat-ui/
COPY nemoguardrails/ ./nemoguardrails/
COPY scripts/ ./scripts/
COPY scripts/provider-list.yaml ./scripts/
COPY scripts/filter_guardrails.py ./scripts/
COPY scripts/entrypoint.sh ./scripts/
RUN chmod +x ./scripts/entrypoint.sh

# Create non-root user and set permissions
RUN useradd --create-home guardrails && \
mkdir -p /app/config && \
mkdir -p /app/.cache/pypoetry && \
chown -R guardrails:guardrails /app
ARG GUARDRAILS_PROFILE=opensource
RUN python3 ./scripts/filter_guardrails.py ./scripts/provider-list.yaml $GUARDRAILS_PROFILE

USER guardrails
ENV POETRY_VIRTUALENVS_IN_PROJECT=1 \
POETRY_NO_INTERACTION=1

# Set Poetry cache and virtualenvs path
ENV POETRY_CACHE_DIR=/app/.cache/pypoetry
ENV POETRY_VIRTUALENVS_PATH=/app/.cache/pypoetry/virtualenvs
RUN poetry install --no-ansi --extras="sdd jailbreak openai nvidia tracing" && \
poetry run pip install "spacy>=3.4.4,<4.0.0" && \
poetry run python -m spacy download en_core_web_lg

# Install all dependencies (main + extras) as non-root user
RUN poetry install --no-interaction --no-ansi --all-extras
RUN poetry run python -m spacy download en_core_web_lg
FROM registry.access.redhat.com/ubi9/python-312

EXPOSE 8000
USER 0
WORKDIR /app

COPY --from=build /app /app
RUN rm -f /etc/security/namespace.conf /usr/lib64/security/pam_namespace.so || true && \
chgrp -R 0 /app && \
chmod -R g+rwX /app

USER 1001

ENV PATH="/app/.venv/bin:$PATH"
EXPOSE 8000
ENTRYPOINT ["./scripts/entrypoint.sh"]
26 changes: 11 additions & 15 deletions scripts/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
#!/bin/bash

# Allow runtime overrides via env vars or args
CONFIG_ID="${CONFIG_ID:-$1}"
PORT="${PORT:-$2}"

# Set defaults if not provided
CONFIG_ID="${CONFIG_ID:-nemo}"
PORT="${PORT:-8000}"
CONFIG_ID="${CONFIG_ID:-${1:-nemo}}"
PORT="${PORT:-${2:-8000}}"

CONFIG_DIR="/app/config/${CONFIG_ID}"

echo "🚀 Starting NeMo Guardrails with config from: $CONFIG_DIR (port: $PORT)"

# Validate config exists
if [[ ! -f "$CONFIG_DIR/config.yaml" ]]; then
echo "❌ ERROR: config.yaml not found in $CONFIG_DIR"
exit 1
echo "❌ ERROR: config.yaml not found in $CONFIG_DIR"
exit 1
fi

# Do NOT attempt to create rails.co if missing (ConfigMap is read-only)
if [[ ! -f "$CONFIG_DIR/rails.co" ]]; then
echo "❌ ERROR: rails.co not found in $CONFIG_DIR (ConfigMap is read-only, please provide it)"
exit 1
echo "❌ ERROR: rails.co not found in $CONFIG_DIR (ConfigMap is read-only, please provide it)"
exit 1
fi

echo "✅ Configuration validated. Starting server..."
exec poetry run nemoguardrails server \
--config "/app/config" \
--port "$PORT" \
--default-config-id "$CONFIG_ID"
exec /app/.venv/bin/nemoguardrails server \
--config "/app/config" \
--port "$PORT" \
--default-config-id "$CONFIG_ID" \
--disable-chat-ui
71 changes: 71 additions & 0 deletions scripts/filter_guardrails.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env python3
import os
import sys
import yaml
import shutil
import logging
from pathlib import Path

logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
logger = logging.getLogger(__name__)


def main():
if len(sys.argv) != 3:
logger.error("Usage: filter_guardrails.py <config-file> <profile>")
sys.exit(1)

config_file = sys.argv[1]
profile = sys.argv[2]

# Load configuration
with open(config_file, "r") as f:
config = yaml.safe_load(f)

if profile not in config["profiles"]:
logger.error(
f"Profile '{profile}' not found. Available: {list(config['profiles'].keys())}"
)
sys.exit(1)

include_closed_source = config["profiles"][profile]["include_closed_source"]
closed_source_list = config["closed_source_guardrails"]

logger.info(f"Profile: {profile}")
logger.info(f"Description: {config['profiles'][profile]['description']}")

library_path = Path("./nemoguardrails/library")
if not library_path.exists():
logger.error(f"Library path {library_path} does not exist")
sys.exit(1)

kept_dirs = []
removed_dirs = []

for guardrail_dir in library_path.iterdir():
if (
not guardrail_dir.is_dir()
or guardrail_dir.name.startswith(".")
or guardrail_dir.name.startswith("__")
):
continue

guardrail_name = guardrail_dir.name
is_closed_source = guardrail_name in closed_source_list

if is_closed_source and not include_closed_source:
logger.info(f"Removing closed source: {guardrail_name}")
shutil.rmtree(guardrail_dir)
removed_dirs.append(guardrail_name)
else:
source_type = "closed source" if is_closed_source else "open source"
logger.info(f"Keeping {source_type}: {guardrail_name}")
kept_dirs.append(guardrail_name)

logger.info(
f"\nSummary: kept {len(kept_dirs)}, removed {len(removed_dirs)} guardrails"
)


if __name__ == "__main__":
main()
21 changes: 21 additions & 0 deletions scripts/provider-list.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Build time guardrails selection
profiles:
opensource:
description: "Open source guardrails only"
include_closed_source: false

all:
description: "All available guardrails (open + closed source)"
include_closed_source: true

# Define which guardrails are closed source (everything else is considered open source)
closed_source_guardrails:
- "activefence"
- "cleanlab"
- "clavata"
- "privateai"
- "fiddler"
- "patronusai"
- "clavata"
- "prompt_security"
- "gcp_moderate_text"
Loading