Skip to content
Draft
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ temp/
*.temp
*.bak
.scratch/
plans/

# Python
__pycache__/
Expand Down
19 changes: 15 additions & 4 deletions projects/egress-gate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ commands work from any directory and do not depend on repository-only files:
egress-gate gates list
egress-gate gates schema
egress-gate validate --policy /absolute/path/to/your-policy.yaml
egress-gate serve --listen 127.0.0.1:50051
egress-gate serve --listen 127.0.0.1:50051 --no-require-pi-receipt
```

## Source-checkout quickstart
Expand All @@ -39,7 +39,7 @@ uv run egress-gate gates list
uv run egress-gate gates schema
uv run egress-gate validate \
--policy examples/regex-redaction/egress-gate-config.yaml
uv run egress-gate serve --listen 127.0.0.1:50051
uv run egress-gate serve --listen 127.0.0.1:50051 --no-require-pi-receipt
uv run egress-gate evaluate \
--policy examples/regex-redaction/egress-gate-config.yaml \
--cases examples/regex-redaction/cases.yaml
Expand All @@ -49,6 +49,13 @@ Use `0.0.0.0` only when the OpenShell supervisor must reach the service across
network namespaces. The development server uses plaintext gRPC. Restrict its
listen port to trusted networks.

The CLI requires managed Pi admission receipts by default, coupling receipt
issuance to provider egress verification. The general Gate quickstarts opt out
explicitly. Keep the default, or pass `--require-pi-receipt`, for managed Pi;
use `--no-require-pi-receipt` only for an intentionally unmanaged deployment.
See the [managed Pi example](examples/pi-attested-admission/README.md) for the
matching Pi and OpenShell fork branches, startup contract, and current limits.

## Policy shape

The registry builds an exact strict schema from installed gate types:
Expand Down Expand Up @@ -87,7 +94,7 @@ need initialization, helper bases, or typed resources use the full class-based

```bash
uv run egress-gate --registry my_gates:registry gates list
uv run egress-gate --registry my_gates:registry serve
uv run egress-gate --registry my_gates:registry serve --no-require-pi-receipt
```

OpenShell owns interception, routing, and credential attachment. Egress Gate
Expand All @@ -103,11 +110,14 @@ from egress_gate.service import EgressGateServer
server = EgressGateServer(
create_builtin_registry(),
timeout_middleware_processing=10,
require_pi_receipt=False,
)
server.serve_sync("127.0.0.1:50051")
```

