darabos commited on
Commit
03c259a
·
unverified ·
2 Parent(s): 458823c 97c9ed9

Merge pull request #177 from biggraph/darabos-workspace-error-handling

Browse files
lynxkite-app/src/lynxkite_app/crdt.py CHANGED
@@ -34,7 +34,7 @@ class WorkspaceWebsocketServer(pycrdt_websocket.WebsocketServer):
34
  """
35
  crdt_path = pathlib.Path(".crdt")
36
  path = crdt_path / f"{name}.crdt"
37
- assert path.is_relative_to(crdt_path)
38
  ystore = pycrdt_websocket.ystore.FileYStore(path)
39
  ydoc = pycrdt.Doc()
40
  ydoc["workspace"] = ws = pycrdt.Map()
@@ -87,7 +87,7 @@ class CodeWebsocketServer(WorkspaceWebsocketServer):
87
  """Initialize a room for a text document with the given name."""
88
  crdt_path = pathlib.Path(".crdt")
89
  path = crdt_path / f"{name}.crdt"
90
- assert path.is_relative_to(crdt_path)
91
  ystore = pycrdt_websocket.ystore.FileYStore(path)
92
  ydoc = pycrdt.Doc()
93
  ydoc["text"] = text = pycrdt.Text()
@@ -261,7 +261,7 @@ async def execute(name: str, ws_crdt: pycrdt.Map, ws_pyd: workspace.Workspace, d
261
  print(f"Running {name} in {ws_pyd.env}...")
262
  cwd = pathlib.Path()
263
  path = cwd / name
264
- assert path.is_relative_to(cwd), "Provided workspace path is invalid"
265
  # Save user changes before executing, in case the execution fails.
266
  ws_pyd.save(path)
267
  ops.load_user_scripts(name)
 
34
  """
35
  crdt_path = pathlib.Path(".crdt")
36
  path = crdt_path / f"{name}.crdt"
37
+ assert path.is_relative_to(crdt_path), f"Path '{path}' is invalid"
38
  ystore = pycrdt_websocket.ystore.FileYStore(path)
39
  ydoc = pycrdt.Doc()
40
  ydoc["workspace"] = ws = pycrdt.Map()
 
87
  """Initialize a room for a text document with the given name."""
88
  crdt_path = pathlib.Path(".crdt")
89
  path = crdt_path / f"{name}.crdt"
90
+ assert path.is_relative_to(crdt_path), f"Path '{path}' is invalid"
91
  ystore = pycrdt_websocket.ystore.FileYStore(path)
92
  ydoc = pycrdt.Doc()
93
  ydoc["text"] = text = pycrdt.Text()
 
261
  print(f"Running {name} in {ws_pyd.env}...")
262
  cwd = pathlib.Path()
263
  path = cwd / name
264
+ assert path.is_relative_to(cwd), f"Path '{path}' is invalid"
265
  # Save user changes before executing, in case the execution fails.
266
  ws_pyd.save(path)
267
  ops.load_user_scripts(name)
lynxkite-app/src/lynxkite_app/main.py CHANGED
@@ -49,7 +49,7 @@ data_path = pathlib.Path()
49
 
50
  def save(req: SaveRequest):
51
  path = data_path / req.path
52
- assert path.is_relative_to(data_path)
53
  req.ws.save(path)
54
 
55
 
@@ -66,7 +66,7 @@ async def save_and_execute(req: SaveRequest):
66
  async def delete_workspace(req: dict):
67
  json_path: pathlib.Path = data_path / req["path"]
68
  crdt_path: pathlib.Path = data_path / ".crdt" / f"{req['path']}.crdt"
69
- assert json_path.is_relative_to(data_path)
70
  json_path.unlink()
71
  crdt_path.unlink()
72
 
@@ -74,7 +74,7 @@ async def delete_workspace(req: dict):
74
  @app.get("/api/load")
75
  def load(path: str):
76
  path = data_path / path
77
- assert path.is_relative_to(data_path)
78
  if not path.exists():
79
  return workspace.Workspace()
80
  return workspace.Workspace.load(path)
@@ -97,7 +97,7 @@ def _get_path_type(path: pathlib.Path) -> str:
97
  @app.get("/api/dir/list")
98
  def list_dir(path: str):
99
  path = data_path / path
