Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
faf3093
feat(egress-gate): add attested Pi admission
johnnygreco Aug 12, 2026
021281f
docs(egress-gate): add Pi admission example
johnnygreco Aug 12, 2026
c5601c0
fix(egress-gate): own Pi integration extension
johnnygreco Aug 12, 2026
355db91
refactor(egress-gate): use user message append hook
johnnygreco Aug 12, 2026
9d53095
refactor(egress-gate): focus Pi example on deny and redact
johnnygreco Aug 12, 2026
22c93e6
docs(egress-gate): replace simulated Pi example
johnnygreco Aug 17, 2026
0540f54
fix(egress-gate): clean up Pi admission integration
johnnygreco Aug 17, 2026
35ec55c
docs(egress-gate): simplify Pi admission demo
johnnygreco Aug 20, 2026
de716d7
chore: add example license headers
johnnygreco Aug 20, 2026
c8be825
chore: ignore local planning files
johnnygreco Aug 24, 2026
80b268d
chore(egress-gate): merge upstream main
johnnygreco Aug 26, 2026
acebc5d
docs(egress-gate): sync Pi example forks
johnnygreco Aug 26, 2026
7f71b16
docs(egress-gate): streamline Pi example setup
johnnygreco Aug 26, 2026
324d744
fix(egress-gate): isolate nested OpenShell checkout
johnnygreco Aug 27, 2026
f512f94
feat(egress-gate): complete Pi attested admission example
johnnygreco Aug 28, 2026
252a977
fix(egress-gate): recreate example provider profile on launch
johnnygreco Aug 28, 2026
18158b9
fix(egress-gate): redact model credentials from Pi tool output
johnnygreco Aug 28, 2026
fb51e76
fix(egress-gate): distinguish credential placeholders from secrets
johnnygreco Aug 28, 2026
8d1b739
fix(egress-gate): allow maximum Pi request payloads
johnnygreco Aug 28, 2026
8d9f96b
feat(egress-gate): isolate managed Pi admission
johnnygreco Aug 28, 2026
d2930e9
refactor(egress-gate): run admitted Pi through standard CLI
johnnygreco Sep 1, 2026
6caa8de
Raise Pi example model token limits
johnnygreco Sep 1, 2026
eb76919
Configure three Pi example models
johnnygreco Sep 1, 2026
67b4642
Use standard Pi models configuration
johnnygreco Sep 1, 2026
5638f7c
refactor(egress-gate): run configured Pi entrypoint
johnnygreco Sep 1, 2026
73b6114
fix(egress-gate): preserve standard Pi extensions
johnnygreco Sep 1, 2026
693ccfe
feat(egress-gate): attest OpenAI Responses context
johnnygreco Sep 1, 2026
9cf1560
refactor(egress-gate): run standard persistent Pi demo
johnnygreco Sep 1, 2026
cd271bb
fix(egress-gate): default Pi demo to empty workspace
johnnygreco Sep 1, 2026
c7b757d
refactor(egress-gate): externalize Pi runtime integration
johnnygreco Sep 2, 2026
8910d79
feat(egress-gate): finalize agent admission contracts
johnnygreco Sep 2, 2026
cc8497e
fix(egress-gate): canonicalize user admission envelope
johnnygreco Sep 2, 2026
ebdf153
feat(egress-gate): admit every Pi history origin
johnnygreco Sep 2, 2026
6ddc86e
fix(egress-gate): accept JavaScript tool arguments
johnnygreco Sep 2, 2026
66459a7
feat(egress-gate): bind complete provider context
johnnygreco Sep 2, 2026
01823dd
fix(egress-gate): join provider text blocks
johnnygreco Sep 2, 2026
3fedae0
docs(egress-gate): note transport history limits
johnnygreco Sep 2, 2026
dd77d48
feat(egress-gate): add self-verifying admission demo
johnnygreco Sep 2, 2026
b03c8ea
fix(egress-gate): verify admitted tool results
johnnygreco Sep 2, 2026
f6d13fe
feat(egress-gate): authenticate bridge calls
johnnygreco Sep 2, 2026
9b6b538
docs(egress-gate): describe bridge caller capability
johnnygreco Sep 2, 2026
4d99082
Merge origin/main into johnny/pi-attested-admission
johnnygreco Sep 2, 2026
946d88c
docs(egress-gate): record integration QA
johnnygreco Sep 2, 2026
b537f4b
docs(egress-gate): clarify final POC limits
johnnygreco Sep 2, 2026
0bf33ca
docs(egress-gate): clarify assistant admission scope
johnnygreco Sep 2, 2026
7506362
docs(egress-gate): record proxy delivery integration
johnnygreco Sep 2, 2026
b05f06b
fix(egress-gate): verify Pi provider responses
johnnygreco Sep 2, 2026
ff8319a
feat(egress-gate): load Pi demo environment automatically
johnnygreco Sep 3, 2026
9e12cf2
docs(egress-gate): record live Pi session findings
johnnygreco Sep 3, 2026
cc696bc
fix(egress-gate): explain unavailable cleanup gateway
johnnygreco Sep 3, 2026
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
4 changes: 4 additions & 0 deletions plans/egress-gate-message-ledger.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Egress Gate message fingerprinting and denied-history ledger plan

> **Status:** Superseded for managed harnesses by send-time whole-context
> admission. This design remains relevant to unmanaged harnesses that cannot
> provide an attested provider context.

## Scope

The first release is intentionally process-local and in-memory. It does not
Expand Down
1 change: 1 addition & 0 deletions projects/egress-gate/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.workspaces/
7 changes: 4 additions & 3 deletions projects/egress-gate/.openshell-middleware-manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"openshell_version": "v0.0.97",
"proto_source": "https://raw.githubusercontent.com/NVIDIA/OpenShell/v0.0.97/proto/supervisor_middleware.proto",
"proto_sha256": "e9d5a992ff5b50a33e9625176aaf6df8496d6774aa2ef3afe5cae7bc83c01105",
"openshell_version": "johnnygreco/OpenShell@8332c459c89124499e76da0a4095af9661aec10f",
"proto_source": "https://raw.githubusercontent.com/johnnygreco/OpenShell/8332c459c89124499e76da0a4095af9661aec10f/proto/supervisor_middleware.proto",
"proto_sha256": "2bda09fcbabc37663fbddfb8c49b6ae2689b25f3315912b0e8416a6bd2ac8e50",
"contract_note": "EvaluateAgentConversation is fork-only until the agent-conversation contract is upstreamed.",
"languages": [
"python"
],
Expand Down
20 changes: 16 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-agent-attestation
```

## 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-agent-attestation
uv run egress-gate evaluate \
--policy examples/regex-redaction/egress-gate-config.yaml \
--cases examples/regex-redaction/cases.yaml
Expand All @@ -49,6 +49,14 @@ 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 context attestations by default, coupling admission
to provider egress verification. The general Gate quickstarts opt out
explicitly. Keep the default, or pass `--require-agent-attestation`, for a
managed harness; use `--no-require-agent-attestation` 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 +95,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-agent-attestation
```

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