In this example, `timeout_middleware_processing` gives each evaluation 10
Make the `require_pi_receipt` choice explicit in programmatic deployments; set
it to `True` for managed Pi. In this unmanaged example,
`timeout_middleware_processing` gives each evaluation 10
seconds. Omitting it uses the one-second service default. The value is expressed
in seconds, must be at least 10 milliseconds, and must resolve to whole
milliseconds. The service passes one resulting `Timeout` through slot
Expand Down Expand Up @@ -136,6 +146,7 @@ timeout failures must deny.
- [Architecture](https://github.com/NVIDIA/OpenShell-Research/blob/main/projects/egress-gate/docs/architecture/index.md)
- [Limits and failures](https://github.com/NVIDIA/OpenShell-Research/blob/main/projects/egress-gate/docs/reference/limits-and-failures.md)
- [Regex redaction composition](https://github.com/NVIDIA/OpenShell-Research/tree/main/projects/egress-gate/examples/regex-redaction)
- [Pi attested-admission example](examples/pi-attested-admission/README.md)
- [Function-based custom gate](https://github.com/NVIDIA/OpenShell-Research/tree/main/projects/egress-gate/examples/custom-gate)
- [Class-based custom gate](https://github.com/NVIDIA/OpenShell-Research/tree/main/projects/egress-gate/examples/class-based-gate)

Expand Down
139 changes: 139 additions & 0 deletions projects/egress-gate/examples/pi-attested-admission/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Managed Pi deny-or-redact example

This example runs the forked Pi CLI inside OpenShell and sends its rendered
user submissions through Egress Gate. It makes real OpenAI API calls and may
incur provider charges.

- `DENY_THIS` is rejected before Pi writes it to session history or starts a
model turn.
- `REDACT_THIS` becomes `[REDACTED]` before Pi writes or sends it.

## Before you start

Use the matching branches:

- [Pi user-message append hook PR](https://github.com/johnnygreco/pi/pull/1)
- [OpenShell managed admission PR](https://github.com/johnnygreco/OpenShell/pull/1)
- [OpenShell Research integration branch](https://github.com/NVIDIA/OpenShell-Research/tree/johnny/pi-attested-admission)

Install each repository's development prerequisites and export:

```shell
export OPENAI_API_KEY=your-key
export EGRESS_GATE_HOST_IP=192.168.1.20
```

`EGRESS_GATE_HOST_IP` must be a non-loopback IPv4 address reachable by the
gateway and sandbox supervisors. `hostname -I` usually shows the available
addresses; choose the address for the host network shared with OpenShell.

The helper expects sibling checkouts named `pi`, `OpenShell`, and
`OpenShell-Research`. For another layout, set `PI_REPO` and `OPENSHELL_REPO` to
absolute paths.

From the `OpenShell-Research` checkout, change to the example directory. Run
all remaining commands there:

```shell
cd projects/egress-gate/examples/pi-attested-admission
```

You can inspect every command before running anything:

```shell
./demo.sh --print all
```

## Try it

Build the Pi fork and register Egress Gate with OpenShell:

```shell
./demo.sh prepare
```

Keep Egress Gate running in one terminal:

```shell title="Terminal 1: Egress Gate"
./demo.sh serve
```

Start the matching OpenShell gateway in a second terminal:

```shell title="Terminal 2: OpenShell gateway"
./demo.sh gateway
```

After the gateway reports that it is ready, launch the real Pi CLI from a
third terminal:

```shell title="Terminal 3: managed Pi"
./demo.sh launch
```

At the Pi prompt, submit both of these in the same session:

```text
Reply with exactly: DENY_THIS
```

```text
Reply with exactly: REDACT_THIS
```

The first submission is denied without starting a model turn. The second makes
a real model call using `[REDACTED]`. Exit Pi, then inspect its persisted
session:

```shell
./demo.sh verify
```

The output must contain `[REDACTED]` and must not contain `DENY_THIS` or
`REDACT_THIS`. The command exits with an error if either check fails.

## How it works

1. Pi renders the user submission and calls its general-purpose
`before_user_message_append` extension hook.
2. The example extension sends that text to OpenShell's sandbox-local admission
bridge.
3. Egress Gate applies `policy.yaml`: it either denies the submission or
returns replacement text plus a short-lived receipt.
4. Pi appends only admitted or replacement text to session history.
5. OpenShell checks the receipt before the model request leaves the sandbox and
injects `OPENAI_API_KEY`; the key is never copied into the sandbox.

## Inspect individual commands

The helper never requires you to trust hidden orchestration. Add `--print` to
any action to show its exact commands without executing them:

```shell
./demo.sh --print prepare
./demo.sh --print launch
```

The actions are deliberately small: `prepare` builds and packages the Pi fork;
`serve` runs Egress Gate; `gateway` runs the matching OpenShell fork; and
`launch` creates the credential provider and sandbox.

## Current scope

This initial integration supports idle, text-only, direct OpenAI Chat
Completions submissions. Images, queued input, retries, compaction, and
automatic continuations after tool calls are unsupported and fail closed. The
next comprehensive boundary is one receipt per provider request; it does not
require one Pi hook per message role.

## Cleanup

Exit Pi, but leave the OpenShell gateway running while cleanup deletes the
sandbox and provider:

```shell
./demo.sh cleanup
```

Then stop the OpenShell gateway and Egress Gate with `Ctrl-C`. To run the
example again, start from `./demo.sh prepare`.
Loading