Add SignPath GitHub policy and raise the signing timeout - #400
Conversation
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 <noreply@anthropic.com>
ReviewScope check first: this PR only touches What it does:
Verified:
One thing worth flagging, not blocking: the policy file's schema ( No correctness, security, or convention issues found otherwise. This is also inert until merged to the default branch, matching the PR's own note, so the blast radius of a mistake here is low. |
First live run of the review workflow failed on PR #399: permission_denials_count: 10 ##[error]Execution failed: Reached maximum number of turns (20) --allowedTools REPLACES the default tool set rather than adding to it, so the resolved list was exactly the four entries I passed - no Read, Grep, or Glob. The prompt tells the reviewer "the PR branch is already checked out in the working directory", then denied it every tool needed to open a file. It spent its turns on denied calls and hit the cap without posting a review. PR #400 passed only because its diff is two small files, so it fit. Adds Read/Grep/Glob plus read-only git diff/log, and raises the cap to 40 turns since a real review needs to read several files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds the SignPath GitHub policy file and fixes the timeout that broke the v1.17.0 release.
Correction to something I said earlier
The policy file does not enable automatic approval. Having read the actual schema, it does close to the opposite kind of job: it lets SignPath impose constraints on a build before it is willing to sign it. Approval mode is a separate setting on the signing policy in the SignPath dashboard. Two different mechanisms.
What the file does
.signpath/policies/PerformanceStudio/release-signing.yml- the path is significant and must match theproject-slugandsigning-policy-slugpassed to the action inrelease.yml.That means a self-hosted runner - one an attacker registered, or one carrying dirty state between jobs - can never produce a signed build. Modest, but real, and it is true of
release.ymltoday (windows-latest).Like the Claude review workflows, this only takes effect from the default branch, so it is inert until the next
dev->mainmerge.Two fields deliberately left out
Both are documented inline in the file, because adding either without the matching repository change would break signing outright:
build.disallow_reruns: trueblocks signing any build from a workflow re-run. A re-run is currently the documented recovery path for this repo -gh release createruns before signing, so a signing failure leaves a published-but-empty release that gets fixed by re-running (all uploads use--clobber). v1.17.0 was recovered exactly that way, minutes ago. Enabling this would have made that recovery impossible.branch_rulesetsrequires the protections it names to actually exist on the branch.maincurrently has no branch protection configured at all, so any ruleset rule here would reject every signing request. Worth adding later, but branch protection has to come first.Timeout fix
The SignPath action defaults to
wait-for-completion-timeout-in-seconds: 600. With a policy that requires manual approval, that means the approval must be caught inside a 10-minute window or the job dies after the release is already public - which is precisely how v1.17.0 ended up published with only the VSIX attached. Raised to 1800s. Irrelevant once approval is automatic, harmless either way.On moving
gh release createafter signingI suggested this earlier and you pushed back that there were ordering dependencies. You were right, and I was too glib.
gh release uploadrequires the release to already exist, and the SSMS extension uploads at step 11, well before signing at step 15. So creation cannot simply move to the end without also moving that upload.There are two real options, neither included here:
vpk upload githublooks the release up by tag - so Velopack may not find it. Needs testing before trusting.Given
release.ymlcannot be exercised outside an actual release, I would rather do that deliberately than fold it into this PR.Test plan
{'github-policies': {'runners': {'require_github_hosted': True}}}release.ymlstill parses; signing timeout reads 1800mainand a release runs - policy files are read from the default branch only🤖 Generated with Claude Code