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
46 changes: 46 additions & 0 deletions .github/workflows/policy-review-mcp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Policy review MCP

"on":
pull_request:
paths:
- projects/use-case-examples/policy-review-mcp/**
- .github/workflows/policy-review-mcp.yml
push:
branches: [main]
paths:
- projects/use-case-examples/policy-review-mcp/**
- .github/workflows/policy-review-mcp.yml
workflow_dispatch:

permissions:
contents: read

concurrency:
group: policy-review-mcp-${{ github.ref }}
cancel-in-progress: true

jobs:
check:
name: Check policy review MCP
runs-on: ubuntu-latest
timeout-minutes: 10
defaults:
run:
working-directory: projects/use-case-examples/policy-review-mcp
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up uv
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
python-version: "3.12"
- name: Install locked dependencies
run: uv sync --locked --group dev
- name: Lint and check formatting
run: |
uv run --locked ruff check .
uv run --locked ruff format --check .
- name: Test without live credentials
run: uv run --locked pytest -q
2 changes: 2 additions & 0 deletions projects/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ they are not presented as production-ready applications.
- `reachy-mini-openshell`: Reachy Mini conversation demo for OpenShell.
- `robotics-policy-prover`: Robotics demonstration of policy-proving
agent-generated actions before execution.
- `policy-review-mcp`: Independent prover and JEV MCP services for reviewing
whether a delegated OpenShell policy stays within a boundary and fits its task.
3 changes: 3 additions & 0 deletions projects/use-case-examples/policy-review-mcp/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Supply this only to the JEV MCP process. Never pass it to the prover process.
# The server requires a nonblank value at startup; it does not load .env files.
TYPESAFE_API_KEY=
8 changes: 8 additions & 0 deletions projects/use-case-examples/policy-review-mcp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.venv/
.pytest_cache/
.ruff_cache/
__pycache__/
*.egg-info/
prover.toml
jev.toml
.env
472 changes: 472 additions & 0 deletions projects/use-case-examples/policy-review-mcp/README.md

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions projects/use-case-examples/policy-review-mcp/demo/check_jev_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Send one small JEV API request without MCP servers or the OpenShell prover."""

import json
import os

from typesafe_sdk import Choice, TypeSafeClient


def main() -> None:
if not os.environ.get("TYPESAFE_API_KEY"):
raise SystemExit("Export TYPESAFE_API_KEY before running this script.")

model = "jev-1.13.0"
with TypeSafeClient(model=model, timeout=30) as client:
response = client.system_one(
state={"task": "Read a file and return a summary. Do not modify it."},
questions={
"write_needed": Choice(
instructions="Does this task require modifying the file?",
criteria={
"yes": "The task requires modifying the file.",
"no": "The task only requires reading the file.",
},
)
},
)

answer = response.answers["write_needed"]
print(
json.dumps(
{
"model": model,
"choice": answer.choice,
"confidence": answer.confidence,
"probabilities": dict(answer.probabilities),
},
indent=2,
)
)


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
version: 1
filesystem_policy:
include_workdir: false
read_only:
- /usr/bin/gh
- /etc/ssl/certs/ca-certificates.crt
read_write:
- /workspace
- /tmp
landlock:
compatibility: hard_requirement
process:
run_as_user: sandbox
run_as_group: sandbox
network_policies:
github:
endpoints:
- host: api.github.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: {method: GET, path: /repos/acme/widget/**}
- allow: {method: POST, path: /repos/acme/widget/issues/42/comments}
binaries:
- path: /usr/bin/gh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: 1
filesystem_policy:
include_workdir: false
read_only: [/usr/bin/gh, /etc/ssl/certs/ca-certificates.crt]
read_write: []
landlock: {compatibility: hard_requirement}
process: {run_as_user: sandbox, run_as_group: sandbox}
network_policies:
github:
endpoints:
- host: api.github.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: {method: GET, path: /repos/acme/widget/**}
- allow: {method: POST, path: /repos/acme/widget/issues/42/comments}
binaries: [{path: /usr/bin/gh}]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: 1
filesystem_policy:
include_workdir: false
read_only: [/workspace]
read_write: []
landlock: {compatibility: hard_requirement}
process: {run_as_user: sandbox, run_as_group: sandbox}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: 1
filesystem_policy:
include_workdir: false
read_only: []
read_write: [/workspace]
landlock: {compatibility: hard_requirement}
process: {run_as_user: sandbox, run_as_group: sandbox}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: 1
filesystem_policy:
include_workdir: false
read_only: [/usr/bin/gh, /etc/ssl/certs/ca-certificates.crt]
read_write: []
landlock: {compatibility: hard_requirement}
process: {run_as_user: sandbox, run_as_group: sandbox}
network_policies:
github:
endpoints:
- host: api.github.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: {method: GET, path: /repos/acme/widget/issues/42}
- allow: {method: GET, path: /repos/acme/widget/issues/42/comments}
- allow: {method: POST, path: /repos/acme/widget/issues/42/comments}
binaries: [{path: /usr/bin/gh}]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: 1
filesystem_policy:
include_workdir: false
read_only: [/usr/bin/gh, /etc/ssl/certs/ca-certificates.crt]
read_write: []
landlock: {compatibility: hard_requirement}
process: {run_as_user: sandbox, run_as_group: sandbox}
network_policies:
github:
endpoints:
- host: api.github.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: {method: POST, path: /repos/acme/widget/issues}
binaries: [{path: /usr/bin/gh}]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: 1
filesystem_policy:
include_workdir: false
read_only: [/usr/bin/gh, /etc/ssl/certs/ca-certificates.crt]
read_write: []
landlock: {compatibility: hard_requirement}
process: {run_as_user: sandbox, run_as_group: sandbox}
network_policies:
github:
endpoints:
- host: api.github.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: {method: GET, path: /repos/acme/widget/issues/42}
- allow: {method: GET, path: /repos/acme/widget/issues/42/comments}
binaries: [{path: /usr/bin/gh}]
Loading
Loading