What
App authentication already works. src/auth/app-client.ts mints its own App JWT via Web Crypto with no dependency, exchanges it at POST /app/installations/{id}/access_tokens, and refreshes 60s before expiry. action.yml requires all three App inputs and forwards them into that path. docs/github-app-setup.md is a correct, complete checklist.
What is missing is not auth. It is that every adopting org performs that checklist by hand.
GitHub's App Manifest flow exists for exactly this: a pre-filled permissions manifest, a browser redirect, and a one-hour exchange code redeemed at POST /app-manifests/{code}/conversions which returns the App's id, private key and webhook secret. A CLI can host a transient localhost redirect for the duration of the flow — the pattern several open-source tools already use — so this stays fully serverless.
Do
A github-warden app register (name open) that:
- Renders the manifest from the permissions table in
docs/github-app-setup.md, ideally derived from the cycles the user has enabled rather than requesting the full superset. The permissions table was checked against the actual API calls in src/cycles/*.ts and is accurate; keep it as the single source.
- Opens the browser, hosts the redirect on localhost, redeems the code.
- Writes back the three values the CLI already reads, or prints them for the user's secret store. Never logs the private key.
- Leaves the webhook off. Warden polls; the checklist already says so, and a webhook-inactive App needs no callback URL and no hosted anything.
Why this and not a published App
Worth writing down so it is not revisited on a false premise.
A GitHub App has exactly one private key, and that key mints an installation token for any installation of that App. Key custody and the ability to act on every installed org are the same thing.
So the two models are:
Bring-your-own-App — what exists today. Each org registers its own App and holds its own key. No webhook, no callback, no hosted component. Fully serverless.
One published App others install. If INTENTIUS owns the App, INTENTIUS owns the key, and minting a token for a customer's installation requires something holding that key to do it for them. That is a token-broker service. "Published App, still zero hosting" is a contradiction, not a hard engineering problem — the moment INTENTIUS becomes App owner it becomes credential custodian, and custodianship implies a live service with standing access to every installed org's governance surface: org admin, membership, PAT revocation, secrets read.
Marketplace listing compounds it independently: listings must handle marketplace_purchase webhook events even when free, forcing a receiver on top of the broker. Note that a public App installable from its own page is a different, lighter thing than a Marketplace-listed one, and needs no review — the two are routinely conflated.
The decisive part: everything the App identity buys — an isolated rate-limit bucket, org-level install with per-repo scoping, audit attribution to app-slug[bot], one-hour token TTL, and the two token-governance endpoints callable only by App installations and never by PATs — is already available today under bring-your-own-App. A listing would add discoverability and a click, and would trade away per-org key custody, which is the tool's actual pitch. This issue closes the UX gap without paying that price.
Cross-repo note
The sibling wardens are getting their own native wrappers — a GitLab CI/CD Component and a Forgejo action — because neither forge has anything app-shaped. GitLab lacks an OAuth2 client-credentials grant; Forgejo has no installation concept and no OAuth2 scopes at all. This command has no counterpart in either, and that asymmetry is a forge capability gap rather than the siblings lagging.
The one thing that should stay aligned across all three is the wrapper input surface: command, config, mode, cycles, fail-on, allow-guardrail-override, with auth as the only intentional difference. action.yml here is the reference shape.
Proof
A fresh org taken from nothing to a working reconcile by one command plus a browser consent, with no value pasted by hand and the private key never written to a log.
What
App authentication already works.
src/auth/app-client.tsmints its own App JWT via Web Crypto with no dependency, exchanges it atPOST /app/installations/{id}/access_tokens, and refreshes 60s before expiry.action.ymlrequires all three App inputs and forwards them into that path.docs/github-app-setup.mdis a correct, complete checklist.What is missing is not auth. It is that every adopting org performs that checklist by hand.
GitHub's App Manifest flow exists for exactly this: a pre-filled permissions manifest, a browser redirect, and a one-hour exchange code redeemed at
POST /app-manifests/{code}/conversionswhich returns the App's id, private key and webhook secret. A CLI can host a transient localhost redirect for the duration of the flow — the pattern several open-source tools already use — so this stays fully serverless.Do
A
github-warden app register(name open) that:docs/github-app-setup.md, ideally derived from the cycles the user has enabled rather than requesting the full superset. The permissions table was checked against the actual API calls insrc/cycles/*.tsand is accurate; keep it as the single source.Why this and not a published App
Worth writing down so it is not revisited on a false premise.
A GitHub App has exactly one private key, and that key mints an installation token for any installation of that App. Key custody and the ability to act on every installed org are the same thing.
So the two models are:
Bring-your-own-App — what exists today. Each org registers its own App and holds its own key. No webhook, no callback, no hosted component. Fully serverless.
One published App others install. If INTENTIUS owns the App, INTENTIUS owns the key, and minting a token for a customer's installation requires something holding that key to do it for them. That is a token-broker service. "Published App, still zero hosting" is a contradiction, not a hard engineering problem — the moment INTENTIUS becomes App owner it becomes credential custodian, and custodianship implies a live service with standing access to every installed org's governance surface: org admin, membership, PAT revocation, secrets read.
Marketplace listing compounds it independently: listings must handle
marketplace_purchasewebhook events even when free, forcing a receiver on top of the broker. Note that a public App installable from its own page is a different, lighter thing than a Marketplace-listed one, and needs no review — the two are routinely conflated.The decisive part: everything the App identity buys — an isolated rate-limit bucket, org-level install with per-repo scoping, audit attribution to
app-slug[bot], one-hour token TTL, and the two token-governance endpoints callable only by App installations and never by PATs — is already available today under bring-your-own-App. A listing would add discoverability and a click, and would trade away per-org key custody, which is the tool's actual pitch. This issue closes the UX gap without paying that price.Cross-repo note
The sibling wardens are getting their own native wrappers — a GitLab CI/CD Component and a Forgejo action — because neither forge has anything app-shaped. GitLab lacks an OAuth2 client-credentials grant; Forgejo has no installation concept and no OAuth2 scopes at all. This command has no counterpart in either, and that asymmetry is a forge capability gap rather than the siblings lagging.
The one thing that should stay aligned across all three is the wrapper input surface:
command,config,mode,cycles,fail-on,allow-guardrail-override, with auth as the only intentional difference.action.ymlhere is the reference shape.Proof
A fresh org taken from nothing to a working reconcile by one command plus a browser consent, with no value pasted by hand and the private key never written to a log.