Personal Access Token to only read private reos

Hello :wave:

Is there a scope for a personal access token that would allow it to read pull requests from private repos, but not change any code?

The scope “repo” seems to grant write access too. I’m building a small CLI to keep track of PRs I need to look at.


1 Like

I can’t see one. You can use a per repository deploy key (ssh) with read-only permissions.

Can you expand on how that would work? eg would this be applicable to the GH API? Most ppl reading this will be coming from there I imagine. Thanks


  1. Assume you have something that can store state. This might be @actions/cache (that’d be evil, but it could work).
  2. Assume you create a read only deploy key and store it as a secret in your repository for your workflow.
  3. Create your workflow and give it the env: / readonly_key: "${{ secrets.readonly_key }}"

Note: this code wasn’t tested, it may have dozens of typos. It was just written for this request, I don’t personally have a need for this task – when I do, I’ll probably make a workflow (or reusable workflow) for it.

# set this as appropriate, but, we're using ssh, so make sure that the syntax is correct for ssh

# store current interesting PRs

# this is magical, you need to ensure your cache restores a file called `prs` before this command runs:
previous_prs=$(perl -ne 's/:.*//' prs > /dev/null || true)

# store current status of PRs

# we want a sandbox
git init sandbox
cd sandbox
# we'll use this key to talk to the repo
echo "$readonly_key" > "$ssh_key"
git config core.sshCommand "ssh -i '$ssh_key'" 
# set our remote
git remote add origin "$repo"

# this line here lets us play with interesting pull requests:
git ls-remote origin 'refs/pull/*/merge' | \
  perl -pne 's{.*/(\d+)/merge}{$1}'| sort -n > "$current_prs"
# ** warning, *occasionally* a `/merge` will not reflect the current state of the PR, but the last time there was *not* a merge conflict
# we could look at 'refs/pull/*/head' -- but that includes closed PRs and PRs with merge conflicts

# get state of interesting PRs
# we want a list of both previous and current ones, this is a silly way to merge the two lists which have different formats and drop duplicates
for pr in $( (echo $previous_prs; cat "$current_prs") | tr ' ' '\n' | sort -u); do
  # we only need the PR number which we have and the sha
  echo "$pr:$(git ls-remote origin refs/pull/$pr/head | perl -pne 's{(\S+).*}{$1}')" >> "$current_state"

# we now have the current state for any currentish PR, including the current state of PRs we previously tracked

# clean up
rm "$ssh_key"

# see drift (this is effectively our "output") -- but, what you do with this is beyond the scope
diff -U0 prs "$current_state"

# update state
# note -- you _might_ want to delete things that are no longer current, otherwise the list of tracked PRs becomes ever growing. For simplicity, that's omitted, it enables us to track a PR that temporarily has merge conflicts, or a PR that gets closed/reopened/goes backwards
mv "$current_state" prs

# if you're using `@actions/cache` to cache `prs` (that step needed to happen before this step), you're done, if not, it's your job to get `prs` stashed at this point so it's available for the next run

This is limited to using the git api and the GitHub magic refs/pull/*/* hierarchy more so than the “GitHub” “API”, however readonly deploy keys are definitely part of the “GitHub” “API” as are the magic refs, so, I claim it fits…

What you choose to do with the /merge items is up to you – you could merely use it to identify PRs to look at, and then use the /head ref.