Skip to content

Commit 4f71c34

Browse files
committed
Fix datetime picker and supervisor review regressions
1 parent f56f8a1 commit 4f71c34

13 files changed

Lines changed: 397 additions & 94 deletions

File tree

packages/server/src/__tests__/supervisor-manager.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,28 @@ describe("SupervisorManager cycle triggers", () => {
540540
expect(manager.get(supervisor.id)?.scheduledAt).toBeUndefined();
541541
});
542542

543+
it("consumes an overdue scheduledAt when turn_completed runs first", async () => {
544+
const supervisor = await manager.create({
545+
sessionId: "sess-overdue-turn-completed",
546+
workspaceId: "ws-1",
547+
objective: "Ship the fix",
548+
evaluatorProviderId: "codex",
549+
scheduledAt: Date.now() - 1_000,
550+
});
551+
552+
const managerInternals = getManagerInternals();
553+
const evaluate = vi.spyOn(managerInternals.evaluator, "evaluate");
554+
555+
const first = await managerInternals.runEvaluation(supervisor.id, "turn_completed");
556+
const second = await managerInternals.runEvaluation(supervisor.id, "scheduled");
557+
558+
expect(first?.trigger).toBe("turn_completed");
559+
expect(second).toBeNull();
560+
expect(manager.get(supervisor.id)?.scheduledAt).toBeUndefined();
561+
expect(manager.get(supervisor.id)?.cycles).toHaveLength(1);
562+
expect(evaluate).toHaveBeenCalledTimes(1);
563+
});
564+
543565
it("retries a due scheduled run until the session becomes runnable", async () => {
544566
vi.useFakeTimers();
545567
let sessionState: Session["state"] = "starting";

packages/server/src/app-routing.test.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ describe("app routing", () => {
4646
rmSync(tempDir, { recursive: true, force: true });
4747
});
4848

49-
const createApp = async (authEnabled = false): Promise<FastifyInstance> => {
49+
const createApp = async (
50+
authEnabled = false,
51+
extraConfig: Record<string, unknown> = {}
52+
): Promise<FastifyInstance> => {
5053
const eventBus = new EventBus();
5154
const fencingMgr = new FencingManager();
5255
const config = {
@@ -60,6 +63,7 @@ describe("app routing", () => {
6063
enabled: authEnabled,
6164
password: authEnabled ? "sekrit" : undefined,
6265
},
66+
...extraConfig,
6367
};
6468
const wsHub = new WsHub({
6569
eventBus,
@@ -173,6 +177,20 @@ describe("app routing", () => {
173177
expect(response.body).toContain('<div id="root">shell</div>');
174178
});
175179

180+
it("does not emit a CSP header for the built entrypoint response", async () => {
181+
const instance = await createApp();
182+
183+
const response = await instance.inject({
184+
method: "GET",
185+
url: "/index.html",
186+
headers: {
187+
accept: "text/html",
188+
},
189+
});
190+
191+
expect(response.headers["content-security-policy"]).toBeUndefined();
192+
});
193+
176194
it("serves headers for the built entrypoint on HEAD /index.html", async () => {
177195
const instance = await createApp();
178196

packages/server/src/app.ts

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -87,34 +87,6 @@ export async function buildFastifyApp(deps: AppDeps): Promise<FastifyInstance> {
8787
})
8888
);
8989

90-
// CSP Header Injection (optional, controlled by `relaxCsp` config)
91-
//
92-
// xterm.js and Monaco Editor internally use `eval` and `new Function` for
93-
// performance optimizations (e.g., JIT-compiled rendering loops). When a
94-
// browser extension (e.g., uBlock Origin, AdGuard) injects a strict CSP,
95-
// these libraries silently fail:
96-
// - xterm.js: terminal shows only "[Process exited with code 0]"
97-
// - Monaco Editor: code editor panel renders blank
98-
//
99-
// When `relaxCsp: true`, we inject a permissive CSP header that allows
100-
// 'unsafe-eval' and 'unsafe-inline', plus WebSocket connections (ws:/wss:).
101-
// This is intended for local development scenarios where browser extensions
102-
// interfere. For production, leave this disabled and configure CSP at the
103-
// reverse proxy level.
104-
if (deps.config.relaxCsp) {
105-
app.addHook("onRequest", async (_request, reply) => {
106-
reply.header(
107-
"Content-Security-Policy",
108-
"default-src 'self'; " +
109-
"script-src 'self' 'unsafe-inline' 'unsafe-eval'; " +
110-
"style-src 'self' 'unsafe-inline'; " +
111-
"connect-src 'self' ws: wss:; " +
112-
"img-src 'self' data: blob:; " +
113-
"font-src 'self' data:;"
114-
);
115-
});
116-
}
117-
11890
await app.register(compress);
11991

12092
await app.register(multipart, {

packages/server/src/config.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export interface ServerConfig {
1818
dataDir: string;
1919
uploadsDir: string;
2020
logLevel: "trace" | "debug" | "info" | "warn" | "error";
21-
relaxCsp: boolean;
2221
webRoot?: string;
2322
appVersion?: string;
2423
auth: {
@@ -122,7 +121,6 @@ export function parseServerConfig(overrides?: Partial<ServerConfig>): ServerConf
122121
dataDir,
123122
uploadsDir,
124123
logLevel: overrides?.logLevel ?? parseLogLevel(process.env.LOG_LEVEL) ?? "info",
125-
relaxCsp: overrides?.relaxCsp ?? process.env.RELAX_CSP === "true",
126124
webRoot: overrides?.webRoot,
127125
appVersion:
128126
overrides?.appVersion ?? process.env.CODER_STUDIO_APP_VERSION ?? resolveDefaultAppVersion(),

packages/server/src/supervisor/manager.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,10 +620,17 @@ export class SupervisorManager {
620620
return null;
621621
}
622622

623+
const shouldConsumeScheduledAt =
624+
trigger === "scheduled" ||
625+
(trigger === "turn_completed" &&
626+
supervisor.scheduledAt !== undefined &&
627+
supervisor.scheduledAt !== null &&
628+
supervisor.scheduledAt <= Date.now());
629+
623630
const evaluatingSupervisor = this.attachCycles(
624631
this.deps.supervisorRepo.update(supervisor.id, {
625632
state: "evaluating",
626-
scheduledAt: trigger === "scheduled" ? null : (supervisor.scheduledAt ?? undefined),
633+
scheduledAt: shouldConsumeScheduledAt ? null : (supervisor.scheduledAt ?? undefined),
627634
stopReason: null,
628635
errorReason: null,
629636
updatedAt: Date.now(),

0 commit comments

Comments
 (0)