You forked a repo whose .github/workflows/renovate.yaml runs under the
upstream org’s GitHub App. The fork inherits the workflow file but not the
App installation, so nothing keeps dependencies current. Two ways to fix
that:
- Install the hosted Renovate App on your fork (30 seconds, no workflow needed).
- Create your own GitHub App and let the workflow already in the repo run under it. More setup, but you own the credentials and can scope them to a single repo.
This is the recipe for option 2. The example repo throughout is
l50/ares; the App is named ares-renovate.
Prerequisites
ghCLI authenticated as the fork owneropCLI (1Password) for credential storage- The fork already contains
.github/renovate.json5and a.github/workflows/renovate.yamlthat uses theactions/create-github-app-tokenaction with secrets namedBOT_APP_ID,BOT_APP_PRIVATE_KEY,BOT_USERNAME,BOT_USER_ID
1. Enable issues on the fork
Renovate’s :dependencyDashboard preset files a tracking issue. Forks
have issues disabled by default.
gh api -X PATCH repos/l50/ares -f has_issues=true
2. Create the App via Manifest flow
The Manifest flow lets you POST a JSON manifest to GitHub and get a fully-configured App back in one click, no clicking through twelve permission checkboxes.
Save this as ares-renovate-app.html and open it in a browser:
<!doctype html>
<form action="https://github.com/settings/apps/new?state=setup" method="post">
<input
type="hidden"
name="manifest"
value='{
"name": "ares-renovate",
"url": "https://github.com/l50/ares",
"redirect_url": "https://localhost/callback",
"public": false,
"default_permissions": {
"actions": "write",
"contents": "write",
"issues": "write",
"metadata": "read",
"pull_requests": "write",
"statuses": "read",
"workflows": "write"
},
"default_events": []
}'
/>
<button type="submit">Create App</button>
</form>
Click the button → GitHub shows a confirmation page → click Create
GitHub App for yourname → your browser fails to load
https://localhost/callback?code=...&state=setup. That’s expected.
Copy the entire URL from the address bar. The code parameter is
a single-use exchange token (1 hour TTL).
3. Exchange the code for App credentials
CODE=<paste-from-url>
gh api -X POST "/app-manifests/${CODE}/conversions" > /tmp/app-resp.json
jq -r '.pem' /tmp/app-resp.json > /tmp/ares-renovate.pem
chmod 600 /tmp/ares-renovate.pem
jq '{id, slug, owner: .owner.login}' /tmp/app-resp.json
Gotcha: don’t pipe the response through RESP=$(gh api ...) and then
echo "$RESP" | jq .... The JSON contains a PEM with embedded
newlines, and various shell/jq combos will mangle it before parsing.
Always write the raw response to a file first.
If that fails and the code is now consumed: the App was still created.
Open https://github.com/settings/apps/<slug>, note the App ID at the
top, scroll to Private keys, click Generate a private key, and
save the downloaded .pem to /tmp/<slug>.pem.
4. Install the App on the fork only
In the App settings page, Install App → click Install next to your account → Only select repositories → pick the fork → Install.
5. Get the bot user ID
The workflow builds the git commit author as
<bot-user-id>+<slug>[bot]@users.noreply.github.com, so it needs the
bot account’s numeric ID (publicly queryable, no auth required):
gh api "/users/ares-renovate%5Bbot%5D" --jq .id
(%5B/%5D are URL-encoded [/].)
6. Store everything in 1Password
Single source of truth: the GH Actions secrets are derived from these fields, so if you rotate or move repos you only have to update one place.
op item create \
--category="API Credential" \
--title="ares-renovate GitHub App (l50/ares)" \
--vault=Personal \
--url="https://github.com/settings/apps/ares-renovate" \
username="ares-renovate[bot]" \
"credential[concealed]=$(cat /tmp/ares-renovate.pem)" \
"App Info.app_id[text]=<your-app-id>" \
"App Info.app_slug[text]=ares-renovate" \
"App Info.bot_user_id[text]=<your-bot-user-id>" \
"App Info.install_repo[text]=l50/ares"
I also put the field → secret mapping into the notes block of the item so future-me doesn’t have to re-derive it.
7. Set the GitHub Actions secrets
REPO=l50/ares
gh secret set BOT_APP_ID --repo "$REPO" --body <app-id>
gh secret set BOT_APP_PRIVATE_KEY --repo "$REPO" < /tmp/ares-renovate.pem
gh secret set BOT_USERNAME --repo "$REPO" --body ares-renovate
gh secret set BOT_USER_ID --repo "$REPO" --body <bot-user-id>
gh secret list --repo "$REPO"
BOT_USERNAME is the slug without the [bot] suffix. The workflow
appends [bot] when it composes the git author string.
8. Tell Renovate it’s allowed to process a fork
By default Renovate refuses to write to forks. Autodiscover skips them with:
INFO: Repository is a fork and not manually configured - skipping -
did you want to run with --fork-processing=enabled?
This is a safety default to keep broadly-installed Renovate from clobbering forks that aren’t the intended target. Since the fork is your target, opt in by adding one env var to the workflow:
# .github/workflows/renovate.yaml, under the Renovate step's env:
RENOVATE_FORK_PROCESSING: enabled
Commit and push to the fork’s default branch. The change is fork-local and shouldn’t be merged back upstream.
9. Validate, then run live
Dry-run first to confirm auth works without spawning PRs:
gh workflow run renovate.yaml --repo "$REPO" -f dryRun=true
gh run list --workflow=renovate.yaml --repo "$REPO" -L 1
Watch the run. If the Generate Token step is green, App ID + PEM match and the App is installed on the repo. If it fails, one of those three is wrong.
Then the real run:
gh workflow run renovate.yaml --repo "$REPO"
10. Scrub local key material
Now that the PEM lives in op and as a GH secret, get it off your disk:
rm -f /tmp/ares-renovate.pem /tmp/app-resp.json /tmp/ares-renovate-app.html
Recover later with:
op read "op://Personal/ares-renovate GitHub App (l50/ares)/credential"
Key rotation
# 1. Generate new key in the App settings UI (downloads .pem)
# 2. Update 1Password
op item edit "ares-renovate GitHub App (l50/ares)" \
"credential[concealed]=$(cat new.pem)"
# 3. Update the GitHub secret
gh secret set BOT_APP_PRIVATE_KEY --repo l50/ares < new.pem
# 4. Revoke the old key in the App settings UI
rm -f new.pem