Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 34 additions & 17 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,24 +293,41 @@ class GitHubHelper {
};
}
getActorPermission(repo, actor) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
// https://docs.github.com/en/graphql/reference/enums#repositorypermission
// https://docs.github.com/en/graphql/reference/objects#repositorycollaboratoredge
// Returns 'READ', 'TRIAGE', 'WRITE', 'MAINTAIN', 'ADMIN'
const query = `query CollaboratorPermission($owner: String!, $repo: String!, $collaborator: String) {
repository(owner:$owner, name:$repo) {
collaborators(login: $collaborator) {
edges {
permission
}
}
}
}`;
const collaboratorPermission = yield this.octokit.graphql(query, Object.assign(Object.assign({}, repo), { collaborator: actor }));
core.debug(`CollaboratorPermission: ${(0, util_1.inspect)(collaboratorPermission.repository.collaborators.edges)}`);
return collaboratorPermission.repository.collaborators.edges.length > 0
? collaboratorPermission.repository.collaborators.edges[0].permission.toLowerCase()
: 'none';
// Use the REST API approach which can detect both direct and team-based permissions
// This is more reliable than the GraphQL approach for team permissions and works better with default GITHUB_TOKEN
try {
const { data: collaboratorPermission } = yield this.octokit.rest.repos.getCollaboratorPermissionLevel(Object.assign(Object.assign({}, repo), { username: actor }));
const permissions = (_a = collaboratorPermission.user) === null || _a === void 0 ? void 0 : _a.permissions;
core.debug(`REST API collaborator permission: ${(0, util_1.inspect)(permissions)}`);
// Use the detailed permissions object to get the highest permission level
if (permissions) {
// Check permissions in order of highest to lowest
if (permissions.admin) {
return 'admin';
}
else if (permissions.maintain) {
return 'maintain';
}
else if (permissions.push) {
return 'write';
}
else if (permissions.triage) {
core.debug(`User ${actor} has triage permission via REST API`);
return 'triage';
}
else if (permissions.pull) {
core.debug(`User ${actor} has read permission via REST API`);
return 'read';
}
}
return 'none';
}
catch (error) {
core.debug(`REST API permission check failed: ${utils.getErrorMessage(error)}`);
return 'none';
}
});
}
tryAddReaction(repo, commentId, reaction) {
Expand Down
2 changes: 1 addition & 1 deletion src/command-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export function configIsValid(config: Command[]): string | null {
}

export function actorHasPermission(
actorPermission: string,
actorPermission: utils.RepoPermission,
commandPermission: string
): boolean {
const permissionLevels = Object.freeze({
Expand Down
63 changes: 39 additions & 24 deletions src/github-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
repo: string
}

type CollaboratorPermission = {

Check warning on line 28 in src/github-helper.ts

View workflow job for this annotation

GitHub Actions / build

'CollaboratorPermission' is defined but never used
repository: {
collaborators: {
edges: [
Expand Down Expand Up @@ -55,32 +55,47 @@
}
}

async getActorPermission(repo: Repository, actor: string): Promise<string> {
// https://docs.github.com/en/graphql/reference/enums#repositorypermission
// https://docs.github.com/en/graphql/reference/objects#repositorycollaboratoredge
// Returns 'READ', 'TRIAGE', 'WRITE', 'MAINTAIN', 'ADMIN'
const query = `query CollaboratorPermission($owner: String!, $repo: String!, $collaborator: String) {
repository(owner:$owner, name:$repo) {
collaborators(login: $collaborator) {
edges {
permission
}
async getActorPermission(
repo: Repository,
actor: string
): Promise<utils.RepoPermission> {
// Use the REST API approach which can detect both direct and team-based permissions
// This is more reliable than the GraphQL approach for team permissions and works better with default GITHUB_TOKEN
try {
const {data: collaboratorPermission} =
await this.octokit.rest.repos.getCollaboratorPermissionLevel({
...repo,
username: actor
})

const permissions = collaboratorPermission.user?.permissions
core.debug(`REST API collaborator permission: ${inspect(permissions)}`)

// Use the detailed permissions object to get the highest permission level
if (permissions) {
// Check permissions in order of highest to lowest
if (permissions.admin) {
return 'admin'
} else if (permissions.maintain) {
return 'maintain'
} else if (permissions.push) {
return 'write'
} else if (permissions.triage) {
core.debug(`User ${actor} has triage permission via REST API`)
return 'triage'
} else if (permissions.pull) {
core.debug(`User ${actor} has read permission via REST API`)
return 'read'
}
}
}`
const collaboratorPermission =
await this.octokit.graphql<CollaboratorPermission>(query, {
...repo,
collaborator: actor
})
core.debug(
`CollaboratorPermission: ${inspect(
collaboratorPermission.repository.collaborators.edges
)}`
)
return collaboratorPermission.repository.collaborators.edges.length > 0
? collaboratorPermission.repository.collaborators.edges[0].permission.toLowerCase()
: 'none'

return 'none'
} catch (error) {
core.debug(
`REST API permission check failed: ${utils.getErrorMessage(error)}`
)
return 'none'
}
}

async tryAddReaction(
Expand Down
8 changes: 8 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import * as core from '@actions/core'

export type RepoPermission =
| 'admin'
| 'maintain'
| 'write'
| 'triage'
| 'read'
| 'none'

export function getInputAsArray(
name: string,
options?: core.InputOptions
Expand Down