Skip to content

fix(signing): require active tag rulesets for release tags in the verifier - #1210

Merged
qnbs merged 3 commits into
mainfrom
fix/verify-tag-ruleset-protection
Nov 10, 2026
Merged

qnbs merged 3 commits into
mainfrom
fix/verify-tag-ruleset-protection

Conversation

@qnbs

@qnbs qnbs commented Nov 10, 2026 •

Copy link
Copy Markdown
Owner

User description

Summary

Part of #1206. Step 1 of 2: make the release-tag verifier independent of github.ref_protected.

Both release workflows require github.ref_protected == true on the v* tag push. GitHub's variables reference says that is true when rulesets apply to the ref, but community reports (discussion 142985, discussion 66588) describe it staying false for tag pushes. If that is the case on the real tag push, both verifier jobs are skipped and nothing publishes. Because release-tags-immutable has no bypass actor, the pushed tag could then not be deleted or moved, so the version would be unusable. No v* tag was created to probe this.

What changes

  • verifyRemoteTag now reads the repository's active tag rulesets (GET /rulesets?targets=tag, then one detail per active repository ruleset) and requires that creation, update, deletion and non_fast_forward are all covered for refs/tags/<tag>. Coverage may be split across rulesets.
  • It fails closed on: no ruleset, a disabled or evaluate-only ruleset, a non-tag target, an inherited ruleset whose rules cannot be read, a different include pattern, an excluded ref, unknown pattern syntax (a pattern outside a safe subset never matches an include and always counts as an exclude), a failed list request, and a list of 100 or more entries that may be truncated.
  • The check runs after the signature and protected-main ancestry checks and before the final tag ref re-read.
  • refPatternMatches is exported and tested directly.

Evidence

  • Live, read-only and unauthenticated: the real signed tag v1.29.2 passes the full verifyRemoteTag path, including the new ruleset coverage for refs/tags/v1.29.2. This also shows the check works with a low-privilege caller, which is what the workflow token is.
  • verifyRemoteTag (44) and signing (72) tests pass locally, including 11 new rejection cases, a split-ruleset acceptance case and the pattern table.

Known limit

The API hides bypass_actors from callers without admin rights, so this check cannot prove that no actor can bypass release-tags-immutable. That stays a setting a maintainer verifies with an authenticated read (done: no bypass actors on ruleset 26812769). It is documented in docs/VERIFIED-SIGNING.md.

Next step

The workflows pin the verifier to 147470682b62, so they do not run this code yet. After this merges, a second small PR moves the pin in docker.yml, tauri-build.yml, scripts/release-security-gate.mjs and the gate test to the resulting protected-main commit and drops the github.ref_protected condition. Until then the workflows keep their current conditions.

Release boundary

No tag, GitHub Release, registry push or Vercel mutation. This PR does not authorize v1.29.3.

Summary by Sourcery

Harden release-tag verification by validating complete active ruleset protection directly through the GitHub rulesets API.

Bug Fixes:

  • Require release-tag verification to confirm that active repository tag rulesets fully protect the pushed tag, rather than relying on unreliable protected-ref status.

Enhancements:

  • Fail closed when tag ruleset coverage is missing, inactive, unsupported, excluded, unreadable, or potentially truncated, while allowing protection to be distributed across multiple rulesets.

Documentation:

  • Document active tag ruleset verification and the limitation that bypass-actor validation requires an authenticated maintainer check.

Tests:

  • Add coverage for ruleset protection scenarios, safe ref-pattern matching, split ruleset coverage, and fail-closed rejection cases.

Chores:

  • Update the changelog and README test-count metrics.

Summary by cubic

Makes release-tag verification depend on active tag rulesets read directly from the rulesets API rather than github.ref_protected, which community reports say stays false for tag pushes. The verifier now requires creation, update, deletion and non-fast-forward coverage for the pushed ref and fails closed on disabled, evaluate-only, mis-targeted, excluded, or unreadable rulesets.

  • Coverage may be split across several active repository rulesets.
  • bypass_actors remains visible only to admins, so the no-bypass guarantee stays a maintainer's authenticated-read check, documented rather than enforced by the verifier.
  • Pattern syntax outside a supported safe subset, including double stars, is treated as unknown and never matches, so it cannot be used to grant or deny coverage. Matching uses an iterative glob so no pattern text reaches a regular expression.

