diff --git a/src/cli/exec-approvals-cli.ts b/src/cli/exec-approvals-cli.ts index 1f1653143..7d04f07c8 100644 --- a/src/cli/exec-approvals-cli.ts +++ b/src/cli/exec-approvals-cli.ts @@ -95,6 +95,14 @@ function exitWithError(message: string): never { throw new Error(message); } +function requireTrimmedNonEmpty(value: string, message: string): string { + const trimmed = value.trim(); + if (!trimmed) { + exitWithError(message); + } + return trimmed; +} + async function loadWritableSnapshotTarget(opts: ExecApprovalsCliOpts): Promise<{ snapshot: ExecApprovalsSnapshot; nodeId: string | null; @@ -262,6 +270,28 @@ function isEmptyAgent(agent: ExecApprovalsAgent): boolean { ); } +async function loadWritableAllowlistAgent(opts: ExecApprovalsCliOpts): Promise<{ + nodeId: string | null; + source: "gateway" | "node" | "local"; + targetLabel: string; + baseHash: string; + file: ExecApprovalsFile; + agentKey: string; + agent: ExecApprovalsAgent; + allowlistEntries: NonNullable; +}> { + const { snapshot, nodeId, source, targetLabel, baseHash } = + await loadWritableSnapshotTarget(opts); + const file = snapshot.file ?? { version: 1 }; + file.version = 1; + + const agentKey = resolveAgentKey(opts.agent); + const agent = ensureAgent(file, agentKey); + const allowlistEntries = Array.isArray(agent.allowlist) ? agent.allowlist : []; + + return { nodeId, source, targetLabel, baseHash, file, agentKey, agent, allowlistEntries }; +} + export function registerExecApprovalsCli(program: Command) { const formatExample = (cmd: string, desc: string) => ` ${theme.command(cmd)}\n ${theme.muted(desc)}`; @@ -364,17 +394,9 @@ export function registerExecApprovalsCli(program: Command) { .option("--agent ", 'Agent id (defaults to "*")') .action(async (pattern: string, opts: ExecApprovalsCliOpts) => { try { - const trimmed = pattern.trim(); - if (!trimmed) { - exitWithError("Pattern required."); - } - const { snapshot, nodeId, source, targetLabel, baseHash } = - await loadWritableSnapshotTarget(opts); - const file = snapshot.file ?? { version: 1 }; - file.version = 1; - const agentKey = resolveAgentKey(opts.agent); - const agent = ensureAgent(file, agentKey); - const allowlistEntries = Array.isArray(agent.allowlist) ? agent.allowlist : []; + const trimmed = requireTrimmedNonEmpty(pattern, "Pattern required."); + const { nodeId, source, targetLabel, baseHash, file, agentKey, agent, allowlistEntries } = + await loadWritableAllowlistAgent(opts); if (allowlistEntries.some((entry) => normalizeAllowlistEntry(entry) === trimmed)) { defaultRuntime.log("Already allowlisted."); return; @@ -398,17 +420,9 @@ export function registerExecApprovalsCli(program: Command) { .option("--agent ", 'Agent id (defaults to "*")') .action(async (pattern: string, opts: ExecApprovalsCliOpts) => { try { - const trimmed = pattern.trim(); - if (!trimmed) { - exitWithError("Pattern required."); - } - const { snapshot, nodeId, source, targetLabel, baseHash } = - await loadWritableSnapshotTarget(opts); - const file = snapshot.file ?? { version: 1 }; - file.version = 1; - const agentKey = resolveAgentKey(opts.agent); - const agent = ensureAgent(file, agentKey); - const allowlistEntries = Array.isArray(agent.allowlist) ? agent.allowlist : []; + const trimmed = requireTrimmedNonEmpty(pattern, "Pattern required."); + const { nodeId, source, targetLabel, baseHash, file, agentKey, agent, allowlistEntries } = + await loadWritableAllowlistAgent(opts); const nextEntries = allowlistEntries.filter( (entry) => normalizeAllowlistEntry(entry) !== trimmed, );