olliesrv: add -strict and -yolo flags
-strict: only tool steps allowed, inline code rejected. -yolo: skip landrun sandbox for execute_code.
This commit is contained in:
parent
9bfccebff6
commit
88ea073135
15
README.md
15
README.md
|
|
@ -123,6 +123,21 @@ The server listens on a Unix socket in the Plan 9 namespace (`$NAMESPACE/ollie`)
|
||||||
|
|
||||||
`olliesrv mount` is for remote instances: it calls `9pfuse <addr> <mnt>` and defaults the mountpoint to `$HOME/mnt/<addr>`.
|
`olliesrv mount` is for remote instances: it calls `9pfuse <addr> <mnt>` and defaults the mountpoint to `$HOME/mnt/<addr>`.
|
||||||
|
|
||||||
|
### Flags
|
||||||
|
|
||||||
|
| Flag | Effect |
|
||||||
|
|------|--------|
|
||||||
|
| `-strict` | Only `{tool}` steps are allowed in `execute_code`; inline `{code}` steps are rejected. |
|
||||||
|
| `-yolo` | Skip the landrun sandbox for all `execute_code` execution. |
|
||||||
|
| `-tcp <addr>` | Also listen on a TCP address (e.g. `:564`). |
|
||||||
|
| `-mount <path>` | Override the FUSE mount path. |
|
||||||
|
|
||||||
|
```sh
|
||||||
|
olliesrv start -strict # tools only, sandboxed
|
||||||
|
olliesrv start -yolo # arbitrary code, no sandbox
|
||||||
|
olliesrv start -strict -yolo # tools only, no sandbox
|
||||||
|
```
|
||||||
|
|
||||||
## Sessions
|
## Sessions
|
||||||
|
|
||||||
### Create
|
### Create
|
||||||
|
|
|
||||||
17
main.go
17
main.go
|
|
@ -20,6 +20,8 @@ const serviceName = "ollie"
|
||||||
|
|
||||||
var mountPath = flag.String("mount", "", "FUSE mount path (default: $HOME/mnt/ollie)")
|
var mountPath = flag.String("mount", "", "FUSE mount path (default: $HOME/mnt/ollie)")
|
||||||
var tcpAddr = flag.String("tcp", "", "also listen on TCP address (e.g. :564)")
|
var tcpAddr = flag.String("tcp", "", "also listen on TCP address (e.g. :564)")
|
||||||
|
var strict = flag.Bool("strict", false, "only allow tool steps; reject inline code")
|
||||||
|
var yolo = flag.Bool("yolo", false, "skip landrun sandbox for execute_code")
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
|
|
@ -115,6 +117,12 @@ func daemonize(pidPath string) {
|
||||||
if *tcpAddr != "" {
|
if *tcpAddr != "" {
|
||||||
args = append(args, "-tcp", *tcpAddr)
|
args = append(args, "-tcp", *tcpAddr)
|
||||||
}
|
}
|
||||||
|
if *strict {
|
||||||
|
args = append(args, "-strict")
|
||||||
|
}
|
||||||
|
if *yolo {
|
||||||
|
args = append(args, "-yolo")
|
||||||
|
}
|
||||||
cmd := exec.Command(exe, args...)
|
cmd := exec.Command(exe, args...)
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
|
|
@ -152,7 +160,14 @@ func runServer(sockPath, pidPath string) {
|
||||||
os.WriteFile(pidPath, []byte(fmt.Sprintf("%d", os.Getpid())), 0644) //nolint:errcheck
|
os.WriteFile(pidPath, []byte(fmt.Sprintf("%d", os.Getpid())), 0644) //nolint:errcheck
|
||||||
|
|
||||||
sink := olog.NewSink(os.Stdout, os.Stderr, olog.ParseLevel(os.Getenv("OLLIE_LOG"), olog.LevelWarn))
|
sink := olog.NewSink(os.Stdout, os.Stderr, olog.ParseLevel(os.Getenv("OLLIE_LOG"), olog.LevelWarn))
|
||||||
srv := New(sink)
|
var srvOpts []ServerOption
|
||||||
|
if *strict {
|
||||||
|
srvOpts = append(srvOpts, WithStrict())
|
||||||
|
}
|
||||||
|
if *yolo {
|
||||||
|
srvOpts = append(srvOpts, WithYolo())
|
||||||
|
}
|
||||||
|
srv := New(sink, srvOpts...)
|
||||||
|
|
||||||
listener, err := net.Listen("unix", sockPath)
|
listener, err := net.Listen("unix", sockPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
15
server.go
15
server.go
|
|
@ -226,10 +226,18 @@ type Server struct {
|
||||||
sessionStore *SessionStore
|
sessionStore *SessionStore
|
||||||
transcriptStore Store
|
transcriptStore Store
|
||||||
tmpStore Store
|
tmpStore Store
|
||||||
|
strict bool
|
||||||
|
yolo bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServerOption configures the 9P server.
|
||||||
|
type ServerOption func(*Server)
|
||||||
|
|
||||||
|
func WithStrict() ServerOption { return func(s *Server) { s.strict = true } }
|
||||||
|
func WithYolo() ServerOption { return func(s *Server) { s.yolo = true } }
|
||||||
|
|
||||||
// New creates a new Server.
|
// New creates a new Server.
|
||||||
func New(sink *olog.Sink) *Server {
|
func New(sink *olog.Sink, opts ...ServerOption) *Server {
|
||||||
memDir := defaultMemDir()
|
memDir := defaultMemDir()
|
||||||
os.MkdirAll(memDir, 0755) //nolint:errcheck
|
os.MkdirAll(memDir, 0755) //nolint:errcheck
|
||||||
transcriptDir := defaultTranscriptDir()
|
transcriptDir := defaultTranscriptDir()
|
||||||
|
|
@ -252,11 +260,16 @@ func New(sink *olog.Sink) *Server {
|
||||||
transcriptStore: NewFlatDirStore(transcriptDir, 0444),
|
transcriptStore: NewFlatDirStore(transcriptDir, 0444),
|
||||||
tmpStore: NewFlatDirStore(tmpDir, 0600),
|
tmpStore: NewFlatDirStore(tmpDir, 0600),
|
||||||
}
|
}
|
||||||
|
for _, o := range opts {
|
||||||
|
o(s)
|
||||||
|
}
|
||||||
s.sessionStore = store.NewSessionStore(store.SessionStoreConfig{
|
s.sessionStore = store.NewSessionStore(store.SessionStoreConfig{
|
||||||
AgentsDir: agentsDir,
|
AgentsDir: agentsDir,
|
||||||
SessionsDir: sessionsDir,
|
SessionsDir: sessionsDir,
|
||||||
Log: s.log,
|
Log: s.log,
|
||||||
Sink: s.sink,
|
Sink: s.sink,
|
||||||
|
Strict: s.strict,
|
||||||
|
Yolo: s.yolo,
|
||||||
SaveTranscript: func(data []byte) error {
|
SaveTranscript: func(data []byte) error {
|
||||||
name := time.Now().Format("20060102T150405") + "-chat.md"
|
name := time.Now().Format("20060102T150405") + "-chat.md"
|
||||||
return storeWrite(s.transcriptStore, name, data)
|
return storeWrite(s.transcriptStore, name, data)
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,10 @@ type SessionStoreConfig struct {
|
||||||
// NewCore, if non-nil, replaces the default backend.New + agent.NewAgentCore
|
// NewCore, if non-nil, replaces the default backend.New + agent.NewAgentCore
|
||||||
// path. It receives the session ID, agent name, and cwd, and returns a Core.
|
// path. It receives the session ID, agent name, and cwd, and returns a Core.
|
||||||
NewCore func(sessionID, agentName, cwd string) (agent.Core, error)
|
NewCore func(sessionID, agentName, cwd string) (agent.Core, error)
|
||||||
|
// Strict rejects inline code steps; only tool steps are allowed.
|
||||||
|
Strict bool
|
||||||
|
// Yolo skips the landrun sandbox.
|
||||||
|
Yolo bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// SessionStore implements Store for session management.
|
// SessionStore implements Store for session management.
|
||||||
|
|
@ -371,8 +375,15 @@ func (s *SessionStore) createSession(args []string) error {
|
||||||
|
|
||||||
cfg := LoadAgentConfig(s.cfg.AgentsDir, agentName, nil)
|
cfg := LoadAgentConfig(s.cfg.AgentsDir, agentName, nil)
|
||||||
|
|
||||||
|
var execOpts []execute.Option
|
||||||
|
if s.cfg.Strict {
|
||||||
|
execOpts = append(execOpts, execute.WithStrict())
|
||||||
|
}
|
||||||
|
if s.cfg.Yolo {
|
||||||
|
execOpts = append(execOpts, execute.WithYolo())
|
||||||
|
}
|
||||||
newDisp := tools.NewDispatcherFunc(map[string]func() tools.Server{
|
newDisp := tools.NewDispatcherFunc(map[string]func() tools.Server{
|
||||||
"execute": execute.Decl(cwd),
|
"execute": execute.Decl(cwd, execOpts...),
|
||||||
})
|
})
|
||||||
|
|
||||||
env := agent.BuildAgentEnv(cfg, newDisp(), cwd)
|
env := agent.BuildAgentEnv(cfg, newDisp(), cwd)
|
||||||
|
|
|
||||||
Reference in New Issue