IdentityNow Webservice connector - After Operation Rule

Hello,

I am trying to build the webservices connector using the Github EA (not SaaS) Rest APIs.

https://docs.github.com/en/[email protected]/rest/collaborators/collaborators

Design:

Get Users -->Operation Account Aggregation → /api/v3/users/
Get User Repos → Get Object → /api/v3/search/repositories?q=user:$response.login$

After Operation rule → calls /repos/{owner}/{repo}/collaborators after getting the details of the owner and repo name from the above call and returns the permissions as groups in a map.

However, I do get group information in that rule of other users as well – Is there a way for me to return the groups information of these additional users in the rule ? The reason I need to do this is because the way the APIs are written, to get the permissions of the collaborators on a specific repository I need to know the owner of the repository and that can only be fetched if I do /api/v3/search/repositories.

Thanks
Vinit Lodaya

First of all, welcome to the forum!

Are you able to share details of your existing rule and perhaps some examples of the responses you are working with? That would help to setup something locally to try to better see what the problem is you are working with.

Thanks!

Hello @philip-ellis,

Thank you. Sure, here it is.

I am just trying to work with one user here so my examples are for a single user. I am also attaching my after operation rule.

  1. Account Aggregation operation : /api/v3/users/ → The response gives me basic user information like name, id, login, email.
    Note: I replaced “https://” to “https:” as the portal was not allowing me to add so many urls.
    response:
{
  "login": "octocat",
  "id": 1,
  "node_id": "MDQ6V=",
  "avatar_url": "https:github.com/images/error/octocat_happy.gif",
  "gravatar_id": "",
  "url": "https:api.github.com/users/octocat",
  "html_url": "https:github.com/octocat",
  "followers_url": "https:api.github.com/users/octocat/followers",
  "following_url": "https:api.github.com/users/octocat/following{/other_user}",
  "gists_url": "https:api.github.com/users/octocat/gists{/gist_id}",
  "starred_url": "https:api.github.com/users/octocat/starred{/owner}{/repo}",
  "subscriptions_url": "https:api.github.com/users/octocat/subscriptions",
  "organizations_url": "https:api.github.com/users/octocat/orgs",
  "repos_url": "https:api.github.com/users/octocat/repos",
  "events_url": "https:api.github.com/users/octocat/events{/privacy}",
  "received_events_url": "https:api.github.com/users/octocat/received_events",
  "type": "User",
  "site_admin": false,
  "name": "monalisa octocat",
  "company": "GitHub",
  "blog": "https:github.com/blog",
  "location": "San Francisco",
  "email": "[email protected] com",
  "hireable": false,
  "bio": "There once was...",
  "public_repos": 2,
  "public_gists": 1,
  "followers": 20,
  "following": 0,
  "created_at": "2008-01-14T04:33:35Z",
  "updated_at": "2008-01-14T04:33:35Z",
  "private_gists": 81,
  "total_private_repos": 100,
  "owned_private_repos": 100,
  "disk_usage": 10000,
  "collaborators": 8,
  "two_factor_authentication": true,
  "plan": {
    "name": "Medium",
    "space": 400,
    "private_repos": 20,
    "collaborators": 0
  }
}
  1. Get Object operation → /api/v3/search/repositories?q=user:$response.login$ (The above Account Aggregation is a parent endpoint hence the login attribute is used) → The response gives me users public and private repositories
    Below example gives me two repositories of the users.
{
    "total_count": 2,
    "incomplete_results": false,
    "items": [
        {
            "id": 8045,
            "node_id": "MDEwOlJlcG9z",
            "name": "Ldap-test-repo",
            "full_name": "octocat/Ldap-test-repo",
            "private": true,
            "owner": {
                "login": "octocat",
                "id": 1252,
                "node_id": "MDQ6VXNl",
                "avatar_url": "https:api.github.com/avatars/u/1252?",
                "gravatar_id": "",
                "url": "https:api.github.com/api/v3/users/octocat",
                "html_url": "https:api.github.com/octocat",
                "followers_url": "https:api.github.com/api/v3/users/octocat/followers",
                "following_url": "https:api.github.com/api/v3/users/octocat/following{/other_user}",
                "gists_url": "https:api.github.com/api/v3/users/octocat/gists{/gist_id}",
                "starred_url": "https:api.github.com/api/v3/users/octocat/starred{/owner}{/repo}",
                "subscriptions_url": "https:api.github.com/api/v3/users/octocat/subscriptions",
                "organizations_url": "https:api.github.com/api/v3/users/octocat/orgs",
                "repos_url": "https:api.github.com/api/v3/users/octocat/repos",
                "events_url": "https:api.github.com/api/v3/users/octocat/events{/privacy}",
                "received_events_url": "https:api.github.com/api/v3/users/octocat/received_events",
                "type": "User",
                "site_admin": true,
                "ldap_dn": "uid=octocat,ou=people,dc=example,dc=io"
            },
            "html_url": "https:api.github.com/octocat/Ldap-test-repo",
            "description": null,
            "fork": false,
            "url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo",
            "forks_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/forks",
            "keys_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/keys{/key_id}",
            "collaborators_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/collaborators{/collaborator}",
            "teams_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/teams",
            "hooks_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/hooks",
            "issue_events_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/issues/events{/number}",
            "events_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/events",
            "assignees_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/assignees{/user}",
            "branches_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/branches{/branch}",
            "tags_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/tags",
            "blobs_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/git/blobs{/sha}",
            "git_tags_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/git/tags{/sha}",
            "git_refs_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/git/refs{/sha}",
            "trees_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/git/trees{/sha}",
            "statuses_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/statuses/{sha}",
            "languages_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/languages",
            "stargazers_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/stargazers",
            "contributors_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/contributors",
            "subscribers_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/subscribers",
            "subscription_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/subscription",
            "commits_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/commits{/sha}",
            "git_commits_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/git/commits{/sha}",
            "comments_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/comments{/number}",
            "issue_comment_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/issues/comments{/number}",
            "contents_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/contents/{+path}",
            "compare_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/compare/{base}...{head}",
            "merges_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/merges",
            "archive_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/{archive_format}{/ref}",
            "downloads_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/downloads",
            "issues_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/issues{/number}",
            "pulls_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/pulls{/number}",
            "milestones_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/milestones{/number}",
            "notifications_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/notifications{?since,all,participating}",
            "labels_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/labels{/name}",
            "releases_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/releases{/id}",
            "deployments_url": "https:api.github.com/api/v3/repos/octocat/Ldap-test-repo/deployments",
            "created_at": "2022-06-01T22:23:09Z",
            "updated_at": "2022-06-02T17:50:32Z",
            "pushed_at": "2022-06-01T22:23:09Z",
            "git_url": "git://api.github.com/octocat/Ldap-test-repo.git",
            "ssh_url": "[email protected] api.github.com:octocat/Ldap-test-repo.git",
            "clone_url": "https:api.github.com/octocat/Ldap-test-repo.git",
            "svn_url": "https:api.github.com/octocat/Ldap-test-repo",
            "homepage": null,
            "size": 0,
            "stargazers_count": 0,
            "watchers_count": 0,
            "language": null,
            "has_issues": true,
            "has_projects": true,
            "has_downloads": true,
            "has_wiki": true,
            "has_pages": false,
            "forks_count": 0,
            "mirror_url": null,
            "archived": false,
            "disabled": false,
            "open_issues_count": 0,
            "license": null,
            "allow_forking": true,
            "is_template": false,
            "visibility": "private",
            "forks": 0,
            "open_issues": 0,
            "watchers": 0,
            "default_branch": "main",
            "permissions": {
                "admin": false,
                "maintain": false,
                "push": true,
                "triage": true,
                "pull": true
            },
            "score": 1.0
        },
        {
            "id": 8044,
            "node_id": "MDEwOlJlcG9zaXMDQ0",
            "name": "LDAP-Test",
            "full_name": "octocat/LDAP-Test",
            "private": false,
            "owner": {
                "login": "octocat",
                "id": 1252,
                "node_id": "MDQ6VXNlc",
                "avatar_url": "https:api.github.com/avatars/u/1252?",
                "gravatar_id": "",
                "url": "https:api.github.com/api/v3/users/octocat",
                "html_url": "https:api.github.com/octocat",
                "followers_url": "https:api.github.com/api/v3/users/octocat/followers",
                "following_url": "https:api.github.com/api/v3/users/octocat/following{/other_user}",
                "gists_url": "https:api.github.com/api/v3/users/octocat/gists{/gist_id}",
                "starred_url": "https:api.github.com/api/v3/users/octocat/starred{/owner}{/repo}",
                "subscriptions_url": "https:api.github.com/api/v3/users/octocat/subscriptions",
                "organizations_url": "https:api.github.com/api/v3/users/octocat/orgs",
                "repos_url": "https:api.github.com/api/v3/users/octocat/repos",
                "events_url": "https:api.github.com/api/v3/users/octocat/events{/privacy}",
                "received_events_url": "https:api.github.com/api/v3/users/octocat/received_events",
                "type": "User",
                "site_admin": true,
                "ldap_dn": "uid=octocat,ou=people,dc=anaplan,dc=io"
            },
            "html_url": "https:api.github.com/octocat/LDAP-Test",
            "description": "This repo is for LDAP integration testing",
            "fork": false,
            "url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test",
            "forks_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/forks",
            "keys_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/keys{/key_id}",
            "collaborators_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/collaborators{/collaborator}",
            "teams_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/teams",
            "hooks_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/hooks",
            "issue_events_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/issues/events{/number}",
            "events_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/events",
            "assignees_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/assignees{/user}",
            "branches_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/branches{/branch}",
            "tags_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/tags",
            "blobs_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/git/blobs{/sha}",
            "git_tags_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/git/tags{/sha}",
            "git_refs_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/git/refs{/sha}",
            "trees_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/git/trees{/sha}",
            "statuses_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/statuses/{sha}",
            "languages_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/languages",
            "stargazers_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/stargazers",
            "contributors_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/contributors",
            "subscribers_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/subscribers",
            "subscription_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/subscription",
            "commits_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/commits{/sha}",
            "git_commits_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/git/commits{/sha}",
            "comments_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/comments{/number}",
            "issue_comment_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/issues/comments{/number}",
            "contents_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/contents/{+path}",
            "compare_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/compare/{base}...{head}",
            "merges_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/merges",
            "archive_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/{archive_format}{/ref}",
            "downloads_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/downloads",
            "issues_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/issues{/number}",
            "pulls_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/pulls{/number}",
            "milestones_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/milestones{/number}",
            "notifications_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/notifications{?since,all,participating}",
            "labels_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/labels{/name}",
            "releases_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/releases{/id}",
            "deployments_url": "https:api.github.com/api/v3/repos/octocat/LDAP-Test/deployments",
            "created_at": "2022-05-25T20:26:32Z",
            "updated_at": "2022-06-01T22:30:08Z",
            "pushed_at": "2022-05-25T20:26:32Z",
            "git_url": "git://api.github.com/octocat/LDAP-Test.git",
            "ssh_url": "[email protected]:octocat/LDAP-Test.git",
            "clone_url": "https:api.github.com/octocat/LDAP-Test.git",
            "svn_url": "https:api.github.com/octocat/LDAP-Test",
            "homepage": null,
            "size": 0,
            "stargazers_count": 0,
            "watchers_count": 0,
            "language": null,
            "has_issues": true,
            "has_projects": true,
            "has_downloads": true,
            "has_wiki": true,
            "has_pages": false,
            "forks_count": 0,
            "mirror_url": null,
            "archived": false,
            "disabled": false,
            "open_issues_count": 0,
            "license": null,
            "allow_forking": true,
            "is_template": false,
            "visibility": "public",
            "forks": 0,
            "open_issues": 0,
            "watchers": 0,
            "default_branch": "main",
            "permissions": {
                "admin": false,
                "maintain": false,
                "push": true,
                "triage": true,
                "pull": true
            },
            "score": 1.0
        }
    ]
}
  1. After operation rule in the above Get-Object endpoint iterates over the items (each repostories) and makes a separate call to the collaborators url to identify the permissions on the repositories and returns a map of permissions(entitlements) that the user has. However during this call, along with details of the user being aggregated permissions of other users are also sent in the reponse.
    Below reponse has octocat (permissions as admin, maintain, push, triage and pull) and testuser1 (permissions as push, triage and pull). I want to return permissions of both the users as entitlements in Identitynow but with the current response I can return only the entitlements for octocat and not testuser1.
[
    {
        "login": "octocat",
        "id": 1252,
        "node_id": "MDQ6VXI=",
        "avatar_url": "https:api.github.com/avatars/u/1252?",
        "gravatar_id": "",
        "url": "https:api.github.com/api/v3/users/octocat",
        "html_url": "https:api.github.com/octocat",
        "followers_url": "https:api.github.com/api/v3/users/octocat/followers",
        "following_url": "https:api.github.com/api/v3/users/octocat/following{/other_user}",
        "gists_url": "https:api.github.com/api/v3/users/octocat/gists{/gist_id}",
        "starred_url": "https:api.github.com/api/v3/users/octocat/starred{/owner}{/repo}",
        "subscriptions_url": "https:api.github.com/api/v3/users/octocat/subscriptions",
        "organizations_url": "https:api.github.com/api/v3/users/octocat/orgs",
        "repos_url": "https:api.github.com/api/v3/users/octocat/repos",
        "events_url": "https:api.github.com/api/v3/users/octocat/events{/privacy}",
        "received_events_url": "https:api.github.com/api/v3/users/octocat/received_events",
        "type": "User",
        "site_admin": true,
        "ldap_dn": "uid=octocat,ou=people,dc=example,dc=io",
        "permissions": {
            "admin": true,
            "maintain": true,
            "push": true,
            "triage": true,
            "pull": true
        }
    },
    {
        "login": "testuser1",
        "id": 1310,
        "node_id": "MDQ6zMTA=",
        "avatar_url": "https:api.github.com/avatars/u/1310?",
        "gravatar_id": "",
        "url": "https:api.github.com/api/v3/users/testuser1",
        "html_url": "https:api.github.com/testuser1",
        "followers_url": "https:api.github.com/api/v3/users/testuser1/followers",
        "following_url": "https:api.github.com/api/v3/users/testuser1/following{/other_user}",
        "gists_url": "https:api.github.com/api/v3/users/testuser1/gists{/gist_id}",
        "starred_url": "https:api.github.com/api/v3/users/testuser1/starred{/owner}{/repo}",
        "subscriptions_url": "https:api.github.com/api/v3/users/testuser1/subscriptions",
        "organizations_url": "https:api.github.com/api/v3/users/testuser1/orgs",
        "repos_url": "https:api.github.com/api/v3/users/testuser1/repos",
        "events_url": "https:api.github.com/api/v3/users/testuser1/events{/privacy}",
        "received_events_url": "https:api.github.com/api/v3/users/testuser1/received_events",
        "type": "User",
        "site_admin": true,
        "ldap_dn": "uid=testuser1,ou=people,dc=example,dc=io",
        "permissions": {
            "admin": false,
            "maintain": false,
            "push": true,
            "triage": true,
            "pull": true
        }
    }
]

