Loading a .gns3 placed directly in the projects root registered the
shared projects directory as the project path (load_project derives
the path from the file's parent directory). Deleting such an entry ran
rmtree on the projects directory itself, wiping every project until a
root-owned file stopped it, and left a zombie entry in the controller.
Three layers of protection:
- Controller.load_project() refuses a .gns3 whose parent directory is
the projects directory; the normal subdirectory layout is unaffected
- the Project.path setter rejects the projects directory itself and
its ancestors, closing the same hole for POST/PUT with an explicit
path
- Project.delete() uses realpath + commonpath instead of commonprefix:
entries whose path is the projects root are refused, and sibling
directories sharing a string prefix (/srv/projects-evil vs
/srv/projects) are no longer treated as inside the projects dir
Also removes the project_load MCP tool: loading by raw server
filesystem path is a footgun for automated clients; projects can still
be opened by project_id via the remaining tools.