From b5370435aef2164cd55eae781e5746798893c827 Mon Sep 17 00:00:00 2001 From: "C. Spencer Beggs" Date: Thu, 28 May 2026 11:39:25 -0400 Subject: [PATCH 1/2] chore: update action names Signed-off-by: C. Spencer Beggs --- .github/workflows/pnpm-update.yml | 2 +- src/services/Attest.test.ts | 2 +- src/services/Attest.wrappers.test.ts | 2 +- src/utils/slsa.test.ts | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pnpm-update.yml b/.github/workflows/pnpm-update.yml index b7f0f19..d0f1462 100644 --- a/.github/workflows/pnpm-update.yml +++ b/.github/workflows/pnpm-update.yml @@ -39,7 +39,7 @@ jobs: fetch-depth: 0 - name: Setup Runtime id: runtime - uses: savvy-web/workflow-runtime-action@main + uses: savvy-web/silk-runtime-action@v1 - name: Update Config Dependencies id: update uses: savvy-web/pnpm-config-dependency-action@v1 diff --git a/src/services/Attest.test.ts b/src/services/Attest.test.ts index f3efd81..b1b9ca0 100644 --- a/src/services/Attest.test.ts +++ b/src/services/Attest.test.ts @@ -48,7 +48,7 @@ const noopOidcLayer: Layer.Layer = Layer.succeed(OidcTokenIssue const makeGitHubClientLayer = ( restResponse: { data: unknown } | undefined, - repo = { owner: "savvy-web", repo: "workflow-release-action" }, + repo = { owner: "savvy-web", repo: "silk-release-action" }, ): Layer.Layer => GitHubClientTest.layer({ restResponses: restResponse ? new Map([["repos.createAttestation", restResponse]]) : new Map(), diff --git a/src/services/Attest.wrappers.test.ts b/src/services/Attest.wrappers.test.ts index 3c8dc38..b09f1b2 100644 --- a/src/services/Attest.wrappers.test.ts +++ b/src/services/Attest.wrappers.test.ts @@ -112,7 +112,7 @@ describe("Attest.provenance — step 6", () => { const slsaPredicate = { buildDefinition: { - buildType: "https://github.com/savvy-web/workflow-release-action/release/v1", + buildType: "https://github.com/savvy-web/silk-release-action/release/v1", externalParameters: { workflow: { ref: "refs/heads/main" } }, }, runDetails: { diff --git a/src/utils/slsa.test.ts b/src/utils/slsa.test.ts index b99b97c..c951a83 100644 --- a/src/utils/slsa.test.ts +++ b/src/utils/slsa.test.ts @@ -32,7 +32,7 @@ const fullClaims: OidcClaims = { sha: "deadbeef".repeat(5), repository: "savvy-web/silk-integration", event_name: "push", - job_workflow_ref: "savvy-web/workflow-release-action/.github/workflows/release.yml@refs/heads/main", + job_workflow_ref: "savvy-web/silk-release-action/.github/workflows/release.yml@refs/heads/main", workflow_ref: "savvy-web/silk-integration/.github/workflows/release.yml@refs/heads/main", repository_id: "123456", repository_owner_id: "654321", @@ -101,7 +101,7 @@ describe("buildSLSAProvenancePredicate — step 8a", () => { digest: { gitCommit: "deadbeef".repeat(5) }, }); expect(predicate.runDetails.builder.id).toBe( - "https://github.com/savvy-web/workflow-release-action/.github/workflows/release.yml@refs/heads/main", + "https://github.com/savvy-web/silk-release-action/.github/workflows/release.yml@refs/heads/main", ); expect(predicate.runDetails.metadata.invocationId).toBe( "https://github.com/savvy-web/silk-integration/actions/runs/987654/attempts/1", @@ -128,7 +128,7 @@ describe("buildSLSAProvenancePredicate — step 8a", () => { "https://github.example.com/savvy-web/silk-integration", ); expect(predicate.runDetails.builder.id).toBe( - "https://github.example.com/savvy-web/workflow-release-action/.github/workflows/release.yml@refs/heads/main", + "https://github.example.com/savvy-web/silk-release-action/.github/workflows/release.yml@refs/heads/main", ); }); From c096e2e575a21a16941c1d513c5b794858d08d4e Mon Sep 17 00:00:00 2001 From: "C. Spencer Beggs" Date: Thu, 28 May 2026 16:26:56 -0400 Subject: [PATCH 2/2] fix: accept null in WebhookPayload string fields GitHub webhook payloads carry body, html_url, and full_name as null when the issue or PR has no description. The schema previously only allowed string or undefined, so ActionEnvironment.payload failed on real pull_request events. Switch the affected optional fields to optional NullOr String. Signed-off-by: C. Spencer Beggs --- .changeset/webhook-payload-null-fields.md | 7 +++++++ src/schemas/EventPayload.test.ts | 18 ++++++++++++++++++ src/schemas/EventPayload.ts | 13 +++++++++---- 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 .changeset/webhook-payload-null-fields.md diff --git a/.changeset/webhook-payload-null-fields.md b/.changeset/webhook-payload-null-fields.md new file mode 100644 index 0000000..d95f969 --- /dev/null +++ b/.changeset/webhook-payload-null-fields.md @@ -0,0 +1,7 @@ +--- +"@savvy-web/github-action-effects": patch +--- + +## Bug Fixes + +- Accept `null` in `WebhookPayload`'s `IssueRef.body`, `IssueRef.html_url`, `Repository.full_name`, and `Repository.html_url` fields. GitHub webhook payloads carry these as `null` (not absent) when the issue or PR has no description, or when an event payload omits the rendered URL. Previously decoding any such payload through `ActionEnvironment.payload` failed with `ActionEnvironmentError: Event payload did not match the expected shape: WebhookPayload — Expected string, actual null`. diff --git a/src/schemas/EventPayload.test.ts b/src/schemas/EventPayload.test.ts index 6bca976..b60518a 100644 --- a/src/schemas/EventPayload.test.ts +++ b/src/schemas/EventPayload.test.ts @@ -14,6 +14,24 @@ describe("WebhookPayload", () => { expect(result.repository?.owner.login).toBe("owner"); }); + it("decodes a pull_request with null body and null html_url", () => { + const result = decode({ + pull_request: { number: 7, body: null, html_url: null }, + }); + expect(result.pull_request?.number).toBe(7); + expect(result.pull_request?.body).toBeNull(); + expect(result.pull_request?.html_url).toBeNull(); + }); + + it("decodes a repository with null full_name and null html_url", () => { + const result = decode({ + repository: { name: "repo", full_name: null, html_url: null, owner: { login: "owner" } }, + }); + expect(result.repository?.name).toBe("repo"); + expect(result.repository?.full_name).toBeNull(); + expect(result.repository?.html_url).toBeNull(); + }); + it("decodes an issues payload", () => { const result = decode({ issue: { number: 12 } }); expect(result.issue?.number).toBe(12); diff --git a/src/schemas/EventPayload.ts b/src/schemas/EventPayload.ts index eb173bc..ccbeba2 100644 --- a/src/schemas/EventPayload.ts +++ b/src/schemas/EventPayload.ts @@ -7,20 +7,25 @@ import { Schema } from "effect"; */ const Repository = Schema.Struct({ name: Schema.String, - full_name: Schema.optional(Schema.String), + full_name: Schema.optional(Schema.NullOr(Schema.String)), owner: Schema.Struct({ login: Schema.String }), - html_url: Schema.optional(Schema.String), + html_url: Schema.optional(Schema.NullOr(Schema.String)), }); /** * An issue / pull-request reference on a webhook payload (typed subset). * + * @remarks + * `body` and `html_url` accept `null` because GitHub webhook payloads carry + * those fields as `null` (not absent) when the issue or PR has no description, + * or for events whose payload omits the rendered URL. + * * @internal */ const IssueRef = Schema.Struct({ number: Schema.Number, - html_url: Schema.optional(Schema.String), - body: Schema.optional(Schema.String), + html_url: Schema.optional(Schema.NullOr(Schema.String)), + body: Schema.optional(Schema.NullOr(Schema.String)), }); /**