After Operation Rule:

import connector.common.JsonUtil;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader;
import java.io.PrintStream;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import sailpoint.tools.GeneralException;
import org.apache.commons.lang3.StringUtils;
import com.google.gson.Gson;
import com.google.gson.JsonParser;

log.error("************* WS after rule start ************** ");

Map response = (Map) JsonUtil.toMap(rawResponseObject);

log.error("**************response from WS after rule is ************** "+response);

log.error("**************requestEndPoint from WS after rule is ************** "+requestEndPoint);

log.error("**************processedResponseObject from WS after rule is ************** "+processedResponseObject);

Map updatedMapInfo = new HashMap();
List itemsList = new ArrayList();
List Finallist = new ArrayList();
Map entsMap = new HashMap();
List entValues = new ArrayList();

if (response.get("items") != null) {

    itemsList = (ArrayList) response.get("items");

    log.error("**************itemsList from WS after rule is ************** "+itemsList);

        for(int d = 0; d < itemsList.size(); d++ ){
            Map itemsValueMap = (Map) itemsList.get(d);

            log.error("**************itemsValueMap from WS after rule is ************** "+itemsValueMap);

            String repoName = itemsValueMap.get("name");
            log.error("**************repo Name from WS after rule is ************** "+repoName);

            //Map permissionsMap = itemsValueMap.get("permissions");
            //log.error("**************permissions from WS after rule is ************** "+permissionsMap);

            String contextURL = requestEndPoint.getContextUrl();
            String login = StringUtils.substringAfter(contextURL, "user:");
            log.error("**************login from WS after rule is ************** "+login);

            String collaboratorsUrl = itemsValueMap.get("collaborators_url");
            log.error("**************collaborators_url from WS after rule is ************** "+collaborators_url);

            String collaboratorsURLForAPICall = StringUtils.substringBefore(collaboratorsUrl, "{");
            log.error("**************collaboratorsURLForAPICall from WS after rule is ************** "+collaboratorsURLForAPICall);

            List allowedStatuses = new ArrayList();
            allowedStatuses.add("2**");

            Object responseForCollaborators = restClient.executeGet(collaboratorsURLForAPICall,null,allowedStatuses);
            log.error("**************responseForCollaborators from WS after rule is ************** "+responseForCollaborators);
            
            //Deserializing the responseForCollaborators as its returned as a String containing an array
            public class MyClassList extends ArrayList{}
            List responseForCollaboratorsList = new Gson().fromJson(responseForCollaborators, MyClassList.class);

            log.error("**************responseForCollaboratorsList from WS after rule is ************** "+responseForCollaboratorsList);
            
            for(int e = 0; e < responseForCollaboratorsList.size(); e++ ){
                Map valueMap = (Map) responseForCollaboratorsList.get(e);
                log.error("**************valueMap from WS after rule is ************** "+valueMap);
                String loginFromCollaborators = valueMap.get("login");
                if(loginFromCollaborators.equalsIgnoreCase(login)){
                    Map permissionsMap = valueMap.get("permissions");
                    Iterator itr = permissionsMap.entrySet().iterator();
            
                    while(itr.hasNext())
                    {
                        Map.Entry entry = itr.next();
                        if(entry.getValue()){
                        entValues.add(repoName + "$" + entry.getKey());
                        }
                    }
                }
            }  
        }
    
    log.error("**************entValues from WS after rule is ************** "+entValues);
    entsMap.put("groups",entValues);
    log.error("**************entsMap from WS after rule is ************** "+entsMap);
    Finallist.add(entsMap);
    updatedMapInfo.put("data", Finallist);
}
log.error("************* WS after rule end ************** ");

