Skip to content

Private pilot GitHub App event bridge

The App bridge is an optional server-side adapter. It does not replace the local markdown record and it does not use a developer's gh session. The reference package is internal/githubapp; deployments supply HTTPS and a GitHub API client around it.

Pilot App registration

Create a private GitHub App owned by the pilot organization, install it only on selected repositories, and use the manifest in examples/github-app-manifest.json. Its complete repository permission set is:

Permission Access Why
Metadata read GitHub-mandatory repository identity used in installation/repository reconciliation
Issues read receive issue and issue-comment proposal events
Pull requests read receive pull-request proposal events
Checks read and write upsert the allowlisted dacli status check

Do not grant Contents, Administration, Actions, Members, Secrets, or any organization permission. The implemented remote write is only POST /repos/{owner}/{repo}/check-runs; UpsertCheck uses the outbox idempotency key as a remote marker. Reconciliation reads the installation and its selected repositories. Expanding the adapter to edit issues or pull requests requires a separate permission and disclosure review.

The server stores the App private key and mints short-lived installation tokens inside its GitHub client. Neither is an adapter configuration field, proposal, outbox value, log payload, nor local-client response. Local clients exchange only signed control-plane envelopes from contracts/controlplane/v1.

Delivery and recovery

The HTTPS handler passes the untouched request to Bridge.Ingest. It reads the raw body once, verifies X-Hub-Signature-256 with HMAC-SHA256, and only then parses or persists it. X-GitHub-Delivery is the inbox idempotency identity. A duplicate with identical content is acknowledged without duplicating its effect; reuse with different content is rejected. The inbox commit precedes the proposal write, so a retry repairs a crash between the two.

Inbound issue, comment, and pull-request data is reduced to an attributed, closed proposal record. The package imports no workspace, store, execution, or feature package and exposes no command callback. Applying a proposal remains a local owner action under dacli's normal grant rules.

Outbound StatusUpdate is a closed metadata structure. It has no fields for source, prompts, transcripts, environment, secrets, credentials, or raw command output. An immutable outbox record is acknowledged separately after an idempotent check upsert. Dispatch re-checks the installation, tenant, repository, and current checks:write grant immediately before the remote call.

Run reconciliation periodically and after every installation, installation_repositories, and repository webhook. GitHub's current view is authoritative for suspension/removal, selected-repository membership, rename, and permissions; local tenant/project assignment is never expanded from remote input. This makes retries, redelivery, permission changes, rename/removal, and out-of-order webhook arrival converge. A suspended or removed installation is refused both at ingress and immediately before dispatch.