fix: require tool approval by default

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-25 21:23:01 +01:00
co-authored by Copilot
parent cc3c04b841
commit 29c054f47d
10 changed files with 56 additions and 8 deletions
+2 -2
View File
@@ -9,7 +9,7 @@ import {
normalizeWorkspaceSettings,
} from '@shared/domain/tooling';
import {
normalizeApprovalPolicy,
applyDefaultToolApprovalPolicy,
normalizePendingApprovalState,
normalizeSessionApprovalSettings,
} from '@shared/domain/approval';
@@ -70,7 +70,7 @@ export class WorkspaceRepository {
...stored,
patterns: mergePatterns(stored.patterns ?? []).map((pattern) => ({
...pattern,
approvalPolicy: normalizeApprovalPolicy(pattern.approvalPolicy),
approvalPolicy: applyDefaultToolApprovalPolicy(pattern.approvalPolicy),
graph: resolvePatternGraph(pattern),
})),
projects,
+2
View File
@@ -21,6 +21,7 @@ import {
normalizePatternModels,
resolveReasoningEffort,
} from '@shared/domain/models';
import { createDefaultToolApprovalPolicy } from '@shared/domain/approval';
import { syncPatternGraph, type PatternDefinition } from '@shared/domain/pattern';
import { isScratchpadProject, SCRATCHPAD_PROJECT_ID } from '@shared/domain/project';
import { applyScratchpadSessionConfig } from '@shared/domain/session';
@@ -37,6 +38,7 @@ function createDraftPattern(defaultModelId: string, defaultReasoningEffort: Patt
mode: 'single',
availability: 'available',
maxIterations: 1,
approvalPolicy: createDefaultToolApprovalPolicy(),
agents: [
{
id: createId('agent'),
+1 -1
View File
@@ -198,7 +198,7 @@ export function PatternEditor({
updateApprovalPolicy((current) => {
const otherRules = (current?.rules ?? []).filter((r) => r.kind !== kind);
if (!enabled) {
return otherRules.length > 0 ? { rules: otherRules } : undefined;
return { rules: otherRules };
}
return { rules: [...otherRules, { kind }] };
});
+19 -1
View File
@@ -46,6 +46,18 @@ const approvalCheckpointKinds: ApprovalCheckpointKind[] = ['tool-call', 'final-r
const approvalCheckpointKindSet = new Set<ApprovalCheckpointKind>(approvalCheckpointKinds);
const approvalStatusSet = new Set<ApprovalStatus>(['pending', 'approved', 'rejected']);
export function createDefaultToolApprovalPolicy(): ApprovalPolicy {
return {
rules: [{ kind: 'tool-call' }],
};
}
export function applyDefaultToolApprovalPolicy(
policy?: Partial<ApprovalPolicy>,
): ApprovalPolicy {
return normalizeApprovalPolicy(policy) ?? createDefaultToolApprovalPolicy();
}
export function isApprovalCheckpointKind(value: string | undefined): value is ApprovalCheckpointKind {
return value !== undefined && approvalCheckpointKindSet.has(value as ApprovalCheckpointKind);
}
@@ -55,6 +67,10 @@ export function isApprovalStatus(value: string | undefined): value is ApprovalSt
}
export function normalizeApprovalPolicy(policy?: Partial<ApprovalPolicy>): ApprovalPolicy | undefined {
if (policy == null) {
return undefined;
}
const rules = Array.isArray(policy?.rules) ? policy.rules : [];
const selectedAgents = new Map<ApprovalCheckpointKind, Set<string>>();
const appliesToAllAgents = new Set<ApprovalCheckpointKind>();
@@ -97,7 +113,9 @@ export function normalizeApprovalPolicy(policy?: Partial<ApprovalPolicy>): Appro
});
if (normalizedRules.length === 0 && autoApprovedToolNames.length === 0) {
return undefined;
return {
rules: [],
};
}
return {
+5 -1
View File
@@ -1,5 +1,6 @@
import type { ChatMessageRecord } from '@shared/domain/session';
import {
applyDefaultToolApprovalPolicy,
normalizeApprovalPolicy,
type ApprovalPolicy,
validateApprovalPolicy,
@@ -513,7 +514,10 @@ export function createBuiltinPatterns(timestamp: string): PatternDefinition[] {
},
];
return patterns.map((pattern) => syncPatternGraph(pattern));
return patterns.map((pattern) => syncPatternGraph({
...pattern,
approvalPolicy: applyDefaultToolApprovalPolicy(pattern.approvalPolicy),
}));
}
function countByKind(graph: PatternGraph): Map<PatternGraphNodeKind, number> {