# The token

Which GitHub token scopes buy which ghchronicle families, and why the automatic GITHUB_TOKEN of a workflow is not enough.

Source: https://docs.jmrp.io/ghchronicle/start/token/

Everything here is read access. The collector never writes to GitHub. What
varies is how much of the account a given token is allowed to see, and a
handful of scopes are worth understanding rather than just granting.

## Creating one

1. Go to `https://github.com/settings/tokens`.

2. Choose the kind of token and give it the scopes below.

    - **Classic**

      `repo`, `read:packages`, `read:user`, `read:org`, `security_events`,
      `read:public_key` and `read:gpg_key` covers everything this collects.

    - **Fine-grained**

      Read access to the repositories, including the repository permission
      Administration, which traffic needs, plus the account permissions for
      followers, gists, packages, plan, Git SSH keys and GPG keys.

3. Put it where the process can read it, and nowhere else.

    ```sh
    export GITHUB_TOKEN=github_pat_...
    ```

    The configuration file refers to it as `${GITHUB_TOKEN}`, which is expanded
    from the environment at start-up. That is what lets the file be committed
    while the token stays out of it.

## What each scope buys

| Scope                         | Without it                                                                                       |
| ----------------------------- | ------------------------------------------------------------------------------------------------ |
| Push access to the repository, and Administration (read) on a fine-grained token | Traffic is a 403. GitHub shows views and clones only to someone who can push to the repository |
| `security_events`             | Dependabot and code scanning alerts look exactly like a repository with the feature switched off |
| `read:packages`               | The container registry is invisible. Package versions cost one call per package                  |
| `read:user`                   | Followers, contributions, gists and social accounts are missing                                  |
| `read:org`                    | Repositories owned by an organisation are not discovered                                         |
| `read:public_key`, `read:gpg_key` | The `keys` family writes nothing, and says nothing. No other scope implies either            |

Traffic is the one that surprises people, because being able to read a
repository is not enough. GitHub shows views and clones only to someone who can
push to the repository, and a fine-grained token also needs the
[repository permission Administration (read)](https://docs.github.com/en/rest/metrics/traffic#get-repository-clones--fine-grained-access-tokens);
a token that lacks either gets a 403 for that repository. The collector records
that as "unavailable" and moves on, which is why the symptom is an empty
traffic panel rather than a failed sweep.

> **Unavailable is not an error**
>
> Anything the token cannot see is recorded as unavailable and skipped. A
> repository with a feature switched off must not stop the sweep for the other
> forty, so the log says `not available (403)` and the sweep continues.

## Why the automatic GITHUB_TOKEN is not enough

A workflow gets a `GITHUB_TOKEN` for free. It is not enough for this, and the
reason is worth being specific about rather than letting someone discover it as
an empty dashboard.

- **It cannot read traffic, not even its own.** Traffic needs push access to
  _every_ repository being collected, and the automatic token has it only for
  the repository the workflow is running in. Even there it gets a 403: GitHub
  also asks for the repository permission Administration, which a workflow
  cannot grant its automatic token.
- **It has no `security_events`.** Dependabot and code scanning alerts are
  invisible to it.
- **It has no `read:packages`.** The container registry is invisible to it.
- **It is not a user.** Everything account-wide (followers, the contribution
  calendar, billing, notifications, the stars you gave) is about the person,
  not about a repository, and the automatic token is an installation, not a
  person.

So a workflow needs a personal access token stored as a repository secret and
passed in as the `token` input. See
[GitHub Actions](https://docs.jmrp.io/ghchronicle/install/actions/).

## Running without a token

Only for the three commands that ask GitHub nothing: `-backfill-status`,
`-publish-dashboard` and `-uninstall`. Everything that collects, a card of
public numbers included, needs one, and without it stops at start-up with
`github.token is empty and GITHUB_TOKEN is unset`. What a token short of a
scope costs is the table above: the part it cannot see is left empty, and the
log says `not available (403)` for each of them, which is the collector
reporting a permission, not a failure.
