Skip to main content

SCM connectors

Prefer a GitHub App (org connector or platform-enforced shared App).

SettingValue
Webhook URLhttps://<public-api>/v1/webhooks/github (API host, not the UI port)
Webhook secretExact same string as GitHub App → Webhook secret (not Client secret / not App ID)

401 Unauthorized on webhook deliveries​

A 401 means the API did find a webhook secret and the HMAC failed.
If no secret is configured and you are not in production/strict mode, the API skips verification (even if GitHub sends a signature).

Local secret?ModeResult
None / emptydevAccept (log: skipping HMAC)
Noneproduction / STEW_AUTH_STRICT=1500 webhook_secret_required
Set, matches GitHubany200/202
Set, mismatchany401 invalid signature

So “I never set a secret” + 401 usually means a secret is present for the product org that owns the App / installation:

  1. Shell / IDE / Docker: GITHUB_WEBHOOK_SECRET in the same process that runs the API
  2. Org GitHub App created via Connectors / manifest (saveGitHubAppConfig) — stored under STEW_DATA_DIR as org_scm_secrets.json / scm_apps.json (per org id, often not the string "local" if you created a real org)
  3. Org Connectors → GitHub → webhookSecret
  4. Platform GitHub App config webhookSecret
  5. Manifest create: GitHub returns webhook_secret once and Codesteward persists it on the org App — you may never have typed it, but it is still configured

The API verifies against all of those candidates (env → platform → installation’s org App → local org App → connectors). A mismatch means GitHub’s current App webhook secret ≠ any of those stored values (e.g. you rotated the secret on github.com without updating Codesteward).

Fix options

A. Match secrets (recommended even for local)

  1. GitHub App → Webhook → copy Webhook secret (not Client secret).
  2. export GITHUB_WEBHOOK_SECRET='…' and restart API.
  3. Redeliver the event.

B. True “no secret” local dev

  1. Unset GITHUB_WEBHOOK_SECRET everywhere the API process gets env from.
  2. Clear connector / platform webhookSecret if set.
  3. Confirm API log on delivery: skipping HMAC verify (dev only).
  4. Do not set NODE_ENV=production or STEW_AUTH_STRICT=1 without a matching secret.

Also:

  • Point ngrok at the API (e.g. 8081), not UI (8080).
  • URL path: https://<ngrok>/v1/webhooks/github.
  • GitHub “Recent Deliveries” response body shows invalid signature vs webhook_secret_required.

Webhook events (subscribe)​

GitHub App default events (manifest + manual create) should include at least:

EventWhy
pull_requestGate reviews and merge outcomes
issue_comment@codesteward mention re-review / learning triage
pull_request_review_threadThread resolved / unresolved → soft accept / reopen of linked findings
pull_request_reviewManifest default (review submitted)
pull_request_review_commentManifest default (inline comments)
check_run / check_suiteCheck runs / status integration (manifest default)
security_advisoryExternal GHSA signal → coverage / FN candidates (eval + soft focus memory)

You do not subscribe to a separate “merge” event. Merges arrive as:

pull_request + action=closed + pull_request.merged=true

Codesteward handles that as a lightweight pr_outcome job (indirect eval / learning), not a full agent re-review.

pull_request actions we use​

ActionBehavior
opened / synchronize / reopened / ready_for_reviewEnqueue gate review (drafts skipped until ready)
closed and merged: trueEnqueue outcome analysis (address / ignore / miss candidates → consolidator)
closed unmerged, other actionsIgnored

Mentions​

SettingValue
Eventissue_comment (PR comments only)
Default token@codesteward (STEW_MENTION_TOKEN to override)
Example@codesteward review

Review threads (indirect eval)​

ActionBehavior
pull_request_review_thread + resolvedMatch finding by scmCommentId → outcome thread_resolved (soft accept); tag finding; consolidator may promote
pull_request_review_thread + unresolvedOutcome thread_unresolved; may reopen acknowledged findings

Requires Codesteward to have published the review comment (so scm_comment_id is stored). Resolved ≠ code fixed — confidence is moderate.

Security advisories (coverage / FN)​

EventBehavior
security_advisory / repository_advisory (published / updated / …)Outcome security_advisory + soft pattern memory (package / GHSA); consolidator may promote important advisories to org scope

Does not mean a user dismissed a Codesteward finding — it is an external signal for possible misses.

Permissions (repository)​

Typical App permissions (aligned with the create-from-manifest flow):

PermissionAccessWhy
ContentsReadClone / diff for review
MetadataReadRepo identity
Pull requestsWriteReview comments / publish
ChecksWriteGate check runs
StatusesWriteCommit status when checks aren’t used
IssuesReadPR-as-issue APIs / comments
Security eventsWrite (optional)SARIF → Code Scanning (enable if you publish SARIF)

Least privilege: start with the table above; add security_events: write only if you upload SARIF to GHAS.

Manifest create​

UI / API manifest registration uses MANIFEST_DEFAULT_EVENTS and MANIFEST_DEFAULT_PERMISSIONS in the product (includes pull_request + issue_comment). After create, confirm the App’s Permissions & events still lists those if you edited the App by hand.

Existing Apps created before merge-outcome support already receive closed on the pull_request event if that event is subscribed — no new event type is required. Re-check only if someone restricted delivery to a subset of actions (GitHub Apps normally deliver all actions for a subscribed event).

GitLab​

SettingValue
Webhook URLhttps://<public-api>/v1/webhooks/gitlab (or your wired path)
TriggerMerge request events
MR actionBehavior
open / update / reopenGate review
mergeOutcome analysis (pr_outcome)
OtherIgnored

Other SCM​

Org connectors support Bitbucket, Azure DevOps, and Gitea with appropriate tokens. Webhook parity for merge-outcome jobs varies; GitHub and GitLab are the primary outcome paths today.

Platform-enforced GitHub App​

Platform operators can enforce a shared GitHub App so tenants install the same App instead of pasting private App credentials. See Platform settings in the UI. Shared Apps must still subscribe to pull_request (including closed/merged) and issue_comment as above.