import type { Request } from "express"; import { forbidden } from "../errors.js"; function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } function hasOwn(value: Record, key: string) { return Object.prototype.hasOwnProperty.call(value, key); } function prefixPath(prefix: string, key: string) { return prefix.length > 0 ? `${prefix}.${key}` : key; } function collectWorkspaceStrategyCommandPaths(raw: unknown, prefix: string): string[] { if (!isRecord(raw)) return []; const paths: string[] = []; if (hasOwn(raw, "provisionCommand")) { paths.push(prefixPath(prefix, "provisionCommand")); } if (hasOwn(raw, "teardownCommand")) { paths.push(prefixPath(prefix, "teardownCommand")); } return paths; } function collectExecutionWorkspaceConfigCommandPaths(raw: unknown, prefix: string): string[] { if (!isRecord(raw)) return []; const paths: string[] = []; if (hasOwn(raw, "provisionCommand")) { paths.push(prefixPath(prefix, "provisionCommand")); } if (hasOwn(raw, "teardownCommand")) { paths.push(prefixPath(prefix, "teardownCommand")); } if (hasOwn(raw, "cleanupCommand")) { paths.push(prefixPath(prefix, "cleanupCommand")); } return paths; } export function assertNoAgentHostWorkspaceCommandMutation(req: Request, paths: string[]) { if (req.actor.type !== "agent" || paths.length === 0) return; throw forbidden( `Agent keys cannot modify host-executed workspace commands (${paths.join(", ")}).`, ); } export function collectAgentAdapterWorkspaceCommandPaths(adapterConfig: unknown): string[] { if (!isRecord(adapterConfig)) return []; return collectWorkspaceStrategyCommandPaths( adapterConfig.workspaceStrategy, "adapterConfig.workspaceStrategy", ); } export function collectProjectExecutionWorkspaceCommandPaths(policy: unknown): string[] { if (!isRecord(policy)) return []; return collectWorkspaceStrategyCommandPaths( policy.workspaceStrategy, "executionWorkspacePolicy.workspaceStrategy", ); } export function collectProjectWorkspaceCommandPaths( workspacePatch: unknown, prefix = "", ): string[] { if (!isRecord(workspacePatch)) return []; return hasOwn(workspacePatch, "cleanupCommand") ? [prefixPath(prefix, "cleanupCommand")] : []; } export function collectIssueWorkspaceCommandPaths(input: { executionWorkspaceSettings?: unknown; assigneeAdapterOverrides?: unknown; }): string[] { const paths: string[] = []; if (isRecord(input.executionWorkspaceSettings)) { paths.push( ...collectWorkspaceStrategyCommandPaths( input.executionWorkspaceSettings.workspaceStrategy, "executionWorkspaceSettings.workspaceStrategy", ), ); } if (isRecord(input.assigneeAdapterOverrides)) { const adapterConfig = input.assigneeAdapterOverrides.adapterConfig; if (isRecord(adapterConfig)) { paths.push( ...collectWorkspaceStrategyCommandPaths( adapterConfig.workspaceStrategy, "assigneeAdapterOverrides.adapterConfig.workspaceStrategy", ), ); } } return paths; } export function collectExecutionWorkspaceCommandPaths(input: { config?: unknown; metadata?: unknown; }): string[] { const paths: string[] = []; if (input.config !== undefined) { paths.push(...collectExecutionWorkspaceConfigCommandPaths(input.config, "config")); } if (isRecord(input.metadata) && hasOwn(input.metadata, "config")) { paths.push(...collectExecutionWorkspaceConfigCommandPaths(input.metadata.config, "metadata.config")); } return paths; }