-
Notifications
You must be signed in to change notification settings - Fork 16
feat: git hooks for commit signature validation for studio #1257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
sujitaw
wants to merge
11
commits into
main
Choose a base branch
from
feat/git_hooks_for_commit_validations
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+218
−5
Open
Changes from 7 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
88415b0
feat/add_git_hooks_for_validation
sujitaw 0ab477f
fix/no signoff
sujitaw 23acf7b
fix/test pre commit
sujitaw 11720ee
fix/updated code for local branch commit range
sujitaw 4ad1282
feat/limit commits check for local branch upto its ancestor
sujitaw 7fbdf90
fix/ellipse comments
sujitaw 65229c0
fix/edge case of pushing to different remote
sujitaw c9e7829
fix/ellipse comment
sujitaw baae980
merge
sujitaw 1877a26
fix/pr comments
sujitaw 22cbdda
merge
sujitaw File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| #!/bin/bash | ||
|
|
||
| # . "$(dirname -- "$0")/_/husky.sh" | ||
|
|
||
| # ANSI colors | ||
| RED="\033[0;31m" | ||
| YELLOW="\033[0;33m" | ||
| CYAN="\033[0;36m" | ||
| GREEN="\033[0;32m" | ||
| RESET="\033[0m" | ||
|
|
||
| commit_msg_file=$1 | ||
|
|
||
| # Guard: ensure commit message file exists | ||
| if [ -z "$commit_msg_file" ] || [ ! -f "$commit_msg_file" ]; then | ||
| echo "⚠️ No commit message file provided or file does not exist." | ||
| echo "👉 Skipping DCO sign-off check." | ||
| exit 0 | ||
| fi | ||
|
|
||
| if ! grep -q "Signed-off-by:" "$commit_msg_file"; then | ||
| echo "${RED} Commit message missing Signed-off-by line ${RESET}" | ||
| echo "${GREEN} Use: git commit -s ... ${RESET}" | ||
| exit 1 | ||
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| #!/bin/bash | ||
|
|
||
| RESET="\033[0m" | ||
| RED="\033[0;31m" | ||
| GREEN="\033[0;32m" | ||
| YELLOW="\033[0;33m" | ||
| BLUE="\033[0;34m" | ||
| CYAN="\033[0;36m" | ||
|
|
||
| # . "$(dirname -- "$0")/_/husky.sh" | ||
|
|
||
| echo "${BLUE}Checking last commit signature...${RESET}" | ||
|
|
||
| last_commit=$(git rev-parse HEAD) | ||
|
|
||
| # Count parents to detect merge commits | ||
| parent_count=$(git rev-list --parents -n 1 $last_commit | awk '{print NF-1}') | ||
|
|
||
| if [ "$parent_count" -gt 1 ]; then | ||
| echo "${BLUE}Skipping merge commit $last_commit${RESET}" | ||
| exit 0 | ||
| fi | ||
|
|
||
| sig_status=$(git log --format='%G?' -n 1 $last_commit) | ||
|
|
||
| if [ "$sig_status" != "G" ]; then | ||
| echo "${RED}❌ Commit $last_commit is not verified!${RESET}" | ||
| echo | ||
| echo "${YELLOW}👉 How to fix:${RESET}" | ||
| echo " 1. Re-sign your last commit with both sign-off (-s) and signature (-S):" | ||
| echo " git commit --amend -sS --no-edit" | ||
| echo | ||
| echo " 2. If you haven't set up commit signing yet:" | ||
| echo " - GPG/SSH signing setup: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits" | ||
| echo | ||
| echo "${CYAN}💡 Tip: You can enable automatic signing for all commits with:${RESET}" | ||
| echo " git config --global commit.gpgsign true" | ||
| echo | ||
| exit 1 | ||
| # In post-commit we usually *warn* not block, but you can `exit 1` if you want strict enforcement | ||
| else | ||
| echo "${GREEN}Commit $last_commit is signed and verified.${RESET}" | ||
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| #!/bin/sh | ||
| cd "$(dirname "$0")/.." # Move to project root (outer folder) | ||
| # cd nextjs # Move into Next.js folder | ||
| npx lint-staged | ||
| #!/usr/bin/env sh | ||
|
|
||
| . "$(dirname -- "$0")/_/husky.sh" | ||
|
|
||
| npx lint-staged |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| #!/bin/bash | ||
|
|
||
| # . "$(dirname -- "$0")/_/husky.sh" | ||
|
|
||
| # ANSI colors | ||
| RED="\033[0;31m" | ||
| YELLOW="\033[0;33m" | ||
| CYAN="\033[0;36m" | ||
| GREEN="\033[0;32m" | ||
| RESET="\033[0m" | ||
|
|
||
| echo "🔒 Checking commit signatures..." | ||
|
|
||
| # Read stdin into a temp file | ||
| TMP_FILE=$(mktemp) | ||
| cat > "$TMP_FILE" | ||
|
|
||
| if [ ! -s "$TMP_FILE" ]; then | ||
| echo "⚠️ Validations wont apply when current branch and remote branch being pushed to are different." | ||
| fi | ||
|
|
||
| while read local_ref local_sha remote_ref remote_sha; do | ||
| # Determine range of commits | ||
| if [ "$remote_sha" = "0000000000000000000000000000000000000000" ]; then | ||
| # Use the branch being pushed (may differ from HEAD) | ||
| if echo "$local_ref" | grep -q '^refs/heads/'; then | ||
| target_branch=${local_ref#refs/heads/} | ||
| else | ||
| target_branch=$(git rev-parse --abbrev-ref HEAD) | ||
| fi | ||
|
|
||
| # Find closest local base branch by commit distance (exclude the target itself) | ||
| base_branch=$( | ||
| git for-each-ref --format='%(refname:short)' refs/heads/ \ | ||
| | grep -vxF "$target_branch" \ | ||
| | while IFS= read -r other_branch; do | ||
| merge_base=$(git merge-base "$target_branch" "$other_branch") || continue | ||
| [ -n "$merge_base" ] || continue | ||
| echo "$(git rev-list --count "${merge_base}..${target_branch}") $other_branch" | ||
| done \ | ||
| | sort -n \ | ||
| | head -n1 \ | ||
| | awk '{print $2}' | ||
| ) | ||
|
|
||
| if [ -z "$base_branch" ]; then | ||
| # Resolve remote default (origin/HEAD) or use $default_branch/main | ||
| base_branch=${default_branch:-$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@')} | ||
| [ -n "$base_branch" ] || base_branch=main | ||
| echo "⚠️ Base branch not found — defaulting to '${base_branch}'" | ||
| fi | ||
|
|
||
| # Prefer local base, else remote tracking | ||
| if git show-ref --verify --quiet "refs/heads/$base_branch"; then | ||
| base_ref="$base_branch" | ||
| else | ||
| base_ref="origin/$base_branch" | ||
| fi | ||
|
|
||
| base_commit=$(git merge-base "$base_ref" "$target_branch" 2>/dev/null || true) | ||
| if [ -n "$base_commit" ]; then | ||
| range="$base_commit..$local_sha" | ||
| else | ||
| # Safe minimal fallback: just the tip commit | ||
| range="$local_sha" | ||
| fi | ||
| else | ||
| range="$remote_sha..$local_sha" | ||
| fi | ||
|
|
||
| unsigned_commits="" | ||
|
|
||
| echo "commit range ${range}" | ||
| # Loop through each commit in range | ||
| for commit in $(git rev-list $range); do | ||
| # Skip merge commits | ||
| parent_count=$(git rev-list --parents -n 1 $commit | awk '{print NF-1}') | ||
| if [ "$parent_count" -gt 1 ]; then | ||
| echo "${CYAN}ℹ️ Skipping merge commit $commit${RESET}" | ||
| continue | ||
| fi | ||
| sig_status=$(git log --format='%G?' -n 1 $commit) | ||
| # Currently only check for "N" - for no signature. | ||
| if [ "$sig_status" = "N" ]; then | ||
| unsigned_commits="$unsigned_commits $commit" | ||
| fi | ||
| done | ||
| exit 1 | ||
sujitaw marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| # If there are unsigned commits, prompt the developer | ||
| if [ -n "$unsigned_commits" ]; then | ||
| echo "${RED}❌ Found unsigned commits:${RESET} $unsigned_commits" | ||
| echo | ||
| echo "${YELLOW}Do you want to automatically sign these commits? [y/N]${RESET}" | ||
| read -r answer </dev/tty | ||
|
|
||
| if [ "$answer" = "y" ] || [ "$answer" = "Y" ]; then | ||
| # The earliest local unsigned commit is the last in the list | ||
| earliest_commit=$(echo $unsigned_commits | awk '{print $NF}') | ||
| parent_commit=$(git rev-parse "${earliest_commit}^") | ||
|
|
||
| echo "${CYAN}🔧 Auto-signing earliest local unsigned commit $earliest_commit...${RESET}" | ||
| # Avoid flattening of merge commits | ||
| # Not sure, if we really want to make it this complex, ideally it should be fine even if we flatten merge commits. | ||
| # Unless, the merge commit appears on the local branch, when trying to sync with the upstreams | ||
| # If we face any issues doing this, we revert to either flattening or maybe check the '--rebase-merges' feasibility. Considering the requirement of git version | ||
| git rebase --onto "$parent_commit" "$parent_commit" \ | ||
| --exec 'if [ $(git rev-list --parents -n 1 HEAD | awk "{print NF-1}") -eq 1 ]; then git commit --amend -sS --no-edit; else echo "Skipping merge commit $(git rev-parse --short HEAD)"; fi' | ||
|
|
||
| echo "${GREEN}✅ Earliest unsigned commit has been signed.${RESET}" | ||
| echo "Please push again: git push --force-with-lease" | ||
| exit 1 | ||
| else | ||
| echo "${YELLOW}You can manually sign commits using:${RESET}" | ||
| echo | ||
| # Latest commit (HEAD) | ||
| echo " - For the latest commit (HEAD):" | ||
| echo " git commit --amend -sS --no-edit" | ||
| echo | ||
| # Earliest local unsigned commit | ||
| earliest_commit=$(echo $unsigned_commits | awk '{print $NF}') | ||
| short_hash=$(git rev-parse --short $earliest_commit) | ||
| parent_commit=$(git rev-parse "${earliest_commit}^") | ||
| echo " - For the earliest unsigned commit $short_hash (skipping merge commits):" | ||
| echo " git rebase --onto $parent_commit $parent_commit \\" | ||
| echo " --exec 'if [ \$(git rev-list --parents -n 1 HEAD | awk \"{print NF-1}\") -eq 1 ]; then git commit --amend -sS --no-edit; else echo \"Skipping merge commit \$(git rev-parse --short HEAD)\"; fi'" | ||
| echo | ||
| echo "Then push normally with:" | ||
| echo " git push" | ||
| echo | ||
| echo "Helpful resources:" | ||
| echo " - GPG signing: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits" | ||
| echo | ||
| echo "${CYAN}💡 Tip: Enable automatic signing for all commits:${RESET}" | ||
| echo " git config --global commit.gpgsign true" | ||
| echo " git config --global user.signingkey <YOUR_KEY_ID>" | ||
| echo | ||
| exit 1 | ||
| fi | ||
| fi | ||
| done < "$TMP_FILE" | ||
|
|
||
| rm -f "$TMP_FILE" | ||
|
|
||
| echo "${GREEN}✅ No unsigned commits found${RESET}" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.