I'm trying to write a GitHub workflow that uses a github-script
in which a GraphQL query determines if a user is part of an organization's team.
Using the GitHub GraphQL Explorer I've created this example query:
query check_if_user_is_team_member($user_login: String!, $org: String!, $team_slug: String!) {
organization(login: $org) {
team(slug: $team_slug) {
members(query: $user_login) {
totalCount
}
}
}
}
When I execute this in GraphQL Explorer with these variables:
{
"user_login": "kwk",
"org": "fedora-llvm-team",
"team_slug": "llvm-toolset-engineers"
}
then I get this result:
{
"data": {
"organization": {
"team": {
"members": {
"totalCount": 1
}
}
}
}
}
In theory one only needs to check the totalCount
for 1
or 0
, right?
In my head I thought that this must be easily portable to a github workflow like this:
name: "Example"
on:
issue_comment:
types: created
jobs:
check-team-membership:
runs-on: ubuntu-latest
steps:
- name: Check if commenter is member of the required team.
uses: actions/github-script@v7
with:
script: |
const query = `query check_if_user_is_team_member($user_login: String!, $org: String!, $team_slug: String!) {
organization(login: $org) {
team(slug: $team_slug) {
members(query: $user_login) {
totalCount
}
}
}
}`;
const variables = {
"user_login": "${{github.event.comment.user.login}}",
"org": "${{github.repository_owner}}",
// NOTE: The team must be visible, or this won't work!
"team_slug": "llvm-toolset-engineers"
}
const result = await github.graphql(query, variables)
console.log(result)
if(result['organization']['team']['members']['totalCount'] != 1) {
core.setFailed("User is not allowed to use the /retest command");
}
I see this output which looks like the concept is not working as expected:
{ organization: { team: null } }
The variables
are also correctly replaced:
const variables = {
"user_login": "kwk",
"org": "fedora-llvm-team",
"team_slug": "llvm-toolset-engineers"
}
The error that I see when the workflow runs is this one:
Error: Unhandled error: TypeError: Cannot read properties of null (reading 'members')
I can only guess but do I have to use a special token other than the GITHUB_TOKEN
that is always available in a workflow run?
EDIT:
I've tried running the query from my local computer using gh api graphql
and it didn't work as well but this time the error message was much more verbose:
$ gh api graphql -f query='query {
organization(login: "fedora-llvm-team") {
team(slug: "llvm-toolset-engineers") {
members(query: "kwk") {
totalCount
}
}
}
}'
{
"data": {
"organization": {
"team": null
}
},
"errors": [
{
"type": "FORBIDDEN",
"path": [
"organization",
"team"
],
"extensions": {
"saml_failure": false
},
"locations": [
{
"line": 3,
"column": 5
}
],
"message": "Resource not accessible by personal access token"
}
]
}
gh: Resource not accessible by personal access token
After that I've created a fined-grained GitHub access token with just these permissions:
When I set GH_TOKEN
or GITHUB_TOKEN
to this token on my local computer I can successfully query the members:
gh api graphql -f query='query {
organization(login: "fedora-llvm-team") {
team(slug: "llvm-toolset-engineers") {
members(query: "kwk") {
totalCount
}
}
}
}'
{
"data": {
"organization": {
"team": {
"members": {
"totalCount": 1
}
}
}
}
}
It looks like I was on the right track after all. The wrong permissions where causing the workflow to fail.
As it turns out, the github-script
documentation has a section on a parameter called github-token
which needs to be passed. Remember, secrets are not inherited by GitHub Actions but you have to pass them manually through input variables.
Here's the necessary change I had to make to my workflow file:
--- .github/workflows/old.yml 2024-04-22 15:58:42.430341249 +0200
+++ .github/workflows/new.yml 2024-04-22 15:59:33.513273930 +0200
@@ -11,6 +11,7 @@
- name: Check if commenter is member of the required team.
uses: actions/github-script@v7
with:
+ github-token: ${{ secrets.MY_TOKEN_WITH_READ_ACCESS_TO_MEMBERS_PERMISSION }}
script: |
const query = `query check_if_user_is_team_member($user_login: String!, $org: String!, $team_slug: String!) {
organization(login: $org) {
In essence, I needed to create a personal access token with permission to read members of the organization:
Then I copied that token and added it as a Repository Secret named MY_TOKEN_WITH_READ_ACCESS_TO_MEMBERS_PERMISSION
to my repository. Here's an example link to do just that: https://github.com/MYORG/MYREPO/settings/secrets/actions/new.
I hope this helps.