implement generic x/elevate with socket broker pattern

x/elevate is now a generic client: reads OLLIE_ELEVATE_SOCKET, sends
{cmd,cwd}, reads back {stdout,stderr,exit_code}. All backend-specific
logic moves to adapters. Add elevate-adapter-superpowerd as the
reference adapter: owns the socket lifecycle, translates the ollie
protocol to superpowerd JSON-RPC ExecuteCommand. Add OLLIE_ELEVATE_SOCKET
to env docs. Update scripts/README.md with protocol spec, adapter
setup, and guide for writing custom adapters.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-04-25 11:41:54 +02:00
parent 1de43c1105
commit 7a88fb3437
4 changed files with 199 additions and 112 deletions

View File

@ -55,6 +55,7 @@ OLLIE_KIRO_TOKEN=... # bearer token or sqlite:// path (auto-detected f
OLLIE_MODEL=qwen/qwen3-235b-a22b
OLLIE_TOOLS_PATH=~/.config/ollie/tools # directory for tool scripts ({tool} steps)
OLLIE_MEMORY_PATH=~/.config/ollie/memory # directory for memory files (ollie/m)
OLLIE_ELEVATE_SOCKET=~/.run/ollie-elevate.sock # socket path for x/elevate adapter
```
Shell environment variables take precedence over the env file.

View File

@ -209,77 +209,52 @@ Outputs to stdout, making it composable with other pipeline stages.
## x/elevate
Sandbox escape hatch invoked by `execute_code` when a step is marked `elevated: true`.
The Landlock sandbox is enforced at the kernel level — certain operations (filesystem
paths outside the sandbox config, specific syscalls) are simply blocked regardless of
what the code does. `x/elevate` provides a controlled way to run those steps outside
the sandbox entirely, without changing user privileges.
The Landlock sandbox is enforced at the kernel level — restrictions apply regardless of
user privileges within the sandboxed process. `x/elevate` is a generic client that
forwards the command to an adapter running outside the sandbox, which executes it and
returns the result.
### Interface
`x/elevate` knows nothing about the backend. It connects to the socket at
`OLLIE_ELEVATE_SOCKET`, sends `{cmd, cwd}`, and reads back `{stdout, stderr,
exit_code}`. The adapter on the other end is backend-specific. Multiple adapters can
coexist at different socket paths; switching backends is a single env var change.
`execute_code` resolves the plugin path and calls:
Set `OLLIE_ELEVATE_SOCKET` in `~/.config/ollie/env`:
```sh
x/elevate -- <cmd>
```
OLLIE_ELEVATE_SOCKET=~/.run/ollie-elevate.sock
```
The working directory is already set to the session's `cwd` before the call. The
script must:
### Protocol
- Write combined stdout/stderr to its own stdout
- Exit with the command's exit code (non-zero is treated as failure)
`x/elevate` sends a newline-terminated JSON object and reads a JSON response:
That's the entire contract. Any script that satisfies it is a valid backend.
The plugin is looked up in `OLLIE_PLUGINS_PATH` (first colon-separated entry) if set,
otherwise in `~/.config/ollie/scripts/x/`. Override via env to use a different location
without modifying the installed scripts.
### The constraint
Because Landlock is kernel-enforced, the backend cannot simply exec the command inside
the sandboxed process — the restrictions apply regardless. The command must reach a
process that was spawned outside of landrun entirely. The only viable pattern is to
forward the command to an external daemon over a socket or pipe, where that daemon runs
in an unsandboxed context and sends the result back.
### Minimal example
The simplest possible backend — direct exec, no sandbox. Suitable for development or
environments where the sandbox itself is not in use:
```sh
#!/bin/sh
# x/elevate: run command outside the sandbox (no landrun in this environment).
shift # drop the '--'
exec sh -c "$1"
```
→ {"cmd": "<shell command>", "cwd": "<working directory>"}\n
← {"stdout": "...", "stderr": "...", "exit_code": 0}
```
### superpowerd example
Any process that listens on a Unix stream socket and speaks this protocol is a valid
adapter.
The default `x/elevate` uses superpowerd as its backend. superpowerd is a hypothetical
external command broker: a daemon running outside any sandbox that receives
`ExecuteCommand` requests over a Unix socket, runs them, and returns the result. This
satisfies the constraint above — the command executes in the daemon's process, which
was never wrapped by landrun.
### x/elevate-adapter-superpowerd
**How it works, step by step:**
The included adapter bridges the ollie elevate protocol to superpowerd, a hypothetical
external command broker. superpowerd is a daemon running outside any sandbox that
accepts `ExecuteCommand` requests over its own Unix socket and runs them in an
unsandboxed context — satisfying the kernel-level constraint.
1. If `SUPERPOWERD_SESSION_TOKEN` is not in the environment, the script re-execs itself
under `superpowers run-session`, which registers a session with the daemon and
re-runs the script with the token set:
**Start the adapter** (outside the sandbox, once per session):
```python
if "SUPERPOWERD_SESSION_TOKEN" not in os.environ:
os.execvp("superpowers", ["superpowers", "run-session", "--",
sys.executable, __file__] + sys.argv[1:])
```
```sh
superpowers run-session -- python3 $OLLIE/x/elevate-adapter-superpowerd
```
2. With the token present, the script connects to the superpowerd Unix socket. The
socket path is resolved in order from `SUPERPOWERD_SOCKET`,
`SUPERPOWERD_SOCKET_DIR/superpowerd.sock`, `$XDG_RUNTIME_DIR/superpowerd/superpowerd.sock`,
or the default `/run/user/<uid>/superpowerd/superpowerd.sock`.
`superpowers run-session` acquires a session token and re-runs the adapter with
`SUPERPOWERD_SESSION_TOKEN` set. The adapter then:
3. A JSON-RPC `ExecuteCommand` request is sent with the token, command string, and cwd:
1. Creates the socket at `OLLIE_ELEVATE_SOCKET` and listens for connections
2. For each request, connects to superpowerd and sends a JSON-RPC `ExecuteCommand`:
```json
{
@ -295,16 +270,23 @@ was never wrapped by landrun.
}
```
4. The response's `stdout`, `stderr`, and `exit_code` are forwarded back to
`execute_code`.
3. Translates the response to the ollie protocol and returns it to `x/elevate`
4. Cleans up the socket on exit (`SIGTERM`/`SIGINT`)
### Custom backends
The superpowerd socket is resolved from `SUPERPOWERD_SOCKET`,
`SUPERPOWERD_SOCKET_DIR/superpowerd.sock`, `$XDG_RUNTIME_DIR/superpowerd/superpowerd.sock`,
or `/run/user/<uid>/superpowerd/superpowerd.sock`.
Any daemon-and-socket design works. The daemon must be running outside landrun; the
`x/elevate` script is the bridge between the sandboxed agent and that daemon.
### Writing your own adapter
**Disabling elevation:** replace `x/elevate` with a script that exits non-zero.
Steps marked `elevated: true` will fail rather than escape the sandbox:
Any daemon that owns `OLLIE_ELEVATE_SOCKET` and speaks the two-message JSON protocol
is a valid adapter. The daemon must be started outside landrun; that's the only
constraint. Use `elevate-adapter-superpowerd` as a template.
### Disabling elevation
Replace `x/elevate` with a script that exits non-zero. Steps marked `elevated: true`
will fail rather than escape the sandbox:
```sh
#!/bin/sh

View File

@ -1,9 +1,11 @@
#!/usr/bin/env python3
"""Elevation plugin: run a command outside the sandbox via superpowers.
"""Sandbox escape hatch for execute_code elevated steps.
Connects to the socket at OLLIE_ELEVATE_SOCKET, sends the command and cwd,
and returns the result. The adapter listening on that socket is responsible
for running the command outside the Landlock sandbox.
Usage: elevate -- <cmd>
Replace this script to use a different elevation mechanism.
"""
import json
import os
@ -11,69 +13,38 @@ import socket
import sys
def _socket_path():
if p := os.environ.get("SUPERPOWERD_SOCKET"):
return p
if d := os.environ.get("SUPERPOWERD_SOCKET_DIR"):
return d + "/superpowerd.sock"
if x := os.environ.get("XDG_RUNTIME_DIR"):
return x + "/superpowerd/superpowerd.sock"
return f"/run/user/{os.getuid()}/superpowerd/superpowerd.sock"
def main():
if "SUPERPOWERD_SESSION_TOKEN" not in os.environ:
os.execvp("superpowers", ["superpowers", "run-session", "--",
sys.executable, __file__] + sys.argv[1:])
sock_path = os.environ.get("OLLIE_ELEVATE_SOCKET")
if not sock_path:
print("elevate: OLLIE_ELEVATE_SOCKET not set", file=sys.stderr)
sys.exit(1)
# sys.argv: ['elevate', '--', '<cmd>']
if len(sys.argv) < 3:
print("usage: elevate -- <cmd>", file=sys.stderr)
sys.exit(1)
cmd = sys.argv[2]
cwd = os.getcwd()
token = os.environ["SUPERPOWERD_SESSION_TOKEN"]
req = json.dumps({"cmd": sys.argv[2], "cwd": os.getcwd()}).encode() + b"\n"
sock_path = _socket_path()
sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
sock.connect(sock_path)
except OSError as e:
print(f"elevate: connect {sock_path}: {e}", file=sys.stderr)
sys.exit(1)
req = json.dumps({
"jsonrpc": "2.0",
"method": "ExecuteCommand",
"id": 1,
"params": {
"auth": {"session_token": token},
"command": cmd,
"working_dir": cwd,
"approval_timeout": 7200,
},
}).encode()
with sock:
sock.sendall(req)
data = sock.recv(1024 * 1024)
sock.shutdown(socket.SHUT_WR)
data = b""
while chunk := sock.recv(65536):
data += chunk
resp = json.loads(data)
rpc_err = resp.get("error")
if rpc_err:
msg = rpc_err.get("message", str(rpc_err)) if isinstance(rpc_err, dict) else str(rpc_err)
print(f"elevate: {msg}", file=sys.stderr)
sys.exit(1)
result = resp.get("result", {})
out = result.get("stdout", "")
err = result.get("stderr", "")
if out:
sys.stdout.write(out)
if err:
sys.stderr.write(err)
sys.exit(result.get("exit_code", 0))
if resp.get("stdout"):
sys.stdout.write(resp["stdout"])
if resp.get("stderr"):
sys.stderr.write(resp["stderr"])
sys.exit(resp.get("exit_code", 0))
if __name__ == "__main__":

View File

@ -0,0 +1,133 @@
#!/usr/bin/env python3
"""Elevation adapter: bridges the ollie elevate protocol to superpowerd.
Creates a Unix socket at OLLIE_ELEVATE_SOCKET, accepts {cmd, cwd} requests
from x/elevate, and forwards them to superpowerd via its ExecuteCommand
JSON-RPC interface. Run this outside the Landlock sandbox.
Usage:
superpowers run-session -- python3 elevate-adapter-superpowerd
Environment:
OLLIE_ELEVATE_SOCKET path for the listening socket (required)
SUPERPOWERD_SESSION_TOKEN set automatically by superpowers run-session
SUPERPOWERD_SOCKET override superpowerd socket path
SUPERPOWERD_SOCKET_DIR directory containing superpowerd.sock
"""
import json
import os
import signal
import socket
import sys
import threading
def sp_socket_path():
if p := os.environ.get("SUPERPOWERD_SOCKET"):
return p
if d := os.environ.get("SUPERPOWERD_SOCKET_DIR"):
return d + "/superpowerd.sock"
if x := os.environ.get("XDG_RUNTIME_DIR"):
return x + "/superpowerd/superpowerd.sock"
return f"/run/user/{os.getuid()}/superpowerd/superpowerd.sock"
def handle(conn):
with conn:
data = b""
while chunk := conn.recv(65536):
data += chunk
if b"\n" in data:
break
try:
req = json.loads(data)
except json.JSONDecodeError as e:
resp = {"stdout": "", "stderr": f"elevate-adapter: bad request: {e}", "exit_code": 1}
conn.sendall(json.dumps(resp).encode())
return
token = os.environ.get("SUPERPOWERD_SESSION_TOKEN", "")
sp_path = sp_socket_path()
sp = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
try:
sp.connect(sp_path)
except OSError as e:
resp = {"stdout": "", "stderr": f"elevate-adapter: connect {sp_path}: {e}", "exit_code": 1}
conn.sendall(json.dumps(resp).encode())
return
sp_req = json.dumps({
"jsonrpc": "2.0",
"method": "ExecuteCommand",
"id": 1,
"params": {
"auth": {"session_token": token},
"command": req["cmd"],
"working_dir": req["cwd"],
"approval_timeout": 7200,
},
}).encode()
with sp:
sp.sendall(sp_req)
sp_data = sp.recv(1024 * 1024)
sp_resp = json.loads(sp_data)
rpc_err = sp_resp.get("error")
if rpc_err:
msg = rpc_err.get("message", str(rpc_err)) if isinstance(rpc_err, dict) else str(rpc_err)
resp = {"stdout": "", "stderr": f"elevate-adapter: {msg}", "exit_code": 1}
else:
result = sp_resp.get("result", {})
resp = {
"stdout": result.get("stdout", ""),
"stderr": result.get("stderr", ""),
"exit_code": result.get("exit_code", 0),
}
conn.sendall(json.dumps(resp).encode())
def main():
if "SUPERPOWERD_SESSION_TOKEN" not in os.environ:
os.execvp("superpowers", ["superpowers", "run-session", "--",
sys.executable, __file__] + sys.argv[1:])
sock_path = os.environ.get("OLLIE_ELEVATE_SOCKET")
if not sock_path:
print("elevate-adapter-superpowerd: OLLIE_ELEVATE_SOCKET not set", file=sys.stderr)
sys.exit(1)
sock_path = os.path.expanduser(sock_path)
os.makedirs(os.path.dirname(sock_path), exist_ok=True)
if os.path.exists(sock_path):
os.unlink(sock_path)
srv = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
srv.bind(sock_path)
srv.listen()
def shutdown(sig, frame):
srv.close()
if os.path.exists(sock_path):
os.unlink(sock_path)
sys.exit(0)
signal.signal(signal.SIGTERM, shutdown)
signal.signal(signal.SIGINT, shutdown)
print(f"elevate-adapter-superpowerd: listening on {sock_path}", file=sys.stderr)
while True:
try:
conn, _ = srv.accept()
except OSError:
break
threading.Thread(target=handle, args=(conn,), daemon=True).start()
if __name__ == "__main__":
main()