100
- assert path.is_relative_to(data_path)
101
  return sorted(
102
  [
103
  DirectoryEntry(
@@ -114,7 +114,7 @@ def list_dir(path: str):
114
  @app.post("/api/dir/mkdir")
115
  def make_dir(req: dict):
116
  path = data_path / req["path"]
117
- assert path.is_relative_to(data_path)
118
  assert not path.exists(), f"{path} already exists"
119
  path.mkdir()
120
 
@@ -122,7 +122,9 @@ def make_dir(req: dict):
122
  @app.post("/api/dir/delete")
123
  def delete_dir(req: dict):
124
  path: pathlib.Path = data_path / req["path"]
125
- assert all([path.is_relative_to(data_path), path.exists(), path.is_dir()])
 
 
126
  shutil.rmtree(path)
127
 
128
 
@@ -146,7 +148,7 @@ async def upload(req: fastapi.Request):
146
  form = await req.form()
147
  for file in form.values():
148
  file_path = data_path / "uploads" / file.filename
149
- assert file_path.is_relative_to(data_path), "Invalid file path"
150
  with file_path.open("wb") as buffer:
151
  shutil.copyfileobj(file.file, buffer)
152
  return {"status": "ok"}
 
49
 
50
  def save(req: SaveRequest):
51
  path = data_path / req.path
52
+ assert path.is_relative_to(data_path), f"Path '{path}' is invalid"
53
  req.ws.save(path)
54
 
55
 
 
66
  async def delete_workspace(req: dict):
67
  json_path: pathlib.Path = data_path / req["path"]
68
  crdt_path: pathlib.Path = data_path / ".crdt" / f"{req['path']}.crdt"
69
+ assert json_path.is_relative_to(data_path), f"Path '{json_path}' is invalid"
70
  json_path.unlink()
71
  crdt_path.unlink()
72
 
 
74
  @app.get("/api/load")
75
  def load(path: str):
76
  path = data_path / path
77
+ assert path.is_relative_to(data_path), f"Path '{path}' is invalid"
78
  if not path.exists():
79
  return workspace.Workspace()
80
  return workspace.Workspace.load(path)
 
97
  @app.get("/api/dir/list")
98
  def list_dir(path: str):
99
  path = data_path / path
100
+ assert path.is_relative_to(data_path), f"Path '{path}' is invalid"
101
  return sorted(
102
  [
103
  DirectoryEntry(
 
114
  @app.post("/api/dir/mkdir")
115
  def make_dir(req: dict):
116
  path = data_path / req["path"]
117
+ assert path.is_relative_to(data_path), f"Path '{path}' is invalid"
118
  assert not path.exists(), f"{path} already exists"
119
  path.mkdir()
120
 
 
122
  @app.post("/api/dir/delete")
123
  def delete_dir(req: dict):
124
  path: pathlib.Path = data_path / req["path"]
125
+ assert all([path.is_relative_to(data_path), path.exists(), path.is_dir()]), (
126
+ f"Path '{path}' is invalid"
127
+ )
128
  shutil.rmtree(path)
129
 
130
 
 
148
  form = await req.form()
149
  for file in form.values():
150
  file_path = data_path / "uploads" / file.filename
151
+ assert file_path.is_relative_to(data_path), f"Path '{file_path}' is invalid"
152
  with file_path.open("wb") as buffer:
153
  shutil.copyfileobj(file.file, buffer)
154
  return {"status": "ok"}
lynxkite-app/web/src/main.tsx CHANGED
@@ -2,21 +2,52 @@ import { StrictMode } from "react";
2
  import { createRoot } from "react-dom/client";
3
  import "@xyflow/react/dist/style.css";
4
  import "./index.css";
5
- import { BrowserRouter, Route, Routes } from "react-router";
 
 
 
 
 
 
 
6
  import Code from "./Code.tsx";
7
  import Directory from "./Directory.tsx";
8
  import Workspace from "./workspace/Workspace.tsx";
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  createRoot(document.getElementById("root")!).render(
11
  <StrictMode>
12
- <BrowserRouter>
13
- <Routes>
14
- <Route path="/" element={<Directory />} />
15
- <Route path="/dir" element={<Directory />} />
16
- <Route path="/dir/*" element={<Directory />} />
17
- <Route path="/edit/*" element={<Workspace />} />
18
- <Route path="/code/*" element={<Code />} />
19
- </Routes>
20
- </BrowserRouter>
21
  </StrictMode>,
22
  );
 
2
  import { createRoot } from "react-dom/client";
3
  import "@xyflow/react/dist/style.css";
4
  import "./index.css";
5
+ import {
6
+ Link,
7
+ Route,
8
+ RouterProvider,
9
+ createBrowserRouter,
10
+ createRoutesFromElements,
11
+ useRouteError,
12
+ } from "react-router";
13
  import Code from "./Code.tsx";
14
  import Directory from "./Directory.tsx";
15
  import Workspace from "./workspace/Workspace.tsx";
16
 
17
+ function WorkspaceError() {
18
+ const error = useRouteError();
19
+ const stack = error instanceof Error ? error.stack : null;
20
+ return (
21
+ <div className="hero min-h-screen">
22
+ <div className="card bg-base-100 shadow-sm">
23
+ <div className="card-body">
24
+ <h2 className="card-title">Something went wrong...</h2>
25
+ <pre>{stack || "Unknown error."}</pre>
26
+ <div className="card-actions justify-end">
27
+ <Link to="/" className="btn btn-primary">
28
+ Close workspace
29
+ </Link>
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ );
35
+ }
36
+
37
+ const router = createBrowserRouter(
38
+ createRoutesFromElements(
39
+ <>
40
+ <Route path="/" element={<Directory />} />
41
+ <Route path="/dir" element={<Directory />} />
42
+ <Route path="/dir/*" element={<Directory />} />
43
+ <Route path="/edit/*" element={<Workspace />} errorElement={<WorkspaceError />} />
44
+ <Route path="/code/*" element={<Code />} />
45
+ </>,
46
+ ),
47
+ );
48
+
49
  createRoot(document.getElementById("root")!).render(
50
  <StrictMode>
51
+ <RouterProvider router={router} />
 
 
 
 
 
 
 
 
52
  </StrictMode>,
53
  );
lynxkite-core/src/lynxkite/core/ops.py CHANGED
@@ -404,7 +404,7 @@ def load_user_scripts(workspace: str):
404
  load_catalogs("plugins loaded")
405
  cwd = pathlib.Path()
406
  path = cwd / workspace
407
- assert path.is_relative_to(cwd), "Provided workspace path is invalid"
408
  for p in path.parents:
409
  req = p / "requirements.txt"
410
  if req.exists():
 
404
  load_catalogs("plugins loaded")
405
  cwd = pathlib.Path()
406
  path = cwd / workspace
407
+ assert path.is_relative_to(cwd), f"Path '{path}' is invalid"
408
  for p in path.parents:
409
  req = p / "requirements.txt"
410
  if req.exists():
lynxkite-graph-analytics/src/lynxkite_graph_analytics/ml_ops.py CHANGED
@@ -20,7 +20,7 @@ op = ops.op_registration(core.ENV)
20
  def load_ws(model_workspace: str):
21
  cwd = pathlib.Path()
22
  path = cwd / model_workspace
23
- assert path.is_relative_to(cwd)
24
  assert path.exists(), f"Workspace {path} does not exist"
25
  ws = workspace.Workspace.load(path)
26
  return ws
 
20
  def load_ws(model_workspace: str):
21
  cwd = pathlib.Path()
22
  path = cwd / model_workspace
23
+ assert path.is_relative_to(cwd), f"Path '{path}' is invalid"
24
  assert path.exists(), f"Workspace {path} does not exist"
25
  ws = workspace.Workspace.load(path)
26
  return ws
lynxkite-lynxscribe/src/lynxkite_lynxscribe/lynxscribe_ops.py CHANGED
@@ -873,7 +873,7 @@ async def get_chat_api(ws: str):
873
 
874
  cwd = pathlib.Path()
875
  path = cwd / ws
876
- assert path.is_relative_to(cwd)
877
  assert path.exists(), f"Workspace {path} does not exist"
878
  ws = workspace.Workspace.load(path)
879
  contexts = await ops.EXECUTORS[ENV](ws)
 
873
 
874
  cwd = pathlib.Path()
875
  path = cwd / ws
876
+ assert path.is_relative_to(cwd), f"Path '{path}' is invalid"
877
  assert path.exists(), f"Workspace {path} does not exist"
878
  ws = workspace.Workspace.load(path)
879
  contexts = await ops.EXECUTORS[ENV](ws)