Skip to content

About

Validate and visiualize how your Renovate configurations merge

Topics

Resources

Security policy

Stars

13 stars

Watchers

0 watching

Forks

Latest commit

 

History

562 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Renovate Config Debugger logo

Renovate Config Debugger

OpenSSF Scorecard

See what Renovate actually does with your config before you commit it. It runs Renovate's own code in your browser, and your config never leaves the page. Think "compiler explorer for Renovate configs".

Try it live — there is nothing to install — or self-host it with a single container.

Paste this and press Run pipeline, or open it pre-filled:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:recommended"],
  "masterIssue": true,
  "packageRules": [
    { "matchManagers": ["npm"], "matchUpdateTypes": ["minor"], "groupName": "npm minor" }
  ]
}

You'll see the deprecated masterIssue rewritten to dependencyDashboard, config:recommended expanded into its full preset tree, and which updates that packageRules entry really matches.

What it solves

  • "Why didn't my packageRule match?" — Describe a hypothetical update in the simulator and see every rule and clause evaluated with Renovate's real matcher code, plus the per-dependency config the matching rules merge to.
  • "What does config:recommended actually do?" — The preset tree expands every extends, with search, roll-ups and an honest summary of which of its ~1,100 presets change anything at all.
  • "Where did this value come from?" — Per-key provenance names the layer that set it: defaults, a preset, global or inherited config, or your repo config.
  • "Will Renovate accept this?" — The pipeline runs stage by stage — parsing, migration of deprecated options, massaging, validation — with before/after diffs and Renovate's own error and warning messages.
  • "What is this repo actually running?" — Load a config straight from owner/repo or a URL; it finds the config file Renovate would use and can bring the org's inherited config along.
  • "Which dependencies does Renovate see?" — With a repo loaded, the Dependencies tab (or the pipeline's Extract phase) runs Renovate's own extractors, customManagers included, over its package files and lists what they found; multi-file managers with no single-file extractor (gradle, sbt) report an honest gap rather than a wrong answer.
  • "Can I show a colleague?" — Share (in the header) puts the whole analysis in the URL fragment: it reopens exactly, never reaches a server log, and never carries tokens.
Global + inherited config layers (self-hosted admins)

Paste a global config (the JSON form of config.js / env / CLI) and an inherited config (inheritConfig, or let a repo load fetch it) alongside the repo config, and the pipeline models the full stack as two extra timeline stages with matching provenance badges: defaults → globalExtends presets → global config → inherited config (validated with Renovate's inherit rules, presets resolved, global-only options stripped) → repo presets → repo config. Repo configs setting global-only options get Renovate's own boundary warning, and platform / endpoint from the global config drive the platform-context control, so overriding them is explicit and visibly warned.

Preset hosting & CORS support

Every fetcher runs in the page, so each host must serve CORS headers. The public default endpoints below verifiably do; self-hosted endpoints usually do not, so their presets fall back to manual injection.

Prefix Status Notes
github> fetched in browser api.github.com (custom endpoint supported)
gitlab> fetched in browser gitlab.com API v4 (custom endpoint supported)
gitea> fetched in browser gitea.com API v1 (custom endpoint supported)
forgejo> fetched in browser codeberg.org API v1 (custom endpoint supported)
npm> fetched in browser registry.npmjs.org (deprecated upstream)
bare owner/repo, local> via platform context resolves against the platform + endpoint set under Advanced — hosts & credentials
http(s)://… manual only arbitrary endpoints rarely serve CORS
azure / bitbucket / bitbucket-server / gerrit (via local>) not supported reachable only via a real Renovate run
codecommit / scm-manager (via local>) not supported Renovate itself does not serve local presets there

Any preset a fetcher cannot reach (self-hosted or air-gapped hosts, a hypothetical preset) can be supplied by hand: select the failed node in the tree and paste its JSON into "Provide preset content manually". The pipeline re-runs with it and flags the node user-supplied.

Private repositories & presets

Reading a private config or preset repo takes two steps, and the second one is easy to miss: sign in with GitHub, then install the App on the repositories it should read. Signing in alone grants nothing — a private repo keeps coming back as "not found" until the App is installed on it. Public repos need neither step.

  1. Sign in with GitHub in the app's toolbar.
  2. Open the App's installation page (this link is for the public deployment; a self-hosted instance uses the operator's own App).
  3. Pick your account or organization. As an org member you may get Install and request instead of Install — an owner then has to approve.
  4. Choose Only select repositories and pick the repos holding your Renovate config or presets, then install. The App asks for a single permission, Contents: read-only, and the selection stays editable afterwards.

docs/GitHub-App-Access.md has the full walkthrough, including org-owner approval, changing the selection later, revoking, and the personal-access-token fallback for GitHub Enterprise Server.

Privacy, tokens & GitHub sign-in
  • Configs never leave the browser except for the preset fetches they themselves declare; all GitHub/GitLab/Gitea/Forgejo/npm content fetches go browser → host API directly, with nothing proxying your config or presets.
  • Access tokens (OAuth or personal access token) live in sessionStorage/memory and are cleared when the tab closes, and never enter a URL. Where a deployment enables the worker's REFRESH_COOKIE — as the public one does — the ~6-month refresh token lives in an HttpOnly cookie scoped to the worker mount, so the session survives a closed tab. localStorage still holds no secret — the marker it gains says only that a session exists. The full table is in docs/Auth-Flow.md.
  • Sign in with GitHub adds exactly one piece of server infrastructure: the stateless packages/oauth-worker, which does nothing but the OAuth code → token / refresh_token → token exchange, because a static site cannot hold the client_secret GitHub still requires. It never sees a config, a preset, or an API request.
  • Signing in also raises the GitHub rate limit from 60 to 5,000 requests/hour. Sign-out clears the local token and fires a best-effort POST /logout, since only the worker can drop the refresh cookie; the chip links to GitHub's authorization page for true revocation.
  • Sign-in is off by default. It turns on only when the deploy provides VITE_GITHUB_CLIENT_ID and VITE_OAUTH_WORKER_URL (plus optional VITE_GITHUB_APP_SLUG) or their RCD_* equivalents. Otherwise a personal access token under Advanced — hosts & credentials is the only GitHub auth, and it is also the fallback for GitHub Enterprise Server, orgs that can't approve the app install, or Worker outages.

CLI & MCP (for agents and scripts)

Warning

The CLI and the MCP server are experimental: subcommands, flags and output shapes may change in any 0.x release.

Everything the app shows is available without a browser — the same engine and the same pinned Renovate, as structured data:

npx -y @renovate-config-debugger/cli digest renovate.json     # the run in one paragraph
npx -y @renovate-config-debugger/cli validate renovate.json   # exit 2 = Renovate would refuse it
npx -y @renovate-config-debugger/cli tree renovate.json       # what `extends` expanded into
npx -y @renovate-config-debugger/cli extract package.json     # the deps to simulate, as Renovate reads them
npx -y @renovate-config-debugger/cli simulate renovate.json --dep '{"depName":"react"}'
npx -y @renovate-config-debugger/cli compare before.json after.json --dep '{"depName":"react"}'

--format json on any subcommand; --help lists them all. validate's exit 2 is a ready-made blocking signal for CI or a Claude Code hook.

For agents, the MCP server gives typed tools instead of flags — the engine boots once, run_config holds the trace, and drill-down questions cost milliseconds:

claude mcp add rcd -- npx -y @renovate-config-debugger/cli mcp

In Claude Code, the plugin bundles that registration with a skill that knows the debugging workflow:

/plugin marketplace add secustor/claude-marketplace
/plugin install renovate-config-debugger@secustor

packages/cli/README.md has the full surface: all subcommands, input options, credentials, the endpoint guard, and the Renovate compatibility table.

Self-hosting (Docker)

Warning

Docker setups are experimental at the moment.

The app is a static bundle, so hosting it is one container:

docker run -p 8080:80 ghcr.io/secustor/renovate-config-debugger   # http://localhost:8080

Every commit publishes an image tagged sha-<short>; releases add semver tags, with latest pointing at the newest release. Verify a release's attestation:

gh attestation verify oci://ghcr.io/secustor/renovate-config-debugger:latest -R secustor/renovate-config-debugger

docker-compose.yml is a worked example of both services — the app and the optional ghcr.io/secustor/renovate-config-debugger-oauth-proxy (token exchange, Node, port 8788) — with every optional variable present but commented out (docker compose up, or --build to build from the checkout). Both are configured at run time, so one image serves OAuth-off and OAuth-on deployments: with both required variables set the container writes /rcd-config.js at startup and the sign-in UI appears; otherwise sign-in stays off.

Variable Required for sign-in Notes
RCD_GITHUB_CLIENT_ID yes Client id of your own GitHub App (public value).
RCD_OAUTH_WORKER_URL yes Base URL of the token-exchange proxy as the browser reaches it.
RCD_GITHUB_APP_SLUG no The App's slug; enables a direct "install on repositories" link.
RCD_GA_MEASUREMENT_ID no GA4 measurement id (G-…); enables Google Analytics. Off unset.
Sign in with GitHub, self-hosted

Sign-in cannot ship turned on: the callback URL, consent screen and client secret all belong to your deployment. You provision two things, both covered step by step in packages/oauth-worker/README.md:

  1. A GitHub App you own, with Contents: read-only and your callback URL.
  2. The token-exchange proxy, because a static page cannot hold the client_secret GitHub still requires. Deploy the Cloudflare Worker, or run the -oauth-proxy image. Both run identical code (the handler is a pure function; the image runs it under Node). It reads GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET and ALLOWED_ORIGINS (comma-separated exact origins, meaning the origin you serve the app from; anything else is refused with 403 before GitHub is contacted).

Self-hosting does not move the privacy boundary. The proxy only ever sees the code → token / refresh_token → token exchange, never a config, a preset or an API request. It keeps no state and logs no bodies or tokens, and every content fetch still goes browser → api.github.com.

Building the images locally
docker build --target app -t rcd-app .                    # the app image
docker build --target oauth-proxy -t rcd-oauth-proxy .    # the proxy image

The build context is the repo root. TLS termination and reverse-proxy setup are deliberately out of scope. Put the app image behind whatever you already run.

Development

mise install       # node + pnpm (or use your own, see package.json engines)
pnpm install
pnpm dev           # dev server
pnpm test          # every workspace test except e2e (which needs a build first)
pnpm typecheck
pnpm lint && pnpm format:check

docs/Architecture.md covers how it all works: the shim plugin, the golden tests, the pinned Renovate.

Developing against the signed-in state

To skip provisioning a GitHub App and Worker, put a token into the gitignored packages/app/.env:

RCD_DEV_FAKE_OAUTH_TOKEN=ghp_xxx   # any GitHub token, e.g. a classic PAT
RCD_DEV_FAKE_OAUTH_LOGIN=octocat   # optional: the login the session menu shows
RCD_DEV_AUTH_SCHEME=oauth          # optional: oauth (default) | cookie | pat

RCD_DEV_AUTH_SCHEME picks which auth shape the token is seeded as: oauth is the signed-in session (tokens live for the tab), cookie additionally plants the persistent-sign-in marker so the cookie-mode code paths run, and pat skips OAuth entirely and seeds the per-host token fallback of an OAuth-off deployment. Seeding never overwrites tokens a tab already holds, so after switching schemes, sign out or use a fresh tab.

pnpm dev then boots already signed in and sends that token on GitHub fetches, so the repo picker lists the token's real repositories. This is dev-server-only (builds never see the variable) and fakes the signed-in state, not the sign-in flow — testing the flow itself takes the real provisioning in packages/oauth-worker/README.md.

Project direction

See roadmap/ for planned features.

About

Validate and visiualize how your Renovate configurations merge

Topics

Resources

Security policy

Stars

13 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages