Skip to content
Open
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **compiler**: `specs` field in `barbacane.yaml` — point to a folder (e.g., `specs: ./specs/`) and all `*.yaml`/`*.json` files are discovered automatically. Used by `barbacane dev` for zero-config operation and as a fallback for `barbacane compile` when `--spec` is omitted.
- **cli**: `barbacane compile` now discovers specs from the manifest's `specs` folder when `--spec` is not provided — `barbacane compile -m barbacane.yaml -o api.bca` works with zero spec args.
- **cli**: `barbacane init` now scaffolds a `specs/` directory and places the generated spec in `specs/api.yaml` with `specs: ./specs/` in the manifest.
- **plugin**: `cel` now binds `request.body_json` in addition to the existing `request.body` string when the inbound `content-type` is `application/json` or any `application/*+json` vendor type. Enables consumer-policy expressions like `request.body_json.model.startsWith('gpt-4o')` without writing string-matching CEL. Empty map on non-JSON content-types and on parse failures (warning logged on failure; never short-circuits the request — a CEL plugin that 500s on every garbled body would let an attacker take down every downstream policy with one bad byte). Prereq for the AI consumer-policy examples in ADR-0030.
- **plugin**: `cel` `on_match.deny: { status, code, message? }` — reject the request with a configurable problem+json status and code when the expression matches. The `code` is exposed both as the URN suffix on the response `type` field and as a `code` field on the body, matching the `error.type = "model_not_permitted"` convention used by `ai-proxy`. Status defaults to 403 and is clamped into the 4xx range — denying as 5xx would mask a policy decision as a server fault. When both `set_context` and `deny` are configured for the same `on_match`, `deny` wins on a match and context is not written. `OnMatch` and `DenyAction` now `deny_unknown_fields`, so operator typos surface at config-load time instead of being silently dropped.

#### AI Gateway middlewares (ADR-0024)
- **`ai-prompt-guard` middleware plugin**: validates LLM chat-completion requests before dispatch — named profiles carry `max_messages`, `max_message_length`, regex `blocked_patterns`, and managed `system_template` with `{var}` substitution. Short-circuits with 400 + RFC 9457 problem+json on violation.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<a href="https://github.com/barbacane-dev/barbacane/actions/workflows/ci.yml"><img src="https://github.com/barbacane-dev/barbacane/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
<a href="https://docs.barbacane.dev"><img src="https://img.shields.io/badge/docs-docs.barbacane.dev-blue" alt="Documentation"></a>
<img src="https://img.shields.io/badge/unit%20tests-517%20passing-brightgreen" alt="Unit Tests">
<img src="https://img.shields.io/badge/plugin%20tests-777%20passing-brightgreen" alt="Plugin Tests">
<img src="https://img.shields.io/badge/plugin%20tests-792%20passing-brightgreen" alt="Plugin Tests">
<img src="https://img.shields.io/badge/integration%20tests-275%20passing-brightgreen" alt="Integration Tests">
<img src="https://img.shields.io/badge/cli%20tests-23%20passing-brightgreen" alt="CLI Tests">
<img src="https://img.shields.io/badge/ui%20tests-44%20passing-brightgreen" alt="UI Tests">
Expand Down
4 changes: 2 additions & 2 deletions plugins/cel/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 26 additions & 2 deletions plugins/cel/config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "urn:barbacane:plugin:cel:config",
"title": "CEL Policy Evaluation Middleware Config",
"description": "Configuration for the CEL policy evaluation middleware plugin. Evaluates inline CEL expressions against request context.\n\nTwo modes:\n- **Access-control** (default, no `on_match`): `true` → continue, `false` → 403 Forbidden.\n- **Routing** (`on_match` present): `true`write context keys and continue, `false` → continue unchanged (no 403). Used with the `ai-proxy` dispatcher to implement policy-driven model routing.",
"description": "Configuration for the CEL policy evaluation middleware plugin. Evaluates inline CEL expressions against request context.\n\nTwo modes:\n- **Access-control** (default, no `on_match`): `true` → continue, `false` → 403 Forbidden.\n- **`on_match`** (present): on `true`, take the configured actions — write context keys (`set_context`) and/or reject with a configured status + code (`deny`). On `false`, continue unchanged (no 403). When both `set_context` and `deny` are present, `deny` wins on a match — a denied request is not also written to context.",
"type": "object",
"required": ["expression"],
"additionalProperties": false,
Expand All @@ -18,7 +18,7 @@
},
"on_match": {
"type": "object",
"description": "When present, switches from access-control mode to routing mode. On a `true` result, the configured context keys are written and the request continues. On a `false` result, the request continues unchanged (no 403). Stack multiple `cel` instances to implement multiple routing rules.",
"description": "Actions to take when the expression evaluates to `true`. On a `false` result the request continues unchanged (no 403). Stack multiple `cel` instances to compose multiple match rules. When both `set_context` and `deny` are configured, a matched request is denied without context being written.",
"additionalProperties": false,
"properties": {
"set_context": {
Expand All @@ -27,6 +27,30 @@
"additionalProperties": {
"type": "string"
}
},
"deny": {
"type": "object",
"description": "Reject the request with the given problem+json status and code when the expression is true. The `code` becomes the URN suffix on the `type` field and is exposed as the `code` field on the response body — the convention used by `ai-proxy` for `model_not_permitted` and similar.",
"required": ["code"],
"additionalProperties": false,
"properties": {
"status": {
"type": "integer",
"description": "HTTP status code. Must be 4xx — denying as 5xx would mask a policy decision as a server fault. Out-of-range values fall back to 403.",
"minimum": 400,
"maximum": 499,
"default": 403
},
"code": {
"type": "string",
"description": "Machine-readable error code, snake_case by convention. Becomes the URN suffix on the response `type` field.",
"pattern": "^[a-z][a-z0-9_]*$"
},
"message": {
"type": "string",
"description": "Human-readable detail message. Falls back to `code` when omitted."
}
}
}
}
}
Expand Down
Loading