fix: validate config_update_string with getInvalidConfigReason and add polling correlation check

Co-Authored-By: mantra <mantra@stack-auth.com>
This commit is contained in:
Devin AI 2026-06-25 22:13:58 +00:00
parent 16a5fb763e
commit f6e121f816
2 changed files with 15 additions and 4 deletions

View File

@ -10,6 +10,7 @@ import { applyConfigUpdate, type GithubRepoRef } from "@/lib/config/repo-agent";
import { createSmartRouteHandler } from "@/route-handlers/smart-route-handler";
import { runAsynchronouslyAndWaitUntil } from "@/utils/background-tasks";
import type { EnvironmentConfigOverrideOverride } from "@hexclave/shared/dist/config/schema";
import { getInvalidConfigReason } from "@hexclave/shared/dist/config/format";
import { adaptSchema, adminAuthTypeSchema, yupNumber, yupObject, yupString } from "@hexclave/shared/dist/schema-fields";
import { StatusError, captureError } from "@hexclave/shared/dist/utils/errors";
@ -68,8 +69,15 @@ export const POST = createSmartRouteHandler({
let configUpdate: EnvironmentConfigOverrideOverride;
try {
configUpdate = JSON.parse(req.body.config_update_string);
} catch {
const parsed: unknown = JSON.parse(req.body.config_update_string);
const reason = getInvalidConfigReason(parsed, { configName: "config_update_string" });
if (reason) {
throw new StatusError(StatusError.BadRequest, reason);
}
// Safe after getInvalidConfigReason confirms it's a valid config object
configUpdate = parsed as EnvironmentConfigOverrideOverride;
} catch (e) {
if (e instanceof StatusError) throw e;
throw new StatusError(StatusError.BadRequest, "config_update_string is not valid JSON.");
}

View File

@ -523,6 +523,7 @@ function GithubPushBody({
// The run is now in flight. Lock the dialog (non-dismissible; Cancel aborts)
// and flag the run as managed by this tab so the page-load watcher stays out
// of the way until we settle.
const runStartedAt = Date.now();
dialogContext?.setGithubRunActive(true);
onRunPhaseChange("running");
setActivity(null);
@ -541,8 +542,10 @@ function GithubPushBody({
continue; // transient — keep polling
}
const run = latest?.type === "pushed-from-github" ? latest.agent_run : null;
if (run == null || run.status === "running") {
if (typeof run?.progress === "string") setActivity(run.progress);
// Ignore stale agent_run entries from a previous run (or read-replica lag).
// The run we just started must have started_at >= our request timestamp.
if (run == null || run.status === "running" || (typeof run.started_at === "number" && run.started_at < runStartedAt - 5000)) {
if (run != null && run.status === "running" && typeof run?.progress === "string") setActivity(run.progress);
continue;
}