Files
pikasTech-unidesk/scripts/src/agentrun/provider-activation.ts
T

182 lines
8.7 KiB
TypeScript

import { readFileSync } from "node:fs";
import type { AgentRunLaneSecretSpec, AgentRunLaneSpec } from "../agentrun-lanes";
import type { UniDeskConfig } from "../config";
import { rootPath } from "../config";
import { sha256Fingerprint } from "../platform-infra-ops-library";
import { capture, captureJsonPayload, compactCapture, record, shQuote } from "./utils";
export const AGENTRUN_MANAGER_RETENTION_ISSUE = "https://github.com/pikasTech/agentrun/issues/280";
export const AGENTRUN_MANAGER_RETENTION_PULL_REQUEST = "https://github.com/pikasTech/agentrun/pull/281";
export const AGENTRUN_MANAGER_RECONCILER_ISSUE = "https://github.com/pikasTech/agentrun/issues/282";
export const AGENTRUN_PROVIDER_ACTIVATION_FENCE_ISSUE = "https://github.com/pikasTech/agentrun/issues/284";
export interface ProviderSecretActivationTarget {
readonly id: string;
readonly targetRef: AgentRunLaneSecretSpec["targetRef"];
readonly desiredEncodedFingerprint: string;
}
export function providerSecretDesiredEncodedFingerprint(value: string): string {
return sha256Fingerprint(Buffer.from(value, "utf8").toString("base64"));
}
export function providerSecretActivationPreflightScript(spec: AgentRunLaneSpec, targets: readonly ProviderSecretActivationTarget[]): string {
const script = readFileSync(rootPath("scripts/src/agentrun/provider-secret-activation-preflight.mjs"), "utf8");
return [
"set -eu",
`namespace=${shQuote(spec.runtime.namespace)}`,
`targets_json_b64=${shQuote(Buffer.from(JSON.stringify(targets), "utf8").toString("base64"))}`,
`match_labels_json_b64=${shQuote(Buffer.from(JSON.stringify(spec.deployment.runner.retention.selectors.matchLabels), "utf8").toString("base64"))}`,
`job_name_prefixes_json_b64=${shQuote(Buffer.from(JSON.stringify(spec.deployment.runner.retention.selectors.jobNamePrefixes), "utf8").toString("base64"))}`,
"tmp_dir=$(mktemp -d)",
"trap 'rm -rf \"$tmp_dir\"' EXIT",
"cat > \"$tmp_dir/provider-secret-activation-preflight.mjs\" <<'NODE'",
script,
"NODE",
"env NAMESPACE=\"$namespace\" TARGETS_JSON_B64=\"$targets_json_b64\" MATCH_LABELS_JSON_B64=\"$match_labels_json_b64\" JOB_NAME_PREFIXES_JSON_B64=\"$job_name_prefixes_json_b64\" node \"$tmp_dir/provider-secret-activation-preflight.mjs\"",
].join("\n");
}
export async function providerSecretActivationPreflight(
config: UniDeskConfig,
spec: AgentRunLaneSpec,
targets: readonly ProviderSecretActivationTarget[],
options: { readonly full?: boolean } = {},
): Promise<Record<string, unknown> & { ok: boolean }> {
const result = await capture(config, spec.nodeKubeRoute, ["sh", "--", providerSecretActivationPreflightScript(spec, targets)]);
const payload = captureJsonPayload(result);
const ok = result.exitCode === 0
&& payload.ok === true
&& payload.targetSecretObservationComplete === true
&& payload.providerSecretDataNoOp === true
&& Number(payload.providerSecretMutationCount ?? -1) === 0;
const visiblePayload = options.full === true ? payload : compactProviderSecretActivationPayload(payload);
return {
...visiblePayload,
ok,
status: ok ? "ready" : "blocked",
reason: ok ? null : payload.reason ?? (result.exitCode === 0 ? "provider-secret-activation-preflight-blocked" : "provider-secret-activation-preflight-failed"),
capture: compactCapture(result, {
full: options.full === true || result.exitCode !== 0,
stdoutTailChars: 2400,
stderrTailChars: 2400,
}),
managerAuthority: {
owner: "agentrun-manager-provider-activation-fence",
requiredBeforeActivation: record(payload).requiresManagerFence === true,
atomicFenceAvailable: false,
mutationAuthorized: false,
noOpOnly: true,
trackingIssue: AGENTRUN_PROVIDER_ACTIVATION_FENCE_ISSUE,
retentionDependencies: {
issue: AGENTRUN_MANAGER_RETENTION_ISSUE,
pullRequest: AGENTRUN_MANAGER_RETENTION_PULL_REQUEST,
stalePendingReconcilerIssue: AGENTRUN_MANAGER_RECONCILER_ISSUE,
sufficientForProviderActivation: false,
valuesPrinted: false,
},
valuesPrinted: false,
},
mutation: false,
runtimeSecretValuesDecoded: false,
valuesPrinted: false,
};
}
function compactProviderSecretActivationPayload(payload: Record<string, unknown>): Record<string, unknown> {
const targetSecrets = Array.isArray(payload.targetSecrets) ? payload.targetSecrets.map(record) : [];
const risks = Array.isArray(payload.activationRisks) ? payload.activationRisks.map(record) : [];
const visibleRisks = risks.slice(0, 1).map((risk) => ({
pod: risk.pod ?? null,
jobName: risk.jobName ?? null,
phase: risk.phase ?? null,
createdAt: risk.createdAt ?? null,
runId: risk.runId ?? null,
commandId: risk.commandId ?? null,
runnerJobId: risk.runnerJobId ?? null,
runnerId: risk.runnerId ?? null,
waitingReasons: Array.isArray(risk.waitingReasons) ? risk.waitingReasons.slice(0, 4) : [],
dependencies: Array.isArray(risk.dependencies)
? risk.dependencies.map(record).slice(0, 2).map((dependency) => ({
source: dependency.source ?? null,
name: dependency.name ?? null,
affectedDesiredKeys: Array.isArray(dependency.affectedDesiredKeys) ? dependency.affectedDesiredKeys.slice(0, 8) : [],
mutationKinds: Array.isArray(dependency.mutationKinds) ? dependency.mutationKinds.slice(0, 4) : [],
reason: dependency.reason ?? null,
valuesPrinted: false,
}))
: [],
classification: risk.classification ?? null,
valuesPrinted: false,
}));
return {
ok: payload.ok === true,
status: payload.status ?? null,
reason: payload.reason ?? null,
observedAt: payload.observedAt ?? null,
target: payload.target ?? null,
targetSecretCount: payload.targetSecretCount ?? targetSecrets.length,
targetSecrets: targetSecrets.map((target) => ({
namespace: target.namespace ?? null,
name: target.name ?? null,
desiredKeys: Array.isArray(target.desiredKeys) ? target.desiredKeys.slice(0, 8) : [],
queryOk: target.queryOk === true,
present: typeof target.present === "boolean" ? target.present : null,
mutationCount: target.mutationCount ?? null,
noOp: target.noOp === true,
mutations: Array.isArray(target.mutations)
? target.mutations.map(record).slice(0, 8).map((mutation) => ({
id: mutation.id ?? null,
key: mutation.key ?? null,
desiredFingerprintSuffix: typeof mutation.desiredEncodedFingerprint === "string" ? mutation.desiredEncodedFingerprint.slice(-12) : null,
runtimeFingerprintSuffix: typeof mutation.runtimeEncodedFingerprint === "string" ? mutation.runtimeEncodedFingerprint.slice(-12) : null,
changeKind: mutation.changeKind ?? null,
valuesPrinted: false,
}))
: [],
valuesPrinted: false,
})),
podObservation: payload.podObservation ?? null,
targetSecretObservationComplete: payload.targetSecretObservationComplete === true,
runnerObservationComplete: payload.runnerObservationComplete === true,
allObservationsComplete: payload.allObservationsComplete === true,
providerSecretMutationCount: payload.providerSecretMutationCount ?? null,
providerSecretDataNoOp: payload.providerSecretDataNoOp === true,
providerSecretMutationAuthorized: payload.providerSecretMutationAuthorized === true,
activationAuthority: payload.activationAuthority ?? null,
activationRiskCount: payload.activationRiskCount ?? risks.length,
activationRisks: visibleRisks,
activationRiskOmittedCount: Math.max(0, Number(payload.activationRiskCount ?? risks.length) - visibleRisks.length),
requiresManagerFence: payload.requiresManagerFence === true,
queryComplete: payload.queryComplete === true,
mutation: false,
runtimeSecretValuesDecoded: false,
valuesPrinted: false,
};
}
export function providerSecretStagedActivation(
spec: AgentRunLaneSpec,
profiles: readonly string[],
): Record<string, unknown> {
return {
status: "blocked-before-secret-activation",
targetProfiles: [...new Set(profiles)],
secretMutationStarted: false,
requiredSequence: [
"agentrun-manager-reconcile-terminalize-and-fence-affected-runners",
"agentrun-manager-acquire-provider-activation-admission-fence-and-secret-cas",
"repeat-provider-secret-activation-preflight",
"sync-yaml-declared-provider-secret",
],
managerTrackingIssue: AGENTRUN_MANAGER_RETENTION_ISSUE,
managerTrackingPullRequest: AGENTRUN_MANAGER_RETENTION_PULL_REQUEST,
managerReconcilerIssue: AGENTRUN_MANAGER_RECONCILER_ISSUE,
providerActivationFenceIssue: AGENTRUN_PROVIDER_ACTIVATION_FENCE_ISSUE,
retry: `bun scripts/cli.ts agentrun provider-profile apply --node ${spec.nodeId} --lane ${spec.lane} --profile <profile> --confirm`,
valuesPrinted: false,
};
}