In this example, `timeout_middleware_processing` gives each evaluation 10
Make the `require_agent_attestation` choice explicit in programmatic deployments;
set it to `True` for a managed harness. 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 +147,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
161 changes: 161 additions & 0 deletions projects/egress-gate/analysis/qa-reports/2026-09-02.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark">
<title>Pi attested-admission integration QA — 2026-09-02</title>
<style>
:root { color-scheme: light dark; font-family: system-ui, sans-serif; line-height: 1.5; }
body { max-width: 960px; margin: 0 auto; padding: 2rem 1rem 4rem; }
h1, h2 { line-height: 1.2; }
table { width: 100%; border-collapse: collapse; }
th, td { border: 1px solid #8888; padding: .55rem; text-align: left; vertical-align: top; }
th { background: #8882; }
code { overflow-wrap: anywhere; }
.pass { color: #087f5b; font-weight: 700; }
</style>
</head>
<body>
<main>
<h1>Pi attested-admission integration QA</h1>
<p><strong>Date:</strong> 2026-09-02 UTC</p>
<p><strong>Live-session update:</strong> 2026-09-03 UTC, through 02:40:14</p>
<p>
This report records the final proof-of-concept integration state across
Pi, OpenShell, and OpenShell Research. It contains only sanitized command
summaries: no credentials, request bodies, model output, environment
values, or local workspace paths.
</p>

<h2>Reviewed revisions</h2>
<table>
<thead><tr><th>Repository</th><th>Integration head</th><th>Upstream base</th></tr></thead>
<tbody>
<tr><td>Pi</td><td><code>177b42723d072b7954a5b1690ccf62c97f075b37</code></td><td><code>e266507b606b9552fa277252644054afd4384b11</code></td></tr>
<tr><td>OpenShell</td><td><code>4d7194dc8166bfafc7236e0212d2e88aee4f7231</code></td><td><code>a6b757d35f983fe4415427484ad06533d32e9e4b</code></td></tr>
<tr><td>OpenShell Research</td><td><code>ff8319a69255ce0f858691095c6ea9f24d9b603f</code></td><td><code>743839dae47621c13a3bc339bad2a2c8d0167591</code></td></tr>
</tbody>
</table>

<h2>Validation</h2>
<table>
<thead><tr><th>Repository</th><th>Result</th></tr></thead>
<tbody>
<tr><td>Pi</td><td><span class="pass">Focused suite passed:</span> 38/38 after the assistant atomic-deny fix. <code>npm run check</code> passed its preliminary gates and reported only unchanged upstream <code>packages/ai</code> catalog TypeScript drift.</td></tr>
<tr><td>OpenShell</td><td><span class="pass">Passed:</span> pre-commit, the full repository test and CI lanes, and <code>mise run go:ci</code>. The merged proxy-delivery end-to-end case passed; the broader Docker lane later failed a separate policy-reload case because its sandbox emitted no JSON result.</td></tr>
<tr><td>OpenShell Research</td><td><span class="pass">Passed:</span> <code>make check</code> and <code>make check-py311</code>, 377/377 tests in each environment after the upstream merge, plus formatting, lint, typing, dependency audit, 11/11 documentation-renderer tests, the clean strict documentation build, and an HTTP 200 artifact preview.</td></tr>
<tr><td>Independent review</td><td><span class="pass">Previously reviewed Pi and OpenShell work clean:</span> no blocker, high, or medium findings. The later proxy-delivery branch integration was validated but not independently re-reviewed when this report was updated.</td></tr>
</tbody>
</table>

<h2>Live end-to-end result</h2>
<p>
The configured machine completed the real <code>./demo.sh verify</code>
workflow and an extended interactive Pi session. The required verifier
cases passed: denied input was not written, redacted input was persisted
only as <code>[REDACTED]</code>, unauthorized bridge and unattested
provider calls were rejected, stock Pi could not bypass attestation, and
an admitted tool-result replacement persisted correctly. The
model-dependent tool-denial case skipped because the model did not choose
to call Bash; this is the verifier's documented non-failing outcome.
</p>

<h2>Exploratory session review</h2>
<p>
The reviewed session is the persistent Pi JSONL session created at
<code>2026-09-03T01:45:53Z</code>, ID
<code>01a064f1-a65a-7fe8-ab58-e20a67f868d7</code>. The review used the
session structure and sanitized Egress Gate decision log; it did not copy
credentials or provider request bodies into this report.
</p>
<table>
<thead><tr><th>Area</th><th>Observed behavior</th><th>Finding</th></tr></thead>
<tbody>
<tr>
<td>Standard Pi workflow</td>
<td>One 158-entry JSONL session preserved 14 user messages, 76 assistant messages, 63 tool results, model and thinking-level changes, and one compaction event. Pi created and edited six chapter files and resumed work across repeated turns.</td>
<td><span class="pass">Working.</span> Persistent sessions, the normal tools, workspace writes, long-running interaction, and the standard TUI path were active.</td>
</tr>
<tr>
<td>Credential isolation</td>
<td>When Pi inspected every <code>PI_*</code> environment variable, it saw model, provider, reasoning, and session metadata but no model API key or OpenShell resolver value.</td>
<td><span class="pass">Working.</span> Proxy-delivered provider authentication kept the credential out of the agent environment.</td>
</tr>
<tr>
<td>Reasoning controls</td>
<td>The session began at <code>high</code>, changed to <code>xhigh</code>, and persisted 72 assistant thinking blocks. Provider usage separately reported reasoning tokens.</td>
<td><span class="pass">Working as a model feature.</span> The model produced reasoning and Pi retained it as ordinary session state.</td>
</tr>
<tr>
<td>Compaction</td>
<td>Pi compacted after a 69,090-token turn. The next provider request used 26,727 input tokens, then read the on-disk progress ledger and returned an accurate current story summary.</td>
<td><span class="pass">Working.</span> The compacted summary describes only the discarded prefix and looks stale in isolation, but <code>firstKeptEntryId</code> retains the Chapter 4 completion and the retained tail contains Chapters 5 and 6.</td>
</tr>
<tr>
<td>Provider failure</td>
<td>Immediately after switching to <code>xhigh</code>, one <code>continue</code> submission produced four retries containing <code>Connection error.</code>, empty content, and zero token usage.</td>
<td><strong>Failure, not denial.</strong> The session does not contain an HTTP status or lower-level cause, so it cannot distinguish the provider, proxy, or network source. The later request succeeded without a configuration change; correlation does not prove that <code>xhigh</code> caused it.</td>
</tr>
<tr>
<td>Reasoning-only completion</td>
<td>The next <code>continue</code> request returned 810 output tokens, of which 807 were reported as reasoning. It stopped successfully with one thinking block, no visible text, and no tool call. The user had to submit <code>write it</code> before work continued.</td>
<td><strong>Usability failure.</strong> This was a provider completion accepted by Pi, not an admission denial. It should first be reproduced against the same endpoint with stock Pi before changing the integration.</td>
</tr>
<tr>
<td>Denied-message audit</td>
<td>All 14 user entries visible in the reviewed JSONL were persisted, but an input denied before append is intentionally absent. The content-safe Egress Gate log has request IDs but no session ID, submission ID, or timestamp that can correlate a denial to this session.</td>
<td><strong>Observability gap.</strong> Pi can prove what was appended; it cannot prove from its own history whether another submitted message was denied. The model's claim that no denial occurred was therefore stronger than its evidence.</td>
</tr>
<tr>
<td>Thinking admission</td>
<td>Assistant thinking is persisted, can be sent on later provider turns, and consumes context. The current append envelope and attested context omit it; only request-time policy scanning covers it when it appears on the wire.</td>
<td><strong>Security-model gap.</strong> The current proof of concept does not guarantee that all persisted or provider-visible reasoning was admitted and bound into the context attestation.</td>
</tr>
<tr>
<td>Sandbox utilities</td>
<td>The model attempted to use <code>bc</code> and <code>file</code>, which are absent from the image. Both Bash tool results were recorded as successful because a later command in each shell invocation exited successfully.</td>
<td><strong>Minor environment/diagnostic issue.</strong> It did not stop the workflow, but demonstrates that a successful tool result does not imply every command in a compound shell command succeeded.</td>
</tr>
</tbody>
</table>

<h2>Decision-log evidence and limits</h2>
<p>
Since the latest Egress Gate server-start record, the content-safe log
contains 80 allows and two denials with
<code>reason_code=attestation_missing</code>. It contains no middleware
errors and no regex-denial reason. This supports the conclusion that the
visible interactive failures were not middleware denials. It cannot prove
which session or submission produced a record because the current log
deliberately omits the correlation fields needed for that join.
</p>

<h2>Recommended follow-up</h2>
<ol>
<li>Add content-free denial audit metadata that can be correlated by sandbox, session, and submission without retaining the denied text or adding it to model context.</li>
<li>Bring assistant thinking inside the same append-admission and whole-context attestation contract as other persisted provider-visible content.</li>
<li>Reproduce the reasoning-only completion and the four connection retries with stock Pi against the same endpoint. Preserve standard Pi behavior unless the integration is shown to be responsible.</li>
<li>Expose enough transport error detail to distinguish an upstream/provider failure from a middleware denial without logging request content or credentials.</li>
</ol>

<h2>Verified design boundary</h2>
<p>
One policy fingerprint connects append-time admission, provider-context
admission, and provider egress. The attestation binds one hash of the
complete ordered user/tool context. System/developer and assistant content
is scanned by the request policy at egress but is not included in that
hash. Denied additions do not enter Pi's live or persisted history.
</p>

<h2>Known limits</h2>
<ul>
<li>Image inputs are unsupported by this example and fail closed.</li>
<li>Provider-context admission precedes transport-specific history rewrites; switching transports with existing tool history or sending orphaned tool calls may fail closed.</li>
<li>Admission payloads are limited to 4 MiB and attestations expire after 300 seconds.</li>
<li>The per-exec bridge token remains in Pi process memory; a same-user process able to read that memory could copy it.</li>
<li>This is a proof of concept. Phase 2b provenance-ledger work, additional message hashing, and production deployment automation remain out of scope.</li>
</ul>
</main>
</body>
</html>
Loading
Loading