Skip to content

Commit c396a54

Browse files
committed
feat: add auth to inspector
1 parent 40fbcc1 commit c396a54

File tree

6 files changed

+142
-81
lines changed

6 files changed

+142
-81
lines changed

packages/actor-core-cli/src/commands/deploy.tsx

Lines changed: 67 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -210,83 +210,83 @@ export const deploy = new Command()
210210
);
211211
}
212212

213-
if (managers.length > 0) {
214-
for (const manager of managers) {
215-
await Rivet.actor.upgrade(manager.id, {
216-
project: projectName,
217-
environment: envName,
218-
body: {
219-
buildTags: {
220-
name: "manager",
221-
current: "true",
222-
},
223-
},
224-
});
225-
}
226-
227-
const manager = managers.find(
228-
(m) => !!createActorEndpoint(m.network),
229-
);
230-
231-
if (!manager) {
232-
throw ctx.error("Failed to find Actor Core Endpoint.", {
233-
hint: "Any existing manager actor is not running or not accessible.",
234-
});
235-
}
213+
// if (managers.length > 0) {
214+
// for (const manager of managers) {
215+
// await Rivet.actor.upgrade(manager.id, {
216+
// project: projectName,
217+
// environment: envName,
218+
// body: {
219+
// buildTags: {
220+
// name: "manager",
221+
// current: "true",
222+
// },
223+
// },
224+
// });
225+
// }
226+
227+
// const manager = managers.find(
228+
// (m) => !!createActorEndpoint(m.network),
229+
// );
230+
231+
// if (!manager) {
232+
// throw ctx.error("Failed to find Actor Core Endpoint.", {
233+
// hint: "Any existing manager actor is not running or not accessible.",
234+
// });
235+
// }
236+
237+
// return manager;
238+
// } else {
239+
const serviceToken = await getServiceToken(RivetHttp, {
240+
project: projectName,
241+
env: envName,
242+
});
236243

237-
return manager;
238-
} else {
239-
const serviceToken = await getServiceToken(RivetHttp, {
240-
project: projectName,
241-
env: envName,
242-
});
244+
const { regions } = await Rivet.actor.regions.list({
245+
project: projectName,
246+
environment: envName,
247+
});
243248

244-
const { regions } = await Rivet.actor.regions.list({
245-
project: projectName,
246-
environment: envName,
247-
});
249+
// find closest region
250+
const region = regions.find(
251+
(r) => r.id === "atl" || r.id === "local",
252+
);
248253

249-
// find closest region
250-
const region = regions.find(
251-
(r) => r.id === "atl" || r.id === "local",
254+
if (!region) {
255+
throw ctx.error(
256+
"No closest region found. Please contact support.",
252257
);
258+
}
253259

254-
if (!region) {
255-
throw ctx.error(
256-
"No closest region found. Please contact support.",
257-
);
258-
}
259-
260-
const { actor } = await Rivet.actor.create({
261-
project: projectName,
262-
environment: envName,
263-
body: {
264-
region: region.id,
265-
tags: { name: "manager", owner: "rivet" },
266-
buildTags: { name: "manager", current: "true" },
267-
runtime: {
268-
environment: {
269-
RIVET_SERVICE_TOKEN: serviceToken,
270-
},
260+
const { actor } = await Rivet.actor.create({
261+
project: projectName,
262+
environment: envName,
263+
body: {
264+
region: region.id,
265+
tags: { name: "manager", owner: "rivet" },
266+
buildTags: { name: "manager", current: "true" },
267+
runtime: {
268+
environment: {
269+
RIVET_SERVICE_TOKEN: serviceToken,
271270
},
272-
network: {
273-
mode: "bridge",
274-
ports: {
275-
http: {
276-
protocol: "https",
277-
routing: {
278-
guard: {},
279-
},
271+
},
272+
network: {
273+
mode: "bridge",
274+
ports: {
275+
http: {
276+
protocol: "https",
277+
routing: {
278+
guard: {},
280279
},
281280
},
282281
},
283-
lifecycle: {
284-
durable: true,
285-
},
286282
},
287-
});
288-
return actor;
289-
}
283+
lifecycle: {
284+
durable: true,
285+
},
286+
},
287+
});
288+
return actor;
289+
// }
290290
},
291291
);
292292

packages/actor-core/src/actor/runtime/actor_router.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -352,10 +352,22 @@ export function createActorRouter(
352352
}
353353
});
354354

355-
app.route(
356-
"/inspect",
357-
createInspectorRouter(handler.upgradeWebSocket, handler.onConnectInspector),
358-
);
355+
if (
356+
(typeof config.inspector === "object" &&
357+
config.inspector.enabled === true) ||
358+
config.inspector === true
359+
) {
360+
app.route(
361+
"/inspect",
362+
createInspectorRouter(
363+
handler.upgradeWebSocket,
364+
handler.onConnectInspector,
365+
typeof config.inspector === "object"
366+
? config.inspector.validateRequest
367+
: undefined,
368+
),
369+
);
370+
}
359371

360372
app.notFound(handleRouteNotFound);
361373
app.onError(handleRouteError);

packages/actor-core/src/actor/runtime/config.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
Handler as HonoHandler,
99
} from "hono";
1010
import type { cors } from "hono/cors";
11+
import { InspectorConfigSchema } from "./inspect";
1112

1213
// Define CORS options schema
1314
type CorsOptions = NonNullable<Parameters<typeof cors>[0]>;
@@ -56,7 +57,7 @@ export type GetUpgradeWebSocket = (
5657
/** Base config used for the actor config across all platforms. */
5758
export const BaseConfigSchema = z.object({
5859
actors: z.record(z.string(), z.custom<AnyActorConstructor>()),
59-
topology: TopologySchema.optional(), // Default value depends on the platform selected
60+
topology: TopologySchema.optional(), // Default value depends on the platform selected
6061
drivers: z
6162
.object({
6263
manager: z.custom<ManagerDriver>().optional(),
@@ -82,5 +83,8 @@ export const BaseConfigSchema = z.object({
8283

8384
/** Peer configuration for coordinated topology. */
8485
actorPeer: ActorPeerConfigSchema.optional().default({}),
86+
87+
/** Inspector configuration */
88+
inspector: InspectorConfigSchema.optional().default(false),
8589
});
8690
export type BaseConfig = z.infer<typeof BaseConfigSchema>;

packages/actor-core/src/actor/runtime/inspect.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { AnyActor } from "@/actor/runtime/actor";
22
import type { Connection, ConnectionId } from "@/actor/runtime/connection";
33
import { throttle } from "@/actor/runtime/utils";
44
import type { UpgradeWebSocket, WSContext } from "hono/ws";
5-
import { Hono, type HonoRequest } from "hono";
5+
import { Hono, type HonoRequest, type Context as HonoContext } from "hono";
66
import * as errors from "@/actor/errors";
77
import { deconstructError, safeStringify } from "@/common/utils";
88
import {
@@ -11,20 +11,30 @@ import {
1111
} from "@/actor/protocol/inspector/to_server";
1212
import type { ToClient } from "@/actor/protocol/inspector/to_client";
1313
import { logger } from "./log";
14+
import { z } from "zod";
15+
16+
export type ValidateInspectorRequest = (c: HonoContext) => Promise<boolean>;
17+
18+
export const InspectorConfigSchema = z
19+
.object({
20+
enabled: z.boolean().optional().default(false),
21+
validateRequest: z.custom<ValidateInspectorRequest>().optional(),
22+
})
23+
.or(z.boolean());
1424

1525
export interface ConnectInspectorOpts {
1626
req: HonoRequest;
1727
}
1828

19-
export interface ConnectInspectortOutput {
29+
export interface ConnectInspectorOutput {
2030
onOpen: (ws: WSContext) => Promise<void>;
2131
onMessage: (message: ToServer) => Promise<void>;
2232
onClose: () => Promise<void>;
2333
}
2434

2535
export type InspectorConnectionHandler = (
2636
opts: ConnectInspectorOpts,
27-
) => Promise<ConnectInspectortOutput>;
37+
) => Promise<ConnectInspectorOutput>;
2838

2939
/**
3040
* Create a router for the inspector.
@@ -33,6 +43,7 @@ export type InspectorConnectionHandler = (
3343
export function createInspectorRouter(
3444
upgradeWebSocket: UpgradeWebSocket | undefined,
3545
onConnect: InspectorConnectionHandler | undefined,
46+
validateRequest: ValidateInspectorRequest | undefined,
3647
) {
3748
const app = new Hono();
3849

@@ -45,6 +56,13 @@ export function createInspectorRouter(
4556
}
4657
return app.get(
4758
"/",
59+
async (c, next) => {
60+
const result = (await validateRequest?.(c)) ?? true;
61+
if (!result) {
62+
return c.json({ error: "Unauthorized" }, 403);
63+
}
64+
await next();
65+
},
4866
upgradeWebSocket(async (c) => {
4967
try {
5068
const handler = await onConnect({ req: c.req });

packages/platforms/rivet/src/actor_handler.ts

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ import type { RivetHandler } from "./util";
77
import { PartitionTopologyActor } from "actor-core/topologies/partition";
88
import { ConfigSchema, type InputConfig } from "./config";
99
import { RivetActorDriver } from "./actor_driver";
10+
import { rivetRequest } from "./rivet_client";
1011

11-
export function createActorHandler(
12-
inputConfig: InputConfig,
13-
): RivetHandler {
12+
export function createActorHandler(inputConfig: InputConfig): RivetHandler {
1413
const config = ConfigSchema.parse(inputConfig);
1514

1615
const handler = {
@@ -31,7 +30,36 @@ export function createActorHandler(
3130
if (!config.drivers.actor) {
3231
config.drivers.actor = new RivetActorDriver(ctx);
3332
}
34-
33+
34+
// Setup inspector
35+
config.inspector = {
36+
enabled: true,
37+
async validateRequest(c) {
38+
const token = c.req.query("token");
39+
40+
if (!token) {
41+
return false;
42+
}
43+
44+
try {
45+
await rivetRequest(
46+
{
47+
endpoint: "http://rivet-server:8080",
48+
token,
49+
project: ctx.metadata.project.slug,
50+
environment: ctx.metadata.environment.slug,
51+
},
52+
"GET",
53+
"/cloud/auth/inspect",
54+
);
55+
return true;
56+
} catch (e) {
57+
console.log("error", e);
58+
return false;
59+
}
60+
},
61+
};
62+
3563
// Setup WebSocket upgrader
3664
if (!config.getUpgradeWebSocket) {
3765
config.getUpgradeWebSocket = () => upgradeWebSocket;
@@ -70,4 +98,3 @@ export function createActorHandler(
7098

7199
return handler;
72100
}
73-

packages/platforms/rivet/src/manager_handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export function createManagerHandler(inputConfig: InputConfig): RivetHandler {
2929
if (!token) throw new Error("missing RIVET_SERVICE_TOKEN");
3030

3131
const clientConfig: RivetClientConfig = {
32-
endpoint,
32+
endpoint: "http://rivet-server:8080",
3333
token,
3434
project: ctx.metadata.project.slug,
3535
environment: ctx.metadata.environment.slug,

0 commit comments

Comments
 (0)