fix(web-sentinel): configure apiserver endpoint for manual trigger

This commit is contained in:
Codex
2026-07-01 11:57:54 +00:00
parent 58ed8c91e2
commit 4c36475094
3 changed files with 25 additions and 12 deletions
@@ -35,10 +35,16 @@ baselines:
sampler: parentbased_traceidratio
samplerArg: "1"
kubernetesApi:
endpoint:
host: 172.16.0.5
port: 6443
egress:
enabled: true
cidr: 10.43.0.1/32
rules:
- cidr: 10.43.0.1/32
port: 443
- cidr: 172.16.0.5/32
port: 6443
scheduler15m: &scheduler-15m
intervalMs: 900000
heartbeatStaleSeconds: 900
+11 -4
View File
@@ -1248,10 +1248,12 @@ function renderSentinelManifests(
function sentinelKubernetesApiEgress(runtime: Record<string, unknown>): readonly Record<string, unknown>[] {
if (booleanAtNullable(runtime, "kubernetesApi.egress.enabled") !== true) return [];
return [{
to: [{ ipBlock: { cidr: stringAt(runtime, "kubernetesApi.egress.cidr") } }],
ports: [{ protocol: "TCP", port: numberAt(runtime, "kubernetesApi.egress.port") }],
}];
const rules = arrayAtNullable(runtime, "kubernetesApi.egress.rules");
const rows = rules.length > 0 ? rules : [{ cidr: stringAt(runtime, "kubernetesApi.egress.cidr"), port: numberAt(runtime, "kubernetesApi.egress.port") }];
return rows.map((rule) => ({
to: [{ ipBlock: { cidr: stringAt(rule, "cidr") } }],
ports: [{ protocol: "TCP", port: numberAt(rule, "port") }],
}));
}
function sentinelContainerEnv(sentinelId: string, runtime: Record<string, unknown>, cicd: Record<string, unknown>, secrets: Record<string, unknown>): readonly Record<string, unknown>[] {
@@ -4385,6 +4387,11 @@ export function arrayAt(value: unknown, path: string): unknown[] {
return found;
}
function arrayAtNullable(value: unknown, path: string): Record<string, unknown>[] {
const found = valueAtPath(value, path);
return Array.isArray(found) ? found.map(record) : [];
}
export function recordTarget(value: unknown, label: string): Record<string, unknown> {
if (!isRecord(value)) throw new Error(`${label} must resolve to an object`);
return value;
@@ -2038,7 +2038,7 @@ async function triggerQuickVerifyCronJob(config: WebProbeSentinelServiceConfig,
return { ok: false, status: "blocked", reason: "scenario-missing", namespace, cronJobName, valuesRedacted: true };
}
const activeJobs = await k8sApiJson("GET", `/apis/batch/v1/namespaces/${encodeURIComponent(namespace)}/jobs?labelSelector=${encodeURIComponent(`unidesk.ai/web-probe-sentinel-id=${config.sentinelId}`)}`, null);
const activeJobs = await k8sApiJson(config, "GET", `/apis/batch/v1/namespaces/${encodeURIComponent(namespace)}/jobs?labelSelector=${encodeURIComponent(`unidesk.ai/web-probe-sentinel-id=${config.sentinelId}`)}`, null);
if (activeJobs.ok === true) {
const active = k8sJobItems(activeJobs.bodyJson).filter((job) => numberAtNullable(job, "status.active") > 0);
if (active.length > 0) {
@@ -2058,7 +2058,7 @@ async function triggerQuickVerifyCronJob(config: WebProbeSentinelServiceConfig,
}
}
const cronJob = await k8sApiJson("GET", `/apis/batch/v1/namespaces/${encodeURIComponent(namespace)}/cronjobs/${encodeURIComponent(cronJobName)}`, null);
const cronJob = await k8sApiJson(config, "GET", `/apis/batch/v1/namespaces/${encodeURIComponent(namespace)}/cronjobs/${encodeURIComponent(cronJobName)}`, null);
if (cronJob.ok !== true) {
return {
ok: false,
@@ -2076,7 +2076,7 @@ async function triggerQuickVerifyCronJob(config: WebProbeSentinelServiceConfig,
const now = nowIso();
const jobName = manualQuickVerifyJobName(config, now);
const job = jobFromCronJobTemplate(config, record(cronJob.bodyJson), jobName, now, reason, source);
const created = await k8sApiJson("POST", `/apis/batch/v1/namespaces/${encodeURIComponent(namespace)}/jobs`, job);
const created = await k8sApiJson(config, "POST", `/apis/batch/v1/namespaces/${encodeURIComponent(namespace)}/jobs`, job);
if (created.ok !== true) {
return {
ok: false,
@@ -2145,9 +2145,9 @@ function jobFromCronJobTemplate(
};
}
async function k8sApiJson(method: "GET" | "POST", path: string, body: Record<string, unknown> | null): Promise<Record<string, unknown>> {
const host = process.env.KUBERNETES_SERVICE_HOST;
const port = Number(process.env.KUBERNETES_SERVICE_PORT_HTTPS ?? process.env.KUBERNETES_SERVICE_PORT ?? 443);
async function k8sApiJson(config: WebProbeSentinelServiceConfig, method: "GET" | "POST", path: string, body: Record<string, unknown> | null): Promise<Record<string, unknown>> {
const host = stringAtNullable(config.runtime, "kubernetesApi.endpoint.host") ?? process.env.KUBERNETES_SERVICE_HOST;
const port = numberAtNullable(config.runtime, "kubernetesApi.endpoint.port") || Number(process.env.KUBERNETES_SERVICE_PORT_HTTPS ?? process.env.KUBERNETES_SERVICE_PORT ?? 443);
if (typeof host !== "string" || host.length === 0) return { ok: false, status: "blocked", reason: "kubernetes-service-env-missing", valuesRedacted: true };
const tokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token";
const caPath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt";