@@ -106,6 +106,126 @@ test("appendProjectPermissionAllows writes unique project-level allow scopes", (
106106 assert . deepEqual ( settings . permissions . allow , [ "read-in-cwd" , "write-in-cwd" ] ) ;
107107} ) ;
108108
109+ test ( "appendProjectPermissionAllows seeds inherited permissions before adding allow scopes" , ( ) => {
110+ const projectRoot = createTempDir ( "deepcode-permission-settings-default-" ) ;
111+
112+ appendProjectPermissionAllows ( projectRoot , [ "query-git-log" ] , {
113+ inheritedPermissions : {
114+ allow : [ "read-in-cwd" ] ,
115+ deny : [ "write-out-cwd" ] ,
116+ ask : [ "network" ] ,
117+ defaultMode : "askAll" ,
118+ } ,
119+ } ) ;
120+
121+ const settingsPath = path . join ( projectRoot , ".deepcode" , "settings.json" ) ;
122+ const settings = JSON . parse ( fs . readFileSync ( settingsPath , "utf8" ) ) ;
123+ assert . deepEqual ( settings . permissions , {
124+ allow : [ "read-in-cwd" , "query-git-log" ] ,
125+ deny : [ "write-out-cwd" ] ,
126+ ask : [ "network" ] ,
127+ defaultMode : "askAll" ,
128+ } ) ;
129+ } ) ;
130+
131+ test ( "appendProjectPermissionAllows moves inherited ask and deny scopes into allow" , ( ) => {
132+ const projectRoot = createTempDir ( "deepcode-permission-settings-move-inherited-" ) ;
133+
134+ appendProjectPermissionAllows ( projectRoot , [ "network" , "write-out-cwd" ] , {
135+ inheritedPermissions : {
136+ allow : [ "read-in-cwd" ] ,
137+ deny : [ "write-out-cwd" ] ,
138+ ask : [ "network" , "mcp" ] ,
139+ defaultMode : "askAll" ,
140+ } ,
141+ } ) ;
142+
143+ const settingsPath = path . join ( projectRoot , ".deepcode" , "settings.json" ) ;
144+ const settings = JSON . parse ( fs . readFileSync ( settingsPath , "utf8" ) ) ;
145+ assert . deepEqual ( settings . permissions , {
146+ allow : [ "read-in-cwd" , "network" , "write-out-cwd" ] ,
147+ deny : [ ] ,
148+ ask : [ "mcp" ] ,
149+ defaultMode : "askAll" ,
150+ } ) ;
151+ } ) ;
152+
153+ test ( "appendProjectPermissionAllows writes inherited permissions even when scope is already allowed" , ( ) => {
154+ const projectRoot = createTempDir ( "deepcode-permission-settings-inherited-existing-" ) ;
155+
156+ appendProjectPermissionAllows ( projectRoot , [ "read-in-cwd" ] , {
157+ inheritedPermissions : {
158+ allow : [ "read-in-cwd" ] ,
159+ deny : [ ] ,
160+ ask : [ "network" ] ,
161+ defaultMode : "askAll" ,
162+ } ,
163+ } ) ;
164+
165+ const settingsPath = path . join ( projectRoot , ".deepcode" , "settings.json" ) ;
166+ const settings = JSON . parse ( fs . readFileSync ( settingsPath , "utf8" ) ) ;
167+ assert . deepEqual ( settings . permissions , {
168+ allow : [ "read-in-cwd" ] ,
169+ deny : [ ] ,
170+ ask : [ "network" ] ,
171+ defaultMode : "askAll" ,
172+ } ) ;
173+ } ) ;
174+
175+ test ( "appendProjectPermissionAllows preserves existing project permissions" , ( ) => {
176+ const projectRoot = createTempDir ( "deepcode-permission-settings-explicit-default-" ) ;
177+ const settingsPath = path . join ( projectRoot , ".deepcode" , "settings.json" ) ;
178+ fs . mkdirSync ( path . dirname ( settingsPath ) , { recursive : true } ) ;
179+ fs . writeFileSync (
180+ settingsPath ,
181+ JSON . stringify ( { permissions : { allow : [ "read-in-cwd" ] , defaultMode : "allowAll" } } ) ,
182+ "utf8"
183+ ) ;
184+
185+ appendProjectPermissionAllows ( projectRoot , [ "query-git-log" ] , {
186+ inheritedPermissions : {
187+ allow : [ "write-in-cwd" ] ,
188+ deny : [ "write-out-cwd" ] ,
189+ ask : [ "network" ] ,
190+ defaultMode : "askAll" ,
191+ } ,
192+ } ) ;
193+
194+ const settings = JSON . parse ( fs . readFileSync ( settingsPath , "utf8" ) ) ;
195+ assert . deepEqual ( settings . permissions , {
196+ allow : [ "read-in-cwd" , "query-git-log" ] ,
197+ defaultMode : "allowAll" ,
198+ } ) ;
199+ } ) ;
200+
201+ test ( "appendProjectPermissionAllows removes existing ask and deny conflicts" , ( ) => {
202+ const projectRoot = createTempDir ( "deepcode-permission-settings-existing-conflict-" ) ;
203+ const settingsPath = path . join ( projectRoot , ".deepcode" , "settings.json" ) ;
204+ fs . mkdirSync ( path . dirname ( settingsPath ) , { recursive : true } ) ;
205+ fs . writeFileSync (
206+ settingsPath ,
207+ JSON . stringify ( {
208+ permissions : {
209+ allow : [ "read-in-cwd" ] ,
210+ deny : [ "network" , "write-out-cwd" ] ,
211+ ask : [ "network" , "mcp" ] ,
212+ defaultMode : "askAll" ,
213+ } ,
214+ } ) ,
215+ "utf8"
216+ ) ;
217+
218+ appendProjectPermissionAllows ( projectRoot , [ "network" ] ) ;
219+
220+ const settings = JSON . parse ( fs . readFileSync ( settingsPath , "utf8" ) ) ;
221+ assert . deepEqual ( settings . permissions , {
222+ allow : [ "read-in-cwd" , "network" ] ,
223+ deny : [ "write-out-cwd" ] ,
224+ ask : [ "mcp" ] ,
225+ defaultMode : "askAll" ,
226+ } ) ;
227+ } ) ;
228+
109229test ( "hasUserPermissionReplies detects permission reply payloads" , ( ) => {
110230 assert . equal ( hasUserPermissionReplies ( { } ) , false ) ;
111231 assert . equal ( hasUserPermissionReplies ( { permissions : [ ] } ) , false ) ;
0 commit comments