Ensure automated backport commits have verified signatures - #2998
asivanadi0 wants to merge 2 commits into
Conversation
Recreate each cherry-picked commit via the GitHub Git Data API so GitHub signs the resulting chain. Matches nvidia-container-toolkit NVIDIA#2012. Signed-off-by: Anpoo Sivanadi <asivanadi0@users.noreply.github.com>
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 📝 WalkthroughWalkthroughAfter pushing the cherry-picked backport branch, the script reads commits relative to the target branch and recreates them through GitHub’s Git Data API. It preserves each commit’s message and tree, chains the commits in oldest-to-newest order, and force-updates the backport branch ref to the final recreated commit. Priority: ➖ Normal Severity of issue fixed: Medium Merge Risk: 🟡 Moderate · up to Use the fetched target SHA and publish the backport branch only after commit recreation succeeds. Otherwise, concurrent target updates can be reversed in the backport diff, and failed runs can leave existing PRs pointing at unrecreated commits. Resolve these issues before merging unless explicitly accepted.
Comment |
There was a problem hiding this comment.
Note
Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.
🟡 Other comments (2)
.github/scripts/backport.js-106-107 (1)
106-107: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winUse the checked-out target SHA for the recreated commit chain.
If the remote target branch advances after
git fetch, the local${targetBranch}and the remotegetRefresult differ. The Git Data API then creates a commit with a tree based on the older target state and a parent based on the newer state. The resulting backport diff can reverse intervening target changes.Suggested fix
- const { data: baseRef } = await github.rest.git.getRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: `heads/${targetBranch}` - }); - let parentSha = baseRef.object.sha; + const targetSha = execSync(`git rev-parse ${targetBranch}`, { encoding: 'utf-8' }).trim(); + let parentSha = targetSha;.github/scripts/backport.js-109-137 (1)
109-137: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winKeep
backportBranchunchanged until API commit recreation succeeds.The script pushes
backportBranchbeforecreateCommitandupdateRef. If either operation fails, the remote ref remains at the pre-API cherry-picked history. An existing PR using this branch can consume that history before a retry completes.Push to a temporary ref, recreate the commits, then create or update
backportBranch. Delete the temporary ref on both success and failure. UsecreateRefwhen the backport branch does not exist;updateRefcannot create it.Suggested fix
const backportBranch = `backport-${prNumber}-to-${targetBranch}`; + const stagingRef = `${backportBranch}-staging-${context.runId}`; + const removeStagingRef = async () => { + try { + await github.rest.git.deleteRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `heads/${stagingRef}` + }); + } catch (error) { + if (error.status !== 404) throw error; + } + }; try { ... - execSync(`git push --force-with-lease origin ${backportBranch}`, { stdio: 'inherit' }); + execSync(`git push --force-with-lease origin ${backportBranch}:${stagingRef}`, { stdio: 'inherit' }); ... - core.info(`Repointing ${backportBranch} at signed commit ${parentSha}`); - await github.rest.git.updateRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: `heads/${backportBranch}`, - sha: parentSha, - force: true - }); + await removeStagingRef(); + let backportRefExists = true; + try { + await github.rest.git.getRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `heads/${backportBranch}` + }); + } catch (error) { + if (error.status === 404) { + backportRefExists = false; + } else { + throw error; + } + } + if (backportRefExists) { + await github.rest.git.updateRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `heads/${backportBranch}`, + sha: parentSha, + force: true + }); + } else { + await github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `refs/heads/${backportBranch}`, + sha: parentSha + }); + } ... } finally { + await removeStagingRef().catch(error => { + core.warning(`Failed to remove staging ref ${stagingRef}: ${error.message}`); + }); // Clean up: go back to main branch
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: NVIDIA/gpu-operator/.coderabbit.yaml
Review profile: QUIET
Plan: Enterprise
Run ID: 18daadee-fd8d-46bc-88fd-e447781f1c84
📒 Files selected for processing (1)
.github/scripts/backport.js
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 11 remain after this review.
Address CodeRabbit feedback on the verified-commit recreation path: - Parent the API-created chain on the checked-out target branch SHA (git rev-parse) instead of a remote getRef that can race ahead. - Push cherry-picks to a per-run staging ref until createCommit succeeds, then create or update the backport branch and always clean up staging. Signed-off-by: Anpoo Sivanadi <sivanadi08@gmail.com>
|
Addressed the two CodeRabbit findings in
Commit: |
|
Any specific reason we want to have staging branch? I would prefer keeping the code patch same as what we had in toolkit patch to avoid drift in future for same backport.js. |
Description
The cherry-pick workflow creates backport commits with a local
git push, so they are unsigned (verified: false). That conflicts with signature verification (#2992) and branch protection that requires signed commits.After pushing the backport branch, recreate each new commit through the GitHub Git Data API (preserving tree, message, and order), then force-update the backport branch to the signed chain. Same approach as NVIDIA/nvidia-container-toolkit#2012. PR creation and conflict handling are unchanged; no bot GPG/SSH key is required.
Fixes #2997
Checklist
make lint)make validate-generated-assets)make validate-modules)Testing
node --check .github/scripts/backport.js