GitHub
What it gives you — the Learn loop: verified root causes drafted as PRs (or issues, below the confidence bar) against your knowledge-catalog repo, via a scoped GitHub App.
Minimal config
forge:
kb_repo: your-org/runlore-kb # the repo the App is installed on
base_branch: main
skip_verdicts: [no_action] # keep benign/self-healed findings out of the PR queue
github_app:
app_id: 123456
installation_id: 7654321
private_key_env: GITHUB_APP_PRIVATE_KEYCreate the App
Settings → Developer settings → GitHub Apps → New GitHub App. Homepage URL: anything (e.g. your repo). Disable Webhooks (RunLore doesn’t receive GitHub webhooks).
Repository permissions (least privilege — grant only these):
Permission Access Why Contents Read & write push the drafted OKF entry to a branch on the KB repo Pull requests Read & write open the curation PR Issues Read & write open knowledge-gap issues for recurring unresolved patterns If your Flux/Argo source repos are private and you want real Git diffs from them (
source_repos.allow), also grant Contents: Read-only and install the App on those repos too. Public source repos need nothing.Create, then Generate a private key — download the
.pem(you only see it once).Note the App ID (on the App’s page).
Install App → install it on only the specific repos it needs (the KB repo, plus any private source repos) — not “All repositories”. Open the installation and note the Installation ID (the number in the install settings URL:
.../installations/<id>).
kubectl -n runlore create secret generic runlore-secrets \
--from-file=GITHUB_APP_PRIVATE_KEY=/path/to/app-private-key.pemVerify it locally
kubectl -n runlore logs deploy/runlore | grep 'curator enabled'Fire a test incident that produces a verified root cause and confirm a PR/issue lands on the KB repo:
kubectl -n runlore logs deploy/runlore | grep 'msg=curated url='Check the App’s installation scope directly:
gh api /installation/repositoriesNotes
Auth is a GitHub App — fine-grained permissions, per-repo installation, and short-lived (1-hour) installation tokens minted on demand from the App’s private key. No long-lived credential ever sits in the cluster.
Never commit the private key or put it in
values.yaml. Store it in aSecret, ideally synced from a vault via External Secrets.Scope the installation to specific repos, and grant only the three write permissions above. Restrict who can administer the App in your org. Rotate the private key periodically anyway.
A private KB repo (via
catalog.git) authenticates with the same curation GitHub App by default — one credential for both reads and writes; setgit.token_envonly to use a different token.source_diffclones source repos over HTTPS with the forge GitHub App installation token — for each private GitHub source repo you list undersource_repos.allow, the App must be installed on that repo withcontents: read, or the clone 404s even though the URL looks right. Public GitHub repos need no grant.github_api_urlis only needed for GitHub Enterprise Server (e.g.https://ghe.example.com/api/v3); omit it for github.com.The installation token is only ever sent to your forge’s git host.
what_changedclones the repo a GitOpsspec.source.repoURLnames, and that field is cluster state — anyone who can create an Argo CDApplicationor a FluxGitRepositorywrites it. A repoURL on any other host therefore clones anonymously (public repos still work; a private one produces no diff). Nothing is lost by this: an installation token authenticates only on the instance the App is installed on.GitHub Enterprise with subdomain isolation needs
forge.git_host. With isolation on, the API is served fromapi.HOSTNAMEwhile git and web stay onHOSTNAME, sogithub_api_urlalone cannot say which host to authenticate a clone to. RunLore refuses to start on that config rather than guess — guessing wrong would withhold the token from every GitOps repo and show up only as an emptywhat_changed:forge: github_api_url: https://api.ghe.example.com # API (subdomain isolation) git_host: ghe.example.com # git remotes / clone authWithout isolation (
https://ghe.example.com/api/v3), the host is unambiguous andgit_hostis not needed.RunLore’s writes are confined to the forge — it has no cluster-mutating permissions.
Reference
- Configuration →
forgefor the full key reference. - Data sources → Source repos — the App’s role in
source_diffauth. - Learning loop — the full curate/triage lifecycle.