Public
Like
min-github-app
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
This Val Town project exposes an HTTP webhook that acts as a lightweight GitHub App backend. It listens for repository creation events, verifies the webhook signature, infers the project type (Android vs. Node.js), synchronizes the required GitHub Actions secrets, and finally dispatches a bootstrap workflow in the new repository.
- Validates
POSTrequests signed withx-hub-signature-256usingGITHUB_APP_WEBHOOK_SECRET. - Confirms the repository was cloned from an approved template. If the template is unknown, it scores the repo tree for Android or Node.js indicators.
- Creates an installation-scoped Octokit client, normalizes the app private key (PKCS#1 → PKCS#8), and hydrates GitHub Actions secrets using the repo public key.
- Waits for
.github/workflows/bootstrap-action.ymlto register, enables it if necessary, and triggers a workflow dispatch on the default branch.
Set these secrets in the Val configuration before deploying:
| Variable | Description |
|---|---|
GITHUB_APP_WEBHOOK_SECRET | Shared secret used to validate incoming GitHub webhooks. |
GITHUB_APP_ID | Numeric GitHub App identifier. |
GITHUB_APP_PRIVATE_KEY | PEM string for the GitHub App private key (PKCS#1 or PKCS#8; literal newlines or \n escapes both work). |
ANDROID_ACTION_SECRETS_JSON | JSON object mapping secret names (prefixed with ANDROID_) to plaintext values for Android projects. |
NODE_ACTION_SECRETS_JSON | JSON object mapping secret names (prefixed with NPM_) to plaintext values for Node.js projects. |
Example secret JSON:
{ "ANDROID_KEYSTORE": "base64-keystore", "ANDROID_KEYSTORE_PASSWORD": "super-secret" }
- Template Mapping – Known templates (e.g.,
https://github.com/cmwen/min-android-app-template) map directly toandroid. - Repo Tree Heuristics – If the template is unknown, the handler fetches the git tree and counts indicator files:
- Android:
build.gradle,gradlew,AndroidManifest.xml, etc. - Node.js:
package.json,pnpm-lock.yaml,vite.config.ts, etc.
- Android:
- Fallback – When the score is inconclusive, type becomes
unknownand no secrets are synced.
- Pulls the repo public key via the Actions API.
- Encrypts each secret with Tweetsodium (
crypto_box_seal). - Upserts secrets using the installation token. Secret names missing the expected prefix still upload, but a warning is logged.
- Polls for
bootstrap-action.ymlregistration (up to ~60 seconds). - Enables the workflow if it is disabled.
- Dispatches the workflow once the repo is ready; otherwise responds with a 202 to allow retrying later.
- Add Templates: Update
TEMPLATE_TYPE_MAPwith new template URLs. - Add Heuristics: Extend
ANDROID_INDICATORS/NODE_INDICATORSor introduce new project types. - Add Secrets: Include additional key/value pairs in the JSON env vars. The handler will encrypt and upload everything it finds.
- Use
vt watchfor rapid iteration while sending signed webhook payloads (e.g., viacurl). - Inspect Val Town logs to confirm classification, secret sync status, and workflow dispatch attempts.
- If workflow dispatch fails with
404, ensure the workflow file exists on the default branch and that GitHub has finished initializing the repo (may take a minute on newly-created repositories).