return updatedMapInfo;

Please let me know if there are any additional questions.

Thanks
Vinit Lodaya

OK now I understand what you are trying to do. This is a tricky one because of how the data gets returned from the github API. I think the only way to solve this will be to work backwards from the repository → collaborators for each API. Going up from a user to their repositories, then back down to the collaborators won’t work.

Ideally there would be an API in github available to filter a list of repositories by a user that has access, but it doesn’t look like this is possible. Because of this the only way I see to do this by using the native APIs would be to call the repositories api, then for each repository, list the collaborators and find the entitlements for each user. From a performance standpoint this might not be possible.

There is a new custom connector product that is coming out soon that would make what you are asking possible and a lot less complex to implement, so if this isn’t something of a high priority to accomplish soon, it might be worth waiting for.

Hello @philip-ellis,

Thank you for your response. When you say work backwards repository → collaborators, so run an entitlement aggregation to find the members and then return a map with members in it ?

Also, the new custom connector is it for the Enterprise server ? I know there is a beta connector out for SaaS GitHub.

Thanks
Vinit Lodaya

For the working backwards part, instead of starting with the users and getting their repositories, I was thinking you would need to start at the repositories and fetch them all, then for each one, get the members that have permission. Ideally you would be able to for each user get the repositories they have permissions to, but I didn’t see that option in the github api.

For the custom connector, it is the next stage of the beta connector, where you can develop and deploy connectors in your tenant. It’s much easier to do for complicated scenarios like these because you can run and debug the entire connector locally before you deploy it. There is an SDK that can be used and the whole experience is a lot better. If there is interest in developing on this platform then feel free to DM me.