Skip to content
Merged
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
102 changes: 102 additions & 0 deletions .github/workflows/sanity-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: PR Sanity Check

on:
pull_request:
types: [opened, synchronize, reopened]

permissions:
pull-requests: write
contents: read

jobs:
sanity-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Fetch base branch
run: git fetch origin ${{ github.base_ref }}

- name: Block disallowed files by extension
run: |
echo "Checking for disallowed file extensions..."
CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)

# Block by extension
BLOCKED=$(echo "$CHANGED_FILES" | grep -E '\.(exe|dll|out|ezdb|db|sqlite|sqlite3)$' || true)
if [ -n "$BLOCKED" ]; then
echo "::error::Disallowed file extensions detected: $BLOCKED"
exit 1
fi

# Block IDE/OS junk folders
JUNK=$(echo "$CHANGED_FILES" | grep -E '^(\.idea/|\.vs/|__pycache__/)' || true)
if [ -n "$JUNK" ]; then
echo "::error::IDE/OS junk detected: $JUNK"
exit 1
fi

# Block OS junk files
OS_JUNK=$(echo "$CHANGED_FILES" | grep -E '(Thumbs\.db|Desktop\.ini|\.DS_Store)$' || true)
if [ -n "$OS_JUNK" ]; then
echo "::error::OS junk files detected: $OS_JUNK"
exit 1
fi

echo "No disallowed file extensions detected."

- name: Block meta/config files from other ecosystems
run: |
echo "Checking for ecosystem files..."
CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)

# Block meta/config files from other language ecosystems
SUSPICIOUS=$(echo "$CHANGED_FILES" | grep -E '^(package\.json|package-lock\.json|yarn\.lock|pnpm-lock\.yaml|bun\.lockb|bunfig\.toml|deno\.json|deno\.jsonc|tsconfig\.json|jsconfig\.json|requirements\.txt|Pipfile|Gemfile|Cargo\.toml|Cargo\.lock)$|node_modules/' || true)

if [ -n "$SUSPICIOUS" ]; then
echo "::error::Ecosystem config files detected: $SUSPICIOUS"
exit 1
fi
echo "No suspicious ecosystem files detected."

- name: Reject binary files except images
run: |
echo "Checking for binary files..."
CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)

for file in $CHANGED_FILES; do
if [ -f "$file" ]; then
MIME=$(file --mime-type -b "$file")

# Allow common image formats
if [[ "$MIME" =~ ^image/(jpeg|png|gif|svg\+xml|webp)$ ]]; then
echo "Allowed image file: $file ($MIME)"
continue
fi

# Reject executables and archives
if file "$file" | grep -qE "executable|binary|archive|compressed"; then
echo "::error::Binary/executable file detected: $file"
exit 1
fi

# Also check charset=binary for other binary types (but not images)
if file --mime "$file" | grep -q "charset=binary" && [[ ! "$MIME" =~ ^image/ ]]; then
echo "::error::Binary file detected: $file ($MIME)"
exit 1
fi
fi
done
echo "No disallowed binary files detected."

- name: Close PR if checks fail
if: failure()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr close ${{ github.event.pull_request.number }} \
--repo ${{ github.repository }} \
--comment "This PR has been automatically closed because it contains disallowed files (binaries, executables, archives, or meta/config files from other ecosystems). Please remove these files and open a new PR."
Loading