Update runbook and deploy skill for the registered GitHub App

Record the real App (siGit Code, ID 3492899) instead of leaving the registration section as generic setup steps, and note the webhook URL and that credentials are already in production. Correct the deployment skill: the queue database is live now that Solid Queue runs, and flag the stacking bin/jobs supervisor.

Seto Elkahfi committed Jul 5, 2026 at 22:11 UTC c82c7e37aa74091845ea571604f9b1260bf554b8
2 files changed +34 -23
.agents/skills/deployment/SKILL.md
+3 -2
index 2e71ee3..159d2ea 100644 --- a/.agents/skills/deployment/SKILL.md +++ b/.agents/skills/deployment/SKILL.md @@ -166,9 +166,10 @@ CREATE DATABASE sigitsi_production_queue OWNER sigitsi; CREATE DATABASE sigitsi_production_cable OWNER sigitsi; ``` -Owning the database lets `sigitsi` create its own tables there, so no extra `GRANT` is needed. Creating them (rather than `ALTER ROLE sigitsi CREATEDB`) keeps the app role least-privileged. The `_cache`/`_queue`/`_cable` databases stay empty by design (see below). +Owning the database lets `sigitsi` create its own tables there, so no extra `GRANT` is needed. Creating them (rather than `ALTER ROLE sigitsi CREATEDB`) keeps the app role least-privileged. `_cache`/`_cable` stay empty by design; `_queue` is live since the siGit Code GitHub App reviews shipped (see below). ## Known issues -- **The solid databases are unused.** Production sets Action Cable to the `redis` adapter (`cable.yml`), never sets `config.cache_store = :solid_cache_store`, and does not run solid_queue (no `queue_adapter`, `bin/jobs` is missing so the hook's `bin/jobs start` no-ops). So `_cache`/`_queue`/`_cable` exist only to satisfy the multi-database scaffold in `config/database.yml` and stay empty. They were created so `rake db:prepare` stops aborting and deploys self-migrate. The cleaner long-term fix is to delete the `cache`/`queue`/`cable` blocks from `config/database.yml` (all environments) so Rails manages only the primary; that removes the empty databases and the need for them to exist at all. +- **`_cache`/`_cable` are unused; `_queue` is not.** Production sets Action Cable to the `redis` adapter (`cable.yml`) and never sets `config.cache_store = :solid_cache_store`, so `_cache`/`_cable` exist only to satisfy the multi-database scaffold in `config/database.yml` and stay empty. Since the siGit Code GitHub App reviews shipped, production **does** run Solid Queue: `production.rb` sets `queue_adapter = :solid_queue` writing to the `queue` database, `bin/jobs` exists, and the hook's `bin/jobs start` starts a real supervisor. `sigitsi_production_queue` must contain the `solid_queue_*` tables — `db:prepare` loads them from `db/queue_schema.rb`; verify with `psql sigitsi_production_queue -c '\dt'`. See `docs/github-app-reviews.md`. +- **`bin/jobs` supervisors stack across deploys.** The hook starts a jobs supervisor on every push but never stops the previous one. Add `pkill -f 'solid_queue' || true` before the `bin/jobs start` line in the post-receive hook. - **Deploy hook is not fail-safe.** No `set -e`, and Puma's stdout truncates the same `output.log` that captured the deploy steps, so migration failures ship silently. Hardening it (fail on a bad `db:prepare`, log deploy output to a separate file) is worthwhile.
docs/github-app-reviews.md
+31 -21
index 94f86e6..b1f5a93 100644 --- a/docs/github-app-reviews.md +++ b/docs/github-app-reviews.md @@ -21,25 +21,26 @@ installations, plus the cached 1-hour installation token) and `github_pr_reviews` (one row per repo + PR + head SHA — the idempotency guard, and the audit trail: status, skip reason, error, comment count). -## Registering the GitHub App (one-time) - -1. GitHub → Settings → Developer settings → **GitHub Apps** → New GitHub App - (register under the org that owns the product). -2. Basics: - - Name: **siGit Code** - - Homepage URL: `https://sigit.si/code` - - Webhook URL: `https://sigit.si/github/webhooks` - - Webhook secret: generate one (`bin/rails secret | head -c 48`) and save it - for step 4. -3. Permissions and events: - - Repository permissions: **Pull requests: Read and write**, - **Contents: Read-only**, **Metadata: Read-only** (mandatory). - - Subscribe to events: **Pull request**. (`installation` and - `installation_repositories` events are always delivered to App webhooks; - there is no checkbox for them.) - - Where can this App be installed: **Any account**. -4. After creating: note the **App ID**, then **Generate a private key** - (downloads a `.pem`). +## The registered App + +The App already exists — do not create a second one. It lives under the +`getsigit` org: + +- Name: **siGit Code**, App ID **3492899** +- Public page: <https://github.com/apps/sigit-code> +- Settings: `github.com/organizations/getsigit/settings/apps/sigit-code` +- Homepage URL: `https://sigit.si/code` +- Webhook URL: `https://sigit.si/github/webhooks` +- Permissions: **Pull requests: Read and write**, **Contents: Read-only**, + **Metadata: Read-only** (mandatory) +- Subscribed events: **Pull request**. (`installation` and + `installation_repositories` are always delivered to App webhooks; there is + no checkbox for them.) + +If you ever register a replacement from scratch, mirror those settings, set +"Where can this App be installed" to **Any account**, generate a webhook +secret (`bin/rails secret | head -c 48`), and **Generate a private key** +(downloads a `.pem`) for the config below. ## Configuration @@ -49,7 +50,7 @@ user's `~/.profile`, which is single-line only: ```yaml github_app: - app_id: "123456" + app_id: "3492899" webhook_secret: "..." private_key: | -----BEGIN RSA PRIVATE KEY----- @@ -57,6 +58,14 @@ github_app: -----END RSA PRIVATE KEY----- ``` +This block is already set in production credentials (verify without booting +the app: `bin/rails runner 'c = Rails.application.credentials.github_app; puts +c.app_id, c.webhook_secret.length'`). When pasting the key, indent every PEM +line to match `private_key: |`; on the server `bin/rails credentials:edit` +needs an editor that waits, e.g. `EDITOR=nano bin/rails credentials:edit`. +Note the `webhook_secret` here is separate from `stripe.webhook_secret`; they +share a key name but live under different top-level parents. + ENV fallback (dev, or single-line values): `GITHUB_APP_ID`, `GITHUB_APP_WEBHOOK_SECRET`, and `GITHUB_APP_PRIVATE_KEY` with literal `\n` escapes in place of newlines. See `.env.example`. @@ -82,7 +91,8 @@ Solid Queue, so on the first deploy: hook starts a jobs supervisor on every deploy but never stops the previous one, so supervisors stack. Add something like `pkill -f 'solid_queue' || true` before the `bin/jobs start` line. -3. Add the App credentials (step above), restart Puma. +3. App credentials are already in production credentials (see Configuration); + restart Puma after the deploy so the new code picks them up. 4. Install the App on a test repo, open a PR, and watch: - the jobs log (`output-jobs.log`) for the review run, - the `github_pr_reviews` row (`status`, `skip_reason`, `error_message`),