The drift checker's --all / --remote mode sparse-checks every live
tool repo from the registry (every status except deprecated and
archived). If the token is scoped to selected repositories, add each new
registry entry to its repository list. This requires cross-repo read access that
the workflow's auto-issued GITHUB_TOKEN does not have. DRIFT_CHECK_TOKEN
is the dedicated fine-grained PAT that fills that gap.
| Mode | Token used | What it can do |
|---|---|---|
self |
GITHUB_TOKEN (default) |
check the calling repo's checkout |
all |
DRIFT_CHECK_TOKEN |
sparse-checkout every registry entry |
| sticky | DRIFT_CHECK_TOKEN |
open / edit / close issues on meta-repo |
The composite action accepts the token as the github-token input. The
meta-repo workflow falls back to GITHUB_TOKEN if DRIFT_CHECK_TOKEN is
unset:
github-token: ${{ secrets.DRIFT_CHECK_TOKEN || secrets.GITHUB_TOKEN }}Create a fine-grained PAT (not classic) at https://github.com/settings/personal-access-tokens.
Resource owner: TMHSDigital (the org that owns all 9 tool repos)
Repository access: select all 9 active registry repos:
TMHSDigital/Developer-Tools-Directory(the meta-repo itself)TMHSDigital/CFX-Developer-ToolsTMHSDigital/Unity-Developer-ToolsTMHSDigital/Docker-Developer-ToolsTMHSDigital/Home-Lab-Developer-ToolsTMHSDigital/Mobile-App-Developer-ToolsTMHSDigital/Plaid-Developer-ToolsTMHSDigital/Monday-Cursor-PluginTMHSDigital/Steam-Cursor-PluginTMHSDigital/steam-mcp
Repository permissions:
| Permission | Level | Why |
|---|---|---|
| Contents | Read | sparse-checkout AGENTS.md, CLAUDE.md, skills/, rules/ |
| Metadata | Read | mandatory for any fine-grained PAT |
The drift checker does NOT need Issues: Write on DRIFT_CHECK_TOKEN.
Sticky-issue upsert uses the workflow's auto-issued GITHUB_TOKEN (with
issues: write granted in the workflow's permissions: block) instead,
because fine-grained PATs can have inconsistent GraphQL access - the
updateIssue mutation has been observed to fail with "Resource not
accessible" even when the REST createIssue succeeds. Two-token model:
DRIFT_CHECK_TOKEN→ cross-repoContents: ReadGITHUB_TOKEN→ same-repoIssues: Write
Expiration: 90 days is recommended. Calendar a rotation.
gh secret set DRIFT_CHECK_TOKEN `
--repo TMHSDigital/Developer-Tools-Directory `
--body "<paste-pat>"Or via the web UI: https://github.com/TMHSDigital/Developer-Tools-Directory/settings/secrets/actions/new
gh secret list --repo TMHSDigital/Developer-Tools-DirectoryShould list DRIFT_CHECK_TOKEN. Trigger a smoke run:
gh workflow run drift-check.yml `
--repo TMHSDigital/Developer-Tools-Directory
gh run watchThe run completes and writes a step summary even if drift is present (exit code 1 is the "drift found" signal, not a failure).
If DRIFT_CHECK_TOKEN is unset, the workflow falls back to
GITHUB_TOKEN. The implications:
| Operation | Without DRIFT_CHECK_TOKEN |
|---|---|
mode=self |
works (meta-repo only) |
mode=all |
fails (cannot read tool repos) |
| sticky issue | works (issues on meta-repo) |
Tool-repo workflows that consume the composite action via mode=self
do NOT need DRIFT_CHECK_TOKEN; their own GITHUB_TOKEN is enough.
When the PAT nears expiration:
- Create the new token with the same scopes.
gh secret set DRIFT_CHECK_TOKEN --body "<new>"- overwrites in place.- Trigger one
workflow_dispatchrun to confirm. - Revoke the old token at https://github.com/settings/personal-access-tokens.
If the old token is revoked before the new one is uploaded, the next scheduled run fails fast on the first sparse-checkout. Sticky-issue state is unaffected.