Canvas: Use GraphSchema to validate state
Change-Id: I342c8959c97f3486c4a7cb2aff92fb930a2b3146
diff --git a/apps/canvas/back/src/index.ts b/apps/canvas/back/src/index.ts
index 38122f8..9456d17 100644
--- a/apps/canvas/back/src/index.ts
+++ b/apps/canvas/back/src/index.ts
@@ -24,6 +24,7 @@
} from "config";
import { Instant, DateTimeFormatter, ZoneId } from "@js-joda/core";
import LogStore from "./log.js";
+import { GraphOrConfigSchema, GraphSchema } from "config/dist/graph.js";
async function generateKey(root: string): Promise<[string, string]> {
const privKeyPath = path.join(root, "key");
@@ -42,6 +43,13 @@
const projectMonitors = new Map<number, ProjectMonitor>();
+function parseGraph(data: string | null | undefined) {
+ if (data == null) {
+ return null;
+ }
+ return GraphSchema.safeParse(JSON.parse(data));
+}
+
const handleProjectCreate: express.Handler = async (req, resp) => {
try {
const tmpDir = tmp.dirSync().name;
@@ -94,26 +102,6 @@
}
};
-const handleSave: express.Handler = async (req, resp) => {
- try {
- await db.project.update({
- where: {
- id: Number(req.params["projectId"]),
- userId: resp.locals.userId,
- },
- data: {
- draft: JSON.stringify(req.body),
- },
- });
- resp.status(200);
- } catch (e) {
- console.log(e);
- resp.status(500);
- } finally {
- resp.end();
- }
-};
-
async function getState(projectId: number, userId: string, state: "deploy" | "draft"): Promise<Graph | null> {
const r = await db.project.findUnique({
where: {
@@ -131,7 +119,7 @@
let currentState: Graph | null = null;
if (state === "deploy") {
if (r.state != null) {
- currentState = JSON.parse(Buffer.from(r.state).toString("utf8"));
+ currentState = parseGraph(r.state)!.data!;
}
} else {
if (r.draft == null) {
@@ -142,10 +130,10 @@
viewport: { x: 0, y: 0, zoom: 1 },
};
} else {
- currentState = JSON.parse(Buffer.from(r.state).toString("utf8"));
+ currentState = parseGraph(r.state)!.data!;
}
} else {
- currentState = JSON.parse(Buffer.from(r.draft).toString("utf8"));
+ currentState = parseGraph(r.draft)!.data!;
}
}
return currentState;
@@ -350,7 +338,7 @@
config.data,
getNetworks(resp.locals.username),
repos,
- p.state ? JSON.parse(Buffer.from(p.state).toString("utf8")) : null,
+ p.state ? parseGraph(p.state)!.data! : undefined,
),
);
await db.project.update({
@@ -431,13 +419,13 @@
}
};
-const handleSaveFromConfig: express.Handler = async (req, resp) => {
+const handleSave: express.Handler = async (req, resp) => {
try {
const projectId = Number(req.params["projectId"]);
const p = await db.project.findUnique({
where: {
id: projectId,
- // userId: resp.locals.userId, TODO(gio): validate
+ userId: resp.locals.userId,
},
select: {
instanceId: true,
@@ -453,10 +441,18 @@
resp.status(404);
return;
}
- const config = ConfigSchema.safeParse(req.body.config);
- if (!config.success) {
+ const gc = GraphOrConfigSchema.safeParse(req.body);
+ if (!gc.success) {
resp.status(400);
- resp.write(JSON.stringify({ error: "Invalid configuration", issues: config.error.format() }));
+ resp.write(JSON.stringify({ error: "Invalid configuration", issues: gc.error.format() }));
+ return;
+ }
+ if (gc.data.type === "graph") {
+ await db.project.update({
+ where: { id: projectId },
+ data: { draft: JSON.stringify(gc.data.graph) },
+ });
+ resp.status(200);
return;
}
let repos: GithubRepository[] = [];
@@ -466,10 +462,10 @@
}
const state = JSON.stringify(
configToGraph(
- config.data,
+ gc.data.config,
getNetworks(resp.locals.username),
repos,
- p.state ? JSON.parse(Buffer.from(p.state).toString("utf8")) : null,
+ p.state ? parseGraph(p.state)!.data! : undefined,
),
);
await db.project.update({
@@ -538,7 +534,7 @@
return;
}
- const state = JSON.parse(Buffer.from(project.state).toString("utf8"));
+ const state = parseGraph(project.state)!.data!;
const env = await getEnv(projectId, resp.locals.userId, resp.locals.username);
const config = generateDodoConfig(projectId.toString(), state.nodes, env);
@@ -1204,7 +1200,6 @@
const projectRouter = express.Router();
projectRouter.use(auth);
projectRouter.post("/:projectId/analyze", handleAnalyzeRepo);
- projectRouter.post("/:projectId/saved/config", handleSaveFromConfig);
projectRouter.post("/:projectId/saved", handleSave);
projectRouter.get("/:projectId/state/stream/deploy", handleStateGetStream("deploy"));
projectRouter.get("/:projectId/state/stream/draft", handleStateGetStream("draft"));
@@ -1235,6 +1230,7 @@
internalApi.use(express.json());
internalApi.post("/api/project/:projectId/workers", handleRegisterWorker);
internalApi.get("/api/project/:projectId/config", handleConfigGet);
+ internalApi.post("/api/project/:projectId/saved", handleSave);
internalApi.post("/api/project/:projectId/deploy", handleDeploy);
internalApi.post("/api/validate-config", handleValidateConfig);