@@ -231,3 +231,36 @@ func Test_PushFiles_NewBranchPreservesModes(t *testing.T) {
231231 require .Equal (t , "100755" , f .entries [0 ].GetMode ())
232232 require .Equal (t , []string {"POST /git/refs" , "POST /git/trees" , "POST /git/commits" , "PATCH /git/refs/heads/main" }, f .writes )
233233}
234+
235+ func Test_PushFiles_TreeTraversalLimit (t * testing.T ) {
236+ for _ , explicit := range []bool {false , true } {
237+ for _ , depth := range []int {64 , 65 } {
238+ name := strings .Repeat ("dir/" , depth - 1 ) + "run"
239+ t .Run (name + map [bool ]string {false : " omitted" , true : " explicit" }[explicit ], func (t * testing.T ) {
240+ f := pushFilesFixture {trees : map [string ]* github.Tree {}, missingBranch : true }
241+ sha := "root"
242+ for i := 1 ; i < depth ; i ++ {
243+ next := sha + "-child"
244+ f .trees [sha ] = & github.Tree {Entries : []* github.TreeEntry {{Path : new ("dir "), Mode : new ("040000 "), Type : new ("tree "), SHA : new (next )}}}
245+ sha = next
246+ }
247+ f .trees [sha ] = & github.Tree {Entries : []* github.TreeEntry {pushFilesTreeEntry ("run" , "100755" , "blob" )}}
248+ file := map [string ]any {"path" : name , "content" : "x" }
249+ if explicit {
250+ file ["mode" ] = "100755"
251+ }
252+ result := f .run (t , []any {file })
253+ if depth > 64 {
254+ require .True (t , result .IsError )
255+ require .Contains (t , result .Content [0 ].(* mcp.TextContent ).Text , "exceeds Git tree traversal limit" )
256+ require .Empty (t , f .treeReads )
257+ require .Empty (t , f .writes )
258+ } else {
259+ require .False (t , result .IsError )
260+ require .Len (t , f .treeReads , depth )
261+ require .Equal (t , "100755" , f .entries [0 ].GetMode ())
262+ }
263+ })
264+ }
265+ }
266+ }
0 commit comments