Rollout

  • Workflows still pin the verifier to the prior commit, so release behavior is unchanged; a follow-up moves the pin and drops the github.ref_protected condition.

Written for commit 6aeb415. Summary will update on new commits.

View guided diff Turn on auto-fix


CodeAnt-AI Description

Require active tag rulesets for release verification

What Changed

  • Release-tag verification now checks active rulesets for the pushed tag instead of relying on GitHub’s protected-ref status.
  • Verification requires creation, update, deletion, and non-fast-forward protection; coverage can be split across rulesets. Missing, unreadable, or unsupported protection fails verification.

Impact

✅ Rejects release tags without full protection
✅ Accepts protection split across active rulesets
✅ Verifies tag protection when GitHub’s protected-ref status is unreliable

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Summary by CodeRabbit

  • Bug Fixes
    • Release tag verification now checks active repository rulesets to confirm the pushed tag is covered by rules for creation, updates, deletion, and non-fast-forward changes. Verification also requires the ruleset information to be fully retrieved.
  • Documentation
    • Updated the verified-signing policy to describe the tag ruleset checks and relevant visibility limitations.
    • Refreshed the README’s reported test count.

…ifier

github.ref_protected is reported as false for tag pushes even when a ruleset applies, which would skip the release verifier jobs and leave an immutable tag unusable. Read the active repository tag rulesets in the verifier and require that creation, update, deletion and non-fast-forward all cover the pushed ref, failing closed on disabled or evaluate-only rulesets, other targets, excluded refs, unknown pattern syntax and an unreadable or possibly truncated list. The workflows keep their current conditions until the pin moves to this commit.
@vercel

vercel Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
worldscript-studio Ignored Ignored Preview Nov 10, 2026 3:05am UTC

@codeant-ai

codeant-ai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

CodeAnt  CodeAnt Review Status

✅  Review completed

Status Commit Started (UTC) Finished (UTC)
✅  #0448a Reviewed your PR 675af20 Nov 10, 2026 · 02:33 02:39

@chatgpt-codex-connector

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ❌ Failed 2026-11-10T02:33:06.962995Z
We couldn’t complete this review. Comment @codex review to try again.
675af20 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@sourcery-ai

sourcery-ai Bot commented Nov 10, 2026

Copy link
Copy Markdown

Sorry @qnbs, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 1 day and 11 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@codeant-ai

codeant-ai Bot commented Nov 10, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Explain Change →

Warning

Review limit reached

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Next included review available in 27 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available. Your 72 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Learn how review limits work.

Review configuration:

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 675af20 and 6aeb415.

Files selected for processing: 2

  • scripts/signing/verify-remote.mjs
  • tests/unit/tooling/verifyRemoteTag.test.ts
Walkthrough

The tag verifier now checks active repository tag rulesets for complete coverage of tag creation, update, deletion, and non-fast-forward operations. The change adds ref-pattern matching, updates verification tests, and revises signing documentation and reported test counts.

Changes: Release tag verification

Layer / File(s) Summary
Ruleset matching and verification
scripts/signing/verify-remote.mjs, scripts/signing/verify-remote.d.mts
The verifier matches supported patterns against tag refs and requires active repository tag rulesets to collectively cover four tag operations. It rejects unreadable or potentially incomplete ruleset data.
Ruleset verification tests
tests/unit/signing.test.ts, tests/unit/tooling/verifyRemoteTag.test.ts
Mocks now provide ruleset API responses. Tests cover split and insufficient ruleset coverage, inactive or inapplicable rulesets, unreadable or potentially truncated results, and pattern matching.
Policy documentation and test counts
CHANGELOG.md, docs/VERIFIED-SIGNING.md, README.md
The changelog and signing policy describe the ruleset checks. The README updates the reported test count from 8721+ to 8725+ and retains the 656-file count.
Merge Risk: Low · previous review 675af

The release-tag verifier's glob matching may differ from GitHub's for unusual nested tag patterns. Normal single-segment release tags are unlikely to be affected. This can be fixed before or shortly after merge.

@sourcery-ai

sourcery-ai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

API

Expose the ruleset ref-pattern matcher as part of the verifier module’s interface for direct testing and use.

  • scripts/signing/verify-remote.d.mts L52
  • scripts/signing/verify-remote.mjs L100-106

