Built-in Guards
Five guards from Provider.Core cover the most common reliability and security concerns: execution time, input schema, rate limiting, circuit breaking, and basic PII detection.
BizFirst.Ai.GuardRails.Provider.Core — Register with services.AddGuardRailsCoreGuards() or via the full-stack services.AddGuardRailsExecution().
TimeoutGuard
| Property | Value |
|---|---|
| Name | "TimeoutGuard" |
| Version | 1.0.0 |
| Supported Phases | Pre Post |
| IsSecurityCritical | false → fail-open (warns when circuit broken) |
How it works
Pre phase: Stores DateTime.UtcNow into context.Metadata["__timeout_start"] (only if not already set — idempotent). No blocking in Pre.
Post phase: Reads the start time, calculates elapsed milliseconds. If elapsed exceeds timeoutMs:
action = "block"→ returnsBlockedwith elapsed_ms and timeout_ms in metadataaction = "warn"→ returnsWarning— allows execution but logs the overrun
If __timeout_start is not in metadata (guard was not pre-initialized), the Post phase returns Success.
Configuration
{
"name": "TimeoutGuard",
"enabled": true,
"config": {
"timeoutMs": 5000, // required; integer; minimum 100ms
"action": "block" // required; "block" | "warn"
}
}
Block result metadata
{
"elapsed_ms": 6234.5,
"timeout_ms": 5000
}
InputValidationGuard
| Property | Value |
|---|---|
| Name | "InputValidationGuard" |
| Version | 1.0.0 |
| Supported Phases | Pre |
| IsSecurityCritical | true → fail-secure |
How it works
Validates context.Input against a JSON schema. If context.Input == null, returns Success (null is allowed). Otherwise:
- Checks each field listed in
requiredis present and non-null - Checks each field in
propertiesmatches its declared JSON type (string,number,boolean,array,object) strictMode=true→ returnsBlockedwith validation errorsstrictMode=false(default) → returnsWarning— allows but logs
Configuration
{
"name": "InputValidationGuard",
"enabled": true,
"config": {
"schema": {
"type": "object",
"required": ["userId", "amount"],
"properties": {
"userId": { "type": "string" },
"amount": { "type": "number" },
"currency": { "type": "string" }
}
},
"strictMode": true // optional; default false
}
}
Block result metadata
{
"validation_errors": [
"Required field 'userId' is missing or null",
"Field 'amount': expected 'number', got 'string'"
]
}
RateLimitingGuard
| Property | Value |
|---|---|
| Name | "RateLimitingGuard" |
| Version | 1.0.0 |
| Supported Phases | Pre |
| IsSecurityCritical | true → fail-secure |
How it works
Checks request count in a sliding window against rps × window (maximum allowed requests). Determines the rate limit key from scope:
| Scope | Key | When to use |
|---|---|---|
"global" | "global" | Platform-wide cap (rare) |
"tenant" | "tenant:{context.TenantId}" | Per-tenant isolation (most common) |
"user" | "user:{context.UserId}" | Per-user quota enforcement |
IRateLimitingOrchestrator from BizFirst.Platform.Operations.Guard for Redis-backed distributed rate limiting.
Configuration
{
"name": "RateLimitingGuard",
"enabled": true,
"config": {
"rps": 50, // required; number; minimum 0.1 — requests per second
"window": 60, // required; integer; minimum 1 — time window in seconds
"scope": "tenant" // required; "global" | "tenant" | "user"
}
}
Block result
{
"IsAllowed": false,
"RetryAfterSeconds": 3,
"Metadata": {
"scope": "tenant",
"requests_in_window": 52,
"limit": 50
}
}
CircuitBreakerGuard
| Property | Value |
|---|---|
| Name | "CircuitBreakerGuard" |
| Version | 1.0.0 |
| Supported Phases | Pre |
| IsSecurityCritical | false → fail-open |
How it works
Monitors health of system dependencies (Redis, RateLimitService, AuditService). Maintains three states:
| State | Behavior | Transition |
|---|---|---|
| Closed Normal | All requests allowed | → Open when failures ≥ threshold |
| Open Blocking | Requests blocked; returns Blocked with retry-after | → HalfOpen after timeout ms |
| HalfOpen Testing | One test request allowed | → Closed on success; → Open on failure |
Task.Delay(10–100ms) — always returns healthy. Production integration requires injecting IHealthCheckService to perform real dependency health checks.
Configuration
{
"name": "CircuitBreakerGuard",
"enabled": true,
"config": {
"threshold": 5, // required; integer; ≥ 1 — failures before opening
"timeout": 60000 // required; integer; ≥ 1000ms — open duration before HalfOpen
}
}
Guard Summary Table
| Guard | Phase | SecurityCritical | Blocks? | Modifies Output? |
|---|---|---|---|---|
| TimeoutGuard | PrePost | false | Yes (Post, action=block, timeout exceeded) | No |
| InputValidationGuard | Pre | true | Yes (strictMode=true) | No |
| RateLimitingGuard | Pre | true | Yes (limit exceeded) | No |
| CircuitBreakerGuard | Pre | false | Yes (circuit open) | No |