Skip to content

docs(dependabot): plan the move from fine-grained PATs to a GitHub App - #135

Merged
twistedmelonman merged 2 commits into
mainfrom
claude/plan-digest-github-app-dee4868f
Sep 12, 2026
Merged

twistedmelonman merged 2 commits into
mainfrom
claude/plan-digest-github-app-dee4868f

Conversation

@twistedmelonman

Copy link
Copy Markdown
Member

Records the decision to move the Dependabot digest from three fine-grained PATs
to a single GitHub App, and plans the migration. Nothing is implemented —
this is the plan only.

Why

A fine-grained PAT has no Checks permission at all
(community#129512), so
it cannot read GitHub Actions results on a private repo, and no scoping changes
that. GitHub does not error: it returns statusCheckRollup with HTTP 200 and
the right totalCount, then nulls every CheckRun.

Measured on nightowlstudiollc/kebab-tax-netlify#280 with all four grantable
permissions in place — 11 of 12 contexts null, seven failing builds reading as
one. Apps do have a Checks permission, and one app installs on all three
owners, which also removes the reason there are three credentials.

What the plan covers

  • HUMAN steps: app creation (with the "Any account" trap called out),
    private key into 1Password, three installs, two secrets.
  • AGENT steps: three create-github-app-token steps pinned to the v3.2.0
    SHA, feeding the existing DIGEST_TOKEN_<OWNER> env names.
  • Cleanup, gated behind a verified run rather than listed before it —
    secret deletion, PAT revocation, 1Password items.

What is deliberately NOT removed

The ask was to revert what the fine-grained-token experiment added. Three
pieces look like artifacts of it and are not, so the plan says so explicitly:

  1. The nulled-checks guard (fix(dependabot): refuse a check rollup the token could not fully read #134). It enforces "an unreadable check is not
    an absent one", which holds for any credential — including an app
    installation missing a permission. It is also the automatic proof the
    migration worked: a published digest means zero nulled contexts.
  2. verify_private_visibility / DIGEST_PROBE_*. An installation scoped
    to selected repositories degrades the same silent public-only way.
  3. run-digest.sh's per-owner token indirection. It reads the token from
    the environment and does not care how it was obtained — which is what makes
    this migration workflow-only, with no digest script changes.

collect.sh needs one edit rather than a revert: its refusal message names
fine-grained tokens specifically and would misdirect if an app installation hit
the same guard.

STATUS.md is corrected — it still said the digest was blocked on tokens that
have since been installed.

Advances #120.

https://claude.ai/code/session_01ESsw699T54JHARkQXrdL3o

Claude Code Bot added 2 commits September 11, 2026 19:41
The three fine-grained tokens cannot do the job and no scoping fixes it: a
fine-grained PAT has no Checks permission at all
(github.com/orgs/community/discussions/129512), so it cannot read GitHub
Actions results on a private repository. Apps do have one, and a single app
installs on all three owners — which also removes the reason there are three
credentials.

The plan records the measurement behind the decision, the human steps (app
creation, private key, three installs, two secrets), the agent steps (workflow
minting via create-github-app-token, pinned to its v3.2.0 SHA), and the
cleanup, gated behind a verified run rather than listed before it.

Three things are called out as NOT fine-grained-token artifacts, because
"remove what the experiment added" would otherwise read as including them:

  - the three-layer nulled-checks guard (#134) — it enforces "unreadable is
    not absent", which holds for any credential, and a published digest is
    itself the proof the migration worked
  - verify_private_visibility and DIGEST_PROBE_* — an installation scoped to
    selected repositories degrades the same silent public-only way
  - run-digest.sh's per-owner DIGEST_TOKEN_<OWNER> indirection — it reads the
    token from the environment and does not care how it was obtained, which is
    what makes this migration workflow-only

collect.sh needs one edit, not a revert: its refusal message names fine-grained
tokens specifically and would misdirect if an app installation ever hit the
same guard.

STATUS.md now states the real blocker. It still said the digest was waiting on
tokens that have since been installed.

Advances #120.

Claude-Session: https://claude.ai/code/session_01ESsw699T54JHARkQXrdL3o
#133 and #134 landed while this plan was in review, so three statements in it
were stale on arrival: the prerequisite line, step 4's "branched from main
after #134 merges", and an open item recommending #133 be closed unmerged.

Step 8 now rewrites a runbook that is accurate rather than one that is wrong —
it condenses the fine-grained material to a paragraph instead of correcting it.

Verified against origin/main rather than assumed: the nulled-checks guard is
present in collect.sh and the checks-unreadable bucket in classify.sh.

Claude-Session: https://claude.ai/code/session_01ESsw699T54JHARkQXrdL3o
@twistedmelonman
twistedmelonman force-pushed the claude/plan-digest-github-app-dee4868f branch from 61c78aa to c9d6d70 Compare September 12, 2026 02:43
@twistedmelonman
twistedmelonman merged commit 66ca06b into main Sep 12, 2026
3 checks passed
@twistedmelonman
twistedmelonman deleted the claude/plan-digest-github-app-dee4868f branch September 12, 2026 02:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant