From e8211b6051d31856b7283e159e4a9d54a02c49b9 Mon Sep 17 00:00:00 2001 From: Erik Darling <2136037+erikdarlingdata@users.noreply.github.com> Date: Sat, 25 Jul 2026 12:01:27 -0400 Subject: [PATCH] Add SignPath GitHub policy and raise the signing timeout Policy (.signpath/policies/PerformanceStudio/release-signing.yml): Path must match the project-slug and signing-policy-slug passed to the SignPath action in release.yml. Only takes effect from the default branch (main), so it is inert until the next dev -> main merge. It requires GitHub-hosted runners, so a self-hosted runner - which an attacker could register, or which could carry dirty state between jobs - can never produce a signed build. Note this file does NOT enable automatic approval; approval mode is a setting on the signing policy in the SignPath dashboard. This file adds constraints SignPath enforces before it will sign. Two fields are deliberately omitted, documented inline, because adding them without the matching repo change would break signing outright: - build.disallow_reruns would have blocked the v1.17.0 recovery, since re-running is the current remedy for a signing failure that already published an empty release. - branch_rulesets requires the protections it names to actually exist, and main currently has no branch protection at all, so any ruleset rule would reject every signing request. Timeout (release.yml): the SignPath action defaults to 600s, so a policy requiring manual approval must be approved inside 10 minutes or the job fails after the release is already published - which is exactly how v1.17.0 ended up public with only the VSIX attached. Raised to 1800s. Co-Authored-By: Claude Fable 5 --- .github/workflows/release.yml | 6 +++ .../PerformanceStudio/release-signing.yml | 40 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 .signpath/policies/PerformanceStudio/release-signing.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 250d5aa..37183af 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -159,6 +159,12 @@ jobs: github-artifact-id: '${{ steps.upload-unsigned.outputs.artifact-id }}' wait-for-completion: true output-artifact-directory: 'signed/win-x64' + # The action's 600s default means a signing policy that requires manual + # approval has to be approved inside a 10-minute window or the release + # fails partway, leaving a published release with no app assets (this + # happened on v1.17.0). 30 minutes is enough to notice the mail and + # approve. Irrelevant once approval is automatic, but harmless. + wait-for-completion-timeout-in-seconds: 1800 - name: Replace unsigned Windows build with signed shell: pwsh diff --git a/.signpath/policies/PerformanceStudio/release-signing.yml b/.signpath/policies/PerformanceStudio/release-signing.yml new file mode 100644 index 0000000..5417e2d --- /dev/null +++ b/.signpath/policies/PerformanceStudio/release-signing.yml @@ -0,0 +1,40 @@ +# SignPath GitHub policy for the "release-signing" signing policy. +# +# Path is significant and must match the SignPath project + policy slugs used in +# .github/workflows/release.yml: +# project-slug: PerformanceStudio +# signing-policy-slug: release-signing +# +# This file only takes effect from the repository's DEFAULT branch (main). On any +# other branch it is inert, so changes here do nothing until they are merged to +# main via the usual dev -> main release merge. +# +# What this file does NOT do: it does not enable automatic approval. Approval mode +# lives on the signing policy in the SignPath dashboard. This file adds constraints +# that SignPath enforces on a build before it is willing to sign it. + +github-policies: + runners: + # release.yml runs on `windows-latest`. Requiring GitHub-hosted runners means a + # self-hosted runner (which an attacker could register, or which could carry + # dirty state between jobs) can never produce a signed build. + require_github_hosted: true + +# Deliberately omitted, with reasons - do not add these without the matching +# repository change, or releases will start failing to sign: +# +# build.disallow_reruns: true +# Blocks signing any build produced by a workflow re-run. A re-run is +# currently the documented recovery path for this repo: `gh release create` +# runs before signing, so a signing failure leaves a published-but-empty +# release that is fixed by re-running (all uploads use --clobber). v1.17.0 +# was recovered exactly this way. Enabling this would make that recovery +# impossible. Revisit only if release.yml is restructured so a failed +# signing never publishes anything. +# +# branch_rulesets: +# Requires the protections it lists to actually exist on the branch. `main` +# currently has NO branch protection configured at all, so any ruleset +# requirement here would reject every signing request. Add protection to +# `main` first (e.g. block force pushes, require PRs), then encode the same +# rules here so SignPath verifies they were in force.