Pull request input document
Reference: every field a pull request policy rule can read.
The input document
Every evaluation builds an input document. Both subjects share a core ( is shortened here; see the release input document for its fields):
{
"version": "prodgator.input/v1",
"subject": "pull_request",
"evaluatedAt": "2026-09-29T09:35:00.000Z",
"repository": { "name": "acme/api", "id": "365246789" },
"commitSha": "9f3c1a0",
"commitSeenAt": "2026-09-29T09:31:10.000Z",
"commitAgeSeconds": 230,
"actor": { "login": "octocat", "providerUserId": "583231", "prodgatorUserId": "user_01H...", "groups": ["grp_release"], "isBot": false },
"checks": [
{ "name": "test", "source": "check_run", "app": null, "status": "completed", "conclusion": "success", "url": null }
],
"labels": ["ready"],
"attestations": [],
"workflows": {
"supported": true,
"known": true,
"settled": false,
"runs": [
{ "runId": "17004151", "workflow": "CI", "finished": true },
{ "runId": "17004152", "workflow": "Docs", "finished": false }
],
"referenced": [
{
"path": "acme/platform/.github/workflows/build.yml",
"ref": "refs/tags/v2",
"sha": "1b9e4c7d2f0a8e6b5c3d1f9a7e5c3b1d9f7a5e3c",
"runId": "17004151",
"workflow": "CI"
}
]
},
"security": null,
"approvals": [
{
"prodgatorUserId": "user_01H...",
"email": "jane@example.com",
"groups": ["group-id"],
"decision": "approved",
"at": "2026-09-29T09:20:00.000Z",
"providerLogin": "jane",
"commitSha": "9f3c1a0"
}
],
"aiAssisted": { "value": true, "tools": ["claude"], "signals": ["commit_trailer"], "current": true }
}- is or .
- is GitHub's numeric repository id, as a string. It is before Prodgator has recorded the run or pull request.
- is who started the deployment (release) or opened the pull request (pull request). is when that person has not linked their GitHub account in Prodgator. lists the approver group ids of the linked account (empty when not linked). is for a GitHub account of type or a login ending in . Inputs stored before and existed lack them. The Allowed actors rule reads .
- and are when Prodgator could not read GitHub facts.
- is when Prodgator first saw : the first evaluation of a pull request's head commit (or merge group commit), or the deployment's creation for a release. is the whole number of seconds from then to . Both are when unknown, for example in inputs stored before they existed. The Required checks rule counts its wait for checks to start from here.
- has the same fields on both subjects, including and . See the release input document for the list.
- lists the reusable workflows the subject's GitHub Actions runs called: every workflow run on for a pull request, the deployment's run for a release. It is when Prodgator could not read the runs. The Required reusable workflow rule reads it.
- holds one entry per call: is the called workflow as (a call inside the same repository gets its name in front), is the ref the caller used (, , or a commit SHA when the call is pinned), the commit the call resolved to, and and the run that made the call. and are when GitHub does not report them. At most 100 calls are listed.
- lists the runs read (at most 50), with false while a run is queued, running or waiting.
- is until a run has reported its calls: no workflow run on the commit yet, or a release whose run Prodgator recorded before it stored the calls.
- is when no more calls are expected: for a pull request, once every run on the commit has finished; for a release, once the run's calls are known (a run's calls are fixed when it starts). It stays when the list of calls was cut at 100.
- is for releases from GitLab and Bitbucket, which do not report reusable workflow calls; the lists are then empty.
- is when your plan does not include security findings, or on a pull request whose policies have no security rule, custom rules or Rego (it is only read then). Otherwise it describes the security findings of the commit compared with a baseline (see the security rule for what counts as new):
- is when a security report, a run report or (for a pull request) a GitHub source reported on the commit.
- On a GitHub or Azure Repos pull request, CI scans the temporary merge commit (). A run report from that build counts for the pull request head it tested, and only for that pull request. A scan of an earlier head does not count for a newer one.
- is the branch new findings are compared with and is (the repository's open findings) or (the open findings uploaded for another base branch).
- , and count by severity (, , , and ): the repository's open findings, the findings reported for the commit, and those that are new.
- names the scanners that reported. lists the 50 worst new findings: , , , (CVE or GHSA ids), and (or ).
- lists the sources that could not be read: , , , or .
- holds each person's latest approval or rejection given in Prodgator. is the head commit the approval was given on; for a release approval, since release approvals are per deployment rather than per commit.
- says whether the pull request is AI-assisted; it is when your plan does not include AI impact (Business and Enterprise), no policy on the pull request has an AI-assisted changes rule, custom rules or Rego (it is only read then), or the classification could not be read. is when it is. lists the AI tools found (, , , , , , , , or ). lists the kinds of evidence: (a commit message ends with an AI tool's trailer), (an AI agent authored a commit), (the description ends with such a trailer), (an AI agent account opened it), (its branch name is an AI agent's, when your organization turned that on), (one of your organization's AI labels; never on Bitbucket, which has no labels), and or (an AI vendor's own records). Labels, the author and the branch are read on every evaluation; commits a few seconds after each push. is once the commits of the head commit were read: with means not known yet. The AI-assisted changes rule reads it.
A pull request input adds these sections on top of the core:
{
"event": "pull_request",
"pullRequest": {
"provider": "github", "number": 42, "title": "Add billing", "url": "https://github.com/acme/api/pull/42",
"state": "open", "draft": false, "merged": false,
"headSha": "9f3c1a0", "headRef": "feat/billing", "headRepository": "acme/api", "isFork": false,
"baseRef": "main", "baseSha": "4f2c1e0", "association": "MEMBER", "authorType": "User",
"createdAt": "2026-09-29T08:00:00Z", "updatedAt": "2026-09-29T09:00:00Z", "mergeGroup": null
},
"reviews": {
"githubDecision": "APPROVED",
"latest": [
{ "login": "reviewer", "providerUserId": "12345", "prodgatorUserId": "user_02H...", "groups": [], "state": "APPROVED", "commitId": "9f3c1a0", "stale": false, "at": "2026-09-29T09:10:00Z", "association": "MEMBER" }
]
},
"files": { "total": 3, "additions": 42, "deletions": 5, "listed": [{ "path": "src/billing.ts", "status": "modified", "additions": 40, "deletions": 5, "previousPath": null }], "truncated": false },
"ownership": { "source": "report", "commitSha": "1b2c3d4", "files": [{ "path": "src/billing.ts", "owners": ["acme/billing"], "line": 12 }], "truncated": false },
"expectedChecks": [{ "name": "build", "integrationId": 15368, "source": "ruleset" }],
"expectedChecksKnown": true,
"pendingSuites": [{ "name": "CI", "source": "workflow_run", "app": "github-actions", "status": "completed", "conclusion": "action_required", "url": "https://github.com/acme/api/actions/runs/1" }]
}- is for a normal evaluation, or for a merge queue evaluation. then holds the merge group's own head and base.
- is true when the pull request's head repository differs from its base repository. is when GitHub reports no head repository (a deleted fork).
- mirrors GitHub's : , , or . keeps one entry per reviewer, the newest decisive review (approval, changes requested or dismissal) or, failing that, the newest comment; is true when that review was given on an earlier commit than the one being evaluated.
- is when Prodgator could not read the changed files; otherwise is true when the pull request has more files than Prodgator lists.
- lists the status checks GitHub requires on the base branch, from rulesets ( is ) and classic branch protection (), whether or not they have reported on the commit. is the GitHub App a rule pins the check to, or . Prodgator Policies is left out. is when Prodgator could not read those rules; may then be incomplete.
- lists GitHub Actions workflow runs on the commit that are queued, waiting or waiting for approval, and other apps' check suites waiting for approval. They may have no check runs in yet.
- lists, for each changed file with code owners, its owners (GitHub logins or , lower-cased, without ) and the line of the ownership file that matched, at most 300 files ( is true past that, or when the changed files are not known). is the commit whose ownership report was used: the base commit, or else the latest report for the base branch. It is when no report exists. When the report could not be read, is , is , is empty and is true. It is only read when a policy has a code owners rule, custom rules or Rego.
GitLab merge requests
A GitLab merge request produces the same document, so one policy serves both providers. is ; a custom rule or a Rego policy can branch on it. The fields are filled from GitLab as follows:
- is the merge request iid (the number in its URL); is the project path and the project id. is always and is .
- is the commit the head pipeline ran on: the merge request's head, or the merged result when the project uses merged results pipelines. stays the merge request's head.
- holds the commit statuses of that commit, one per name, newest wins: every pipeline job and any external status, with set to . A job is and ; is , or when the job allows failure; is ; and jobs (not started) are ; is ; anything queued is . Prodgator Policies is left out.
- has one entry per approver GitLab lists on the merge request (GitLab resets approvals on a push by default, so they stand for the current head), one entry per reviewer who requested changes, and for a reviewer who reviewed without a decision. is derived: when any reviewer requested changes; otherwise, when the merge request needs approvals, once none are left and until then; otherwise with at least one approver and with none.
- comes from the merge request's diffs, with additions and deletions counted from each diff.
- is empty and is true: GitLab has no required-status rules to read. is empty: every pipeline job is already in , and the pipeline itself stays running while the Prodgator Policies status is pending, so it is never waited on. It holds the head pipeline only when the commit statuses could not be read. is an empty list.
- are the merge request's labels.
- counts what the commit () introduces from security reports and run reports sent for it. GitLab has no code scanning, dependency review or secret scanning sources to read, so never lists them. As for GitHub, it is only read when a policy has a security rule, custom rules or Rego.
- is always : ownership reports come only from GitHub runs, so a code owners rule follows its When the base branch has no ownership report setting and its reason says that GitLab merge requests have no report.
Bitbucket pull requests
A Bitbucket Cloud pull request produces the same document. is . The fields are filled from Bitbucket as follows:
- is the pull request id; is and the repository UUID, braces included (). is always and is . and each review's are Bitbucket account UUIDs, which is what a linked Bitbucket account matches.
- and are the full hash of the pull request's head commit.
- holds the commit's build statuses, one per key: is and , is , is , and is , with set to . Prodgator Policies is left out.
- has one entry per participant who approved and one entry per participant who requested changes. Bitbucket lists only standing decisions, so they count for the current head. is when anyone requested changes, when anyone approved, and otherwise.
- comes from the pull request's diffstat.
- is always empty: Bitbucket pull requests have no labels.
- is empty and is true: Bitbucket's branch restrictions count builds, they do not name them. and are empty lists.
- and are filled as for GitLab merge requests: security reports and run reports only, and no ownership report.
Azure DevOps pull requests
An Azure Repos pull request produces the same document. is . The fields are filled from Azure DevOps as follows:
- is the pull request id; is and the repository GUID. is always . and each review's are Azure DevOps identity GUIDs, which is what a linked Azure DevOps account matches.
- and are the full hash of the pull request's source commit.
- holds the statuses on the pull request and on its head commit, the latest one per genre and name. is and , is and , and are , and is , with set to . prodgator/policies is left out.
- is built from reviewer votes: approved (10) and approved with suggestions (5) are , rejected (-10) is , waiting for the author (-5) is , and no vote adds nothing. A group reviewer is left out: its members vote. is when anyone rejected, when every required reviewer has voted and at least one approved (or, with no required reviewer, when anyone approved), and otherwise. Prodgator reads votes and never casts one.
- comes from the changes of the latest iteration.
- holds the pull request's labels.
- is empty and is true: Azure DevOps' status policies do not name builds the way GitHub's required checks do. and are empty lists, because Azure Pipelines report as statuses from the moment they start.
- and are filled as for GitLab merge requests: security reports and run reports only, and no ownership report.
A Rego policy that reads both subjects branches on :
package prodgator.policy
pr_result := {
"rule": "checks_pass",
"status": "pass" if count([c | some c in input.checks; c.conclusion != "success"]) == 0 else "fail",
"blocking": true,
"reason": sprintf("%d checks read", [count(input.checks)]),
}
release_result := {
"rule": "main_only",
"status": "pass" if input.release.branch == "main" else "fail",
"blocking": true,
"reason": sprintf("deploying from %v", [input.release.branch]),
}
results := [pr_result] if input.subject == "pull_request"
else := [release_result]Release policies read the same core plus a section. See Release input document.
Read a result and approve
What the Prodgator Policies check says, how a merge past a failing check is recorded, and approving a pull request in Prodgator.
Limits and GitHub API use
How many evaluations a commit costs, how Prodgator shares your GitHub rate limit, and the hard limits for pull request gates.