Canvas: Handle repo diff

Refactor github and appmanager clients.
Remove dev mode ports/ingress definitions.

Change-Id: I0ca15cec897d5a8cfa1c89b8ec9c09c408686c64
diff --git a/apps/canvas/back/src/github.ts b/apps/canvas/back/src/github.ts
index 850185d..60d2191 100644
--- a/apps/canvas/back/src/github.ts
+++ b/apps/canvas/back/src/github.ts
@@ -9,6 +9,13 @@
 	ssh_url: z.string(),
 });
 
+const DeployKeysSchema = z.array(
+	z.object({
+		id: z.number(),
+		key: z.string(),
+	}),
+);
+
 export type GithubRepository = z.infer<typeof GithubRepositorySchema>;
 
 export class GithubClient {
@@ -35,7 +42,6 @@
 	async addDeployKey(repoPath: string, key: string) {
 		const sshUrl = repoPath;
 		const repoOwnerAndName = sshUrl.replace("git@github.com:", "").replace(".git", "");
-
 		await axios.post(
 			`https://api.github.com/repos/${repoOwnerAndName}/keys`,
 			{
@@ -48,4 +54,24 @@
 			},
 		);
 	}
+
+	async removeDeployKey(repoPath: string, key: string) {
+		const sshUrl = repoPath;
+		const repoOwnerAndName = sshUrl.replace("git@github.com:", "").replace(".git", "");
+		const response = await axios.get(`https://api.github.com/repos/${repoOwnerAndName}/keys`, {
+			headers: this.getHeaders(),
+		});
+		const result = DeployKeysSchema.safeParse(response.data);
+		if (!result.success) {
+			throw new Error("Failed to parse deploy keys response");
+		}
+		const deployKeys = result.data.filter((k) => k.key === key);
+		await Promise.all(
+			deployKeys.map((deployKey) =>
+				axios.delete(`https://api.github.com/repos/${repoOwnerAndName}/keys/${deployKey.id}`, {
+					headers: this.getHeaders(),
+				}),
+			),
+		);
+	}
 }