Skip to content

fix(release): retry GitHub PR metadata snapshot - #715

Merged
syzsunshine219 merged 1 commit into
mainfrom
codex/fix-draft-release-snapshot
Oct 22, 2026
Merged

syzsunshine219 merged 1 commit into
mainfrom
codex/fix-draft-release-snapshot

Conversation

@syzsunshine219

@syzsunshine219 syzsunshine219 commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes a failure in GitHub Draft Release v2 when building the complete release snapshot because a GitHub commit-to-PR API response was truncated.

Changes

  • Persist and validate the raw paginated API response for each commit.
  • Retry transient or truncated API responses up to three times.
  • Fail closed after all retries and report the affected commit SHA.
  • Add a workflow regression assertion for the retry and validation logic.

Validation

  • npm run test:release-workflow -- --run: 31 tests passed, including 21 release workflow tests.
  • A shell simulation confirmed that a truncated response is retried successfully and produces PULL_REQUESTS.json.

@Memtensor-AI

Copy link
Copy Markdown
Collaborator

πŸ€– Open Code Review

Target: PR #715
Task: 3346a8f06fd42c1b
Base: main
Head: codex/fix-draft-release-snapshot

πŸ” OpenCodeReview found 4 issue(s) in this PR.

⚠️ 1 warning(s) occurred during review.


1. .github/workflows/github-draft-release-v2.yml (L367-L374)

Bug: gh api --paginate already concatenates paginated results into a single JSON array, so -s 'add' is wrong for single-file output.

When --paginate is used and output is redirected to a single file (> "$pr_response"), gh writes one combined JSON array (not one array per page). Applying jq -s slurps that one array into a wrapper array [[ ... ]], and then add flattens it back β€” this works accidentally, but it adds unnecessary complexity and is fragile if gh ever changes its paging output format. More importantly, the jq -e -s 'length > 0 and all(.[]; type == "array")' validation at line 366 implicitly depends on this wrapping behavior.

Dropping -s and removing add | makes both the validation and the transform cleaner and correct:

jq -r '.[] | { number, title, htmlUrl: .html_url, ... }' "$pr_response"

This also eliminates the empty-array add β†’ null β†’ .[] crash described in the previous comment.

πŸ’‘ Suggested Change

Before:

                jq -s 'add | .[] | {
                  number,
                  title,
                  htmlUrl: .html_url,
                  mergedAt: .merged_at,
                  baseRef: .base.ref,
                  headRef: .head.ref
                }' "$pr_response" >> release-assets/PULL_REQUESTS.jsonl

After:

                jq -r '.[] | {
                  number,
                  title,
                  htmlUrl: .html_url,
                  mergedAt: .merged_at,
                  baseRef: .base.ref,
                  headRef: .head.ref
                }' "$pr_response" >> release-assets/PULL_REQUESTS.jsonl

2. .github/workflows/github-draft-release-v2.yml (L378-L379)

Reliability: Warning is emitted and sleep is executed even after the final (3rd) failed attempt.

The echo + sleep block runs unconditionally after every failed attempt, including the last one. After the 3rd attempt fails, the loop exits naturally and then waits an additional sleep 6 seconds before the if [[ "$pr_success" != "true" ]] block exits with failure. The sleep after the final attempt is wasted time.

Fix: guard the sleep behind a check that skips it on the last iteration.

πŸ’‘ Suggested Change

Before:

              echo "::warning title=Retrying pull request evidence::GitHub PR metadata for commit $commit_sha was unavailable or malformed (attempt $attempt/3)." >&2
              sleep "$((attempt * 2))"

After:

              echo "::warning title=Retrying pull request evidence::GitHub PR metadata for commit $commit_sha was unavailable or malformed (attempt $attempt/3)." >&2
              if [[ "$attempt" -lt 3 ]]; then
                sleep "$((attempt * 2))"
              fi

3. .github/workflows/github-draft-release-v2.yml (L358)

Security / correctness: Unvalidated commit_sha used in a filename and a URL path without sanitisation.

commit_sha is sourced from jq -r '.commits[].sha' release-assets/COMPARE.json, which is derived from a GitHub API response. While SHA values are expected to be hex strings, constructing a filesystem path (release-assets/PR_${commit_sha}.json) and embedding it directly in the API URL (/commits/${commit_sha}/pulls) without any validation leaves a small but real injection surface if the upstream JSON were ever tampered with or the field contained unexpected content (e.g. path-traversal characters like ../).

Consider validating the SHA with a regex guard before use:

[[ "$commit_sha" =~ ^[0-9a-f]{40}$ ]] || { echo "::error::Unexpected SHA format: $commit_sha" >&2; exit 1; }
πŸ’‘ Suggested Change

Before:

            pr_response="release-assets/PR_${commit_sha}.json"

After:

            [[ "$commit_sha" =~ ^[0-9a-f]{40}$ ]] || { echo "::error title=Invalid commit SHA::Unexpected SHA format encountered: $commit_sha" >&2; exit 1; }
            pr_response="release-assets/PR_${commit_sha}.json"

4. .github/workflows/github-draft-release-v2.yml (L366)

Bug: Validation rejects valid empty-PR responses, causing spurious retries and false failures.

The guard condition length > 0 and all(.[]; type == "array") (with -s slurp) treats an empty JSON array [] from the GitHub API as invalid and triggers a retry. However, an empty array is a legitimate response when a commit has no associated pull requests (e.g., direct pushes). This means every such commit will exhaust all 3 attempts and then exit 1, aborting the release workflow even though no real error occurred.

The intent of the check appears to be detecting a truncated/corrupt response (e.g., gh wrote nothing or wrote malformed JSON). A better check would simply validate that the file is well-formed JSON without requiring it to be non-empty:

jq -e 'type == "array"' "$pr_response" >/dev/null 2>&1

This accepts [] as valid while still catching empty files or non-array responses.

πŸ’‘ Suggested Change

Before:

&& jq -e -s 'length > 0 and all(.[]; type == "array")' "$pr_response" >/dev/null 2>&1; then

After:

&& jq -e 'type == "array"' "$pr_response" >/dev/null 2>&1; then

Generated by cloud-assistant via Open Code Review.

@syzsunshine219
syzsunshine219 merged commit d56ad47 into main Oct 22, 2026
2 of 3 checks passed
@syzsunshine219
syzsunshine219 deleted the codex/fix-draft-release-snapshot branch October 22, 2026 16:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants