refactor: move agentrun session policy into yaml

This commit is contained in:
Codex
2026-06-14 17:51:42 +00:00
parent 13c84af59f
commit 961d8f1d43
3 changed files with 212 additions and 36 deletions
+117 -31
View File
@@ -10,9 +10,9 @@ import { runRemoteSshCommandCapture } from "./remote";
import { startJob } from "./jobs";
import {
AGENTRUN_CONFIG_PATH,
agentRunDefaultProviderId,
agentRunLaneSummary,
agentRunPipelineRunName,
agentRunProviderCredentialRefs,
resolveAgentRunLaneTarget,
type AgentRunLaneSpec,
} from "./agentrun-lanes";
@@ -45,6 +45,7 @@ export function agentRunHelp(): unknown {
"bun scripts/cli.ts agentrun apply -f - --dry-run",
"bun scripts/cli.ts agentrun send session/<sessionId> --aipod Artificer --prompt-stdin",
"bun scripts/cli.ts agentrun explain task",
"bun scripts/cli.ts agentrun explain session-policy",
"bun scripts/cli.ts agentrun control-plane plan --node D601 --lane v02",
"bun scripts/cli.ts agentrun control-plane apply --node D601 --lane v02 --dry-run",
"bun scripts/cli.ts agentrun control-plane status --node D601 --lane v02",
@@ -1536,6 +1537,7 @@ function nextPagedResourceCommand(command: string, nextAfterSeq: string, limit:
}
function agentRunExplain(kindRaw: string): string {
if (kindRaw === "session-policy" || kindRaw === "provider-policy") return renderAgentRunSessionPolicyExplanation();
const kind = parseResourceKind(kindRaw);
if (kind === "task") {
return [
@@ -4599,21 +4601,21 @@ function isExplicitSessionSendBody(input: Record<string, unknown>): boolean {
async function sessionRunBodyFromArgs(sessionId: string, args: string[], input: Record<string, unknown>): Promise<Record<string, unknown>> {
const existing = await fetchAgentRunSessionOrNull(sessionId, args);
const defaultProviderId = agentRunDefaultProviderId();
const sessionPolicy = readAgentRunClientConfig().client.sessionPolicy;
const profile = agentRunOption(args, "profile")
?? agentRunOption(args, "backend-profile")
?? stringOrNull(input.backendProfile)
?? stringOrNull(existing?.backendProfile)
?? "codex";
?? sessionPolicy.backendProfile;
const body: Record<string, unknown> = { ...input };
body.tenantId = agentRunOption(args, "tenant-id") ?? stringOrNull(body.tenantId) ?? stringOrNull(existing?.tenantId) ?? "unidesk";
body.projectId = agentRunOption(args, "project-id") ?? stringOrNull(body.projectId) ?? stringOrNull(existing?.projectId) ?? "default";
body.providerId = agentRunOption(args, "provider-id") ?? stringOrNull(body.providerId) ?? stringOrNull(existing?.providerId) ?? defaultProviderId;
body.tenantId = agentRunOption(args, "tenant-id") ?? stringOrNull(body.tenantId) ?? stringOrNull(existing?.tenantId) ?? sessionPolicy.tenantId;
body.projectId = agentRunOption(args, "project-id") ?? stringOrNull(body.projectId) ?? stringOrNull(existing?.projectId) ?? sessionPolicy.projectId;
body.providerId = agentRunOption(args, "provider-id") ?? stringOrNull(body.providerId) ?? stringOrNull(existing?.providerId) ?? sessionPolicy.providerId;
body.backendProfile = profile;
body.workspaceRef = jsonObjectOption(args, "workspace-json") ?? record(body.workspaceRef);
if (Object.keys(record(body.workspaceRef)).length === 0) body.workspaceRef = { kind: "opaque", path: "." };
if (Object.keys(record(body.workspaceRef)).length === 0) body.workspaceRef = cloneJsonRecord(sessionPolicy.workspaceRef);
body.executionPolicy = jsonObjectOption(args, "execution-policy-json") ?? record(body.executionPolicy);
if (Object.keys(record(body.executionPolicy)).length === 0) body.executionPolicy = defaultAgentRunExecutionPolicy(profile);
if (Object.keys(record(body.executionPolicy)).length === 0) body.executionPolicy = defaultAgentRunExecutionPolicy(profile, sessionPolicy);
const inheritedSessionRef = existing === null ? {} : {
conversationId: existing.conversationId,
threadId: existing.threadId,
@@ -4636,15 +4638,17 @@ async function sessionSendWithAipodRest(sessionId: string, aipod: string, args:
const metadata = record(sessionRef.metadata);
const title = agentRunOption(args, "title") ?? stringOrNull(task.title);
if (title) metadata.title = title;
const defaultProviderId = agentRunDefaultProviderId();
const sessionPolicy = readAgentRunClientConfig().client.sessionPolicy;
const backendProfile = stringOrNull(task.backendProfile) ?? sessionPolicy.backendProfile;
const executionPolicy = record(task.executionPolicy);
const runBody: Record<string, unknown> = {
tenantId: task.tenantId,
projectId: task.projectId,
providerId: task.providerId ?? defaultProviderId,
backendProfile: task.backendProfile,
workspaceRef: task.workspaceRef ?? { kind: "opaque", path: "." },
tenantId: stringOrNull(task.tenantId) ?? sessionPolicy.tenantId,
projectId: stringOrNull(task.projectId) ?? sessionPolicy.projectId,
providerId: stringOrNull(task.providerId) ?? sessionPolicy.providerId,
backendProfile,
workspaceRef: task.workspaceRef ?? cloneJsonRecord(sessionPolicy.workspaceRef),
sessionRef: { ...sessionRef, sessionId, metadata },
executionPolicy: task.executionPolicy,
executionPolicy: Object.keys(executionPolicy).length === 0 ? defaultAgentRunExecutionPolicy(backendProfile, sessionPolicy) : executionPolicy,
resourceBundleRef: task.resourceBundleRef,
traceSink: { kind: "aipod-session", aipod, sessionId, valuesPrinted: false },
};
@@ -4808,6 +4812,7 @@ export function parseAgentRunClientConfigYaml(raw: string, sourcePath = "config/
const transport = stringFieldFromRecord(client, "transport", "client");
if (role !== "render-only") throw new Error(`${sourcePath}: client.role must be render-only`);
if (transport !== "direct-http") throw new Error(`${sourcePath}: client.transport must be direct-http`);
const sessionPolicy = readAgentRunSessionPolicyConfig(client, sourcePath);
const publicExposure = readAgentRunPublicExposureConfig(input.publicExposure, baseUrl.replace(/\/+$/u, "/"), sourcePath);
return {
sourcePath,
@@ -4824,11 +4829,35 @@ export function parseAgentRunClientConfigYaml(raw: string, sourcePath = "config/
client: {
role,
transport,
sessionPolicy,
},
publicExposure,
};
}
function readAgentRunSessionPolicyConfig(client: Record<string, unknown>, sourcePath: string): AgentRunSessionPolicyConfig {
const pathValue = "client.sessionPolicy";
const sessionPolicy = record(client.sessionPolicy);
const workspaceRef = record(sessionPolicy.workspaceRef);
const executionPolicy = record(sessionPolicy.executionPolicy);
const secretScope = record(executionPolicy.secretScope);
stringFieldFromRecord(workspaceRef, "kind", `${pathValue}.workspaceRef`);
stringFieldFromRecord(executionPolicy, "sandbox", `${pathValue}.executionPolicy`);
stringFieldFromRecord(executionPolicy, "approval", `${pathValue}.executionPolicy`);
positiveIntegerFieldFromRecord(executionPolicy, "timeoutMs", `${pathValue}.executionPolicy`);
stringFieldFromRecord(executionPolicy, "network", `${pathValue}.executionPolicy`);
booleanFieldFromRecord(secretScope, "allowCredentialEcho", `${pathValue}.executionPolicy.secretScope`);
return {
sourcePath,
tenantId: stringFieldFromRecord(sessionPolicy, "tenantId", pathValue),
projectId: stringFieldFromRecord(sessionPolicy, "projectId", pathValue),
providerId: stringFieldFromRecord(sessionPolicy, "providerId", pathValue),
backendProfile: stringFieldFromRecord(sessionPolicy, "backendProfile", pathValue),
workspaceRef: cloneJsonRecord(workspaceRef),
executionPolicy: cloneJsonRecord(executionPolicy),
};
}
function validateAgentRunConfigEnvelope(input: Record<string, unknown>, sourcePath: string): void {
if (input.version !== 1) throw new Error(`${sourcePath}: version must be 1`);
if (input.kind !== "AgentRunConfig") throw new Error(`${sourcePath}: kind must be AgentRunConfig`);
@@ -5115,28 +5144,58 @@ function jsonInputDisclosureFromArgs(args: string[]): Record<string, unknown> {
};
}
function defaultAgentRunExecutionPolicy(profile: string): Record<string, unknown> {
const keys = profile === "sub2api" || profile === "codex" ? ["auth.json", "config.toml"] : ["auth.json", "config.toml"];
function defaultAgentRunExecutionPolicy(profile: string, sessionPolicy: AgentRunSessionPolicyConfig = readAgentRunClientConfig().client.sessionPolicy): Record<string, unknown> {
const { spec } = resolveAgentRunLaneTarget({});
const credentials = agentRunProviderCredentialRefs(spec, profile);
if (credentials.length === 0) {
throw new AgentRunRestError("validation-failed", `config/agentrun.yaml has no providerCredential Secret binding for backendProfile=${profile} on default lane ${spec.nodeId}/${spec.lane}`);
}
const providerCredentials = credentials.map((credential) => {
if (credential.secretRef.namespace !== spec.runtime.namespace) {
throw new AgentRunRestError("validation-failed", `providerCredential ${profile} Secret ${credential.secretRef.name} is in namespace ${credential.secretRef.namespace}, expected default lane namespace ${spec.runtime.namespace}`);
}
return {
profile: credential.profile,
secretRef: {
name: credential.secretRef.name,
keys: credential.secretRef.keys,
},
};
});
const basePolicy = cloneJsonRecord(sessionPolicy.executionPolicy);
const secretScope = record(basePolicy.secretScope);
return {
sandbox: "workspace-write",
approval: "never",
timeoutMs: 900000,
network: "enabled",
...basePolicy,
secretScope: {
allowCredentialEcho: false,
providerCredentials: [
{
profile,
secretRef: {
name: `agentrun-v01-provider-${profile}`,
keys,
},
},
],
...secretScope,
providerCredentials,
},
};
}
function renderAgentRunSessionPolicyExplanation(): string {
const config = readAgentRunClientConfig();
const { spec } = resolveAgentRunLaneTarget({});
const sessionPolicy = config.client.sessionPolicy;
const credentials = agentRunProviderCredentialRefs(spec, sessionPolicy.backendProfile);
const execution = defaultAgentRunExecutionPolicy(sessionPolicy.backendProfile, sessionPolicy);
const credentialSources = credentials.map((credential) => ({
profile: credential.profile,
secretRef: credential.secretRef,
valuesPrinted: false,
}));
return [
"KIND: session-policy",
`CONFIG: ${config.sourcePath}`,
`DEFAULT LANE: ${spec.nodeId}/${spec.lane}`,
`DEFAULTS: tenantId=${sessionPolicy.tenantId} projectId=${sessionPolicy.projectId} providerId=${sessionPolicy.providerId} backendProfile=${sessionPolicy.backendProfile}`,
`WORKSPACE: ${JSON.stringify(sessionPolicy.workspaceRef)}`,
`EXECUTION: ${JSON.stringify(execution)}`,
`PROVIDER CREDENTIAL SOURCES: ${JSON.stringify(credentialSources)}`,
"VALUES: secret payloads are not printed",
].join("\n");
}
function safeAgentRunEnvelope(envelope: Record<string, unknown>): Record<string, unknown> {
return pickCompact(envelope, ["ok", "failureKind", "message", "code", "details", "valuesPrinted"]);
}
@@ -5160,6 +5219,22 @@ function numberFieldFromRecord(obj: Record<string, unknown>, key: string, pathVa
return value;
}
function positiveIntegerFieldFromRecord(obj: Record<string, unknown>, key: string, pathValue: string): number {
const value = obj[key];
if (!Number.isInteger(value) || Number(value) <= 0) throw new Error(`${pathValue}.${key} must be a positive integer`);
return Number(value);
}
function booleanFieldFromRecord(obj: Record<string, unknown>, key: string, pathValue: string): boolean {
const value = obj[key];
if (typeof value !== "boolean") throw new Error(`${pathValue}.${key} must be a boolean`);
return value;
}
function cloneJsonRecord(value: Record<string, unknown>): Record<string, unknown> {
return JSON.parse(JSON.stringify(value)) as Record<string, unknown>;
}
interface AgentRunClientConfig {
sourcePath: string;
manager: {
@@ -5175,10 +5250,21 @@ interface AgentRunClientConfig {
client: {
role: string;
transport: string;
sessionPolicy: AgentRunSessionPolicyConfig;
};
publicExposure: AgentRunPublicExposure | null;
}
interface AgentRunSessionPolicyConfig {
sourcePath: string;
tenantId: string;
projectId: string;
providerId: string;
backendProfile: string;
workspaceRef: Record<string, unknown>;
executionPolicy: Record<string, unknown>;
}
interface AgentRunPublicExposure {
enabled: true;
proxyName: string;