Пример #1
0
        public override IEnumerable <PolicyViolation> GetViolations(PolicyAnalysisContext context)
        {
            foreach (var repo in context.Org.Repos)
            {
                var isRepoOwnedByMicrosoft = repo.IsOwnedByMicrosoft();
                if (isRepoOwnedByMicrosoft)
                {
                    foreach (var userAccess in repo.Users.Where(ua => ua.Describe().IsCollaborator))
                    {
                        var user                  = userAccess.User;
                        var permission            = userAccess.Permission;
                        var userWorksForMicrosoft = context.IsMicrosoftUser(user);
                        if (!userWorksForMicrosoft && permission != CachedPermission.Pull)
                        {
                            yield return(new PolicyViolation(
                                             Descriptor,
                                             title: $"Non-Microsoft contributor '{user.Login}' should only have 'pull' permission for '{repo.Name}'",
                                             body: $@"
                                    The non-Microsoft contributor {user.Markdown()} was granted {permission.Markdown()} for the Microsoft-owned repo {repo.Markdown()}.

                                    Only Microsoft users should have more than `pull` permissions.

                                    * If this is a Microsoft user, they need to [link](https://docs.opensource.microsoft.com/tools/github/accounts/linking.html) their account.
                                    * If this isn't a Microsoft user, their permission needs to be changed to `pull`.
                                ",
                                             org: context.Org,
                                             repo: repo,
                                             user: user
                                             ));
                        }
                    }
                }
            }
            ;
        }
        public override IEnumerable <PolicyViolation> GetViolations(PolicyAnalysisContext context)
        {
            var allowedPermission = CachedPermission.Pull;
            var microsoftTeam     = context.Org.GetMicrosoftTeam();

            foreach (var team in context.Org.Teams)
            {
                var isOwnedByMicrosoft = team.IsOwnedByMicrosoft();
                var grantsMoreThanPullAccessToMicrosoftRepo = team.Repos.Any(r => r.Permission != allowedPermission && r.Repo.IsOwnedByMicrosoft());;

                if (!isOwnedByMicrosoft && grantsMoreThanPullAccessToMicrosoftRepo)
                {
                    yield return(new PolicyViolation(
                                     Descriptor,
                                     title: $"Team '{team.Name}' must be owned by Microsoft",
                                     body: $@"
                            Team {team.Markdown()} grants at least one Microsoft-owned repo more than {allowedPermission.Markdown()} permissions. The team must be owned by Microsoft.

                            To indicate that the team is owned by Microsoft, ensure that one of the parent teams is {microsoftTeam.Markdown()}.
                        ",
                                     org: context.Org,
                                     team: team
                                     ));
                }
            }
        }
Пример #3
0
        public override IEnumerable <PolicyViolation> GetViolations(PolicyAnalysisContext context)
        {
            foreach (var team in context.Org.Teams)
            {
                var isOwnedByMicrosoft = team.IsOwnedByMicrosoft();
                if (isOwnedByMicrosoft)
                {
                    foreach (var user in team.Members)
                    {
                        var isMicrosoftUser = context.IsMicrosoftUser(user);
                        if (!isMicrosoftUser)
                        {
                            yield return(new PolicyViolation(
                                             Descriptor,
                                             title: $"Microsoft owned team '{team.Name}' shouldn't contain '{user.Login}'",
                                             body: $@"
                                    Microsoft owned team {team.Markdown()} shouldn't contain user {user.Markdown()} because they are not an employee.

                                    * If this is a Microsoft user, they need to [link](https://docs.opensource.microsoft.com/tools/github/accounts/linking.html) their account.
                                    * If this team is supposed to represent Microsoft and non-Microsoft, the team shouldn't be owned by Microsoft
                                    * If this isn't a Microsoft user, they need to be removed from this team.
                                ",
                                             org: context.Org,
                                             team: team,
                                             user: user
                                             ));
                        }
                    }
                }
            }
            ;
        }
Пример #4
0
        public override IEnumerable <PolicyViolation> GetViolations(PolicyAnalysisContext context)
        {
            var botsTeam = context.Org.GetBotsTeam();

            if (botsTeam == null)
            {
                yield break;
            }

            foreach (var user in context.Org.Users)
            {
                var isKnownBot        = user.IsBot();
                var isPotentiallyABot = user.IsPotentiallyABot();
                if (!isKnownBot && isPotentiallyABot)
                {
                    yield return(new PolicyViolation(
                                     Descriptor,
                                     title: $"User '{user.Login}' should be marked as a bot",
                                     body: $@"
                            The user {user.Markdown()} appears to be a bot.

                            * If this is in fact a human, mark this issue as `policy-override` and close the issue
                            * If this is a bot, add it to the team {botsTeam.Markdown()}
                        ",
                                     org: context.Org,
                                     team: botsTeam,
                                     user: user
                                     ));
                }
            }
        }
Пример #5
0
        public override IEnumerable <PolicyViolation> GetViolations(PolicyAnalysisContext context)
        {
            foreach (var repo in context.Org.Repos)
            {
                foreach (var teamAccess in repo.Teams)
                {
                    var team = teamAccess.Team;
                    if (team.IsMarkerTeam() &&
                        teamAccess.Permission != CachedPermission.Pull)
                    {
                        yield return(new PolicyViolation(
                                         Descriptor,
                                         title: $"Repo '{repo.Name}' should only grant '{team.Name}' with 'pull' permissions",
                                         body: $@"
                                The marker team {team.Markdown()} is only used to indicate ownership. It should only ever grant `pull` permissions.

                                Change the permissions for {team.Markdown()} in repo {repo.Markdown()} to `pull`.
                            ",
                                         org: context.Org,
                                         repo: repo,
                                         team: team
                                         ));
                    }
                }
            }
        }
Пример #6
0
        public override IEnumerable <PolicyViolation> GetViolations(PolicyAnalysisContext context)
        {
            foreach (var repo in context.Org.Repos)
            {
                if (!repo.IsOwnedByMicrosoft())
                {
                    continue;
                }

                var adminTeams = repo.Teams.Where(ta => ta.Permission == CachedPermission.Admin)
                                 .Select(ta => ta.Team);

                var recommendation = string.Join(", ", adminTeams.Select(a => a.Markdown()));

                if (recommendation.Length > 0)
                {
                    recommendation = "Consider adding the user to one of these teams: " + recommendation + ".";
                }
                else
                {
                    recommendation = "Grant a team `admin` permissions for this repo and ensure the user is in that team.";
                }

                foreach (var userAccess in repo.Users)
                {
                    var user               = userAccess.User;
                    var isAdmin            = userAccess.Permission == CachedPermission.Admin;
                    var isDirectlyAssigned = userAccess.Describe().IsCollaborator;

                    if (isAdmin && isDirectlyAssigned)
                    {
                        yield return(new PolicyViolation(
                                         Descriptor,
                                         title: $"Admin access for '{user.Login}' in repo '{repo.Name}' should be granted via a team",
                                         body: $@"
                                The user {user.Markdown()} shouldn't be directly added as an admin for repo {repo.Markdown()}. Instead, the user should be in a team that is granted `admin` permissions.

                                {recommendation}
                            ",
                                         org: context.Org,
                                         repo: repo,
                                         user: user
                                         ));
                    }
                }
            }
        }
Пример #7
0
        private static async Task RunAsync(string orgName, string outputFileName, string cacheLocation, string githubToken, string ospoToken, string policyRepo)
        {
            var isForExcel   = outputFileName == null;
            var gitHubClient = await GitHubClientFactory.CreateAsync(githubToken);

            var ospoClient = await OspoClientFactory.CreateAsync(ospoToken);

            var cachedOrg = await CachedOrg.LoadAsync(gitHubClient, orgName, Console.Out, cacheLocation, forceUpdate : false);

            var userLinks = await MicrosoftUserLinks.LoadAsync(ospoClient);

            var context    = new PolicyAnalysisContext(cachedOrg, userLinks);
            var violations = PolicyRunner.Run(context);

            SaveVioloations(orgName, outputFileName, isForExcel, violations);

            if (!string.IsNullOrEmpty(policyRepo))
            {
                await FilePolicyViolationsAsync(gitHubClient, orgName, policyRepo, violations);
            }
        }
        public override IEnumerable <PolicyViolation> GetViolations(PolicyAnalysisContext context)
        {
            foreach (var team in context.Org.Teams)
            {
                var hasChildren = team.Children.Any();
                var hasRepos    = team.Repos.Any();
                var isUsed      = hasChildren || hasRepos;

                if (!isUsed)
                {
                    yield return(new PolicyViolation(
                                     Descriptor,
                                     title: $"Unused team '{team.Name}' should be removed",
                                     body: $@"
                            Team {team.Markdown()} doesn't have any associated repos nor nested teams. It should either be used or removed.
                        ",
                                     org: context.Org,
                                     team: team
                                     ));
                }
            }
        }
Пример #9
0
        public override IEnumerable <PolicyViolation> GetViolations(PolicyAnalysisContext context)
        {
            const int Threshold = 4;

            foreach (var team in context.Org.Teams)
            {
                var numberOfMaintainers = team.Maintainers.Count;

                if (numberOfMaintainers > Threshold)
                {
                    yield return(new PolicyViolation(
                                     Descriptor,
                                     title: $"Team '{team.Name}' has too many maintainers",
                                     body: $@"
                            The team {team.Markdown()} has {numberOfMaintainers} maintainers. Reduce the number of maintainers to {Threshold} or less.
                        ",
                                     org: context.Org,
                                     team: team
                                     ));
                }
            }
        }
        public override IEnumerable <PolicyViolation> GetViolations(PolicyAnalysisContext context)
        {
            var now       = DateTimeOffset.Now;
            var threshold = TimeSpan.FromDays(365);

            foreach (var repo in context.Org.Repos)
            {
                var alreadyArchived = repo.IsArchived;
                var inactivity      = now - repo.LastPush;
                if (!alreadyArchived && inactivity > threshold)
                {
                    yield return(new PolicyViolation(
                                     Descriptor,
                                     title: $"Inactive repo '{repo.Name}' should be archived",
                                     body: $@"
                            The last push to repo {repo.Markdown()} is more than {threshold.TotalDays:N0} days ago. It should be archived.
                        ",
                                     org: context.Org,
                                     repo: repo
                                     ));
                }
            }
        }
Пример #11
0
        public override IEnumerable <PolicyViolation> GetViolations(PolicyAnalysisContext context)
        {
            const int Threshold = 4;

            foreach (var repo in context.Org.Repos)
            {
                var numberOfAdmins = repo.Users.Count(ua => ua.Permission == CachedPermission.Admin &&
                                                      !ua.Describe().IsOwner);

                if (numberOfAdmins > Threshold)
                {
                    yield return(new PolicyViolation(
                                     Descriptor,
                                     title: $"Repo '{repo.Name}' has too many admins",
                                     body: $@"
                            The repo {repo.Markdown()} has {numberOfAdmins} admins. Reduce the number of admins to {Threshold} or less.
                        ",
                                     org: context.Org,
                                     repo: repo
                                     ));
                }
            }
        }
Пример #12
0
        public override IEnumerable <PolicyViolation> GetViolations(PolicyAnalysisContext context)
        {
            foreach (var user in context.Org.Users)
            {
                var userClaimsToBeWorkingForMicrosoft = user.IsClaimingToBeWorkingForMicrosoft();
                var isMicrosoftUser = context.IsMicrosoftUser(user);

                if (userClaimsToBeWorkingForMicrosoft && !isMicrosoftUser)
                {
                    yield return(new PolicyViolation(
                                     Descriptor,
                                     title: $"Microsoft-user '{user.Login}' should be linked",
                                     body: $@"
                            User {user.Markdown()} appears to be a Microsoft employee. They should be [linked](https://opensource.microsoft.com/link) to a Microsoft account.

                            For more details, see [documentation](https://docs.opensource.microsoft.com/tools/github/accounts/linking.html).
                        ",
                                     org: context.Org,
                                     user: user
                                     ));
                }
            }
        }
        public override IEnumerable <PolicyViolation> GetViolations(PolicyAnalysisContext context)
        {
            const int Threshold = 2;

            foreach (var repo in context.Org.Repos)
            {
                var isArchived     = repo.IsArchived;
                var numberOfAdmins = repo.Users.Count(ua => ua.Permission == CachedPermission.Admin &&
                                                      !ua.Describe().IsOwner);
                if (!isArchived && numberOfAdmins < Threshold)
                {
                    yield return(new PolicyViolation(
                                     Descriptor,
                                     title: $"Repo '{repo.Name}' needs more admins",
                                     body: $@"
                            The repo {repo.Markdown()} has {numberOfAdmins} admins (excluding organization owners). It is recommended to have at least {Threshold} admins.
                        ",
                                     org: context.Org,
                                     repo: repo
                                     ));
                }
            }
        }