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:

  1. Install the hosted Renovate App on your fork (30 seconds, no workflow needed).
  2. 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

  • gh CLI authenticated as the fork owner
  • op CLI (1Password) for credential storage
  • The fork already contains .github/renovate.json5 and a .github/workflows/renovate.yaml that uses the actions/create-github-app-token action with secrets named BOT_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