From e0cd823ace5d101ab10e98e270f2ec60f6130f84 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Mar 2026 14:14:57 +0000 Subject: [PATCH 1/2] Initial plan From af15f0c6a8da23a7fad65b79d610c3bc27969acb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Mar 2026 14:34:15 +0000 Subject: [PATCH 2/2] Fix TrustSignal verification failures: zero-SHA push, accept header, check_suite detailsUrl Co-authored-by: chrismaz11 <24700273+chrismaz11@users.noreply.github.com> --- apps/action/dist/index.js | 6 +- src/trustsignal/client.ts | 1 + src/trustsignal/github.ts | 10 ++- tests/normalizeEvent.test.ts | 105 ++++++++++++++++++++++++++++++++ tests/trustsignalClient.test.ts | 1 + 5 files changed, 119 insertions(+), 4 deletions(-) diff --git a/apps/action/dist/index.js b/apps/action/dist/index.js index 0f904f2..b5b977e 100644 --- a/apps/action/dist/index.js +++ b/apps/action/dist/index.js @@ -4175,6 +4175,7 @@ var TrustSignalVerificationClient = class { method: "POST", headers: { "content-type": "application/json", + "accept": "application/json", authorization: `Bearer ${this.apiKey}` }, body: payloadText, @@ -4296,11 +4297,12 @@ function normalizeReleasePayload(payload) { } }; } +var ZERO_SHA = "0000000000000000000000000000000000000000"; function normalizePushPayload(payload) { const repository = payload.repository; const ref = String(payload.ref || ""); const branchName = ref.replace("refs/heads/", ""); - if (branchName && repository.default_branch && branchName !== repository.default_branch) { + if (branchName && repository.default_branch && branchName !== repository.default_branch || !payload.after || payload.after === ZERO_SHA) { return null; } return { @@ -4342,7 +4344,7 @@ function normalizeCheckSuitePayload(payload) { headSha, externalId: `check_suite:${checkSuite.id}`, summaryContext: `check suite ${checkSuite.id}`, - detailsUrl: checkSuite.url, + detailsUrl: checkSuite.html_url || `${repository.html_url}/commit/${headSha}`, provenance: { action: payload.action, checkSuiteStatus: checkSuite.status, diff --git a/src/trustsignal/client.ts b/src/trustsignal/client.ts index 8efbce9..6924197 100644 --- a/src/trustsignal/client.ts +++ b/src/trustsignal/client.ts @@ -56,6 +56,7 @@ export class TrustSignalVerificationClient { method: "POST", headers: { "content-type": "application/json", + "accept": "application/json", authorization: `Bearer ${this.apiKey}`, }, body: payloadText, diff --git a/src/trustsignal/github.ts b/src/trustsignal/github.ts index 1081aad..3c62d97 100644 --- a/src/trustsignal/github.ts +++ b/src/trustsignal/github.ts @@ -79,12 +79,18 @@ export function normalizeReleasePayload(payload: Record): GitHubVer }; } +const ZERO_SHA = "0000000000000000000000000000000000000000"; + export function normalizePushPayload(payload: Record): GitHubVerificationEnvelope | null { const repository = payload.repository; const ref = String(payload.ref || ""); const branchName = ref.replace("refs/heads/", ""); - if (branchName && repository.default_branch && branchName !== repository.default_branch) { + if ( + (branchName && repository.default_branch && branchName !== repository.default_branch) || + !payload.after || + payload.after === ZERO_SHA + ) { return null; } @@ -137,7 +143,7 @@ export function normalizeCheckSuitePayload(payload: Record): GitHub headSha, externalId: `check_suite:${checkSuite.id}`, summaryContext: `check suite ${checkSuite.id}`, - detailsUrl: checkSuite.url, + detailsUrl: checkSuite.html_url || `${repository.html_url}/commit/${headSha}`, provenance: { action: payload.action, checkSuiteStatus: checkSuite.status, diff --git a/tests/normalizeEvent.test.ts b/tests/normalizeEvent.test.ts index ff9e3b0..0b4afaf 100644 --- a/tests/normalizeEvent.test.ts +++ b/tests/normalizeEvent.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from "vitest"; import { normalizeWorkflowRunEvent } from "../src/webhooks/handlers/workflowRun"; +import { normalizePushPayload, normalizeCheckSuitePayload } from "../src/trustsignal/github"; describe("normalizeWorkflowRunEvent", () => { it("normalizes a completed workflow run", () => { @@ -29,3 +30,107 @@ describe("normalizeWorkflowRunEvent", () => { expect(job?.headSha).toBe("abc123"); }); }); + +describe("normalizePushPayload", () => { + it("returns null for branch deletion events (zero SHA)", () => { + const result = normalizePushPayload({ + ref: "refs/heads/main", + before: "abc1234def5678901234567890abcdef12345678", + after: "0000000000000000000000000000000000000000", + repository: { + name: "repo", + default_branch: "main", + html_url: "https://github.com/acme/repo", + owner: { login: "acme" }, + }, + }); + + expect(result).toBeNull(); + }); + + it("returns null when after is missing", () => { + const result = normalizePushPayload({ + ref: "refs/heads/main", + before: "abc1234def5678901234567890abcdef12345678", + repository: { + name: "repo", + default_branch: "main", + html_url: "https://github.com/acme/repo", + owner: { login: "acme" }, + }, + }); + + expect(result).toBeNull(); + }); + + it("returns an envelope for a default-branch push with a valid SHA", () => { + const result = normalizePushPayload({ + ref: "refs/heads/main", + before: "abc1234def5678901234567890abcdef12345678", + after: "def5678abc1234901234567890abcdef12345678", + repository: { + name: "repo", + default_branch: "main", + html_url: "https://github.com/acme/repo", + owner: { login: "acme" }, + }, + }); + + expect(result).not.toBeNull(); + expect(result?.headSha).toBe("def5678abc1234901234567890abcdef12345678"); + expect(result?.externalId).toBe("push:def5678abc1234901234567890abcdef12345678"); + }); +}); + +describe("normalizeCheckSuitePayload", () => { + it("uses html_url for detailsUrl when available", () => { + const result = normalizeCheckSuitePayload({ + action: "requested", + check_suite: { + id: 321, + head_sha: "def5678abc1234901234567890abcdef12345678", + status: "queued", + conclusion: null, + html_url: "https://github.com/acme/repo/actions/runs/321", + url: "https://api.github.com/repos/acme/repo/check-suites/321", + app: { slug: "some-app" }, + pull_requests: [], + }, + repository: { + id: 1, + name: "repo", + default_branch: "main", + html_url: "https://github.com/acme/repo", + owner: { login: "acme" }, + }, + }); + + expect(result).not.toBeNull(); + expect(result?.detailsUrl).toBe("https://github.com/acme/repo/actions/runs/321"); + }); + + it("falls back to commit URL for detailsUrl when html_url is absent", () => { + const result = normalizeCheckSuitePayload({ + action: "requested", + check_suite: { + id: 654, + head_sha: "abc1234def5678901234567890abcdef12345678", + status: "queued", + conclusion: null, + url: "https://api.github.com/repos/acme/repo/check-suites/654", + app: { slug: "some-app" }, + pull_requests: [], + }, + repository: { + id: 1, + name: "repo", + default_branch: "main", + html_url: "https://github.com/acme/repo", + owner: { login: "acme" }, + }, + }); + + expect(result).not.toBeNull(); + expect(result?.detailsUrl).toBe("https://github.com/acme/repo/commit/abc1234def5678901234567890abcdef12345678"); + }); +}); diff --git a/tests/trustsignalClient.test.ts b/tests/trustsignalClient.test.ts index 32ef252..31dd3bd 100644 --- a/tests/trustsignalClient.test.ts +++ b/tests/trustsignalClient.test.ts @@ -56,6 +56,7 @@ describe("TrustSignalVerificationClient", () => { method: "POST", headers: expect.objectContaining({ authorization: "Bearer secret", + "accept": "application/json", }), }) );