agent: separate uname (principal) from session ID

Session identity is now a numeric UID (starting at 10000) assigned at
creation and never changed. Session names can be renamed freely without
affecting the 9P identity.

- AgentCoreConfig.Uname carries the principal
- pushSessionEnv sets OLLIE_UNAME on the execute server
- startMount gated by WithMount() option (not env var)
- Close() uses context timeout to avoid hanging on fusermount
This commit is contained in:
Levi Neely 2026-05-19 15:06:16 +02:00
parent e20f9a7a06
commit 1e96d4c7f4
2 changed files with 23 additions and 7 deletions

View File

@ -235,6 +235,7 @@ type AgentCoreConfig struct {
AgentsDir string AgentsDir string
SessionsDir string SessionsDir string
SessionID string SessionID string
Uname string // immutable user principal for 9P identity
CWD string // working directory for tool execution and system prompt CWD string // working directory for tool execution and system prompt
Session *Session Session *Session
Env AgentEnv Env AgentEnv
@ -257,6 +258,7 @@ type agent struct {
agentsDir string agentsDir string
sessionsDir string sessionsDir string
sessionID string sessionID string
uname string
dispatcher tools.Dispatcher dispatcher tools.Dispatcher
newDispatcher func() tools.Dispatcher newDispatcher func() tools.Dispatcher
newBackend func(string) (backend.Backend, error) newBackend func(string) (backend.Backend, error)
@ -311,6 +313,9 @@ func (s *agent) pushSessionEnv() {
if srv, ok := s.dispatcher.GetServer("execute"); ok { if srv, ok := s.dispatcher.GetServer("execute"); ok {
if es, ok := srv.(tools.EnvSetter); ok { if es, ok := srv.(tools.EnvSetter); ok {
es.SetEnv("OLLIE_SESSION_ID", s.sessionID) es.SetEnv("OLLIE_SESSION_ID", s.sessionID)
if s.uname != "" {
es.SetEnv("OLLIE_UNAME", s.uname)
}
} }
} }
} }
@ -416,6 +421,7 @@ func NewAgentCore(cfg AgentCoreConfig) Core {
agentsDir: cfg.AgentsDir, agentsDir: cfg.AgentsDir,
sessionsDir: cfg.SessionsDir, sessionsDir: cfg.SessionsDir,
sessionID: cfg.SessionID, sessionID: cfg.SessionID,
uname: cfg.Uname,
cwd: paths.ExpandHome(cfg.CWD), cwd: paths.ExpandHome(cfg.CWD),
startupMessages: cfg.Env.Messages, startupMessages: cfg.Env.Messages,
dispatcher: cfg.Env.dispatcher, dispatcher: cfg.Env.dispatcher,

View File

@ -42,8 +42,9 @@ type Server struct {
lockDir string lockDir string
// mountProc is the ollie-9p-mount subprocess for this session's FUSE proxy. // mountProc is the ollie-9p-mount subprocess for this session's FUSE proxy.
mountProc *os.Process mountProc *os.Process
mountPath string mountPath string
mountEnabled bool
// Strict rejects inline {code} steps; only {tool} steps are allowed. // Strict rejects inline {code} steps; only {tool} steps are allowed.
Strict bool Strict bool
@ -75,6 +76,9 @@ func WithStrict() Option { return func(s *Server) { s.Strict = true } }
// WithYolo skips the landrun sandbox. // WithYolo skips the landrun sandbox.
func WithYolo() Option { return func(s *Server) { s.Yolo = true } } func WithYolo() Option { return func(s *Server) { s.Yolo = true } }
// WithMount enables per-session FUSE mount for 9P identity.
func WithMount() Option { return func(s *Server) { s.mountEnabled = true } }
// WithAllowExecutors restricts which executors are available. // WithAllowExecutors restricts which executors are available.
func WithAllowExecutors(names []string) Option { func WithAllowExecutors(names []string) Option {
return func(s *Server) { return func(s *Server) {
@ -362,7 +366,8 @@ func (e *Server) SetEnv(key, value string) {
e.envExtra = make(map[string]string) e.envExtra = make(map[string]string)
} }
e.envExtra[key] = value e.envExtra[key] = value
if key == "OLLIE_SESSION_ID" && value != "" { // Start mount once we have the principal.
if key == "OLLIE_UNAME" && value != "" {
e.startMount(value) e.startMount(value)
} }
e.envMu.Unlock() e.envMu.Unlock()
@ -370,9 +375,12 @@ func (e *Server) SetEnv(key, value string) {
// startMount launches ollie-9p-mount for this session. Must be called with envMu held. // startMount launches ollie-9p-mount for this session. Must be called with envMu held.
func (e *Server) startMount(sessionID string) { func (e *Server) startMount(sessionID string) {
if !e.mountEnabled {
return
}
bin, err := exec.LookPath("ollie-9p-mount") bin, err := exec.LookPath("ollie-9p-mount")
if err != nil { if err != nil {
return // binary not installed; skip silently return
} }
mnt := filepath.Join(os.TempDir(), "ollie-mount-"+sessionID) mnt := filepath.Join(os.TempDir(), "ollie-mount-"+sessionID)
os.MkdirAll(mnt, 0755) //nolint:errcheck os.MkdirAll(mnt, 0755) //nolint:errcheck
@ -404,9 +412,11 @@ func (e *Server) Close() {
e.mountPath = "" e.mountPath = ""
e.envMu.Unlock() e.envMu.Unlock()
if proc != nil { if proc != nil {
exec.Command("fusermount", "-u", mnt).Run() //nolint:errcheck ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
syscall.Kill(proc.Pid, syscall.SIGKILL) //nolint:errcheck exec.CommandContext(ctx, "fusermount", "-u", mnt).Run() //nolint:errcheck
os.Remove(mnt) //nolint:errcheck cancel()
syscall.Kill(proc.Pid, syscall.SIGKILL) //nolint:errcheck
os.Remove(mnt) //nolint:errcheck
} }
} }