Search code examples
rubygithubsonarqubeauthorizationsonarqube-ops

Sonarqube GitHub Authentication Plugin: Why are users Removed from Groups after Login?


I think I'm having some issues with SonarQube's GitHub Authentication plugin. I'm creating a SonarQube server via Kitchen.io on an EC2 instance, and then running a Ruby script utilizing the SonarQube API and GitHub API to find matching projects between the two. Then, I map the GitHub teams owning those projects to SonarQube as groups, adding existing users in SonarQube to their respective groups.

The problem: when a Git user authenticates to SonarQube using GitHub, the user is removed from all of the groups that they've been added to by my script. Is there a configuration item I'm missing that discards permissions when a user logs in based on remediation?

My Ruby code:

#RUNNING RULE: GitHub Teams = SonarQube Groups
#git_client and @sonar_client are configured in-script (redacted here)
#get the list of repos associated with git_client ID
gh_repo = []

git_client.repos.each do |repo|
    gh_repo.push(repo.name);
end

#get the existing projects on SonarQube, store their names in sonar_projects
project_index = @sonar_client.projects.index
project_index = JSON.parse(project_index)
sonar_projects = []
project_index.each do |projects|
    sonar_projects.push(projects['nm']);
end

#find common projects and repos
common_projects = sonar_projects & gh_repo;

#get list of organziations associated with client
org_array = []
git_client.organizations.each do |org|
    org_array.push(org.login);
end

#get teams for each common project, and get info to set permissions in SonarQube
teams = []
team_names = []
team_permissions =[]
org_array.each do |org|
    common_projects.each do |project|
        begin
            git_client.repo_teams("#{org}/#{project}").each do |team|
                teams.push(team);
                team_names.push(team.name);
                team_permissions.push({:team_name => team.name, :project => project})
            end
        rescue => exception
            #specifies what was rescued
            puts "[LOG] " + exception.inspect
            next
        end
    end
end

#get user groups from SonarQube
group_index = @sonar_client.user_groups.search
group_index = JSON.parse(group_index)
sonar_groups = []
sonar_group_names = []
group_index['groups'].each do |group|
    sonar_groups.push(group);
    sonar_group_names.push(group['name']);
end

#find difference between sonar groups and organization team names
groups_to_create = team_names - sonar_group_names;

#create groups in SonarQube to mirror GitHub, and refresh sonar_groups
groups_to_create.each do |group|
    @sonar_client.user_groups.create(:name => group, :login => group);
end
group_index = @sonar_client.user_groups.search
group_index = JSON.parse(group_index)
sonar_groups = []
sonar_group_names = []
group_index['groups'].each do |group|
    sonar_groups.push(group);
    sonar_group_names.push(group['name']);
end

#get members from GitHub teams
git_members = []
teams.each do |team|
    git_members.push({:team_id => team.id, :team_name => team.name, :members => git_client.team_members(team.id)});
end

#get members from SonarQube groups
sonar_members = []
sonar_groups.each do |group|
    users = JSON.parse(@sonar_client.user_groups.users({:name => group['name']}))['users'];
    sonar_members.push({:group_name => group['name'], :members => users});
end

#get difference between GitHub teams and SonarQube groups, and add users to to SonarQube groups
existing_users = (JSON.parse(@sonar_client.users.search))['users'];
git_members.each do |team|
    gits = []
    qubes = []
    users_to_add = []
    (team[:members]).each do |member|
        gits.push(member[:login])
    end
    search_result = sonar_members.select {|group| group[:group_name] == team[:team_name]};
    (search_result[0][:members]).each do |member|
        qubes.push(member['login']);
    end
    users_to_add = gits - qubes;
    users_to_add.each do |adding_user|
        user_exists = existing_users.select{|user| user['login'] == adding_user};
        if user_exists == []
            puts "[LOG] User doesn't exist in SonarQube. User must perform first-time login"
        else
             @sonar_client.user_groups.add_user(:name => search_result[0][:group_name], :login => adding_user);
        end
    end
end

#gives group permissions to view code to newly generated groups
if team_permissions != []
    team_permissions.each do |team|
        @sonar_client.permissions.add_group({:group_name => team[:team_name], :permission => 'codeviewer', :project_key => team[:project]})
    end
end

Thank you in advance for your help, and please let me know if I can improve my question with additional information or background.

-MoldyCheese


UPDATE!!!-----------------------------------------------------------------------

Alrighty, I cut out the logic pertaining to adding members to groups as SonarQube handles the synchronization of users to groups. In addition, I made the necessary changes to how I create groups to match how groups are named in SonarQube. In order for the synchronization to occur, the organization that a team belongs to must be included AND the team's name must be down-cased. For example, a GitHub team 'myTeam' in the 'myOrg' organization will only be synced with the SonarQube group 'myOrg/myteam'. My final solution is below:

#RUNNING RULE: GitHub Teams = SonarQube Groups
#git_client and @sonar_client are configured in-script (redacted here)
#get list of organziations associated with client
org_array = []
git_client.organizations.each do |org|
    org_array.push(org.login);
end

#get the list of repos associated with git_client ID
gh_repo = []
org_array.each do |org|
    git_client.org_repos(org).each do |repo|
        gh_repo.push(repo.name);
    end
end

#get the existing projects on SonarQube, store their names in sonar_projects
project_index = @sonar_client.projects.index
project_index = JSON.parse(project_index)
sonar_projects = []
project_index.each do |projects|
    sonar_projects.push(projects['nm']);
end

#find common projects and repos
common_projects = sonar_projects & gh_repo;

#get teams for each common project, and get info to set permissions in SonarQube
teams = []
team_names = []
team_permissions =[]
org_array.each do |org|
    common_projects.each do |project|
        begin
            git_client.repo_teams("#{org}/#{project}").each do |team|
                teams.push(team);
                team_names.push("#{org}/#{team.name.downcase}");
                team_permissions.push({:team_name => "#{org}/#{team.name.downcase}", :project => project})
            end
        rescue => exception
            #specifies what was rescued
            puts "[LOG] " + exception.inspect
            next
        end
    end
end

#get user groups from SonarQube
group_index = @sonar_client.user_groups.search
group_index = JSON.parse(group_index)
sonar_groups = []
sonar_group_names = []
group_index['groups'].each do |group|
    sonar_groups.push(group);
    sonar_group_names.push(group['name']);
end

#find difference between sonar groups and organization team names
groups_to_create = team_names - sonar_group_names;

#create groups in SonarQube to mirror GitHub, and refresh sonar_groups
groups_to_create.each do |group|
    @sonar_client.user_groups.create(:name => group, :login => group);
end
group_index = @sonar_client.user_groups.search
group_index = JSON.parse(group_index)
sonar_groups = []
sonar_group_names = []
group_index['groups'].each do |group|
    sonar_groups.push(group);
    sonar_group_names.push(group['name']);
end

#gives group permissions to view code to newly generated groups
if team_permissions != []
    team_permissions.each do |team|
        @sonar_client.permissions.add_group({:group_name => team[:team_name], :permission => 'codeviewer', :project_key => team[:project]})
    end
end

Hope my solution can help others!

-MoldyCheese


Solution

  • The GitHub Authentication plugin is able to synchronize user groups.

    The "Synchronize teams as groups" setting must be set to true, and each GitHub's team that you want to synchronize must be created as group in SonarQube.

    Then, when a user will authenticate in Sonarqube with his GitHub account, he'll automatically belong to the groups that match his teams.