Skip to content

bug: PR attestation silently truncates the commit list on GitHub, GitLab and Azure #1082

Description

@dangrondahl

Problem

kosli attest pullrequest records only the first page of a pull request's commits. Anything beyond the page limit is dropped. No error, no warning, and the payload is valid, so nothing fails — the attestation just records fewer commits than the PR contains.

Provider Limit Cause
GitHub first 100 commits(first: 100, after: $commitCursor) at internal/github/github.go:414. HasNextPage/EndCursor are selected (:411-412) but never read; the query runs once (:438-446 is a retry loop, not pagination) and pr.Commits.Nodes is passed straight through (:464).
GitLab first 20 internal/gitlab/gitlab.go:172 passes &gitlab.GetMergeRequestCommitsOptions{} with ListOptions zeroed, so no per_page is sent and GitLab applies its default of 20.
Azure first response internal/azure/azure.go:166-177 reads prCommitsResponse.Value and ignores the continuation token.
Bitbucket none Correctly follows next (internal/bitbucket/bitbucket.go:217).

GitHub's approvers have the same defect: reviews(first: 100, ...) at :421 is equally unpaginated.

Why it matters

A pull request attestation is a compliance record. A silently incomplete commit list is worse than a failed attestation: the attestation looks complete, passes server validation, and is queryable — but under-reports what actually shipped. Any policy or audit that reasons over relevant_commits inherits the gap.

The GitLab limit of 20 is low enough to hit routinely; a 25-commit MR loses 5 commits with no indication.

Reproduce

Attest any PR with more commits than the provider's limit, then compare the attestation's commits array against the PR. Counts diverge; nothing errors.

Fix

Paginate all three:

  • GitHub — loop on pageInfo.hasNextPage, feeding endCursor into $commitCursor, for both commits and reviews.
  • GitLab — set ListOptions{PerPage: 100} and follow Response.NextPage until exhausted.
  • Azure — follow the continuation token.

Add a test per provider with more commits than one page.

Scope

Every file:line above was verified by reading the code, but this has not been observed against a real PR exceeding a page limit — the truncation is established from the code paths, not from a measured under-count.

Unrelated to #1081 despite touching the same PREvidence.Commits field: that one is about the field being dropped entirely when empty, this one is about it being incomplete when large. Different fixes, different severities.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions