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
3 changes: 2 additions & 1 deletion .mike.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ version_selector: true
title_switch: true
versions_file: docs/versions/versions.json
versions:
- 4.4.0
- 4.3.1
- 4.3.0
- 4.2.2
Expand Down Expand Up @@ -35,4 +36,4 @@ versions:
- 0.3.2
- latest
aliases:
latest: 4.3.1
latest: 4.4.0
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@ Release Notes

___

v4.4.0 (2026-03-14)
-------------------

New Features (v4.4.0)
------------

- **Configurable cloud IP refresh interval**: New `cloud_ip_refresh_interval` config field (default: 3600s, valid range: 60-86400s) allows tuning how often cloud provider IP ranges are refreshed. The interval is propagated to Redis TTL for cache consistency.
- **Change detection logging for cloud IP refreshes**: When cloud IP ranges are refreshed, additions and removals are logged per provider (e.g., `+12 added, -3 removed`), providing visibility into IP range mutations.
- **Context-aware detection engine**: Suspicious pattern rules are now tagged with applicable input contexts (`query_param`, `url_path`, `header`, `request_body`). Patterns are only evaluated against relevant input sources, reducing false positives.
- **Structured JSON logging**: New `log_format="json"` config option outputs logs as structured JSON (`{"timestamp": "...", "level": "...", "logger": "...", "message": "..."}`), enabling integration with log aggregation systems (ELK, Datadog, CloudWatch).
- **Per-provider `last_updated` timestamps**: `CloudManager` now tracks when each provider's IP ranges were last refreshed via `cloud_handler.last_updated["AWS"]`, returning `datetime | None`.

___

v4.3.1 (2026-03-11)
-------------------

Expand Down
75 changes: 70 additions & 5 deletions docs/api/cloud-manager.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ Class Definition
```python
class CloudManager:
_instance = None
ip_ranges: dict[str, set[ipaddress.IPv4Network]]
ip_ranges: dict[str, set[ipaddress.IPv4Network | ipaddress.IPv6Network]]
redis_handler: Any = None
agent_handler: Any = None
logger: logging.Logger
last_updated: dict[str, datetime | None]

def __new__(cls: type["CloudManager"]) -> "CloudManager":
if cls._instance is None:
Expand All @@ -30,9 +32,12 @@ class CloudManager:
"GCP": set(),
"Azure": set(),
}
cls._instance.last_updated = {
"AWS": None, "GCP": None, "Azure": None,
}
cls._instance.redis_handler = None
cls._instance.agent_handler = None
cls._instance.logger = logging.getLogger("fastapi_guard.handlers.cloud")
# IP ranges are loaded on-demand, not at initialization
return cls._instance
```

Expand All @@ -43,7 +48,7 @@ Redis Integration

When Redis is enabled, CloudManager automatically:

- Caches cloud IP ranges in Redis with 1-hour TTL
- Caches cloud IP ranges in Redis with configurable TTL (default: 1 hour, set via `cloud_ip_refresh_interval`)
- Uses cached ranges if available
- Synchronizes ranges across instances

Expand All @@ -56,9 +61,64 @@ refresh
-------

```python
def refresh(self):
def refresh(self, providers: set[str] = _ALL_PROVIDERS):
"""
Refresh IP ranges from all cloud providers.
Synchronous refresh of IP ranges from cloud providers.
Only available when Redis is not enabled.
"""
```

refresh_async
-------------

```python
async def refresh_async(
self,
providers: set[str] = _ALL_PROVIDERS,
ttl: int = 3600
):
"""
Async refresh of IP ranges with Redis caching.

Args:
providers: Set of provider names to refresh
ttl: Redis cache TTL in seconds (default: 3600)
"""
```

initialize_redis
----------------

```python
async def initialize_redis(
self,
redis_handler: Any,
providers: set[str] = _ALL_PROVIDERS,
ttl: int = 3600
):
"""
Initialize Redis integration and load IP ranges.

Args:
redis_handler: Redis handler instance
providers: Set of provider names to load
ttl: Redis cache TTL in seconds (default: 3600)
"""
```

_log_range_changes
------------------

```python
def _log_range_changes(
self,
provider: str,
old_ranges: set[ipaddress.IPv4Network | ipaddress.IPv6Network],
new_ranges: set[ipaddress.IPv4Network | ipaddress.IPv6Network],
) -> None:
"""
Log additions and removals when IP ranges change for a provider.
Called automatically during refresh operations.
"""
```

