History

fix build

Rhys Sullivan committed 8 months ago

Commit 380105a1 parent f3e9beb6 files · +63 −22Browse files

Unified · Split

6 files
  1. executor/apps/web/src/components/tools/install-configs.ts +3 −7
  2. executor/apps/web/src/components/tools/setup-card.tsx +4 −5
  3. executor/packages/database/src/auth/identity.test.ts +3 −4
  4. executor/packages/database/src/auth/mcp_api_key.test.ts +3 −4
  5. executor/packages/database/src/auth/naming.test.ts +25 −0
  6. executor/packages/database/src/auth/naming.ts +25 −2
executor/apps/web/src/components/tools/install-configs.ts+3−7
@@ -8,22 +8,18 @@ export function getAddMcpInstallConfig( · 7 unmodified lines
8 mcpUrl: string,8 mcpUrl: string,
9 serverName: string,9 serverName: string,
10 auth?: {10 auth?: {
11 apiKeyEnvName?: string;11 apiKey?: string;
12 },12 },
13): McpInstallConfig {13): McpInstallConfig {
14 const apiKeyEnvName = auth?.apiKeyEnvName?.trim() || "API_KEY";
15 const headerArg = auth14 const headerArg = auth
16 ? ` --header "x-api-key: $${apiKeyEnvName}"`15 ? ` --header "x-api-key: ${auth.apiKey}"`
17 : "";
18 const exportLine = auth
19 ? `${apiKeyEnvName}="<paste-api-key-from-above>"`
20 : "";16 : "";
21 17
22 return {18 return {
23 type: "command",19 type: "command",
24 description: "Run once to install for all supported clients (via add-mcp):",20 description: "Run once to install for all supported clients (via add-mcp):",
25 content: auth21 content: auth
26 ? `${exportLine}\nnpx add-mcp "${mcpUrl}" --transport http --name "${serverName}" --all${headerArg}`22 ? `npx add-mcp "${mcpUrl}" --transport http --name "${serverName}" --all${headerArg}`
27 : `npx add-mcp "${mcpUrl}" --transport http --name "${serverName}" --all${headerArg}`,23 : `npx add-mcp "${mcpUrl}" --transport http --name "${serverName}" --all${headerArg}`,
28 };24 };
29}25}
executor/apps/web/src/components/tools/setup-card.tsx+4−5
@@ -3,6 +3,7 @@ · 2 unmodified lines
3import { useMemo, useState } from "react";3import { useMemo, useState } from "react";
4import { useQuery } from "convex/react";4import { useQuery } from "convex/react";
5import { Check, Copy } from "lucide-react";5import { Check, Copy } from "lucide-react";
6import type { Id } from "@executor/database/convex/_generated/dataModel";
6import { Button } from "@/components/ui/button";7import { Button } from "@/components/ui/button";
7import { Input } from "@/components/ui/input";8import { Input } from "@/components/ui/input";
8import { Label } from "@/components/ui/label";9import { Label } from "@/components/ui/label";
@@ -50,7 +51,7 @@ export function McpSetupCard({ · 41 unmodified lines
50 workspaceId,51 workspaceId,
51 sessionId,52 sessionId,
52}: {53}: {
53 workspaceId?: string;54 workspaceId?: Id<"workspaces">;
54 sessionId?: string;55 sessionId?: string;
55}) {56}) {
56 const [copiedKey, setCopiedKey] = useState<string | null>(null);57 const [copiedKey, setCopiedKey] = useState<string | null>(null);
@@ -81,12 +82,12 @@ export function McpSetupCard({ · 24 unmodified lines
81 isAnonymousSession && workspaceId82 isAnonymousSession && workspaceId
82 ? {83 ? {
83 workspaceId,84 workspaceId,
84 sessionId,85 sessionId
85 }86 }
86 : "skip",87 : "skip",
87 );88 );
88 89
89 const apiKeyEnvName = anonymousMcpApiKey?.envVar ?? "API_KEY";90
90 const apiKeyValue = anonymousMcpApiKey?.enabled91 const apiKeyValue = anonymousMcpApiKey?.enabled
91 ? anonymousMcpApiKey.apiKey92 ? anonymousMcpApiKey.apiKey
92 : null;93 : null;
@@ -104,7 +105,6 @@ export function McpSetupCard({ · 11 unmodified lines
104 serverName,105 serverName,
105 isAnonymousSession106 isAnonymousSession
106 ? {107 ? {
107 apiKeyEnvName,
108 apiKey: apiKeyValue ?? "your-api-key-here",108 apiKey: apiKeyValue ?? "your-api-key-here",
109 }109 }
110 : undefined,110 : undefined,
@@ -139,7 +139,6 @@ export function McpSetupCard({ · 28 unmodified lines
139 139
140 {isAnonymousSession && (140 {isAnonymousSession && (
141 <div className="mt-2 space-y-1.5">141 <div className="mt-2 space-y-1.5">
142 <Label className="text-xs text-muted-foreground">API Key ({apiKeyEnvName})</Label>
143 <div className="flex items-center gap-2">142 <div className="flex items-center gap-2">
144 <Input143 <Input
145 value={apiKeyValue ?? "Loading API key..."}144 value={apiKeyValue ?? "Loading API key..."}
executor/packages/database/src/auth/identity.test.ts+3−4
@@ -130,8 +130,7 @@ test("getAuthKitUserProfile retries with normalized user id", async () => { · 129 unmodified lines
130 "workos|user_01KH1TVHS4WJCPQG2XQJGMMJMJ",130 "workos|user_01KH1TVHS4WJCPQG2XQJGMMJMJ",
131 "user_01KH1TVHS4WJCPQG2XQJGMMJMJ",131 "user_01KH1TVHS4WJCPQG2XQJGMMJMJ",
132 ]);132 ]);
133 expect(result).toEqual({133 expect(result).not.toBeNull();
134 id: "user_01KH1TVHS4WJCPQG2XQJGMMJMJ",134 expect(result?.id).toBe("user_01KH1TVHS4WJCPQG2XQJGMMJMJ");
135 email: "alex@example.com",135 expect(result?.email).toBe("alex@example.com");
136 });
137});136});
executor/packages/database/src/auth/mcp_api_key.test.ts+3−4
@@ -20,10 +20,9 @@ test("issueMcpApiKey + verifyMcpApiKey round trip", async () => { · 19 unmodified lines
20 20
21 expect(apiKey).toBeTruthy();21 expect(apiKey).toBeTruthy();
22 const verified = await verifyMcpApiKey(apiKey);22 const verified = await verifyMcpApiKey(apiKey);
23 expect(verified).toEqual({23 expect(verified).not.toBeNull();
24 workspaceId: "workspace_123",24 expect(verified?.workspaceId).toBe("workspace_123" as Id<"workspaces">);
25 accountId: "account_456",25 expect(verified?.accountId).toBe("account_456" as Id<"accounts">);
26 });
27});26});
28 27
29test("verifyMcpApiKey rejects tampered token", async () => {28test("verifyMcpApiKey rejects tampered token", async () => {
executor/packages/database/src/auth/naming.test.ts+25−0
@@ -0,0 +1,25 @@
1import { expect, test } from "bun:test";
2import { derivePersonalNames } from "./naming";
3
4test("derivePersonalNames ignores generated fallback full name", () => {
5 const names = derivePersonalNames({
6 fullName: "User GMMJMJ",
7 email: "alex@example.com",
8 workosUserId: "user_01KH1TVHS4WJCPQG2XQJGMMJMJ",
9 });
10
11 expect(names.organizationName).toBe("Alex's Organization");
12 expect(names.workspaceName).toBe("Alex's Workspace");
13});
14
15test("derivePersonalNames prefers first name when available", () => {
16 const names = derivePersonalNames({
17 firstName: "Alex",
18 fullName: "User GMMJMJ",
19 email: "alex@example.com",
20 workosUserId: "user_01KH1TVHS4WJCPQG2XQJGMMJMJ",
21 });
22
23 expect(names.organizationName).toBe("Alex's Organization");
24 expect(names.workspaceName).toBe("Alex's Workspace");
25});
executor/packages/database/src/auth/naming.ts+25−2
@@ -14,6 +14,29 @@ function escapeRegex(value: string): string { · 13 unmodified lines
14 return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");14 return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
15}15}
16 16
17function isGeneratedIdentityLabel(value: string, workosUserId: string): boolean {
18 const normalizedValue = value.trim();
19 const normalizedWorkosUserId = workosUserId.trim();
20 if (!normalizedValue) {
21 return false;
22 }
23
24 const fallbackSuffix = normalizedWorkosUserId.slice(-6);
25 if (fallbackSuffix && new RegExp(`^user\\s+${escapeRegex(fallbackSuffix)}$`, "i").test(normalizedValue)) {
26 return true;
27 }
28
29 if (/^user\s+[a-z0-9]{6,}$/i.test(normalizedValue)) {
30 return true;
31 }
32
33 if (/^(?:workos\|)?user_[a-z0-9]+$/i.test(normalizedValue)) {
34 return true;
35 }
36
37 return normalizedValue.toLowerCase() === normalizedWorkosUserId.toLowerCase();
38}
39
17export function isGeneratedPersonalOrganizationName(name: string, workosUserId: string): boolean {40export function isGeneratedPersonalOrganizationName(name: string, workosUserId: string): boolean {
18 if (/workspace$/i.test(name)) {41 if (/workspace$/i.test(name)) {
19 return true;42 return true;
@@ -40,12 +63,12 @@ export function isGeneratedPersonalWorkspaceName(name: string, workosUserId: str · 20 unmodified lines
40 63
41function deriveOwnerLabel(args: { firstName?: string; fullName?: string; email?: string; workosUserId: string }): string {64function deriveOwnerLabel(args: { firstName?: string; fullName?: string; email?: string; workosUserId: string }): string {
42 const firstName = args.firstName?.trim();65 const firstName = args.firstName?.trim();
43 if (firstName && !/^my$/i.test(firstName)) {66 if (firstName && !/^my$/i.test(firstName) && !/^user$/i.test(firstName)) {
44 return firstName;67 return firstName;
45 }68 }
46 69
47 const fullName = args.fullName?.trim();70 const fullName = args.fullName?.trim();
48 if (fullName && !fullName.includes("@")) {71 if (fullName && !fullName.includes("@") && !isGeneratedIdentityLabel(fullName, args.workosUserId)) {
49 return fullName;72 return fullName;
50 }73 }
51 74