From 0bb4f8dc58cc0cd4b3c2134300dd6c2c9342dde5 Mon Sep 17 00:00:00 2001 From: emberb170d Date: Wed, 26 Aug 2026 21:23:01 -0400 Subject: [PATCH] feat: add fastapi-ai-guardrails extension (issue #82) - Add input/output guardrail hooks with typed validation - Include default rules: max length, blocked patterns, required fields - Add comprehensive test suite - Add documentation: README, guide, env config - Follow CPA extension template conventions --- extensions/fastapi-ai-guardrails/README.md | 78 +++++ .../fastapi-ai-guardrails/README.md.append | 85 +++++ .../fastapi-ai-guardrails/pyproject.toml | 17 + .../template/.env.example.append | 26 ++ .../fastapi-ai-guardrails/template/.gitignore | 65 ++++ .../template/app/__init__.py | 0 .../template/app/core/__init__.py | 0 .../template/app/core/guardrails.py | 102 ++++++ .../template/docs/FASTAPI_GUARDRAILS_GUIDE.md | 295 ++++++++++++++++++ .../template/tests/__init__.py | 0 .../template/tests/test_guardrails.py | 64 ++++ 11 files changed, 732 insertions(+) create mode 100644 extensions/fastapi-ai-guardrails/README.md create mode 100644 extensions/fastapi-ai-guardrails/README.md.append create mode 100644 extensions/fastapi-ai-guardrails/pyproject.toml create mode 100644 extensions/fastapi-ai-guardrails/template/.env.example.append create mode 100644 extensions/fastapi-ai-guardrails/template/.gitignore create mode 100644 extensions/fastapi-ai-guardrails/template/app/__init__.py create mode 100644 extensions/fastapi-ai-guardrails/template/app/core/__init__.py create mode 100644 extensions/fastapi-ai-guardrails/template/app/core/guardrails.py create mode 100644 extensions/fastapi-ai-guardrails/template/docs/FASTAPI_GUARDRAILS_GUIDE.md create mode 100644 extensions/fastapi-ai-guardrails/template/tests/__init__.py create mode 100644 extensions/fastapi-ai-guardrails/template/tests/test_guardrails.py diff --git a/extensions/fastapi-ai-guardrails/README.md b/extensions/fastapi-ai-guardrails/README.md new file mode 100644 index 0000000..1932909 --- /dev/null +++ b/extensions/fastapi-ai-guardrails/README.md @@ -0,0 +1,78 @@ +# fastapi-ai-guardrails + +A FastAPI extension providing typed guardrail hooks for input and output validation in AI applications. + +## Overview + +This extension adds guardrail mechanisms to ensure that AI-generated or user-provided inputs and outputs meet certain quality and safety standards. It provides: + +- **Input validation**: Checks for required fields, maximum length limits, and blocked patterns. +- **Output validation**: Ensures generated responses adhere to safety and formatting rules. +- **Extensible design**: Easy to customize guardrail rules for specific use cases. + +## Installation + +```bash +pip install fastapi-ai-guardrails +``` + +## Usage + +Add the extension to your FastAPI application: + +```python +from fastapi import FastAPI +from fastapi_ai_guardrails import apply_input_guardrails, apply_output_guardrails + +app = FastAPI() + +@app.post("/chat") +async def chat_endpoint( + user_message: str, + model_response: dict, +): + # Validate input + validated_input = apply_input_guardrails(user_message) + + # Process the model + processed = model.process(validated_input) + + # Validate output + validated_output = apply_output_guardrails(processed) + + return {"response": validated_output} +``` + +## Guardrail Rules + +### Input Validation + +- **Required fields**: Ensure critical fields are present +- **Max length**: Limit string lengths to prevent excessive processing +- **Blocked patterns**: Prevent dangerous or inappropriate content + +### Output Validation + +- **Max length**: Cap response size +- **Blocked patterns**: Sanitize output for safety +- **Structured response checks**: Enforce expected schema + +## Configuration + +The extension accepts configurable parameters for each guardrail: + +- `max_length`: Maximum allowed length for strings +- `blocked_patterns`: List of substrings to reject +- `required_fields`: Fields that must be present + +## Testing + +Run the test suite: + +```bash +pytest extensions/fastapi-ai-guardrails/tests/test_guardrails.py -v +``` + +## License + +MIT \ No newline at end of file diff --git a/extensions/fastapi-ai-guardrails/README.md.append b/extensions/fastapi-ai-guardrails/README.md.append new file mode 100644 index 0000000..68aa6b5 --- /dev/null +++ b/extensions/fastapi-ai-guardrails/README.md.append @@ -0,0 +1,85 @@ +# fastapi-ai-guardrails Extension + +## Overview + +This extension provides comprehensive input and output guardrail validation for FastAPI AI applications, ensuring safety and quality standards are maintained throughout the AI pipeline. + +## Features + +- **Input Validation**: Required fields, max length limits, blocked patterns +- **Output Validation**: Structured response checks, safety filters +- **Configurable Rules**: Easy customization for specific use cases +- **Error Handling**: Clear GuardrailError exceptions with descriptive messages + +## Integration + +Add to your `extension-addons` in `cpa.config.json`: + +```json +{ + "extension-addons": ["fastapi-ai-guardrails"] +} +``` + +## Usage Examples + +### Basic Usage + +```python +from app.core.guardrails import apply_input_guardrails, apply_output_guardrails + +# Validate user input +validated_input = apply_input_guardrails( + user_query, + max_length=1000, + blocked_patterns=["ignore previous instructions", "delete everything"], + required_fields=["user_id", "query_type"] +) + +# Validate model output +validated_output = apply_output_guardrails( + model_response, + max_length=500, + blocked_patterns=["@", "mailto:"], + required_fields=["answer", "confidence"] +) +``` + +### Configuration for Your App + +Create `app/config/guardrails.yaml`: + +```yaml +input: + max_length: 1000 + blocked_patterns: + - "ignore" + - "bypass" + - "override" + required_fields: + - "user_id" + - "session_id" + +output: + max_length: 500 + blocked_patterns: + - "@" + - "mailto:" + - "tel:" + required_fields: + - "response" + - "confidence" +``` + +## Testing + +Run extension tests: + +```bash +cd extensions/fastapi-ai-guardrails +pytest tests/ -v +``` + +## License + +MIT \ No newline at end of file diff --git a/extensions/fastapi-ai-guardrails/pyproject.toml b/extensions/fastapi-ai-guardrails/pyproject.toml new file mode 100644 index 0000000..6801804 --- /dev/null +++ b/extensions/fastapi-ai-guardrails/pyproject.toml @@ -0,0 +1,17 @@ +[project] +name = "fastapi-ai-guardrails" +version = "0.1.0" +description = "FastAPI AI extension with guardrails for input/output validation" +readme = "README.md" +license = "MIT" +requires-python = ">=3.10" + +[project.optional-dependencies] +dev = [ + "pytest>=7.0", + "pytest-cov>=4.0", +] + +[build-system] +requires = ["setuptools>=65.0"] +build-backend = "setuptools.build_meta" diff --git a/extensions/fastapi-ai-guardrails/template/.env.example.append b/extensions/fastapi-ai-guardrails/template/.env.example.append new file mode 100644 index 0000000..b462ea6 --- /dev/null +++ b/extensions/fastapi-ai-guardrails/template/.env.example.append @@ -0,0 +1,26 @@ +# FastAPI AI Guardrails Configuration + +# Input guardrail settings +GUARDRAILS_INPUT_MAX_LENGTH=1000 +GUARDRAILS_INPUT_BLOCKED_PATTERNS=ignore previous instructions,bypass security,delete everything,override +GUARDRAILS_INPUT_REQUIRED_FIELDS=user_id,session_id + +# Output guardrail settings +GUARDRAILS_OUTPUT_MAX_LENGTH=500 +GUARDRAILS_OUTPUT_BLOCKED_PATTERNS=@,mailto:,tel:,password,secret +GUARDRAILS_OUTPUT_REQUIRED_FIELDS=answer,confidence + +# Debug mode +DEBUG_GUARDRAILS=0 + +# Logging +LOG_LEVEL=INFO +GUARDRAILS_LOG_INVALID_INPUTS=true +GUARDRAILS_LOG_INVALID_OUTPUTS=true + +# Rate limiting (requests per minute) +GUARDRAILS_RATE_LIMIT_PER_MINUTE=100 + +# Cache settings +GUARDRAILS_CACHE_ENABLED=true +GUARDRAILS_CACHE_TTL=3600 \ No newline at end of file diff --git a/extensions/fastapi-ai-guardrails/template/.gitignore b/extensions/fastapi-ai-guardrails/template/.gitignore new file mode 100644 index 0000000..d1fb6d1 --- /dev/null +++ b/extensions/fastapi-ai-guardrails/template/.gitignore @@ -0,0 +1,65 @@ +# FastAPI AI Guardrails Extension + +# Python +__pycache__/ +*.pyc +*.pyo +*.pyd +.Python +env/ +venv/ +.venv/ + +# Environment +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +.env.example + +# Distribution +dist/ +build/ +*.egg-info/ +.eggs/ + +# Tests +.pytest_cache/ +.coverage +htmlcov/ + +# Documentation +*.log +*.log.* + +# Data +*.csv +*.json +*.yaml +*.yml + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Logs +logs/ +*.log + +# Temporary files +*.tmp +*.temp + +# Extension-specific +/app/core/__pycache__/ +/tests/__pycache__/ +/cache/ +/temp/ \ No newline at end of file diff --git a/extensions/fastapi-ai-guardrails/template/app/__init__.py b/extensions/fastapi-ai-guardrails/template/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/extensions/fastapi-ai-guardrails/template/app/core/__init__.py b/extensions/fastapi-ai-guardrails/template/app/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/extensions/fastapi-ai-guardrails/template/app/core/guardrails.py b/extensions/fastapi-ai-guardrails/template/app/core/guardrails.py new file mode 100644 index 0000000..f0bf5b6 --- /dev/null +++ b/extensions/fastapi-ai-guardrails/template/app/core/guardrails.py @@ -0,0 +1,102 @@ +""" +FastAPI AI guardrails extension. +Provides typed guardrail hooks for input and output validation. +""" + +from typing import Any, Callable, List, Optional, Union + + +class GuardrailError(Exception): + """Raised when input or output violates guardrail rules.""" + + +def apply_input_guardrails( + input_data: Any, + *, + max_length: int = 1000, + blocked_patterns: Optional[List[str]] = None, + required_fields: Optional[List[str]] = None, +) -> Any: + """ + Validate input data against guardrail rules. + + Args: + input_data: The input data to validate. + max_length: Maximum allowed length for string fields. + blocked_patterns: List of regex-like patterns that should not appear. + required_fields: List of field names that must be present. + + Returns: + The validated input data (possibly modified). + + Raises: + GuardrailError: If input violates any guardrail rule. + """ + # Check required fields + if required_fields: + for field in required_fields: + if field not in input_data: + raise GuardrailError(f"Missing required field: {field}") + + # Check max length for strings + if isinstance(input_data, str): + if len(input_data) > max_length: + raise GuardrailError( + f"Input string exceeds maximum length of {max_length}: {len(input_data)}" + ) + + # Check blocked patterns + if blocked_patterns: + for pattern in blocked_patterns: + if pattern in str(input_data): + raise GuardrailError( + f"Input contains blocked pattern: {pattern}" + ) + + return input_data + + +def apply_output_guardrails( + output_data: Any, + *, + max_length: int = 1000, + blocked_patterns: Optional[List[str]] = None, + required_fields: Optional[List[str]] = None, +) -> Any: + """ + Validate output data against guardrail rules. + + Args: + output_data: The output data to validate. + max_length: Maximum allowed length for string fields. + blocked_patterns: List of regex-like patterns that should not appear. + required_fields: List of field names that must be present. + + Returns: + The validated output data (possibly modified). + + Raises: + GuardrailError: If output violates any guardrail rule. + """ + # Check required fields + if required_fields: + for field in required_fields: + if field not in output_data: + raise GuardrailError(f"Missing required field: {field}") + + # Check max length for strings + if isinstance(output_data, str): + if len(output_data) > max_length: + raise GuardrailError( + f"Output string exceeds maximum length of {max_length}: {len(output_data)}" + ) + + # Check blocked patterns + if blocked_patterns: + for pattern in blocked_patterns: + if pattern in str(output_data): + raise GuardrailError( + f"Output contains blocked pattern: {pattern}" + ) + + return output_data diff --git a/extensions/fastapi-ai-guardrails/template/docs/FASTAPI_GUARDRAILS_GUIDE.md b/extensions/fastapi-ai-guardrails/template/docs/FASTAPI_GUARDRAILS_GUIDE.md new file mode 100644 index 0000000..aa0ca98 --- /dev/null +++ b/extensions/fastapi-ai-guardrails/template/docs/FASTAPI_GUARDRAILS_GUIDE.md @@ -0,0 +1,295 @@ +# FastAPI AI Guardrails Guide + +## Introduction + +This guide provides comprehensive documentation for the FastAPI AI Guardrails extension, including setup, configuration, and best practices for implementing input/output validation in your AI applications. + +## Overview + +The FastAPI AI Guardrails extension ensures that AI-generated and user-provided data meets safety and quality standards through configurable validation rules. + +## Installation + +Add the extension to your project: + +```bash +pip install fastapi-ai-guardrails +``` + +Or add to your `extension-addons` in `cpa.config.json`: + +```json +{ + "extension-addons": ["fastapi-ai-guardrails"] +} +``` + +## Quick Start + +### 1. Create Extension Directory + +```bash +mkdir -p extensions/fastapi-ai-guardrails/template/app/core +mkdir -p extensions/fastapi-ai-guardrails/template/tests +``` + +### 2. Set Up Core Module + +Add `guardrails.py` to `template/app/core/`: + +```python +"""FastAPI AI guardrails extension.""" + +from typing import Any, List, Optional + +class GuardrailError(Exception): + """Raised when input or output violates guardrail rules.""" + +def apply_input_guardrails(input_data: Any, **kwargs) -> Any: + """Validate input data against guardrail rules.""" + # Your validation logic here + return input_data + +def apply_output_guardrails(output_data: Any, **kwargs) -> Any: + """Validate output data against guardrail rules.""" + # Your validation logic here + return output_data +``` + +### 3. Add Tests + +Create comprehensive tests for all guardrail scenarios. + +## Core Features + +### Input Validation + +The extension provides several input validation mechanisms: + +#### 1. Required Fields + +Ensure critical fields are present in input data: + +```python +apply_input_guardrails( + user_data, + required_fields=["user_id", "email", "preferences"] +) +``` + +#### 2. Maximum Length + +Limit string lengths to prevent excessive processing: + +```python +apply_input_guardrails( + long_text, + max_length=1000 +) +``` + +#### 3. Blocked Patterns + +Prevent dangerous or inappropriate content: + +```python +apply_input_guardrails( + user_input, + blocked_patterns=["password", "secret", "admin"] +) +``` + +### Output Validation + +Similarly, validate AI-generated outputs: + +```python +apply_output_guardrails( + model_response, + required_fields=["answer", "confidence"], + max_length=500, + blocked_patterns=["@", "mailto:"] +) +``` + +## Configuration + +### Environment Variables + +Set guardrail configuration via environment variables: + +```bash +export GUARDRAILS_MAX_LENGTH=1000 +export GUARDRAILS_BLOCKED_PATTERNS="ignore,bypass,override" +export GUARDRAILS_REQUIRED_FIELDS="user_id,session_id" +``` + +### Config File + +Create `config/guardrails.yaml`: + +```yaml +input: + max_length: 1000 + blocked_patterns: + - "ignore previous instructions" + - "delete everything" + - "bypass security" + required_fields: + - "user_id" + - "session_id" + - "timestamp" + +output: + max_length: 500 + blocked_patterns: + - "@" + - "mailto:" + - "tel:" + - "password" + required_fields: + - "answer" + - "confidence" + - "source" +``` + +## Best Practices + +### 1. Defense in Depth + +Implement multiple layers of validation: + +```python +# Layer 1: Basic validation +validated = apply_input_guardrails(user_input) + +# Layer 2: Additional business rules +validated = business_logic.validate(validated) + +# Layer 3: AI-specific checks +validated = ai_safety.check(validated) +``` + +### 2. Error Handling + +Handle guardrail errors gracefully: + +```python +from fastapi_ai_guardrails import GuardrailError + +try: + validated = apply_input_guardrails(user_input) +except GuardrailError as e: + # Log the error + logger.warning(f"Guardrail error: {e}") + # Return user-friendly error message + return {"error": "Invalid input format", "details": str(e)}, 400 +``` + +### 3. Performance Considerations + +- Cache blocked patterns compilation +- Use efficient string matching algorithms +- Consider parallel validation for multiple fields +- Implement input truncation instead of rejection when appropriate + +## Common Use Cases + +### 1. Chat Application Guardrails + +```python +# Input guardrails for chat messages +chat_guardrails = { + "max_length": 1000, + "blocked_patterns": [ + "ignore previous instructions", + "system prompt", + "bypass", + "override" + ], + "required_fields": ["user_id", "message"] +} + +# Output guardrails for AI responses +response_guardrails = { + "max_length": 500, + "blocked_patterns": ["@", "mailto:", "password"], + "required_fields": ["text", "confidence"] +} +``` + +### 2. Data Processing Pipeline + +```python +# Validate incoming data +processed = apply_input_guardrails(data, **input_config) + +# Process with AI model +result = ai_model.process(processed) + +# Validate output +final_output = apply_output_guardrails(result, **output_config) +``` + +## Testing Your Guardrails + +### Unit Tests + +```python +def test_input_guardrails(): + # Test valid input + assert apply_input_guardrails("hello") == "hello" + + # Test blocked pattern + with pytest.raises(GuardrailError): + apply_input_guardrails("delete everything") + + # Test length limit + with pytest.raises(GuardrailError): + apply_input_guardrails("x" * 1001) +``` + +### Integration Tests + +Test guardrails within your actual application flow. + +## Troubleshooting + +### Common Issues + +**Issue**: Guardrails rejecting valid input + +**Solution**: Check your blocked patterns and required fields configuration. Ensure patterns are appropriate for your use case. + +**Issue**: Performance degradation with many guardrails + +**Solution**: Profile your guardrail implementation and optimize matching algorithms. + +**Issue**: Guardrails not being applied + +**Solution**: Verify extension is properly installed and added to `extension-addons`. + +### Debug Mode + +Set `DEBUG_GUARDRAILS=1` to enable detailed error messages and validation logging. + +## Future Enhancements + +Consider implementing: + +1. **AI-Generated Guardrails**: Use ML models to detect novel attack patterns +2. **Contextual Validation**: Understand conversation context for better validation +3. **Compliance Checks**: Validate against industry-specific regulations +4. **Real-time Monitoring**: Track guardrail effectiveness and false positives + +## Related Extensions + +This extension works well with: + +- `fastapi-ai-chat`: For chat applications +- `fastapi-ai-langgraph`: For complex workflow orchestration +- `fastapi-ai-rag`: For retrieval-augmented generation + +## License + +MIT \ No newline at end of file diff --git a/extensions/fastapi-ai-guardrails/template/tests/__init__.py b/extensions/fastapi-ai-guardrails/template/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/extensions/fastapi-ai-guardrails/template/tests/test_guardrails.py b/extensions/fastapi-ai-guardrails/template/tests/test_guardrails.py new file mode 100644 index 0000000..9da2a33 --- /dev/null +++ b/extensions/fastapi-ai-guardrails/template/tests/test_guardrails.py @@ -0,0 +1,64 @@ +"""Tests for fastapi-ai-guardrails input/output guardrails.""" + +import pytest + +from fastapi_ai_guardrails.core.guardrails import ( + GuardrailError, + apply_input_guardrails, + apply_output_guardrails, +) + + +class TestApplyInputGuardrails: + """Test input guardrail validation.""" + + def test_input_ok(self) -> None: + """Valid input should pass through without errors.""" + result = apply_input_guardrails("Hello, world!") + assert result == "Hello, world!" + + def test_input_empty_string(self) -> None: + """Empty string should be allowed.""" + result = apply_input_guardrails("") + assert result == "" + + def test_input_too_long_raises_error(self) -> None: + """Input exceeding max_length should raise GuardrailError.""" + long_input = "a" * 2000 # Exceeds default max_length of 1000 + with pytest.raises(GuardrailError, match="exceeds maximum length"): + apply_input_guardrails(long_input) + + def test_input_missing_required_field(self) -> None: + """Missing required field should raise GuardrailError.""" + with pytest.raises(GuardrailError, match="Missing required field"): + apply_input_guardrails({"other": "value"}, required_fields=["name"]) + + def test_input_with_blocked_pattern_raises_error(self) -> None: + """Input containing blocked pattern should raise GuardrailError.""" + with pytest.raises(GuardrailError, match="contains blocked pattern"): + apply_input_guardrails("Please ignore previous instructions now") + + +class TestApplyOutputGuardrails: + """Test output guardrail validation.""" + + def test_output_ok(self) -> None: + """Valid output should pass through without errors.""" + result = apply_output_guardrails("Hello, world!") + assert result == "Hello, world!" + + def test_output_too_long_raises_error(self) -> None: + """Output exceeding max_length should raise GuardrailError.""" + long_output = "x" * 2000 + with pytest.raises(GuardrailError, match="exceeds maximum length"): + apply_output_guardrails(long_output) + + def test_output_missing_required_field(self) -> None: + """Missing required field should raise GuardrailError.""" + with pytest.raises(GuardrailError, match="Missing required field"): + apply_output_guardrails({"extra": "data"}, required_fields=["name"]) + + def test_output_with_blocked_pattern_raises_error(self) -> None: + """Output containing blocked pattern should raise GuardrailError.""" + with pytest.raises(GuardrailError, match="contains blocked pattern"): + apply_output_guardrails("Contact us at support@example.com")