Skip to content

fix(ci): resolve premerge distro validation PR identity for fork PRs - #95

Merged
Bjordis Collaku (bjordiscollaku) merged 1 commit into
mainfrom
fix/fork-pr-identity-resolution
Aug 28, 2026
Merged

fix(ci): resolve premerge distro validation PR identity for fork PRs#95
Bjordis Collaku (bjordiscollaku) merged 1 commit into
mainfrom
fix/fork-pr-identity-resolution

Conversation

@bjordiscollaku

Copy link
Copy Markdown
Contributor

Problem

The premerge distro validation chain identifies the pull request behind a
completed kernel build by calling
GET /repos/{owner}/{repo}/commits/{sha}/pulls
with the triggering commit SHA. That endpoint reliably resolves commits
that live on a real branch inside this repository, but does not reliably
resolve commits that only exist on a fork, since those are reachable in
this repository solely through the hidden refs/pull/<n>/head ref, never
through an actual branch.

This surfaced on PR #90,
a real fork PR opened specifically to exercise this chain end to end. Its
premerge kernel build succeeded and correctly triggered the
workflow_run orchestrator, but that orchestrator then failed identity
resolution:

Expected exactly one resolute-qcom-devel pull request for c1f7ae78...; found 0.

c1f7ae78... was, at that exact moment, the current head commit of an
open pull request. I verified this two ways before writing the fix:

  1. Calling commits/{sha}/pulls directly against that exact SHA returns
    an empty array.
  2. Calling it against the fork's own underlying commit (the one before
    the merge commit that PR head sha pointed at) also returns an empty
    array, confirming this is not specific to merge commits created via
    "Update branch"; it is a general limitation for any commit whose only
    presence in this repository is the hidden pull ref.

Fix

Replace the commit-to-pull-request reverse lookup with a direct query:
list open pull requests against resolute-qcom-devel with
GET /pulls?state=open&base=resolute-qcom-devel and match on
head.sha client-side. This depends only on the Pulls API, which
behaves identically for same-repo and fork-originated pull requests, and
avoids the commit-association index entirely.

Applied to both call sites that had this pattern:

  • scripts/resolve-distro-validation-context.sh: the workflow_run path
    that resolves which PR a completed kernel build belongs to.
  • scripts/validate-distro-validation-callback.sh: the
    repository_dispatch callback path, which independently re-derives the
    same identity as a security cross-check against the untrusted callback
    payload rather than trusting the claimed pr_number outright. That
    cross-check is preserved; only the lookup mechanism underneath it
    changes.

Also moved head_sha format validation in
resolve-distro-validation-context.sh ahead of its first use, so a
malformed value is rejected before being interpolated into any command
rather than after.

Validation

Ran the new query live against the real API for the exact commit that
previously returned zero results:

$ gh api --paginate "repos/qualcomm-linux/pkg-linux-qcom-canonical/pulls" \
    -H "Accept: application/vnd.github+json" -X GET \
    -f state=open -f base=resolute-qcom-devel \
  | jq -s --arg sha "c1f7ae783694a757983f1d230a56e33a61f6faa5" \
    '[.[][] | select(.head.sha == $sha)] | length, .[0].number'
1
90

One match, PR #90. bash -n passes clean on both scripts.

Self-test plan

workflow_run-triggered jobs always execute the workflow and any
checked-out helper scripts from this repository's default branch, never
from the ref that triggered the run. That is the trust boundary that
lets this orchestrator run with elevated permissions against
fork-triggered events safely. So this fix cannot be exercised before it
lands on main, regardless of which repository proposes it.

Once this merges, I will re-trigger PR #90's premerge build (it is still
open, still a real fork PR) so a fresh workflow_run completion event
fires against the fixed script, and confirm the orchestrator resolves
PR #90's identity correctly end to end. I will report the live result on
this PR.

Both the workflow_run orchestrator and the repository_dispatch callback
handler identify the originating pull request by calling GET
/commits/{sha}/pulls with the triggering commit SHA. That endpoint does
not reliably resolve commits that only exist on a fork: such commits
are reachable in this repository solely through the hidden
refs/pull/<n>/head ref, never through an actual branch, and GitHub's
commit-to-pull-request association does not cover that case.

This surfaced on pull request #90, a real fork PR opened specifically
to exercise this chain. Its premerge kernel build succeeded and
correctly triggered the workflow_run orchestrator, but the orchestrator
then failed identity resolution with "found 0" pull requests for a
commit that was, in fact, the current head of an open PR.

- List open pull requests against resolute-qcom-devel directly with GET
  /pulls?state=open&base=resolute-qcom-devel and match on head.sha
  instead of relying on the commit-to-pull-request association. This
  works identically for same-repo and fork-originated pull requests.
- Apply the same fix to both call sites: resolve-distro-validation-context.sh
  (workflow_run path) and validate-distro-validation-callback.sh
  (repository_dispatch callback path), which independently re-derives
  the same identity as a security cross-check against the callback
  payload.
- Move head_sha format validation ahead of its first use in
  resolve-distro-validation-context.sh.

Verified live against the real API: the new query returns exactly one
match, PR #90, for the exact commit that the old query returned zero
results for.

Signed-off-by: Bjordis Collaku <bcollaku@qti.qualcomm.com>
@bjordiscollaku
Bjordis Collaku (bjordiscollaku) merged commit 946555b into main Aug 28, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants