refactor: reuse common ops primitives

This commit is contained in:
Codex
2026-06-14 17:59:45 +00:00
parent aa90eadfb2
commit 0c9735024e
4 changed files with 53 additions and 64 deletions
+13 -58
View File
@@ -1,5 +1,16 @@
import { readFileSync } from "node:fs";
import { rootPath } from "./config";
import {
asRecord,
arrayField,
booleanField,
integerField,
optionalIntegerField,
optionalStringField,
readYamlRecord,
recordField,
stringArrayField,
stringField,
} from "./platform-infra-ops-library";
export const AGENTRUN_CONFIG_PATH = "config/agentrun.yaml";
@@ -355,7 +366,7 @@ export function agentRunPipelineRunName(spec: AgentRunLaneSpec, sourceCommit: st
function readAgentRunControlPlaneConfig(env: NodeJS.ProcessEnv): AgentRunControlPlaneConfig {
const configPath = env.AGENTRUN_CONTROL_PLANE_CONFIG ?? rootPath(AGENTRUN_CONFIG_PATH);
const root = asRecord(Bun.YAML.parse(readFileSync(configPath, "utf8")) as unknown, configPath);
const root = readYamlRecord<Record<string, unknown>>(configPath);
validateConfigEnvelope(root, configPath);
const controlPlane = recordField(root, "controlPlane", configPath);
const defaultTarget = recordField(controlPlane, "default", `${configPath}.controlPlane`);
@@ -648,62 +659,6 @@ function optionalEnvPair(obj: Record<string, unknown>, key: string, path: string
};
}
function asRecord(value: unknown, path: string): Record<string, unknown> {
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${path} must be a YAML object`);
return value as Record<string, unknown>;
}
function recordField(obj: Record<string, unknown>, key: string, path: string): Record<string, unknown> {
return asRecord(obj[key], `${path}.${key}`);
}
function stringField(obj: Record<string, unknown>, key: string, path: string): string {
const value = obj[key];
if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${path}.${key} must be a non-empty string`);
return value.trim();
}
function optionalStringField(obj: Record<string, unknown>, key: string, path: string): string | undefined {
const value = obj[key];
if (value === undefined || value === null) return undefined;
if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${path}.${key} must be a non-empty string when set`);
return value.trim();
}
function booleanField(obj: Record<string, unknown>, key: string, path: string): boolean {
const value = obj[key];
if (typeof value !== "boolean") throw new Error(`${path}.${key} must be a boolean`);
return value;
}
function integerField(obj: Record<string, unknown>, key: string, path: string): number {
const value = obj[key];
if (!Number.isInteger(value)) throw new Error(`${path}.${key} must be an integer`);
return Number(value);
}
function optionalIntegerField(obj: Record<string, unknown>, key: string, path: string): number | undefined {
const value = obj[key];
if (value === undefined || value === null) return undefined;
if (!Number.isInteger(value)) throw new Error(`${path}.${key} must be an integer when set`);
return Number(value);
}
function arrayField(obj: Record<string, unknown>, key: string, path: string): Record<string, unknown>[] {
const value = obj[key];
if (!Array.isArray(value)) throw new Error(`${path}.${key} must be a YAML array`);
return value.map((item, index) => asRecord(item, `${path}.${key}[${index}]`));
}
function stringArrayField(obj: Record<string, unknown>, key: string, path: string): string[] {
const value = obj[key];
if (!Array.isArray(value)) throw new Error(`${path}.${key} must be a YAML array`);
return value.map((item, index) => {
if (typeof item !== "string" || item.trim().length === 0) throw new Error(`${path}.${key}[${index}] must be a non-empty string`);
return item.trim();
});
}
function stringRecordField(obj: Record<string, unknown>, path: string): Readonly<Record<string, string>> {
const result: Record<string, string> = {};
for (const [key, value] of Object.entries(obj)) {
+2 -2
View File
@@ -1,4 +1,3 @@
import { createHash } from "node:crypto";
import { chmodSync, copyFileSync, existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { spawnSync } from "node:child_process";
@@ -25,6 +24,7 @@ import {
renderAgentRunGitopsFiles,
type AgentRunArtifactService,
} from "./agentrun-manifests";
import { sha256Fingerprint } from "./platform-infra-ops-library";
export function agentRunHelp(): unknown {
return {
@@ -3669,7 +3669,7 @@ function readSecretSourceValue(spec: AgentRunLaneSpec, source: LaneSecretSource)
redactedPath: sourceRef.startsWith("/") ? redactAbsoluteSecretPath(sourceRef) : `.state/secrets/${sourceRef}`,
value,
valueBytes: Buffer.byteLength(value, "utf8"),
fingerprint: `sha256:${createHash("sha256").update(value).digest("hex")}`,
fingerprint: sha256Fingerprint(value),
};
}
+36 -2
View File
@@ -72,6 +72,18 @@ export function fingerprintValues(values: Record<string, string>, keys: string[]
return `sha256:${hash.digest("hex")}`;
}
export function sha256Hex(value: string): string {
return createHash("sha256").update(value).digest("hex");
}
export function sha256Fingerprint(value: string): string {
return `sha256:${sha256Hex(value)}`;
}
export function shortSha256Fingerprint(value: string, chars = 12): string {
return sha256Hex(value).slice(0, chars);
}
export function fingerprintEnvValues(values: Record<string, string>, keys: string[]): string {
const material = keys
.slice()
@@ -178,14 +190,14 @@ export function recordField(obj: Record<string, unknown>, key: string, path: str
export function stringField(obj: Record<string, unknown>, key: string, path: string): string {
const value = obj[key];
if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${path}.${key} must be a non-empty string`);
return value;
return value.trim();
}
export function optionalStringField(obj: Record<string, unknown>, key: string, path: string): string | undefined {
const value = obj[key];
if (value === undefined || value === null) return undefined;
if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${path}.${key} must be a non-empty string when set`);
return value;
return value.trim();
}
export function booleanField(obj: Record<string, unknown>, key: string, path: string): boolean {
@@ -200,6 +212,19 @@ export function numberField(obj: Record<string, unknown>, key: string, path: str
return value;
}
export function integerField(obj: Record<string, unknown>, key: string, path: string): number {
const value = obj[key];
if (!Number.isInteger(value)) throw new Error(`${path}.${key} must be an integer`);
return Number(value);
}
export function optionalIntegerField(obj: Record<string, unknown>, key: string, path: string): number | undefined {
const value = obj[key];
if (value === undefined || value === null) return undefined;
if (!Number.isInteger(value)) throw new Error(`${path}.${key} must be an integer when set`);
return Number(value);
}
export function arrayField(obj: Record<string, unknown>, key: string, path: string): Record<string, unknown>[] {
const value = obj[key];
if (!Array.isArray(value)) throw new Error(`${path}.${key} must be an array`);
@@ -212,6 +237,15 @@ export function stringListField(obj: Record<string, unknown>, key: string, path:
return value as string[];
}
export function stringArrayField(obj: Record<string, unknown>, key: string, path: string): string[] {
const value = obj[key];
if (!Array.isArray(value)) throw new Error(`${path}.${key} must be an array`);
return value.map((item, index) => {
if (typeof item !== "string" || item.trim().length === 0) throw new Error(`${path}.${key}[${index}] must be a non-empty string`);
return item.trim();
});
}
export function yamlFieldLabel(configLabel: string, path: string, key: string): string {
const prefix = path.length > 0 ? `${path}.` : "";
return `${configLabel}.${prefix}${key}`;
+2 -2
View File
@@ -1,4 +1,3 @@
import { createHash } from "node:crypto";
import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
@@ -6,6 +5,7 @@ import type { UniDeskConfig } from "./config";
import { rootPath } from "./config";
import type { RenderedCliResult } from "./output";
import { applyPk01CaddyBlock, prepareFrpcSecret, renderFrpcManifest, type PublicServiceExposure, type PublicServiceTarget } from "./platform-infra-public-service";
import { shortSha256Fingerprint } from "./platform-infra-ops-library";
import {
codexPoolSentinelSummary,
codexPoolSentinelRuntimeImage,
@@ -3793,7 +3793,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
}
function fingerprint(value: string): string {
return createHash("sha256").update(value).digest("hex").slice(0, 12);
return shortSha256Fingerprint(value);
}
export function codexPoolSentinelProbeConfigFingerprint(input: {