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
66 changes: 66 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,72 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht

## [Unreleased]

## [0.13.0] - 2026-05-17

**Theme: operator surface + OVERT Phase 3 path.** Four additions that
close the most legible competitive gaps without diluting the kernel
position. Hot policy reload meets the Galileo Agent Control selling
point on its own ground. The OVERT 1.0 Phase 3 Independent Attestation
Provider (IAP) reference closes the AAL-3 → AAL-4 promotion path that
v0.11.0's Provisional Receipt opens, so Vaara owns the full path
without forcing dependence on an external IAP vendor. Named injection
and PII detectors expose existing scoring surface under buyer-visible
labels. A static HTML article-coverage dashboard adds the auditor-
facing visual artefact that the peer set has converged on.

### Added
- **Hot policy reload.** New `vaara.policy.controller.PolicyController`
owns the live `Policy` and runs registered listeners under a write
lock on `reload()`. `AdaptiveScorer.apply_policy(policy)` rebinds
thresholds and sequence patterns atomically under the scorer's own
RLock; an `evaluate()` call in flight on another thread either sees
the old `(allow, deny)` pair or the new one, never a torn half.
Conformal calibration, MWU expert state, and agent profiles are
preserved across reloads. Malformed reloads are rejected with the
previous policy left live. `POST /v1/policy/reload` accepts a
server-side path or an inline body; `vaara serve --policy PATH`
enables the endpoint; `vaara policy reload POLICY_PATH` triggers
reload over HTTP from the operator's shell.
- **OVERT 1.0 AAL-4 Phase 3 IAP reference.** New
`vaara.attestation.iap` ships a `Phase3Attestation` dataclass that
wraps a Vaara `BaseEnvelope` with a notary Ed25519 signature (over a
domain-separated prefix + canonical-CBOR of the inner envelope
including its signature) and a transparency-log inclusion proof.
Structural independence between the Arbiter key and the notary key
is enforced at both emit and verify. New
`vaara.attestation.transparency_log.InProcessTransparencyLog`
implements an RFC 6962-style binary Merkle tree with domain-
separated leaf and internal hashes; `append()` /
`inclusion_proof()` / `root_hash` match the shape a sigstore Rekor
adapter would expose, so a production deployment can swap in Rekor
at the same call sites without changing the IAP contract.
- **Named injection + PII detector aliases.** `vaara.detect.detect_injection`
routes free text through the same AdversarialClassifier behind
vaara-bench-v1's published numbers (heuristic fallback when the ml
extra is absent; the `backend` field reports which path served the
call). `vaara.detect.detect_pii` is a zero-dependency regex extractor
over six categories — email, phone, US SSN, IPv4, credit_card
(Luhn-checked), IBAN (mod-97 checksum). `POST /v1/detect/injection`
and `POST /v1/detect/pii` mirror the CLI. `vaara detect injection`
and `vaara detect pii` read text from `--text`, `--file`, or
`--stdin` and exit non-zero when the detector fires.
- **Static HTML article-coverage dashboard.**
`vaara.compliance.dashboard.render_html` produces a single
self-contained HTML page with embedded CSS, no JavaScript, no
external assets, no network calls. Same content as the Markdown
renderer (system metadata, audit-trail integrity, summary, critical
gaps, per-domain article tables, detailed per-article sections) with
status badges as colored pills and a print-friendly stylesheet.
`vaara compliance dashboard --db PATH --out PATH` writes the page;
a trailing slash or existing directory drops `index.html` inside.
- **OpenAPI spec coverage.** `docs/openapi.yaml` adds
`/v1/detect/injection`, `/v1/detect/pii`, and `/v1/policy/reload`
with full request and response schemas. The spec remains the
authoritative integration surface.
- 53 new tests (14 PolicyController + reload HTTP; 11 IAP +
transparency-log; 19 detect (injection + PII + HTTP); 9 HTML
dashboard). Total 586 passing, 12 skipped.
Comment on lines +9 to +73
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Verify the release date.

The changelog shows release date 2026-05-17, but according to the PR context the current date is May 16, 2026. If this PR hasn't merged yet, the release date should either match the actual release date or be updated when the release is cut.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 9 - 73, The CHANGELOG entry header "## [0.13.0] -
2026-05-17" has the wrong date; verify whether the release was actually on
2026-05-17 or still pending and update the header in CHANGELOG.md accordingly
(either set the correct release date or use an "Unreleased"/date-to-be-filled
marker), making sure the version header "## [0.13.0] - 2026-05-17" is edited to
the confirmed value.


## [0.12.0] - 2026-05-16

**Theme: agentic OVERT reference, published benchmark, product liability hook.**
Expand Down
33 changes: 26 additions & 7 deletions COMPLIANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,19 @@ Vaara's position in this picture:
change.** The hash chain, the commit-prove receipt pair, and the
HTTP API surface all produce structured, signable artefacts that
an IAP can co-sign, batch into a transparency log, or seal under
eIDAS qualified trust services. Future work: a documented IAP
adapter interface.
eIDAS qualified trust services.
- **Vaara ships a reference IAP from v0.13.0
(`vaara.attestation.iap`).** `Phase3Attestation` wraps an AAL-3
`BaseEnvelope` with a notary Ed25519 signature over canonical CBOR
of all nine envelope fields (the inner Arbiter signature bound by
reference) plus a transparency-log inclusion proof. Structural
independence between the Arbiter key and the notary key is
enforced at both emit and verify. `InProcessTransparencyLog` is an
RFC 6962-style binary Merkle log; production deployments swap in
sigstore Rekor or an equivalent independently-operated log at the
same call sites. Operators MAY run the reference IAP themselves;
an *independent* IAP for AAL-4 still requires a separate operator
controlling the notary keys.

This positioning is deliberate. Vaara does not claim AAL-4
conformance and does not market a self-attestation pattern.
Expand Down Expand Up @@ -279,10 +290,15 @@ correspondence.
type) - ✅. Denials emit a `DENY` event on the hash chain with
policy id and violation reason.
- **TOOL-1.4** (provisional receipt before execution, upgrade to full
attestation after notary validation) - ◐ at AAL-3. The Article 12
commit-prove receipt pair (shipped v0.10.0) is the Phase 2
Provisional Receipt. Phase 3 (full notary attestation) requires an
external IAP per the OVERT-position section above.
attestation after notary validation) - ✅ structurally at AAL-3,
with the AAL-3 → AAL-4 path now implementable in-tree. The Article
12 commit-prove receipt pair (shipped v0.10.0) is the Phase 2
Provisional Receipt; the v0.11.0 OVERT Base Envelope is the
attested form. v0.13.0 ships a reference Phase 3 IAP
(`vaara.attestation.iap.emit_phase3_attestation`) that notary-signs
the Provisional Receipt and anchors it in a transparency log.
Reaching AAL-4 still requires the notary keys to live with an
independent operator.
- **TOOL-2.1** (explicit function allowlist with hash in policy
attestation) - ✅. Policy hash flows into `encoder_binary_identity`
in the Base Envelope (v0.11.0).
Expand Down Expand Up @@ -310,7 +326,10 @@ correspondence.
- **TOOL-5** (tamper-evident tool-call log with epoch attestation) -
✅ for TOOL-5.1 and TOOL-5.2 (hash-chained `AuditTrail`,
Article 12 commit-prove receipt pair). TOOL-5.3 epoch notary
attestation is the external-IAP layer.
attestation is satisfied by the v0.13.0 reference IAP
(`vaara.attestation.iap`) paired with the in-process transparency
log; a sigstore Rekor-backed log can substitute at the same call
sites.

### Section 11.5 - MCP Server Trust Governance

Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,11 @@ curl -sX POST http://localhost:8000/v1/score \

The contract is in [docs/openapi.yaml](docs/openapi.yaml). Vaara defines the interface. Control-plane and orchestration vendors call it. Integration recipes for adopters live under `examples/recipes/`.

v0.13.0 adds three operator-facing endpoints. `POST /v1/policy/reload` atomically swaps the running policy without restarting the agent process (start with `vaara serve --policy PATH` to enable; in-flight requests keep the old thresholds, the next request sees the new ones). `POST /v1/detect/injection` and `POST /v1/detect/pii` expose Vaara's adversarial scorer and a zero-dependency PII extractor as named buyer-visible endpoints; the corresponding `vaara detect injection` and `vaara detect pii` CLI subcommands exit non-zero when the detector fires, so they slot into CI gates. `vaara compliance dashboard --db PATH --out site/` renders a single-file static HTML article-coverage page from the same evidence model as `vaara compliance report`.

## OVERT 1.0 attestation

Vaara implements the OVERT 1.0 ([overt.is](https://overt.is/)) Protocol Profile 1.0 Base Envelope. OVERT 1.0 is an open standard for runtime trust in AI systems, authored by Glacis Technologies and published 25 March 2026. Closed-schema 9-field structure at AAL-3 Phase 2 (Provisional Receipt), canonical CBOR (RFC 8949), Ed25519 signatures, HMAC-SHA256 keyed commitments, IEEE-754 float rejection. External Independent Attestation Providers can promote AAL-3 emission to AAL-4 by attaching Phase 3 notary signatures and transparency-log inclusion proofs.
Vaara implements the OVERT 1.0 ([overt.is](https://overt.is/)) Protocol Profile 1.0 Base Envelope. OVERT 1.0 is an open standard for runtime trust in AI systems, authored by Glacis Technologies and published 25 March 2026. Closed-schema 9-field structure at AAL-3 Phase 2 (Provisional Receipt), canonical CBOR (RFC 8949), Ed25519 signatures, HMAC-SHA256 keyed commitments, IEEE-754 float rejection. v0.13.0 adds a reference Phase 3 IAP (`vaara.attestation.iap`) that notary-signs the Provisional Receipt and anchors it in a transparency log; production deployments can swap in sigstore Rekor or an equivalent independently-operated log at the same call sites.

```
pip install 'vaara[attestation]'
Expand All @@ -87,7 +89,7 @@ from vaara.attestation.overt import emit_base_envelope, make_request_commitment,
envelope = emit_base_envelope(
signing_key=key,
request_commitment=make_request_commitment(payload, operator_key=op_key),
encoder_binary_identity=encoder_binary_identity(arbiter_version="vaara/0.12.0", policy_hash=ph),
encoder_binary_identity=encoder_binary_identity(arbiter_version="vaara/0.13.0", policy_hash=ph),
non_content_metadata={"action_class": "tx.transfer", "decision": "escalate"},
monotonic_counter=42,
arbiter_instance_identifier=uuid_bytes,
Expand Down
182 changes: 182 additions & 0 deletions docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,95 @@ paths:
application/json:
schema: { $ref: "#/components/schemas/VerifyResponse" }

/v1/detect/injection:
post:
tags: [detect]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# Check if the file exists and get its size
ls -lh docs/openapi.yaml && wc -l docs/openapi.yaml

Repository: vaaraio/vaara

Length of output: 145


🏁 Script executed:

# Read the global tags section (around lines 30-32)
sed -n '25,45p' docs/openapi.yaml

Repository: vaaraio/vaara

Length of output: 778


🏁 Script executed:

# Read line 171 to verify the detect tag usage
sed -n '165,180p' docs/openapi.yaml

Repository: vaaraio/vaara

Length of output: 655


🏁 Script executed:

# Read line 215 to verify the policy tag usage
sed -n '210,220p' docs/openapi.yaml

Repository: vaaraio/vaara

Length of output: 515


🏁 Script executed:

# Find all tags used in operation definitions
rg 'tags:\s*\[' docs/openapi.yaml -o | sort | uniq

Repository: vaaraio/vaara

Length of output: 65


🏁 Script executed:

# Get all tags used in operation definitions with context
rg 'tags:\s*\[(\w+)\]' docs/openapi.yaml -o --replace '$1' | sort | uniq

Repository: vaaraio/vaara

Length of output: 90


🏁 Script executed:

# Verify the exact global tags declaration
sed -n '30,35p' docs/openapi.yaml

Repository: vaaraio/vaara

Length of output: 251


Declare detect and policy in the global OpenAPI tags list.

Lines 171 and 215 reference tags not declared in the top-level catalog (lines 30–32). Without these declarations, generated documentation loses tag descriptions and grouping metadata.

📌 Proposed spec patch
 tags:
   - { name: score, description: Risk evaluation }
   - { name: audit, description: Hash-chained audit trail }
   - { name: server, description: Server identity and liveness }
+  - { name: detect, description: Prompt-injection and PII detection }
+  - { name: policy, description: Runtime policy operations }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/openapi.yaml` at line 171, Top-level OpenAPI tags are missing entries
for the tags used elsewhere; add global tag declarations for "detect" and
"policy" in the document's top-level tags array so generated docs can show their
descriptions and grouping metadata. Specifically, create entries named detect
and policy (e.g., tags: - name: detect description: "..." and - name: policy
description: "...") with appropriate descriptions (and optional externalDocs) so
the API operations that reference the detect and policy tags pick up their
metadata.

summary: Score text for prompt-injection likelihood.
description: |
Routes through the Vaara adversarial scorer (the same model
behind vaara-bench-v1). Falls back to a small regex heuristic
set when the `ml` extra is not installed; the backend field
in the response reports which path served the call.
operationId: detectInjection
requestBody:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/DetectInjectionRequest" }
responses:
"200":
description: Detection result.
content:
application/json:
schema: { $ref: "#/components/schemas/DetectInjectionResponse" }

/v1/detect/pii:
post:
tags: [detect]
summary: Scan text for PII.
description: |
Regex-based extractor over six categories: email, phone, ssn,
ipv4, credit_card (Luhn-checked), iban (checksum-checked).
Returns per-finding category, value, offset, and length so
callers can highlight or redact in place.
operationId: detectPII
requestBody:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/DetectPIIRequest" }
responses:
"200":
description: Detection result.
content:
application/json:
schema: { $ref: "#/components/schemas/DetectPIIResponse" }

/v1/policy/reload:
post:
tags: [policy]
summary: Atomically reload the running policy.
description: |
Parse and validate a new policy document, then swap it in atomically.
The scorer's thresholds and sequence patterns rebind under its own
lock so an evaluate() call in flight on another thread either sees
the old pair or the new pair, never a torn half. Conformal
calibration, MWU expert state, and agent profiles are preserved.

Exactly one of `path` (server-side file path) or `body` (parsed
policy document) must be supplied. The server must have been
started with `vaara serve --policy PATH` for this endpoint to be
available; otherwise it returns `409 policy_not_configured`. A
malformed document returns `422 policy_invalid` and leaves the
previously loaded policy in place.
operationId: reloadPolicy
requestBody:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/PolicyReloadRequest" }
responses:
"200":
description: Reload accepted, new policy active.
content:
application/json:
schema: { $ref: "#/components/schemas/PolicyReloadResponse" }
"400":
description: Request supplied both `path` and `body`, or neither.
content:
application/json:
schema: { $ref: "#/components/schemas/Error" }
"409":
description: Server has no PolicyController; reload is disabled.
content:
application/json:
schema: { $ref: "#/components/schemas/Error" }
"422":
description: Policy document failed to parse or validate.
content:
application/json:
schema: { $ref: "#/components/schemas/Error" }

/v1/server:
get:
tags: [server]
Expand Down Expand Up @@ -416,6 +505,99 @@ components:
threshold_deny: { type: number, format: float }
alpha: { type: number, format: float }

DetectInjectionRequest:
type: object
required: [text]
properties:
text: { type: string, maxLength: 100000 }
threshold:
type: number
format: float
minimum: 0
maximum: 1
nullable: true

DetectInjectionResponse:
type: object
required: [detected, score, threshold, bundle_version, backend]
properties:
detected: { type: boolean }
score: { type: number, format: float, minimum: 0, maximum: 1 }
threshold: { type: number, format: float, minimum: 0, maximum: 1 }
bundle_version: { type: string }
backend:
type: string
enum: [vaara_adversarial, heuristic]

DetectPIIRequest:
type: object
required: [text]
properties:
text: { type: string, maxLength: 100000 }

DetectPIIFinding:
type: object
required: [category, value, offset, length]
properties:
category:
type: string
enum: [email, phone, ssn, ipv4, credit_card, iban]
value: { type: string }
offset: { type: integer, minimum: 0 }
length: { type: integer, minimum: 1 }

DetectPIIResponse:
type: object
required: [detected, categories, findings]
properties:
detected: { type: boolean }
categories:
type: array
items: { type: string }
findings:
type: array
items: { $ref: "#/components/schemas/DetectPIIFinding" }

PolicyReloadRequest:
type: object
description: |
Exactly one of `path` or `body` must be supplied. `path` lets the
server read the policy file directly; `body` carries an inline
parsed document for cases where the operator runs on a different
host than the server.
properties:
path: { type: string, maxLength: 4096 }
body:
type: object
additionalProperties: true
format:
type: string
enum: [json, yaml]
nullable: true

PolicyReloadResponse:
type: object
required:
- version
- thresholds_default
- sequence_count
- action_class_count
- escalation_route_count
properties:
version:
type: integer
minimum: 1
description: Monotonic generation counter; increments on every accepted reload.
thresholds_default:
type: object
required: [escalate, deny]
properties:
escalate: { type: number, format: float, minimum: 0, maximum: 1 }
deny: { type: number, format: float, minimum: 0, maximum: 1 }
sequence_count: { type: integer, minimum: 0 }
action_class_count: { type: integer, minimum: 0 }
escalation_route_count: { type: integer, minimum: 0 }

Error:
type: object
required: [error]
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "vaara"
version = "0.12.0"
version = "0.13.0"
description = "Adaptive AI Agent Execution Layer for risk scoring, audit trails, and regulatory compliance"
requires-python = ">=3.10"
license = "Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion src/vaara/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
oversight.
"""

__version__ = "0.12.0"
__version__ = "0.13.0"

from vaara.pipeline import InterceptionPipeline, InterceptionResult

Expand Down
Loading