@@ -10,6 +10,11 @@ import nodePath from 'node:path';
1010
1111import type { PolicySettings } from './types.js' ;
1212import { ApprovalMode , PolicyDecision , InProcessCheckerType } from './types.js' ;
13+ import { isDirectorySecure } from '../utils/security.js' ;
14+
15+ vi . mock ( '../utils/security.js' , ( ) => ( {
16+ isDirectorySecure : vi . fn ( ) . mockResolvedValue ( { secure : true } ) ,
17+ } ) ) ;
1318
1419afterEach ( ( ) => {
1520 vi . clearAllMocks ( ) ;
@@ -28,7 +33,53 @@ describe('createPolicyEngineConfig', () => {
2833 vi . spyOn ( Storage , 'getSystemPoliciesDir' ) . mockReturnValue (
2934 '/non/existent/system/policies' ,
3035 ) ;
36+ // Reset security check to default secure
37+ vi . mocked ( isDirectorySecure ) . mockResolvedValue ( { secure : true } ) ;
38+ } ) ;
39+
40+ it ( 'should filter out insecure system policy directories' , async ( ) => {
41+ const { Storage } = await import ( '../config/storage.js' ) ;
42+ const systemPolicyDir = '/insecure/system/policies' ;
43+ vi . spyOn ( Storage , 'getSystemPoliciesDir' ) . mockReturnValue ( systemPolicyDir ) ;
44+
45+ vi . mocked ( isDirectorySecure ) . mockImplementation ( async ( path : string ) => {
46+ if ( nodePath . resolve ( path ) === nodePath . resolve ( systemPolicyDir ) ) {
47+ return { secure : false , reason : 'Insecure directory' } ;
48+ }
49+ return { secure : true } ;
50+ } ) ;
51+
52+ // We need to spy on loadPoliciesFromToml to verify which directories were passed
53+ // But it is not exported from config.js, it is imported.
54+ // We can spy on the module it comes from.
55+ const tomlLoader = await import ( './toml-loader.js' ) ;
56+ const loadPoliciesSpy = vi . spyOn ( tomlLoader , 'loadPoliciesFromToml' ) ;
57+ loadPoliciesSpy . mockResolvedValue ( {
58+ rules : [ ] ,
59+ checkers : [ ] ,
60+ errors : [ ] ,
61+ } ) ;
62+
63+ const { createPolicyEngineConfig } = await import ( './config.js' ) ;
64+ const settings : PolicySettings = { } ;
65+
66+ await createPolicyEngineConfig (
67+ settings ,
68+ ApprovalMode . DEFAULT ,
69+ '/tmp/mock/default/policies' ,
70+ ) ;
71+
72+ // Verify loadPoliciesFromToml was called
73+ expect ( loadPoliciesSpy ) . toHaveBeenCalled ( ) ;
74+ const calledDirs = loadPoliciesSpy . mock . calls [ 0 ] [ 0 ] ;
75+
76+ // The system directory should NOT be in the list
77+ expect ( calledDirs ) . not . toContain ( systemPolicyDir ) ;
78+ // But other directories (user, default) should be there
79+ expect ( calledDirs ) . toContain ( '/non/existent/user/policies' ) ;
80+ expect ( calledDirs ) . toContain ( '/tmp/mock/default/policies' ) ;
3181 } ) ;
82+
3283 it ( 'should return ASK_USER for write tools and ALLOW for read-only tools by default' , async ( ) => {
3384 const actualFs =
3485 await vi . importActual < typeof import ( 'node:fs/promises' ) > (
0 commit comments