Skip to main content

The App is installed. The check is not a gate yet.

Installing the GitHub App posts CodeRifts / issuer. Until branch protection requires that check and the reader job name CodeRifts / contract-gate, a red result does not stop a merge. The check stays advisory. The reader is the required check; the App is the second, issuer-side context.

1

Require the check

Two required contexts. Miss one and the merge is not the gate. Measured 2026-10-11 on coderifts/demo: ruleset 22074842 alone, enforcement active, bypass_actors empty, required checks CodeRifts / issuer (2860592) and CodeRifts / contract-gate (15368). Classic branch protection is deleted: GET /repos/coderifts/demo/branches/main/protection answers 404 Branch not protected. The template job name is the context.

  1. Reader. The context is CodeRifts / contract-gate, GitHub Actions, app id 15368. The template job name is the context. The Actions issuer is shared, so the app id does not name which workflow ran.
  2. Issuer. The context is CodeRifts / issuer, the CodeRifts App, app id 2860592 (GET /apps/coderifts). The reader is the required check; the App is the second, issuer-side context.
  3. Bypass empty. On classic branch protection, enforce_admins is on. In the UI: Settings → Branches → the rule for the default branch → Include administrators. On a ruleset, bypass_actors is empty. The reader may be on either surface. Measured 2026-10-11 on coderifts/demo: ruleset 22074842 is active, bypass_actors is empty, and classic branch protection is deleted (GET /repos/coderifts/demo/branches/main/protection answers 404 Branch not protected). enforce_admins is absent from the ruleset response. An admin override is refused with “2 of 2 required status checks are failing.”

Replace the old App-bound CodeRifts / contract-gate row with CodeRifts / issuer. Left in place, that row stays expected. The checks[] form is what stores app_id. The legacy contexts[] form cannot.

gh api -X PUT repos/OWNER/REPO/branches/main/protection \
  -H "Accept: application/vnd.github+json" --input - <<'JSON'
{
  "required_status_checks": {
    "strict": false,
    "checks": [
      { "context": "CodeRifts / contract-gate", "app_id": 15368 },
      { "context": "CodeRifts / issuer", "app_id": 2860592 }
    ]
  },
  "enforce_admins": true,
  "required_pull_request_reviews": null,
  "restrictions": null
}
JSON

Read it back. An app_id of null means the binding did not take. strict is left false here on purpose: the check is the gate, not a rebase. This call replaces the protection object; read the current rule first if the branch already has other required checks. Measured 2026-10-11 on coderifts/demo, that classic protection call is not the live surface: GET /repos/coderifts/demo/branches/main/protection answers 404 Branch not protected. The live surface is ruleset 22074842.

2

Open a pull request that changes a contract

Without a grant the check is red. A config-only change is green. The public examples are demo pull request #4 (a contract change) and demo pull request #22 (config only).

the reader verifies the receipt offline; the demo's PR #4 is red on both contexts

3

Verify one decision yourself

Take the receipt off the check and verify it on /verify/. The page checks the signature offline. A green check on GitHub is not that verification.

.coderifts.yml names the contract artifacts to track. Policy keys do not move the grant. A grant is the signed receipt for one operation on one change, not a key in that file. contract_artifacts: none suppresses a comment when a repository has no contract artifact. It does not change what the check concludes (src/config-parser.js).

Back to coderifts.com

Need help? Contact hello@coderifts.com