# Native OpenShell + Odile Gate OpenShell v0.1.5 HTTP-request middleware. Runs beside your OpenShell deployment; Gate hosts the download files, not this gRPC service. Requires Python 3.10+ or Docker and an existing Gate Free or Pro project. No model provider or payment is needed. The native hook verifies EdDSA extension JWTs (exact type, issuer, audience and expiry), checks that the signed sandbox UUID matches the request context, and selects a controller-owned Gate app/run binding. It calls only `GET /g//_gate/run`, requires the expected app/run and `state: active`, then returns ALLOW unchanged. Gate alone checks the actual action, scope, approval, limits and idempotency, then executes it. The hook never calls the requested business route. ## Install the pinned contract Download the files listed by https://gate.odilelabs.com/integrations/openshell/manifest.json and verify their SHA-256 hashes. Keep `extension.proto` and `supervisor_middleware.proto` in `proto/` when building the Dockerfile. They are unchanged NVIDIA v0.1.5 Apache-2.0 protocol contracts; retain their copyright notices and LICENSE. For a Python process, use a virtual environment: ```sh python3 -m venv .venv .venv/bin/pip install -r requirements.txt .venv/bin/python -m grpc_tools.protoc -I proto --python_out=. --grpc_python_out=. proto/extension.proto proto/supervisor_middleware.proto .venv/bin/python -m unittest discover -p test_server.py -v .venv/bin/python server.py --config /absolute/private/config.json ``` Alternatively build the supplied Dockerfile and run it with a read-only mount of the private config directory. Its default user is 1000; use the UID/GID owning your private files. Expose TLS only where the gateway and supervisor can reach it. Do not add a Docker daemon socket to the middleware container. ## Configure authority outside the agent 1. Obtain the exact gateway issuer and public JWKS over its already trusted TLS connection (discovery: `/.well-known/openid-configuration`, keys: `/.well-known/jwks.json`). Provision the public JWKS file before restarting the gateway: authenticated startup `Describe` must not depend on fetching keys from a gateway still starting. Never copy its private signing key. Unknown/rotated signing keys fail closed; refresh trusted public keys and restart the middleware when rotating. 2. Copy `config.example.json` to your private directory and replace the gateway ID and file paths. Supply a TLS server certificate/key with the endpoint's exact DNS/IP SAN and configure its CA in `gateway.toml.example`. Config, bindings, app-key, run-token and TLS private-key files must be regular files with mode 0600 in a private directory. Have your operator place credential values directly in the files. Never put credentials in policy YAML, command arguments, source control or chat. 3. Start with `{}` in `bindings.json`; start the middleware first, register it using `gateway.toml.example`, then restart OpenShell. `openshell gateway info` must list `odile/gate 0.1.0`, protocol 1.0. Keep TLS/JWT enabled; do not use `allow_insecure_transport` or `fail_open`. 4. Create the sandbox with `policy.yaml`, adapted to your agent's exact executable and necessary filesystem paths. Keep Gate as its only business destination. Until its immutable sandbox UUID is bound, calls fail closed. Your trusted controller writes a binding using `bindings.example.json` and the app/run IDs returned by Gate. Use sandbox UUID, never sandbox name, workspace name or an agent-supplied task label. Replace the binding file atomically; rebind newly created sandboxes explicitly. 5. Give the agent only its app key and matching run token. It calls `https://gate.odilelabs.com/g//...` with its app bearer and `x-odile-run`; no admin, approver or upstream secret enters the sandbox. Make runs mandatory with `PUT /api/projects//apps//runs {"mode":"all"}`. Keep the upstream's own authentication and ownership checks. For Colima, one tested layout is a native Mac gateway, middleware container with host-loopback TLS port publication, and a host-network supervisor. The same `https://127.0.0.1:` must pass TLS checks from the Mac gateway AND VM host namespace. A bridge-network supervisor needs a different reachable endpoint. Do not assume Mac LAN addresses or VM-only hostnames work from both peers. ## Approvals, revocation and evidence Gate's `202 approval_required` remains an HTTP response; a separate named approver reviews it. Resume the identical call with `x-odile-action`. Do not wait for human approval inside a gRPC callback. Writes need an Idempotency-Key. Changed approvals, repeated writes and uncertain outcomes retain Gate's existing refusal/recovery behavior. Revoking a parent invalidates children: the next native preflight refuses the inactive run, while Gate also rechecks revocation before dispatch to close the preflight/send race. Native stdout is JSON containing request UUID, signed sandbox UUID, bound run ID, decision and stable reason only. No headers, paths, bodies or tokens are logged. Join this trusted service record with OpenShell OCSF middleware events and Gate run/audit IDs; a caller-supplied correlation header is not identity proof. Keep these logs and Gate proof exports under your own retention policy. Limits: the hook is a live-run preflight, not a standalone action-permit API. Gate still accepts valid app/run bearers from other clients; this does not make Gate OpenShell-only. Network policy must prevent direct upstream access. Only HTTP requests are advertised; no response or WebSocket inspection is provided by this adapter. Bodies above 1 MiB fail closed. Each request adds a bounded read-only Gate lookup; no positive authorization cache hides revocation. Middleware failure blocks the request. A write already sent cannot be undone by later revocation. Test your deployment and workload; v0.1.5 testing does not prove other releases or capacity limits.