Skip to content

fix(promote): git-tag existence check misread 422 as an existing tag#28

Open
bdimitrov-netzine wants to merge 1 commit into
mainfrom
fix/promote-git-tag-existence-check
Open

fix(promote): git-tag existence check misread 422 as an existing tag#28
bdimitrov-netzine wants to merge 1 commit into
mainfrom
fix/promote-git-tag-existence-check

Conversation

@bdimitrov-netzine

@bdimitrov-netzine bdimitrov-netzine commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Fix

Use the refs API (git/ref/tags/$TAG) for a clean existence check (real 404 when missing), and only resolve the commit when the tag actually exists. Create-only / never-move / idempotent semantics are unchanged.

…g tag)

The 'Tag promoted commit' step used `gh api repos/$REPO/commits/$TAG` to
resolve an existing tag to its commit. For a tag that does not exist, that
endpoint returns HTTP 422 with a JSON error body; gh api prints the body to
stdout and skips --jq, so `2>/dev/null || true` captured the raw JSON into
CUR. A non-empty, non-matching CUR then tripped the never-move guard and the
job failed with 'Refusing to move the tag' — even though the tag was absent.

Switch the existence check to the refs API (git/ref/tags/$TAG), which cleanly
404s when the tag is missing, and only resolve the commit when it exists.
Preserves the create-only / never-move / idempotent semantics.

Observed on run 29075877856 (testnet-v1.2.2 promotion); the tag was created
manually out-of-band so this only fixes the workflow going forward.
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Claude finished @bdimitrov-netzine's task in 1m 0s —— View job


PR Review

  • Gather context and read changed files
  • Review the workflow fix
  • Post final review

Verdict: LGTM — the fix is correct and well-reasoned.

Root cause diagnosis

The PR description is accurate. gh api repos/$REPO/commits/$TAG returns HTTP 422 (not 404) when the ref doesn't resolve, and gh api prints the error JSON body to stdout even on non-2xx responses while silently skipping --jq. The 2>/dev/null || true pattern only suppressed stderr and exit-code errors, not the JSON body printed to stdout, so CUR was set to a non-empty string that didn't match $COMMIT, tripping the never-move guard.

The fix

-          # Idempotent + never-move: resolve any existing tag to its commit.
-          CUR=$(gh api "repos/$REPO/commits/$TAG" --jq '.sha' 2>/dev/null || true)
-          if [ -n "$CUR" ]; then
+          # Idempotent + never-move
+          if gh api "repos/$REPO/git/ref/tags/$TAG" >/dev/null 2>&1; then
+            CUR=$(gh api "repos/$REPO/commits/$TAG" --jq '.sha')
             if [ "$CUR" = "$COMMIT" ]; then

Why this works:

  • git/ref/tags/$TAG returns a proper HTTP 404 (not 422) for a missing ref, which makes gh api exit non-zero — so the if condition cleanly fails without touching stdout.
  • >/dev/null 2>&1 suppresses both the ref JSON body (not needed) and any error message, keeping only the exit code for the branch condition.
  • Commit resolution via commits/$TAG is now only called when the tag is confirmed to exist, so it runs without || true and will hard-fail under set -euo pipefail if something unexpected happens — correct fail-fast behavior.

Design correctness for annotated tags:
git/ref/tags/$TAG returns the tag object SHA for annotated tags (not the commit SHA), so the separate commits/$TAG call to resolve the final commit SHA is still necessary and correct. The two-step split is the right design here, not an oversight.

No issues found

  • The create-only / never-move / idempotent semantics are fully preserved.
  • No race-condition risk beyond what already existed (the window between the two gh api calls is negligible and was also present in the original).
  • No security concerns — all values are GitHub-controlled API responses or workflow-owned env vars.
  • The change is minimal and scoped exactly to the bug.

@github-actions

Copy link
Copy Markdown
Contributor

Security Scan - Code

Severity: HIGH, CRITICAL

No vulnerabilities found

View scan results

Report Summary

┌─────────────────────────────────────────────┬────────────┬─────────────────┬───────────────────┐
│                   Target                    │    Type    │ Vulnerabilities │ Misconfigurations │
├─────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ Cargo.lock                                  │   cargo    │        0        │         -         │
├─────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ crates/testing/fuzz-targets/Cargo.lock      │   cargo    │        0        │         -         │
├─────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ crates/testing/fuzz-targets/fuzz/Cargo.lock │   cargo    │        0        │         -         │
├─────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ etc/state-sum/Cargo.lock                    │   cargo    │        0        │         -         │
├─────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ etc/tps/package-lock.json                   │    npm     │        0        │         -         │
├─────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ rayls-contracts/package-lock.json           │    npm     │        0        │         -         │
├─────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ etc/chaos-network/Dockerfile                │ dockerfile │        -        │         0         │
├─────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ etc/docker-network/Dockerfile               │ dockerfile │        -        │         0         │
├─────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ etc/docker-replay/Dockerfile                │ dockerfile │        -        │         0         │
└─────────────────────────────────────────────┴────────────┴─────────────────┴───────────────────┘
Legend:
- '-': Not scanned
- '0': Clean (no security findings detected)

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