Gate task execution on approval source refs

This commit is contained in:
ZacharyZhang-NY committed 2026-05-23 21:52:52 -04:00
1 parent 4dbd8997c0
commit c59be97b79
12 files changed
+183 -16

No files matched your search

@@ -1,6 +1,6 @@
import type { DatabaseSync } from "node:sqlite";
import type { RunTaskInput } from "../../shared/commands";
import { PROVIDER_EXECUTION_MODE } from "../../shared/domain";
import { APPROVAL_STATE, PROVIDER_EXECUTION_MODE, RISK_LEVEL } from "../../shared/domain";
import { createId } from "../../shared/ids";
import { AuditService } from "./audit-service";
import { ProviderService } from "./provider-service";
@@ -61,6 +61,11 @@ interface WorkspaceRow {
repo_ref: string;
}
interface TaskApprovalRow {
id: string;
state: string;
}
export class TaskExecutionService {
private readonly audit: AuditService;
@@ -73,6 +78,7 @@ export class TaskExecutionService {
async runTask(input: RunTaskInput): Promise<string> {
const task = this.requireTask(input.orgId, input.taskId);
this.assertExecutionApproval(input.orgId, task);
const agent = this.requireAssignedAgent(input.orgId, task);
const provider = this.requireAgentProvider(input.orgId, agent);
const runId = this.createRun(input.orgId, task.id, agent.id, provider.id);
@@ -141,6 +147,23 @@ export class TaskExecutionService {
return agent;
}
private assertExecutionApproval(orgId: string, task: TaskExecutionTaskRow): void {
if (task.risk !== RISK_LEVEL.HIGH && task.requires_filesystem !== 1) return;
const approval = this.db.prepare(`
select id, state
from approvals
where org_id = ?
and source_entity_type = 'task'
and source_entity_id = ?
and kind in ('task_risk', 'task_execution')
order by created_at desc
limit 1
`).get(orgId, task.id) as TaskApprovalRow | undefined;
if (!approval || approval.state !== APPROVAL_STATE.APPROVED) {
throw new Error("Approved task execution approval is required.");
}
}
private requireAgentProvider(orgId: string, agent: TaskExecutionAgentRow): TaskExecutionProviderRow {
if (!agent.model_provider_id) throw new Error("Task assignee requires a model provider.");
const provider = this.db.prepare(`