refactor: dedupe agent and reply runtimes

This commit is contained in:
Peter Steinberger
2026-03-02 19:47:30 +00:00
parent 8768487aee
commit 9617ac9dd5
53 changed files with 1828 additions and 1176 deletions

View File

@@ -6,12 +6,9 @@ import {
type ExecSecurity,
buildEnforcedShellCommand,
evaluateShellAllowlist,
maxAsk,
minSecurity,
recordAllowlistUse,
requiresExecApproval,
resolveAllowAlwaysPatterns,
resolveExecApprovals,
} from "../infra/exec-approvals.js";
import { detectCommandObfuscation } from "../infra/exec-obfuscation-detect.js";
import type { SafeBinProfile } from "../infra/exec-safe-bin-policy.js";
@@ -19,10 +16,13 @@ import { logInfo } from "../logger.js";
import { markBackgrounded, tail } from "./bash-process-registry.js";
import {
buildExecApprovalRequesterContext,
resolveRegisteredExecApprovalDecision,
buildExecApprovalTurnSourceContext,
registerExecApprovalRequestForHostOrThrow,
} from "./bash-tools.exec-approval-request.js";
import {
resolveApprovalDecisionOrUndefined,
resolveExecHostApprovalContext,
} from "./bash-tools.exec-host-shared.js";
import {
DEFAULT_APPROVAL_TIMEOUT_MS,
DEFAULT_NOTIFY_TAIL_CHARS,
@@ -67,16 +67,12 @@ export type ProcessGatewayAllowlistResult = {
export async function processGatewayAllowlist(
params: ProcessGatewayAllowlistParams,
): Promise<ProcessGatewayAllowlistResult> {
const approvals = resolveExecApprovals(params.agentId, {
const { approvals, hostSecurity, hostAsk, askFallback } = resolveExecHostApprovalContext({
agentId: params.agentId,
security: params.security,
ask: params.ask,
host: "gateway",
});
const hostSecurity = minSecurity(params.security, approvals.agent.security);
const hostAsk = maxAsk(params.ask, approvals.agent.ask);
const askFallback = approvals.agent.askFallback;
if (hostSecurity === "deny") {
throw new Error("exec denied: host=gateway security=deny");
}
const allowlistEval = evaluateShellAllowlist({
command: params.command,
allowlist: approvals.allowlist,
@@ -172,20 +168,19 @@ export async function processGatewayAllowlist(
preResolvedDecision = registration.finalDecision;
void (async () => {
let decision: string | null = null;
try {
decision = await resolveRegisteredExecApprovalDecision({
approvalId,
preResolvedDecision,
});
} catch {
emitExecSystemEvent(
`Exec denied (gateway id=${approvalId}, approval-request-failed): ${params.command}`,
{
sessionKey: params.notifySessionKey,
contextKey,
},
);
const decision = await resolveApprovalDecisionOrUndefined({
approvalId,
preResolvedDecision,
onFailure: () =>
emitExecSystemEvent(
`Exec denied (gateway id=${approvalId}, approval-request-failed): ${params.command}`,
{
sessionKey: params.notifySessionKey,
contextKey,
},
),
});
if (decision === undefined) {
return;
}