execute: per-session FUSE mount for 9P identity
The execute server now starts ollie-9p-mount when OLLIE_SESSION_ID is set, giving each agent session its own FUSE proxy that attaches to olliesrv with Uname=session_id. Tools see the full namespace through $OLLIE but all 9P operations carry the session's identity. Close() tears down the mount on session destroy.
This commit is contained in:
parent
5efed7040d
commit
e20f9a7a06
|
|
@ -445,6 +445,14 @@ func NewAgentCore(cfg AgentCoreConfig) Core {
|
|||
// Close releases resources for this session, including its tmpdir.
|
||||
func (s *agent) Close() {
|
||||
s.log.Debug("Close() session=%q", s.sessionID)
|
||||
if s.dispatcher != nil {
|
||||
if srv, ok := s.dispatcher.GetServer("execute"); ok {
|
||||
if c, ok := srv.(interface{ Close() }); ok {
|
||||
s.log.Debug("Close() calling execute.Close()")
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
if s.sessionID != "" {
|
||||
os.RemoveAll(filepath.Join(ollieTmpDir(), s.sessionID)) //nolint:errcheck
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ type Server struct {
|
|||
// step dispatch. Set once at session init via SetLockDir; empty disables locking.
|
||||
lockDir string
|
||||
|
||||
// mountProc is the ollie-9p-mount subprocess for this session's FUSE proxy.
|
||||
mountProc *os.Process
|
||||
mountPath string
|
||||
|
||||
// Strict rejects inline {code} steps; only {tool} steps are allowed.
|
||||
Strict bool
|
||||
|
||||
|
|
@ -358,9 +362,54 @@ func (e *Server) SetEnv(key, value string) {
|
|||
e.envExtra = make(map[string]string)
|
||||
}
|
||||
e.envExtra[key] = value
|
||||
if key == "OLLIE_SESSION_ID" && value != "" {
|
||||
e.startMount(value)
|
||||
}
|
||||
e.envMu.Unlock()
|
||||
}
|
||||
|
||||
// startMount launches ollie-9p-mount for this session. Must be called with envMu held.
|
||||
func (e *Server) startMount(sessionID string) {
|
||||
bin, err := exec.LookPath("ollie-9p-mount")
|
||||
if err != nil {
|
||||
return // binary not installed; skip silently
|
||||
}
|
||||
mnt := filepath.Join(os.TempDir(), "ollie-mount-"+sessionID)
|
||||
os.MkdirAll(mnt, 0755) //nolint:errcheck
|
||||
cmd := exec.Command(bin, "-u", sessionID, mnt)
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return
|
||||
}
|
||||
// Reap in background so Wait works later.
|
||||
go cmd.Wait() //nolint:errcheck
|
||||
// Wait for mount to be ready.
|
||||
for i := 0; i < 20; i++ {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
if _, err := os.Stat(filepath.Join(mnt, "s")); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
e.mountProc = cmd.Process
|
||||
e.mountPath = mnt
|
||||
e.envExtra["OLLIE"] = mnt
|
||||
}
|
||||
|
||||
// Close tears down the per-session FUSE mount.
|
||||
func (e *Server) Close() {
|
||||
e.envMu.Lock()
|
||||
proc := e.mountProc
|
||||
mnt := e.mountPath
|
||||
e.mountProc = nil
|
||||
e.mountPath = ""
|
||||
e.envMu.Unlock()
|
||||
if proc != nil {
|
||||
exec.Command("fusermount", "-u", mnt).Run() //nolint:errcheck
|
||||
syscall.Kill(proc.Pid, syscall.SIGKILL) //nolint:errcheck
|
||||
os.Remove(mnt) //nolint:errcheck
|
||||
}
|
||||
}
|
||||
|
||||
// executeElevated runs cmd outside the sandbox via x/elevate.
|
||||
// Returns (output, error); a non-zero exit code is treated as an error.
|
||||
func (e *Server) executeElevated(ctx context.Context, cmd, dir string, timeout int) (string, error) {
|
||||
|
|
|
|||
Reference in New Issue