diff --git a/src/data/copilot-associations-data.ts b/src/data/copilot-associations-data.ts index d8dc590..b49c185 100644 --- a/src/data/copilot-associations-data.ts +++ b/src/data/copilot-associations-data.ts @@ -1,4 +1,3 @@ -import { listRepoCollaborators } from "../restapi/collaborators"; import { listCopilotSeats } from "../restapi/copilot"; import { getAuditLogForActor } from "../restapi/organizations"; import { listRepoContributors } from "../restapi/repositories"; @@ -32,13 +31,13 @@ export async function generateCopilotAssociationsData({ const copilot_seats = await fetchCopilotSeats(org, per_page); // because the audit may not reflect that a copilot user is in a team, we need to get all teams and their members - await fetchOrgTeamsMembers(org, per_page, teams); + await fetchOrgTeamsMembers(org, per_page, teams, copilot_seats); // for every copilot user, get their active areas (repos and teams) by looking at the audit log // NOTE: there is rate limiting with audit log and its not intended to be used in this way constantly // may need to reconsider other otpions for future for (const seat of copilot_seats) { - await processActiveAreas(org, seat.assignee, time_period, per_page, teams, repositories); + await processActiveAreas(org, seat.assignee, time_period, per_page, repositories); } return { copilot_seats, teams, repositories }; @@ -57,27 +56,23 @@ async function fetchCopilotSeats(org: string, per_page: number): Promise 0; } - if (seat_assignee && !teams[team_name].copilot_users.includes(seat_assignee)) { - logger.debug(`Found team ${team_name} for user ${seat_assignee}`); - teams[team_name].copilot_users.push(seat_assignee); - } - if (!has_loaded_members) { const team_slug = teams[team_name].team_name; for await (const member of listTeamMembers({ org, team_slug, per_page })) { const member_name = member.login; teams[team_name].members.push(member_name); logger.debug(`Found team member ${member_name} for team ${team_name}`); + + if (org_copilot_seats.some(seat => seat.assignee === member_name) && !teams[team_name].copilot_users.includes(member_name)) { + teams[team_name].copilot_users.push(member_name); + logger.debug(`Added copilot user ${member_name} to team ${team_name}`); + } } } } async function processRepositories(repository_owner_name: string, seat_assignee: string, per_page: number, repositories: { [repo: string]: Repository }) { - const collaborator_affiliation = 'direct'; if (repositories[repository_owner_name]) { if (!repositories[repository_owner_name].associated_copilot_users.includes(seat_assignee)) { logger.trace(`Found repo ${repository_owner_name} for user ${seat_assignee}`); @@ -109,20 +103,9 @@ async function processRepositories(repository_owner_name: string, seat_assignee: } } else { const [owner, repo_name] = repository_owner_name.split("/"); - repositories[repository_owner_name] = { repo_owner: owner, repo_name: repo_name, collaborators: [], collaborator_affiliation: collaborator_affiliation, contributors: [], associated_copilot_users: [seat_assignee] }; + repositories[repository_owner_name] = { repo_owner: owner, repo_name: repo_name, contributors: [], associated_copilot_users: [seat_assignee] }; logger.trace(`Found repo ${owner}/${repo_name} for user ${seat_assignee}`); - // collaborators - let collaborator_count: number = 0; - for await (const collaborator of listRepoCollaborators({ owner, repo: repo_name, per_page, affiliation: collaborator_affiliation })) { - const collaborator_name = collaborator.login; - logger.trace(`Found collaborator ${collaborator_name} for repo ${repo_name}`); - repositories[repository_owner_name].collaborators.push(collaborator_name); - - collaborator_count++; - } - logger.info(`Found ${collaborator_count} collaborators for repo ${repo_name}`); - // contributors let contributor_count: number = 0; for await (const contributor of listRepoContributors({ owner, repo: repo_name, per_page })) { @@ -137,10 +120,10 @@ async function processRepositories(repository_owner_name: string, seat_assignee: } } -async function fetchOrgTeamsMembers(org: string, per_page: number, teams: { [team: string]: TeamInfo }) { +async function fetchOrgTeamsMembers(org: string, per_page: number, teams: { [team: string]: TeamInfo }, org_copilot_seats: CopilotSeatAssignee[]) { let team_count: number = 0; for await (const team of listTeams({ org, per_page })) { - processTeams(org, team.slug, undefined, per_page, teams); + processTeams(org, team.slug, per_page, teams, org_copilot_seats); team_count++; } logger.info(`Found ${team_count} total teams in org ${org}`); @@ -232,7 +215,7 @@ async function* getUserActiveAreas({ if (!actor) { continue; } - + const team = audit_log_entry.team; const repository = audit_log_entry.repository || audit_log_entry.repo; const timestamp = timestampToDate(audit_log_entry["@timestamp"]); diff --git a/src/report/copilot-associations-report.ts b/src/report/copilot-associations-report.ts index 56aac8b..ebbcdb4 100644 --- a/src/report/copilot-associations-report.ts +++ b/src/report/copilot-associations-report.ts @@ -17,9 +17,7 @@ export interface CopilotAssociationsData { repositories: { [repo_name: string]: { repo_owner: string; - repo_name: string; - collaborators: string[]; - collaborator_affiliation: string; + repo_name: string; contributors: string[]; associated_copilot_users: string[]; }; @@ -107,8 +105,9 @@ function getTeamAssociations(data: CopilotAssociationsData): CopilotAssociation[ if (copilot_users.length === 0) { results.push(createAssociation(member, team.team_name, false, "Unknown", "team")); } - } else { - results.push(createAssociation(member, team.team_name, true, "Self", "team")); + } else { + logger.warn(`Found copilot user ${member} in team ${team.team_name}, ignoring for report...`); + //results.push(createAssociation(member, team.team_name, true, "Self", "team")); } } } @@ -123,19 +122,6 @@ function getRepositoryAssociations(data: CopilotAssociationsData): CopilotAssoci const repo = data.repositories[repo_name]; const copilot_users = repo.associated_copilot_users; - for (const collaborator of repo.collaborators) { - if (!copilot_users.includes(collaborator)) { - for (const copilot_user of copilot_users) { - results.push(createAssociation(collaborator, repo.repo_name, false, copilot_user, "repository")); - } - if (copilot_users.length === 0) { - results.push(createAssociation(collaborator, repo.repo_name, false, "Unknown", "repository")); - } - } else { - results.push(createAssociation(collaborator, repo.repo_name, true, "Self", "repository")); - } - } - for (const contributor of repo.contributors) { if (!copilot_users.includes(contributor)) { for (const copilot_user of copilot_users) { @@ -145,7 +131,8 @@ function getRepositoryAssociations(data: CopilotAssociationsData): CopilotAssoci results.push(createAssociation(contributor, repo.repo_name, false, "Unknown", "repository")); } } else { - results.push(createAssociation(contributor, repo.repo_name, true, "Self", "repository")); + logger.warn(`Found copilot user ${contributor} in repo ${repo.repo_name}, ignoring for report...`); + //results.push(createAssociation(contributor, repo.repo_name, true, "Self", "repository")); } } } diff --git a/src/shared/shared-types.ts b/src/shared/shared-types.ts index 958ec1b..f6d9291 100644 --- a/src/shared/shared-types.ts +++ b/src/shared/shared-types.ts @@ -27,9 +27,7 @@ export interface UserSummary { export type Repository = { repo_owner: string; - repo_name: string; - collaborators: string[]; - collaborator_affiliation: string; + repo_name: string; contributors: string[]; associated_copilot_users: string[]; };