Expand Down Expand Up @@ -102,4 +162,9 @@ is_cloud = cloud_handler.is_cloud_ip(
# Refresh IP ranges manually if needed
cloud_handler.refresh() # Synchronous refresh
await cloud_handler.refresh_async() # Asynchronous with Redis

# Check when a provider was last refreshed
aws_updated = cloud_handler.last_updated["AWS"]
if aws_updated:
print(f"AWS ranges last refreshed: {aws_updated.isoformat()}")
```
48 changes: 46 additions & 2 deletions docs/api/sus-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,56 @@ async def get_all_patterns(cls) -> list[str]:
"""Get all registered patterns (default + custom)."""

@classmethod
async def get_all_compiled_patterns(cls) -> list[re.Pattern]:
"""Get all compiled regex patterns."""
async def get_all_compiled_patterns(cls) -> list[tuple[re.Pattern, frozenset[str]]]:
"""
Get all compiled regex patterns with their applicable contexts.

Returns:
List of (compiled_pattern, context_set) tuples.
Context set contains applicable input sources:
"query_param", "url_path", "header", "request_body", "unknown"
"""
```

___

Context-Aware Filtering
------------------------

Patterns are tagged with the input contexts where they are applicable, reducing false positives by only matching patterns against relevant input sources.

**Context Types:**

| Context | Description |
|---------|-------------|
| `query_param` | URL query string parameters |
| `url_path` | URL path segments |
| `header` | HTTP request headers |
| `request_body` | Request body content (JSON, form data) |
| `unknown` | Unidentified source (all patterns apply) |

**Filtering Rules:**

- When context is `unknown` or `request_body`, all patterns are evaluated
- For specific contexts (`query_param`, `url_path`, `header`), only patterns tagged for that context are checked
- Custom patterns added via `add_pattern()` always apply to all contexts

**Example:** A SQL injection pattern tagged for `query_param` and `request_body` will fire on `?id=1 OR 1=1` but not on a URL path like `/api/union/select`.

**Context Definitions by Attack Type:**

- **XSS**: `query_param`, `header`, `request_body`
- **SQL Injection**: `query_param`, `request_body`
- **Directory/Path Traversal**: `url_path`, `query_param`, `request_body`
- **Command Injection**: `query_param`, `request_body`
- **File Inclusion**: `url_path`, `query_param`, `request_body`
- **XXE/XML**: `header`, `request_body`
- **SSRF**: `query_param`, `request_body`
- **Sensitive File Probing**: `url_path`, `request_body`
- **CMS Probing**: `url_path`, `request_body`

___

Detection Methods
-----------------

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ You can also download the example app as a Docker container from [GitHub Contain
docker pull ghcr.io/rennf93/fastapi-guard-example:latest

# Or pull a specific version (matches library releases)
docker pull ghcr.io/rennf93/fastapi-guard-example:v4.3.1
docker pull ghcr.io/rennf93/fastapi-guard-example:v4.4.0
```

___
Expand Down
14 changes: 14 additions & 0 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ Release Notes

___

v4.4.0 (2026-03-14)
-------------------

New Features (v4.4.0)
------------

- **Configurable cloud IP refresh interval**: New `cloud_ip_refresh_interval` config field (default: 3600s, valid range: 60-86400s) allows tuning how often cloud provider IP ranges are refreshed. The interval is propagated to Redis TTL for cache consistency.
- **Change detection logging for cloud IP refreshes**: When cloud IP ranges are refreshed, additions and removals are logged per provider (e.g., `+12 added, -3 removed`), providing visibility into IP range mutations.
- **Context-aware detection engine**: Suspicious pattern rules are now tagged with applicable input contexts (`query_param`, `url_path`, `header`, `request_body`). Patterns are only evaluated against relevant input sources, reducing false positives.
- **Structured JSON logging**: New `log_format="json"` config option outputs logs as structured JSON (`{"timestamp": "...", "level": "...", "logger": "...", "message": "..."}`), enabling integration with log aggregation systems (ELK, Datadog, CloudWatch).
- **Per-provider `last_updated` timestamps**: `CloudManager` now tracks when each provider's IP ranges were last refreshed via `cloud_handler.last_updated["AWS"]`, returning `datetime | None`.

___

v4.3.1 (2026-03-11)
-------------------

Expand Down
27 changes: 27 additions & 0 deletions docs/tutorial/configuration/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,33 @@ Available log levels:

___

Structured JSON Logging
------------------------

FastAPI Guard supports structured JSON log output for integration with log aggregation systems like ELK, Datadog, or CloudWatch:

```python
config = SecurityConfig(
log_format="json",
custom_log_file="security.log"
)
```

When `log_format="json"` is set, all log output (both console and file) uses structured JSON:

```json
{"timestamp": "2026-03-14 08:30:00,123", "level": "INFO", "logger": "fastapi_guard", "message": "Request from 192.168.1.1"}
{"timestamp": "2026-03-14 08:30:01,456", "level": "WARNING", "logger": "fastapi_guard", "message": "Suspicious activity detected from 10.0.0.5"}
```

The default `log_format="text"` preserves the human-readable format:

```text
[fastapi_guard] 2026-03-14 08:30:00 - INFO - Request from 192.168.1.1
```

___

Performance Optimization
-------------------------

Expand Down
9 changes: 7 additions & 2 deletions docs/tutorial/configuration/security-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ Cloud Provider Settings
| `ipinfo_token` | str | None | IPInfo API token for geolocation |
| `block_cloud_providers` | dict | {} | Cloud providers to block |
| `cloud_provider_cache_ttl` | int | 86400 | Cache TTL for cloud provider data |
| `cloud_ip_refresh_interval` | int | 3600 | Interval in seconds between cloud IP range refreshes (60-86400) |

Security Headers Settings
------------------------
Expand Down Expand Up @@ -172,7 +173,7 @@ Logging Settings
| `log_enabled` | bool | True | Enable request logging |
| `log_level` | str | "INFO" | Logging level |
| `custom_log_file` | str | None | Custom log file path |
| `log_format` | str | "default" | Log format (default, json) |
| `log_format` | Literal["text", "json"] | "text" | Log output format: "text" for plain text, "json" for structured JSON |
| `mask_sensitive_data` | bool | True | Mask sensitive data in logs |

Usage Example
Expand Down Expand Up @@ -244,7 +245,11 @@ config = SecurityConfig(

# Logging
custom_log_file="security.log",
log_level="WARNING"
log_level="WARNING",
log_format="json",

# Cloud provider refresh
cloud_ip_refresh_interval=1800,
)
```

Expand Down
38 changes: 36 additions & 2 deletions docs/tutorial/ip-management/cloud-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,51 @@ ___
IP Range Updates
----------------

Cloud IP ranges are automatically updated daily. You can manually refresh them:
Cloud IP ranges are refreshed automatically at a configurable interval (default: 1 hour). You can adjust the refresh interval:

```python
config = SecurityConfig(
block_cloud_providers={"AWS", "GCP", "Azure"},
cloud_ip_refresh_interval=1800, # Refresh every 30 minutes
)
```

Valid range: 60 to 86400 seconds (1 minute to 24 hours).

When IP ranges are refreshed, changes are logged automatically:

```text
Cloud IP range update for AWS: +12 added, -3 removed
```

You can also manually trigger a refresh:

```python
from guard.handlers.cloud_handler import cloud_handler

# Refresh IP ranges
cloud_handler.refresh()
```

___

Provider Status
---------------

Track when each provider's IP ranges were last refreshed:

```python
from guard.handlers.cloud_handler import cloud_handler

for provider in ("AWS", "GCP", "Azure"):
updated = cloud_handler.last_updated[provider]
if updated:
print(f"{provider}: last updated {updated.isoformat()}")
else:
print(f"{provider}: not yet loaded")
```

___

Custom IP Checking
-------------------

Expand Down
4 changes: 4 additions & 0 deletions docs/tutorial/security/detection-engine/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ When enabled, provides heuristic-based detection:
- Returns probability scores and detected attack types
- Must be explicitly enabled in configuration

### 5. Context-Aware Pattern Filtering

Patterns are tagged with applicable input contexts (e.g., `query_param`, `url_path`, `header`, `request_body`). During detection, only patterns relevant to the current input source are evaluated. This reduces false positives — for example, XSS patterns are not checked against URL paths, and sensitive file probing patterns are not checked against headers.

### 4. Performance Monitoring

Tracks execution metrics:
Expand Down
3 changes: 2 additions & 1 deletion docs/versions/versions.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"4.4.0": "4.4.0",
"4.3.1": "4.3.1",
"4.3.0": "4.3.0",
"4.2.2": "4.2.2",
Expand Down Expand Up @@ -31,5 +32,5 @@
"0.3.4": "0.3.4",
"0.3.3": "0.3.3",
"0.3.2": "0.3.2",
"latest": "4.3.1"
"latest": "4.4.0"
}
Loading
Loading