22 * @vitest -environment node
33 */
44import { WorkflowLockedError } from '@sim/platform-authz/workflow'
5- import { workflowAuthzMockFns } from '@sim/testing'
5+ import { createAgentBlock , workflowAuthzMockFns } from '@sim/testing'
66import { beforeEach , describe , expect , it , vi } from 'vitest'
77
88const mocks = vi . hoisted ( ( ) => ( {
9+ isFeatureEnabled : vi . fn ( ) ,
910 recordAudit : vi . fn ( ) ,
1011 resolveContext : vi . fn ( ) ,
1112 resolvePermission : vi . fn ( ) ,
@@ -26,6 +27,10 @@ const mocks = vi.hoisted(() => ({
2627 collectGraphIds : vi . fn ( ) ,
2728} ) )
2829
30+ vi . mock ( '@/lib/core/config/feature-flags' , ( ) => ( {
31+ isFeatureEnabled : mocks . isFeatureEnabled ,
32+ } ) )
33+
2934vi . mock ( '@sim/audit' , ( ) => ( {
3035 AuditAction : { WORKFLOW_UPDATED : 'workflow.updated' } ,
3136 AuditResourceType : { WORKFLOW : 'workflow' } ,
@@ -171,6 +176,7 @@ const GRAPH_IDS = { blockIds: ['block-1'], edgeIds: [], subflowIds: [] }
171176describe ( 'applyWorkflowOperations' , ( ) => {
172177 beforeEach ( ( ) => {
173178 vi . clearAllMocks ( )
179+ mocks . isFeatureEnabled . mockResolvedValue ( false )
174180 mocks . resolveContext . mockResolvedValue ( context )
175181 mocks . resolvePermission . mockResolvedValue ( 'write' )
176182 workflowAuthzMockFns . mockAssertWorkflowMutable . mockResolvedValue ( undefined )
@@ -194,6 +200,52 @@ describe('applyWorkflowOperations', () => {
194200 mocks . assertIdsUnclaimed . mockResolvedValue ( undefined )
195201 } )
196202
203+ it . each ( [
204+ {
205+ principal : { kind : 'personal_api_key' as const , userId : 'user-1' , keyId : 'key-1' } ,
206+ dryRun : false ,
207+ } ,
208+ {
209+ principal : { kind : 'personal_api_key' as const , userId : 'user-1' , keyId : 'key-1' } ,
210+ dryRun : true ,
211+ } ,
212+ { principal : copilotPrincipal , dryRun : false } ,
213+ { principal : copilotPrincipal , dryRun : true } ,
214+ ] ) (
215+ 'gates variable mode edits for $principal.kind (dryRun=$dryRun)' ,
216+ async ( { principal, dryRun } ) => {
217+ const agent = createAgentBlock ( {
218+ id : 'agent' ,
219+ subBlocks : {
220+ tools : {
221+ id : 'tools' ,
222+ type : 'tool-input' ,
223+ value : [ { type : 'function' , usageControlExpression : '<start.toolMode>' } ] ,
224+ } ,
225+ } ,
226+ data : { canonicalModes : { '0:agentToolUsageControl' : 'advanced' } } ,
227+ } )
228+ mocks . applyOperations . mockReturnValue ( {
229+ state : graph ( { agent } ) ,
230+ validationErrors : [ ] ,
231+ skippedItems : [ ] ,
232+ } )
233+ const input = { workflowId : 'workflow-1' , operations, layout : 'none' as const , dryRun }
234+ await expect ( applyWorkflowOperations . execute ( { principal, input } ) ) . rejects . toMatchObject ( {
235+ code : 'validation' ,
236+ message : 'Variable agent tool permission modes are disabled' ,
237+ } )
238+ expect ( mocks . replace ) . not . toHaveBeenCalled ( )
239+ expect ( mocks . recordAudit ) . not . toHaveBeenCalled ( )
240+ expect ( mocks . notify ) . not . toHaveBeenCalled ( )
241+
242+ mocks . isFeatureEnabled . mockResolvedValue ( true )
243+ await expect ( applyWorkflowOperations . execute ( { principal, input } ) ) . resolves . toMatchObject ( {
244+ dryRun,
245+ } )
246+ }
247+ )
248+
197249 it ( 'writes once, through the shared persistence primitive' , async ( ) => {
198250 const result = await applyWorkflowOperations . execute ( {
199251 principal : sessionPrincipal ,
0 commit comments