@@ -1117,6 +1117,7 @@ func Test_ListIssues(t *testing.T) {
11171117 },
11181118 "totalCount" : 2 ,
11191119 },
1120+ "isPrivate" : false ,
11201121 },
11211122 })
11221123
@@ -1132,6 +1133,7 @@ func Test_ListIssues(t *testing.T) {
11321133 },
11331134 "totalCount" : 2 ,
11341135 },
1136+ "isPrivate" : false ,
11351137 },
11361138 })
11371139
@@ -1147,6 +1149,7 @@ func Test_ListIssues(t *testing.T) {
11471149 },
11481150 "totalCount" : 1 ,
11491151 },
1152+ "isPrivate" : false ,
11501153 },
11511154 })
11521155
@@ -1272,8 +1275,8 @@ func Test_ListIssues(t *testing.T) {
12721275 }
12731276
12741277 // Define the actual query strings that match the implementation
1275- qBasicNoLabels := "query($after:String$direction:OrderDirection!$first:Int!$orderBy:IssueOrderField!$owner:String!$repo:String!$states:[IssueState!]!){repository(owner: $owner, name: $repo){issues(first: $first, after: $after, states: $states, orderBy: {field: $orderBy, direction: $direction}){nodes{number,title,body,state,databaseId,author{login},createdAt,updatedAt,labels(first: 100){nodes{name,id,description}},comments{totalCount}},pageInfo{hasNextPage,hasPreviousPage,startCursor,endCursor},totalCount}}}"
1276- qWithLabels := "query($after:String$direction:OrderDirection!$first:Int!$labels:[String!]!$orderBy:IssueOrderField!$owner:String!$repo:String!$states:[IssueState!]!){repository(owner: $owner, name: $repo){issues(first: $first, after: $after, labels: $labels, states: $states, orderBy: {field: $orderBy, direction: $direction}){nodes{number,title,body,state,databaseId,author{login},createdAt,updatedAt,labels(first: 100){nodes{name,id,description}},comments{totalCount}},pageInfo{hasNextPage,hasPreviousPage,startCursor,endCursor},totalCount}}}"
1278+ qBasicNoLabels := "query($after:String$direction:OrderDirection!$first:Int!$orderBy:IssueOrderField!$owner:String!$repo:String!$states:[IssueState!]!){repository(owner: $owner, name: $repo){issues(first: $first, after: $after, states: $states, orderBy: {field: $orderBy, direction: $direction}){nodes{number,title,body,state,databaseId,author{login},createdAt,updatedAt,labels(first: 100){nodes{name,id,description}},comments{totalCount}},pageInfo{hasNextPage,hasPreviousPage,startCursor,endCursor},totalCount},isPrivate }}"
1279+ qWithLabels := "query($after:String$direction:OrderDirection!$first:Int!$labels:[String!]!$orderBy:IssueOrderField!$owner:String!$repo:String!$states:[IssueState!]!){repository(owner: $owner, name: $repo){issues(first: $first, after: $after, labels: $labels, states: $states, orderBy: {field: $orderBy, direction: $direction}){nodes{number,title,body,state,databaseId,author{login},createdAt,updatedAt,labels(first: 100){nodes{name,id,description}},comments{totalCount}},pageInfo{hasNextPage,hasPreviousPage,startCursor,endCursor},totalCount},isPrivate }}"
12771280
12781281 for _ , tc := range tests {
12791282 t .Run (tc .name , func (t * testing.T ) {
@@ -1349,6 +1352,172 @@ func Test_ListIssues(t *testing.T) {
13491352 }
13501353}
13511354
1355+ func Test_ListIssues_IFC_InsidersMode (t * testing.T ) {
1356+ t .Parallel ()
1357+
1358+ serverTool := ListIssues (translations .NullTranslationHelper )
1359+
1360+ mockIssues := []map [string ]any {
1361+ {
1362+ "number" : 1 ,
1363+ "title" : "An issue" ,
1364+ "body" : "body" ,
1365+ "state" : "OPEN" ,
1366+ "databaseId" : 1 ,
1367+ "createdAt" : "2023-01-01T00:00:00Z" ,
1368+ "updatedAt" : "2023-01-01T00:00:00Z" ,
1369+ "author" : map [string ]any {"login" : "user1" },
1370+ "labels" : map [string ]any {"nodes" : []map [string ]any {}},
1371+ "comments" : map [string ]any {"totalCount" : 0 },
1372+ },
1373+ }
1374+
1375+ pageInfo := map [string ]any {
1376+ "hasNextPage" : false ,
1377+ "hasPreviousPage" : false ,
1378+ "startCursor" : "" ,
1379+ "endCursor" : "" ,
1380+ }
1381+
1382+ makeResponse := func (isPrivate bool ) githubv4mock.GQLResponse {
1383+ return githubv4mock .DataResponse (map [string ]any {
1384+ "repository" : map [string ]any {
1385+ "issues" : map [string ]any {
1386+ "nodes" : mockIssues ,
1387+ "pageInfo" : pageInfo ,
1388+ "totalCount" : 1 ,
1389+ },
1390+ "isPrivate" : isPrivate ,
1391+ },
1392+ })
1393+ }
1394+
1395+ query := "query($after:String$direction:OrderDirection!$first:Int!$orderBy:IssueOrderField!$owner:String!$repo:String!$states:[IssueState!]!){repository(owner: $owner, name: $repo){issues(first: $first, after: $after, states: $states, orderBy: {field: $orderBy, direction: $direction}){nodes{number,title,body,state,databaseId,author{login},createdAt,updatedAt,labels(first: 100){nodes{name,id,description}},comments{totalCount}},pageInfo{hasNextPage,hasPreviousPage,startCursor,endCursor},totalCount},isPrivate}}"
1396+
1397+ vars := map [string ]any {
1398+ "owner" : "octocat" ,
1399+ "repo" : "hello" ,
1400+ "states" : []any {"OPEN" , "CLOSED" },
1401+ "orderBy" : "CREATED_AT" ,
1402+ "direction" : "DESC" ,
1403+ "first" : float64 (30 ),
1404+ "after" : (* string )(nil ),
1405+ }
1406+
1407+ reqParams := map [string ]any {"owner" : "octocat" , "repo" : "hello" }
1408+
1409+ t .Run ("insiders mode disabled omits ifc label from result meta" , func (t * testing.T ) {
1410+ matcher := githubv4mock .NewQueryMatcher (query , vars , makeResponse (false ))
1411+ gqlClient := githubv4 .NewClient (githubv4mock .NewMockedHTTPClient (matcher ))
1412+ deps := BaseDeps {
1413+ GQLClient : gqlClient ,
1414+ Flags : FeatureFlags {InsidersMode : false },
1415+ }
1416+ handler := serverTool .Handler (deps )
1417+
1418+ request := createMCPRequest (reqParams )
1419+ result , err := handler (ContextWithDeps (context .Background (), deps ), & request )
1420+ require .NoError (t , err )
1421+ require .False (t , result .IsError )
1422+
1423+ assert .Nil (t , result .Meta , "result meta should be nil when insiders mode is disabled" )
1424+ })
1425+
1426+ t .Run ("insiders mode enabled on public repo emits public untrusted label" , func (t * testing.T ) {
1427+ matcher := githubv4mock .NewQueryMatcher (query , vars , makeResponse (false ))
1428+ gqlClient := githubv4 .NewClient (githubv4mock .NewMockedHTTPClient (matcher ))
1429+ deps := BaseDeps {
1430+ GQLClient : gqlClient ,
1431+ Flags : FeatureFlags {InsidersMode : true },
1432+ }
1433+ handler := serverTool .Handler (deps )
1434+
1435+ request := createMCPRequest (reqParams )
1436+ result , err := handler (ContextWithDeps (context .Background (), deps ), & request )
1437+ require .NoError (t , err )
1438+ require .False (t , result .IsError )
1439+
1440+ require .NotNil (t , result .Meta )
1441+ ifcLabel , ok := result .Meta ["ifc" ]
1442+ require .True (t , ok , "result meta should contain ifc key" )
1443+
1444+ ifcJSON , err := json .Marshal (ifcLabel )
1445+ require .NoError (t , err )
1446+ var ifcMap map [string ]any
1447+ require .NoError (t , json .Unmarshal (ifcJSON , & ifcMap ))
1448+
1449+ assert .Equal (t , "untrusted" , ifcMap ["integrity" ])
1450+ confList , ok := ifcMap ["confidentiality" ].([]any )
1451+ require .True (t , ok , "confidentiality should be a list" )
1452+ require .Len (t , confList , 1 )
1453+ assert .Equal (t , "public" , confList [0 ])
1454+ })
1455+
1456+ t .Run ("insiders mode enabled on private repo emits private untrusted label with collaborators" , func (t * testing.T ) {
1457+ matcher := githubv4mock .NewQueryMatcher (query , vars , makeResponse (true ))
1458+ gqlClient := githubv4 .NewClient (githubv4mock .NewMockedHTTPClient (matcher ))
1459+ restClient := github .NewClient (MockHTTPClientWithHandlers (map [string ]http.HandlerFunc {
1460+ GetReposCollaboratorsByOwnerByRepo : mockResponse (t , http .StatusOK , []* github.User {
1461+ {Login : github .Ptr ("octocat" )},
1462+ {Login : github .Ptr ("alice" )},
1463+ {Login : github .Ptr ("bob" )},
1464+ }),
1465+ }))
1466+ deps := BaseDeps {
1467+ Client : restClient ,
1468+ GQLClient : gqlClient ,
1469+ Flags : FeatureFlags {InsidersMode : true },
1470+ }
1471+ handler := serverTool .Handler (deps )
1472+
1473+ request := createMCPRequest (reqParams )
1474+ result , err := handler (ContextWithDeps (context .Background (), deps ), & request )
1475+ require .NoError (t , err )
1476+ require .False (t , result .IsError )
1477+
1478+ require .NotNil (t , result .Meta )
1479+ ifcLabel , ok := result .Meta ["ifc" ]
1480+ require .True (t , ok , "result meta should contain ifc key" )
1481+
1482+ ifcJSON , err := json .Marshal (ifcLabel )
1483+ require .NoError (t , err )
1484+ var ifcMap map [string ]any
1485+ require .NoError (t , json .Unmarshal (ifcJSON , & ifcMap ))
1486+
1487+ assert .Equal (t , "untrusted" , ifcMap ["integrity" ])
1488+ confList , ok := ifcMap ["confidentiality" ].([]any )
1489+ require .True (t , ok , "confidentiality should be a list" )
1490+ assert .Equal (t , []any {"octocat" , "alice" , "bob" }, confList )
1491+ })
1492+
1493+ t .Run ("insiders mode enabled on private repo falls back to owner when collaborators lookup fails" , func (t * testing.T ) {
1494+ matcher := githubv4mock .NewQueryMatcher (query , vars , makeResponse (true ))
1495+ gqlClient := githubv4 .NewClient (githubv4mock .NewMockedHTTPClient (matcher ))
1496+ restClient := github .NewClient (MockHTTPClientWithHandlers (map [string ]http.HandlerFunc {
1497+ GetReposCollaboratorsByOwnerByRepo : mockResponse (t , http .StatusInternalServerError , "boom" ),
1498+ }))
1499+ deps := BaseDeps {
1500+ Client : restClient ,
1501+ GQLClient : gqlClient ,
1502+ Flags : FeatureFlags {InsidersMode : true },
1503+ }
1504+ handler := serverTool .Handler (deps )
1505+
1506+ request := createMCPRequest (reqParams )
1507+ result , err := handler (ContextWithDeps (context .Background (), deps ), & request )
1508+ require .NoError (t , err )
1509+ require .False (t , result .IsError )
1510+
1511+ require .NotNil (t , result .Meta )
1512+ ifcJSON , err := json .Marshal (result .Meta ["ifc" ])
1513+ require .NoError (t , err )
1514+ var ifcMap map [string ]any
1515+ require .NoError (t , json .Unmarshal (ifcJSON , & ifcMap ))
1516+
1517+ assert .Equal (t , []any {"octocat" }, ifcMap ["confidentiality" ])
1518+ })
1519+ }
1520+
13521521func Test_UpdateIssue (t * testing.T ) {
13531522 // Verify tool definition
13541523 serverTool := IssueWrite (translations .NullTranslationHelper )
0 commit comments