Skip to content

fix(ci): reject unsafe release dispatch tags#249

Open
MikeTomlin19 wants to merge 3 commits into
Gitlawb:mainfrom
MikeTomlin19:agent/harden-release-tag-239
Open

fix(ci): reject unsafe release dispatch tags#249
MikeTomlin19 wants to merge 3 commits into
Gitlawb:mainfrom
MikeTomlin19:agent/harden-release-tag-239

Conversation

@MikeTomlin19

@MikeTomlin19 MikeTomlin19 commented Jul 25, 2026

Copy link
Copy Markdown

Summary

Reject unsafe manual release tags before writing them to $GITHUB_OUTPUT, preventing multiline input from injecting additional step outputs.

Motivation & context

The existing v[0-9]* shell pattern is a prefix check, not a complete validation rule, and echo "tag=$TAG" writes embedded newlines verbatim. A crafted workflow_dispatch tag can therefore add attacker-controlled output keys consumed by later release steps.

Closes #239

Kind of change

  • Bug fix
  • Feature
  • Security fix
  • Docs
  • Tests / CI
  • Refactor (no behavior change)
  • Breaking or protocol change (issue required first)

What changed

  • Moved tag resolution into one shared, allowlist-validating helper used by all three release jobs.
  • Rejects empty, multiline, whitespace-containing, and shell-metacharacter inputs before any output is written.
  • Uses printf for the validated tag and version outputs.
  • Preserves the existing v[0-9]* release-tag shape check.
  • Added executable valid/newline/empty/whitespace/metacharacter/bad-shape regression cases and a blocking PR-check job that runs them.

How a reviewer can verify

scripts/test-resolve-release-tag.sh

go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.7 \
  -ignore 'label "macos-15-intel" is unknown' \
  .github/workflows/release.yml .github/workflows/pr-checks.yml

The regression script verifies that v1.2.3 writes exactly tag=v1.2.3 and version=1.2.3, while empty, multiline, whitespace-containing, shell-metacharacter, and bad-shape inputs fail before writing any output. It also asserts that all three release jobs call the tested resolver.

Before you request review

  • Scope is one logical change; no unrelated churn
  • cargo test --workspace passes locally (Rust sources are unchanged)
  • New behavior is covered by validation cases
  • cargo fmt --all and cargo clippy --workspace --all-targets -- -D warnings are clean (Rust sources are unchanged)
  • Commit titles use Conventional Commits (feat(...), fix(...), docs(...))
  • Docs / .env.example updated if behavior or config changed (N/A)
  • Checked existing PRs so this isn't a duplicate

Protocol & signing impact

N/A — this does not change identity, signatures, UCANs, ref certificates, or P2P wire formats.

Notes for reviewers

The ignored Actionlint diagnostic is an existing repository baseline: Actionlint 1.7.7 does not recognize GitHub's macos-15-intel runner label. With that unrelated diagnostic ignored, the workflow is clean.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a shared Bash script for validating and resolving release tags, updates Docker and npm release jobs to use it, and adds PR checks covering valid, empty, and multiline inputs plus workflow usage counts.

Changes

Release tag validation

Layer / File(s) Summary
Resolver validation and tests
scripts/resolve-release-tag.sh, scripts/test-resolve-release-tag.sh
The resolver validates release-tag input, writes tag and version outputs, and tests valid, empty, and multiline arguments.
Publishing workflow integration
.github/workflows/release.yml
Docker, Docker manifest, and npm publishing jobs check out the script and use it for release-tag resolution.
PR validation job
.github/workflows/pr-checks.yml
Adds a five-minute job that runs the release-tag resolver test harness.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • Gitlawb/node#233: Updates release workflow tag and version handling for the npm publishing path.
  • Gitlawb/node#235: Reworks Docker publishing and backfill tagging flow in the release workflow.

Suggested labels: kind:ci, kind:bug

Suggested reviewers: beardthelion

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR addresses #239 by validating release tags before output writes and preserving the release-tag shape check.
Out of Scope Changes check ✅ Passed The added test job and helper scripts support the same release-tag hardening and do not appear unrelated.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title is concise and accurately summarizes the main change: hardening CI release tag handling.
Description check ✅ Passed The description follows the template and includes summary, motivation, change details, verification, and review notes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the workflow-change Fork PR edits CI workflows — mandatory human review label Jul 25, 2026
@MikeTomlin19
MikeTomlin19 marked this pull request as ready for review July 25, 2026 19:30

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I found an issue that needs to be addressed before this is ready.

Findings

  • [P3] Add the claimed regression coverage, or correct the PR description
    .github/workflows/release.yml:86
    The PR says that the new validation cases are covered, but this change adds no executable check for any of the three Resolve release tag blocks; Actionlint only validates workflow syntax and does not execute the shell. A later edit can therefore restore the newline $GITHUB_OUTPUT injection while CI remains green. Add a focused probe that exercises a valid tag and a newline-containing tag for each resolver (or remove the coverage claim).

@MikeTomlin19

Copy link
Copy Markdown
Author

Addressed the requested executable coverage in 64e228f.

The three release jobs now call one shared scripts/resolve-release-tag.sh implementation. scripts/test-resolve-release-tag.sh executes that resolver with a valid tag, a newline-injection value, and an empty value; it verifies exact valid outputs, verifies invalid cases write nothing, and asserts that all three workflow steps use the tested helper.

The regression script is now a blocking release tag validation job in pr-checks.yml.

Validation:

  • scripts/test-resolve-release-tag.sh — passed
  • bash -n scripts/resolve-release-tag.sh scripts/test-resolve-release-tag.sh — passed
  • Actionlint 1.7.7 — passed with only the repository's pre-existing macos-15-intel runner-label diagnostic ignored

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/test-resolve-release-tag.sh`:
- Around line 16-28: Add rejected test cases in
scripts/test-resolve-release-tag.sh for release tags containing whitespace,
shell metacharacters, and values that do not match the v[0-9]* format. Follow
the existing newline and empty-tag assertions: invoke $resolver with each
invalid value, require failure, and verify the corresponding GITHUB_OUTPUT file
remains empty.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5ae66396-c00b-4045-a864-498dc8c16b79

📥 Commits

Reviewing files that changed from the base of the PR and between 111cff7 and 64e228f.

📒 Files selected for processing (4)
  • .github/workflows/pr-checks.yml
  • .github/workflows/release.yml
  • scripts/resolve-release-tag.sh
  • scripts/test-resolve-release-tag.sh

Comment thread scripts/test-resolve-release-tag.sh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

workflow-change Fork PR edits CI workflows — mandatory human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci(release): unanchored tag validation glob lets a multiline dispatch input inject step outputs

2 participants