Skip to content

Commit 158b9c5

Browse files
author
Shaw
committed
e2e fixes
1 parent b8a60c0 commit 158b9c5

2 files changed

Lines changed: 198 additions & 0 deletions

File tree

packages/benchmarks/orchestrator/random_baseline_runner.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ def _hermes_env_payload(score: float) -> dict[str, Any]:
303303

304304

305305
def _hyperliquid_payload(score: float) -> dict[str, Any]:
306+
signature = f"synthetic-calibration-{score:.6f}"
306307
return {
307308
"final_score": score,
308309
"total_score": score,
@@ -311,6 +312,13 @@ def _hyperliquid_payload(score: float) -> dict[str, Any]:
311312
"penalty": 0,
312313
"total_scenarios": 2,
313314
"passed_scenarios": _passed_count(score),
315+
"scenarios": [
316+
{
317+
"id": "synthetic-calibration",
318+
"success": True,
319+
"unique_signatures": [signature],
320+
}
321+
],
314322
"mode": "synthetic-calibration",
315323
"demo_mode": False,
316324
}
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
// Live auth/backend smoke for real SIWE and SIWS endpoints.
2+
//
3+
// This intentionally talks to the configured live API with no route mocks.
4+
// It is opt-in because successful runs create real wallet-backed users/API
5+
// keys in the target environment.
6+
//
7+
// Enable with:
8+
// CLOUD_E2E_LIVE_URL=https://www.elizacloud.ai \
9+
// CLOUD_E2E_LIVE_AUTH=1 \
10+
// bun run test:e2e tests/e2e/live-auth-backend.spec.ts
11+
12+
import { expect, test } from "@playwright/test";
13+
import bs58 from "bs58";
14+
import nacl from "tweetnacl";
15+
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
16+
17+
const LIVE_URL = process.env.CLOUD_E2E_LIVE_URL?.trim();
18+
const LIVE_AUTH_ENABLED = process.env.CLOUD_E2E_LIVE_AUTH === "1";
19+
const API_BASE_URL = resolveApiBaseUrl();
20+
21+
interface NonceResponse {
22+
nonce: string;
23+
domain: string;
24+
uri: string;
25+
chainId: string | number;
26+
version: string;
27+
statement?: string;
28+
}
29+
30+
interface WalletVerifyResponse {
31+
apiKey: string;
32+
address: string;
33+
isNewAccount: boolean;
34+
user: { id: string; wallet_address: string | null; organization_id: string };
35+
organization: { id: string; name: string; slug: string } | null;
36+
}
37+
38+
function resolveApiBaseUrl(): string {
39+
const explicit = process.env.CLOUD_E2E_LIVE_API_URL?.trim();
40+
if (explicit) return explicit.replace(/\/+$/, "");
41+
if (!LIVE_URL) return "https://api.elizacloud.ai";
42+
43+
const url = new URL(LIVE_URL);
44+
if (
45+
url.hostname === "elizacloud.ai" ||
46+
url.hostname === "www.elizacloud.ai"
47+
) {
48+
return "https://api.elizacloud.ai";
49+
}
50+
if (url.hostname === "dev.elizacloud.ai") {
51+
return "https://api-dev.elizacloud.ai";
52+
}
53+
return url.origin;
54+
}
55+
56+
function endpoint(path: string): string {
57+
return `${API_BASE_URL}${path}`;
58+
}
59+
60+
function buildWalletMessage(params: {
61+
chain: "Ethereum" | "Solana";
62+
domain: string;
63+
address: string;
64+
statement?: string;
65+
uri: string;
66+
chainId: string | number;
67+
nonce: string;
68+
issuedAt: Date;
69+
}): string {
70+
const lines = [
71+
`${params.domain} wants you to sign in with your ${params.chain} account:`,
72+
params.address,
73+
"",
74+
];
75+
if (params.statement) {
76+
lines.push(params.statement, "");
77+
}
78+
lines.push(
79+
`URI: ${params.uri}`,
80+
"Version: 1",
81+
`Chain ID: ${params.chainId}`,
82+
`Nonce: ${params.nonce}`,
83+
`Issued At: ${params.issuedAt.toISOString()}`,
84+
);
85+
return lines.join("\n");
86+
}
87+
88+
async function fetchJson<T>(
89+
path: string,
90+
init?: RequestInit,
91+
): Promise<{ response: Response; body: T }> {
92+
const response = await fetch(endpoint(path), {
93+
signal: AbortSignal.timeout(30_000),
94+
...init,
95+
headers: {
96+
...(init?.body ? { "Content-Type": "application/json" } : {}),
97+
...init?.headers,
98+
},
99+
});
100+
const text = await response.text();
101+
const body = text ? (JSON.parse(text) as T) : ({} as T);
102+
return { response, body };
103+
}
104+
105+
async function expectDashboardAccepts(apiKey: string) {
106+
const { response, body } = await fetchJson<{
107+
user?: unknown;
108+
organization?: unknown;
109+
}>("/api/v1/dashboard", {
110+
headers: { Authorization: `Bearer ${apiKey}` },
111+
});
112+
113+
expect(response.status, JSON.stringify(body)).toBe(200);
114+
expect(body.user, "dashboard user").toBeTruthy();
115+
}
116+
117+
test.describe("live: wallet auth backend", () => {
118+
test.skip(!LIVE_URL, "set CLOUD_E2E_LIVE_URL to enable live cloud tests");
119+
test.skip(
120+
!LIVE_AUTH_ENABLED,
121+
"set CLOUD_E2E_LIVE_AUTH=1 to run real wallet auth against the live API",
122+
);
123+
124+
test("SIWE issues a real API key that can read dashboard data", async () => {
125+
const account = privateKeyToAccount(generatePrivateKey());
126+
const { response: nonceResponse, body: nonce } =
127+
await fetchJson<NonceResponse>("/api/auth/siwe/nonce?chainId=1");
128+
expect(nonceResponse.status, JSON.stringify(nonce)).toBe(200);
129+
expect(nonce.nonce).toMatch(/^[0-9a-f]{32}$/);
130+
131+
const message = buildWalletMessage({
132+
chain: "Ethereum",
133+
domain: nonce.domain,
134+
address: account.address,
135+
statement: nonce.statement,
136+
uri: nonce.uri,
137+
chainId: nonce.chainId,
138+
nonce: nonce.nonce,
139+
issuedAt: new Date(),
140+
});
141+
const signature = await account.signMessage({ message });
142+
143+
const { response: verifyResponse, body: verify } =
144+
await fetchJson<WalletVerifyResponse>("/api/auth/siwe/verify", {
145+
method: "POST",
146+
body: JSON.stringify({ message, signature }),
147+
});
148+
149+
expect(verifyResponse.status, JSON.stringify(verify)).toBe(200);
150+
expect(verify.apiKey).toBeTruthy();
151+
expect(verify.address.toLowerCase()).toBe(account.address.toLowerCase());
152+
expect(verify.user.organization_id).toBeTruthy();
153+
await expectDashboardAccepts(verify.apiKey);
154+
});
155+
156+
test("SIWS issues a real API key that can read dashboard data", async () => {
157+
const keypair = nacl.sign.keyPair();
158+
const address = bs58.encode(keypair.publicKey);
159+
const { response: nonceResponse, body: nonce } =
160+
await fetchJson<NonceResponse>("/api/auth/siws/nonce");
161+
expect(nonceResponse.status, JSON.stringify(nonce)).toBe(200);
162+
expect(nonce.nonce).toMatch(/^[0-9a-f]{32}$/);
163+
164+
const message = buildWalletMessage({
165+
chain: "Solana",
166+
domain: nonce.domain,
167+
address,
168+
statement: nonce.statement,
169+
uri: nonce.uri,
170+
chainId: nonce.chainId,
171+
nonce: nonce.nonce,
172+
issuedAt: new Date(),
173+
});
174+
const signature = bs58.encode(
175+
nacl.sign.detached(new TextEncoder().encode(message), keypair.secretKey),
176+
);
177+
178+
const { response: verifyResponse, body: verify } =
179+
await fetchJson<WalletVerifyResponse>("/api/auth/siws/verify", {
180+
method: "POST",
181+
body: JSON.stringify({ message, signature }),
182+
});
183+
184+
expect(verifyResponse.status, JSON.stringify(verify)).toBe(200);
185+
expect(verify.apiKey).toBeTruthy();
186+
expect(verify.address).toBe(address);
187+
expect(verify.user.organization_id).toBeTruthy();
188+
await expectDashboardAccepts(verify.apiKey);
189+
});
190+
});

0 commit comments

Comments
 (0)