Skip to content

Hash collisions in GraphQL aliases in success lifecycle #1116

@smorrisods

Description

@smorrisods

I ran into an interesting failure in our CI pipeline when the success lifecycle of the semantic-release/github plugin ran the other day. It didn't block our release but left the PR and issue updates incomplete. The error surfaced was:

Error: Field 'commit429fa6' has an argument conflict: {oid:"/"429fa60a84f7b59f9e4a20bfbea6b0fa977a1e1e/""} or {oid:"/"429fa667b462b60b31769e5268cfbc6835793c14/""}

This occurred due to two different commits within the release we were making sharing the same first 6 characters of their SHA (429fa6). It turns out the query builder, which builds the query to pass to GitHub's API, uses the first 6 characters of the SHA to create GraphQL aliases:

commit${sha.slice(0, 6)}: object(oid: "${sha}") { ... }

This code is located at Line 460 in success.js.

Our CI pipeline failure

Background

This behaviour was introduced in PR #857, which rewrote the success lifecycle to use GitHub’s GraphQL API for better rate-limit handling.

The intention behind truncating to 6 characters was likely to keep aliases short and readable, but it introduces collisions in real-world repositories. As commits within a repo increase there is a higher likelihood of collision due to the birthday paradox effect.

In our case, we had a number of rapid changes occur and a larger than normal amount of commits generated that all wound up in the same release.

I ran some analysis on our repository of 2,724 commits (at the time of writing) and discovered we have two collision pairs of commits when considering the first 6 characters of the SHA. The first collision pair contains two commits two years apart. The offending collision pair that surfaced this issue contains two commits a few weeks apart.

Impact

  • GraphQL requires unique aliases for fields with different arguments.
  • When two commits share the same prefix, the query fails with an argument conflict error from the GitHub GraphQL API.
  • This breaks the success lifecycle and prevents associated PRs from being fetched.

Proposed Fix

Use a longer short SHA prefix, ≥7–12 chars. GitHub uses 7 digit short SHAs, however the longer the slice the smaller the collision space is.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions