Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 56 additions & 3 deletions .github/workflows/provenance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,15 @@ jobs:
runs-on: ubuntu-latest

permissions:
contents: read
# `contents: write` needed to create the v<version> tag via gh api
# at the end of this job. Token is scoped to the dedicated tag step
# via GH_TOKEN env; never persisted in `.git/config` (checkout keeps
# persist-credentials: false so build/install steps can't reach it).
contents: write
id-token: write # NPM trusted publishing via OIDC

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 (2026-05-20)
with:
persist-credentials: false

Expand Down Expand Up @@ -201,7 +205,9 @@ jobs:
run: pnpm install --loglevel error

- run: INLINED_SOCKET_CLI_PUBLISHED_BUILD=1 pnpm run build:dist
- run: npm publish --provenance --access public --tag "${NPM_DIST_TAG}"
- name: Publish socket
id: publish_socket
run: npm publish --provenance --access public --tag "${NPM_DIST_TAG}"
continue-on-error: true
env:
NPM_DIST_TAG: ${{ inputs.dist-tag }}
Expand All @@ -225,3 +231,50 @@ jobs:
NPM_DIST_TAG: ${{ inputs.dist-tag }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} # zizmor: ignore[secrets-outside-env]
SOCKET_CLI_DEBUG: ${{ inputs.debug }}

# Create v<version> git tag at the published commit SHA after a
# successful socket-package publish, idempotently. GitHub Release
# Immutability ("Disallow assets and tags from being modified once a
# release is published") freezes tags once bound to a Release, so:
# - existing tag at same SHA → no-op
# - existing tag at different SHA → hard-fail (operator recovery
# required)
# Gated on the first publish step (publish_socket — the `socket` npm
# package) actually succeeding; the cli / cli-with-sentry publishes
# use `continue-on-error: true` and don't gate the tag.
#
# Uses gh api (not `git push`) so the token only lives in this step's
# env, never written to `.git/config` by an earlier `actions/checkout`
# with persist-credentials: true (which would leak it to every later
# step including `pnpm install` postinstall scripts).
- name: Tag release (idempotent)
if: steps.publish_socket.outcome == 'success'
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
run: |
PUBLISHED_SHA=$(git rev-parse HEAD)
PUBLISHED_VERSION=$(node -p "require('./package.json').version")
TAG="v$PUBLISHED_VERSION"

# Look up any existing tag via the API. 200 → exists; 404 → absent.
EXISTING_JSON=$(gh api "repos/$REPO/git/ref/tags/$TAG" 2>/dev/null || echo "")
if [ -n "$EXISTING_JSON" ]; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

404 response body breaks tag existence check

High Severity

gh api outputs the 404 JSON response body ({"message":"Not Found",…}) to stdout even on failure. The 2>/dev/null only suppresses stderr, and in bash $(cmd1 || cmd2), stdout from the failed cmd1 is still captured. So when a tag does not exist, EXISTING_JSON contains the error JSON (non-empty), causing [ -n "$EXISTING_JSON" ] to be true. The subsequent node -p then tries to access .object.sha on the error object, which throws a TypeError and fails the step under set -e. Tags can never be created for new versions — the primary purpose of this change.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7e12956. Configure here.

EXISTING_SHA=$(echo "$EXISTING_JSON" | node -p "JSON.parse(require('fs').readFileSync(0,'utf8')).object.sha")
if [ "$EXISTING_SHA" = "$PUBLISHED_SHA" ]; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Annotated tags cause false SHA mismatch failure

Medium Severity

For annotated (signed) tags, the GitHub git/ref/tags API returns the tag object SHA in object.sha, not the commit SHA. Comparing this against PUBLISHED_SHA (a commit SHA from git rev-parse HEAD) will always mismatch, causing a hard-fail even when the tag points to the correct commit. The PR description notes that previous tags were hand-created with git tag -s (which creates annotated tags), so a re-run against those versions would incorrectly trigger the "requires manual recovery" error path.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7e12956. Configure here.

echo "Tag $TAG already exists at $PUBLISHED_SHA — no-op."
exit 0
fi
echo "::error::Tag $TAG exists at $EXISTING_SHA but publish SHA is $PUBLISHED_SHA."
echo "::error::Release immutability is enabled; this requires manual recovery:"
echo "::error:: 1. Delete any GitHub Release tied to $TAG"
echo "::error:: 2. Delete the tag via the API"
echo "::error:: 3. Re-run this workflow"
exit 1
fi

gh api "repos/$REPO/git/refs" \
-X POST \
-f "ref=refs/tags/$TAG" \
-f "sha=$PUBLISHED_SHA"
echo "Created tag $TAG at $PUBLISHED_SHA"
Loading