Implementation

Implement fail-closed matching and ruleset coverage checks, then require complete active tag protection during remote tag verification.

  • scripts/signing/verify-remote.mjs L70-99, L107-144, L296

Documentation

Explain the verifier’s ruleset requirements and bypass-actor visibility limit, and clarify the signing snapshot table formatting.

  • CHANGELOG.md L10
  • README.md L23-1032 (4 small edits)
  • docs/VERIFIED-SIGNING.md L15-19, L66-69

Tests

Exercise ruleset API responses, complete and split protection coverage, fail-closed cases, and supported or unknown ref-pattern matching.

  • tests/unit/signing.test.ts L897-914
  • tests/unit/tooling/verifyRemoteTag.test.ts L44-87, L105-132, L296-480 (+4 small edits)

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@codeant-ai

codeant-ai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

View results CodeAnt  CodeAnt Quality Gate Results

Commit 6aeb4152 · Scanned Nov 10, 2026 at 03:05 UTC

✅  Overall Status: PASSED

Quality Gate Status Details
New code coverage ⚪  Not applicable Not applicable — no applicable code changes
Secrets ✅  Passed 0 secrets found
Duplicate code ✅  Passed 0.0% duplicated
SAST ✅  Passed No security issues
Bugs ✅  Passed Rating S · No bugs
IaC ✅  Passed No IAC issues

@codeant-ai

codeant-ai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

View results CodeAnt  CodeAnt Coverage Report

Commit 6aeb4152 · Scanned Nov 10, 2026 at 03:05 UTC

⚪  Overall Status: Not applicable

Coverage Status Details
New Code Coverage ⚪  Not applicable Not applicable — no applicable code changes

New-code coverage threshold not configured; coverage is reported but not enforced.

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Nov 10, 2026
codescene-access[bot]

This comment was marked as outdated.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 7df9f17 and 675af20.

Files selected for processing: 7

  • CHANGELOG.md
  • README.md
  • docs/VERIFIED-SIGNING.md
  • scripts/signing/verify-remote.d.mts
  • scripts/signing/verify-remote.mjs
  • tests/unit/signing.test.ts
  • tests/unit/tooling/verifyRemoteTag.test.ts

Included review availability: This review used your included allowance. 0 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Comment thread scripts/signing/verify-remote.mjs Resolved
@codeant-ai

codeant-ai Bot commented Nov 10, 2026

Copy link
Copy Markdown

CodeAnt  CodeAnt Nitpicks

1 code suggestion

1. An active inherited tag ruleset is skipped without reading its rules; when local rulesets cover all four protections, verification succeeds despite the unreadable inherited policy.

Incomplete implementation · scripts/signing/verify-remote.mjs:99

@codeant-ai

codeant-ai Bot commented Nov 10, 2026

Copy link
Copy Markdown

CodeAnt  CodeAnt PR Risk

🟢  Low Risk

  • The PR appears safe to merge; no actionable issues were identified in the review.

Assessed commit: 675af20934c7

Without a documented guarantee of how GitHub matches a double star across path separators, an include match could over-match and an exclude could under-match. Treat any pattern containing it as unknown, which never includes a ref and always excludes it, so ruleset coverage cannot depend on that semantics.
codescene-access[bot]

This comment was marked as outdated.

@github-actions

github-actions Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

[check-pr-size] PR size is over the target tier (normal profile): 7 files, 438 meaningful lines, 3 commits — limit ≤8 files / ≤400 lines / ≤6 commits. Consider splitting into smaller, independently reviewable PRs.

Comment thread scripts/signing/verify-remote.mjs Fixed
@codecov

codecov Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

…xpression

CodeQL reported incomplete escaping where the pattern was turned into a RegExp. Match the restricted pattern subset with an iterative glob matcher in which star and question mark never consume a path separator, so no pattern text reaches a regular expression.

@codescene-access codescene-access Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gates Passed
3 Quality Gates Passed

See analysis details in CodeScene

Absence of Expected Change Pattern

  • WorldScript-Studio/tests/unit/signing.test.ts is usually changed with: WorldScript-Studio/scripts/signing/signing-core.mjs

Quality Gate Profile: The Bare Minimum
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants