fix: switch monitor root via sentinel yaml

This commit is contained in:
Codex
2026-06-28 03:28:10 +00:00
parent f371008af9
commit e4b9446ca9
8 changed files with 173 additions and 25 deletions
+55 -4
View File
@@ -164,6 +164,14 @@ export interface HwlabRuntimeWebProbeSentinelRegistryItemSpec {
readonly configRef: string;
}
export interface HwlabRuntimeWebProbeMonitorRootSpec {
readonly enabled: boolean;
readonly sentinelId: string;
readonly publicBaseUrl: string;
readonly routePrefix: "/";
readonly caddyManagedBlockOwner: string;
}
export interface HwlabRuntimeWebProbeAlertThresholdsSpec {
readonly sameOriginApiSlowMs: number;
readonly partialApiSlowMs: number;
@@ -206,6 +214,7 @@ export interface HwlabRuntimeObservabilitySpec {
export interface HwlabRuntimeObservabilityWebProbeSpec {
readonly sentinel?: HwlabRuntimeWebProbeSentinelSpec;
readonly sentinels?: readonly HwlabRuntimeWebProbeSentinelRegistryItemSpec[];
readonly monitorRoot?: HwlabRuntimeWebProbeMonitorRootSpec;
}
export interface HwlabRuntimeObservabilityMetricsEndpointSpec {
@@ -1141,14 +1150,56 @@ function observabilityConfig(value: unknown, path: string): HwlabRuntimeObservab
function observabilityWebProbeConfig(value: unknown, path: string): HwlabRuntimeObservabilityWebProbeSpec | undefined {
if (value === undefined) return undefined;
const raw = asRecord(value, path);
const allowed = new Set(["sentinel", "sentinels"]);
const allowed = new Set(["sentinel", "sentinels", "monitorRoot"]);
for (const key of Object.keys(raw)) {
if (!allowed.has(key)) throw new Error(`${path}.${key} is not allowed; observability.webProbe currently only owns sentinel/sentinels`);
if (!allowed.has(key)) throw new Error(`${path}.${key} is not allowed; observability.webProbe currently only owns sentinel/sentinels/monitorRoot`);
}
if (raw.sentinel !== undefined && raw.sentinels !== undefined) throw new Error(`${path} may declare sentinel or sentinels, not both`);
const sentinel = raw.sentinel === undefined ? undefined : webProbeSentinelConfig(raw.sentinel, `${path}.sentinel`);
const sentinels = raw.sentinels === undefined ? undefined : webProbeSentinelRegistryConfig(raw.sentinels, `${path}.sentinels`);
const monitorRoot = raw.monitorRoot === undefined ? undefined : webProbeMonitorRootConfig(raw.monitorRoot, `${path}.monitorRoot`);
if (monitorRoot !== undefined) {
if (sentinels !== undefined && !sentinels.some((item) => item.id === monitorRoot.sentinelId)) {
throw new Error(`${path}.monitorRoot.sentinelId must reference one entry from ${path}.sentinels`);
}
if (sentinel !== undefined && monitorRoot.sentinelId !== "workbench-dsflash-go-tool-call-10x") {
throw new Error(`${path}.monitorRoot.sentinelId must be workbench-dsflash-go-tool-call-10x for legacy sentinel config`);
}
}
return {
...(raw.sentinel === undefined ? {} : { sentinel: webProbeSentinelConfig(raw.sentinel, `${path}.sentinel`) }),
...(raw.sentinels === undefined ? {} : { sentinels: webProbeSentinelRegistryConfig(raw.sentinels, `${path}.sentinels`) }),
...(sentinel === undefined ? {} : { sentinel }),
...(sentinels === undefined ? {} : { sentinels }),
...(monitorRoot === undefined ? {} : { monitorRoot }),
};
}
function webProbeMonitorRootConfig(value: unknown, path: string): HwlabRuntimeWebProbeMonitorRootSpec {
const raw = asRecord(value, path);
const allowed = new Set(["enabled", "sentinelId", "publicBaseUrl", "routePrefix", "caddyManagedBlockOwner"]);
for (const key of Object.keys(raw)) {
if (!allowed.has(key)) throw new Error(`${path}.${key} is not allowed; monitorRoot may only contain enabled/sentinelId/publicBaseUrl/routePrefix/caddyManagedBlockOwner`);
}
const sentinelId = stringField(raw, "sentinelId", path);
if (!/^[a-z0-9][a-z0-9-]{1,80}$/u.test(sentinelId)) throw new Error(`${path}.sentinelId must be a stable lowercase sentinel id`);
const publicBaseUrl = stringField(raw, "publicBaseUrl", path).replace(/\/+$/u, "");
try {
const parsed = new URL(publicBaseUrl);
if (parsed.protocol !== "https:") throw new Error("must use https");
if (parsed.pathname !== "/" || parsed.search.length > 0 || parsed.hash.length > 0) throw new Error("must point to the public origin root");
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`${path}.publicBaseUrl must be an https origin root URL: ${message}`);
}
const routePrefix = stringField(raw, "routePrefix", path);
if (routePrefix !== "/") throw new Error(`${path}.routePrefix must be / for the monitor root switch`);
const caddyManagedBlockOwner = stringField(raw, "caddyManagedBlockOwner", path);
if (!/^[a-z0-9][a-z0-9-]{1,100}$/u.test(caddyManagedBlockOwner)) throw new Error(`${path}.caddyManagedBlockOwner must be a stable lowercase owner id`);
return {
enabled: booleanField(raw, "enabled", path),
sentinelId,
publicBaseUrl,
routePrefix,
caddyManagedBlockOwner,
};
}