diff --git a/.github/workflows/check-conflict-markers.yml b/.github/workflows/check-conflict-markers.yml new file mode 100644 index 0000000..655b3e7 --- /dev/null +++ b/.github/workflows/check-conflict-markers.yml @@ -0,0 +1,27 @@ +# SPDX-FileCopyrightText: 2025 SecPal Contributors +# SPDX-License-Identifier: AGPL-3.0-or-later + +name: Check for Merge Conflict Markers + +on: + pull_request: + branches: [main] + push: + branches: [main] + +permissions: + contents: read + +jobs: + check-conflicts: + name: Check for Git Conflict Markers + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run conflict marker check + run: | + chmod +x scripts/check-conflict-markers.sh + ./scripts/check-conflict-markers.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index fc409e8..df5a40b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- **Git Conflict Marker Detection** - Automated check for unresolved merge conflicts + - `scripts/check-conflict-markers.sh` - Scans all tracked files for conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`, `|||||||` with space) + - `.github/workflows/check-conflict-markers.yml` - CI integration (runs on all PRs and pushes to main) + - `docs/scripts/CHECK_CONFLICT_MARKERS.md` - Complete usage guide with examples and troubleshooting + - Exit codes: 0 = clean, 1 = conflicts detected + - Prevents accidental commits of broken code from merge conflicts + - Colored output shows exact file locations and line numbers - **RBAC Phase 3: API Endpoints & Authorization** - Role management REST API (#107) - `POST /api/v1/users/{id}/roles` - Assign role with temporal parameters (valid_from, valid_until, auto_revoke) - `GET /api/v1/users/{id}/roles` - List user roles with expiry info (is_active, is_expired status) diff --git a/docs/scripts/CHECK_CONFLICT_MARKERS.md b/docs/scripts/CHECK_CONFLICT_MARKERS.md new file mode 100644 index 0000000..081eb55 --- /dev/null +++ b/docs/scripts/CHECK_CONFLICT_MARKERS.md @@ -0,0 +1,196 @@ + + +# Git Conflict Marker Detection + +The `check-conflict-markers.sh` script detects unresolved Git merge conflict markers in tracked files to prevent accidental commits of broken code. + +## Problem + +When resolving merge conflicts, developers sometimes forget to remove conflict markers: + +```bash + <<<<<<< HEAD + code from current branch + ======= + code from incoming branch + >>>>>>> feature-branch +``` + +These markers cause: + +- **Syntax errors** in source code +- **Runtime failures** in scripts and configuration files +- **Broken builds** in CI/CD pipelines +- **Production incidents** if deployed + +## Solution + +This script automatically detects conflict markers in all tracked text files before they reach the repository. + +## Usage + +### Manual Check + +```bash +# Check all tracked files +./scripts/check-conflict-markers.sh +``` + +### CI/CD Integration + +The script runs automatically in CI via GitHub Actions on every PR and push to `main`. + +### Pre-commit Hook + +Add to `.git/hooks/pre-commit`: + +```bash +#!/bin/bash +# Run conflict marker check +if [ -f scripts/check-conflict-markers.sh ]; then + ./scripts/check-conflict-markers.sh || exit 1 +fi +``` + +## Detected Patterns + +The script detects these conflict markers: + +| Marker | Meaning | +| -------------------------- | ------------------------------- | +| `<<<<<<<` | Start of conflict (from HEAD) | +| `=======` | Separator between changes | +| `>>>>>>>` | End of conflict (from incoming) | +| `\|\|\|\|\|\|\|` (+ space) | Optional: diff3 style marker | + +## Exit Codes + +- `0` - No conflict markers found ✅ +- `1` - Conflict markers detected ❌ + +## Example Output + +### Success (No Conflicts) + +```bash +═══════════════════════════════════════════════════════════════ +Git Conflict Marker Detection +═══════════════════════════════════════════════════════════════ + +───────────────────────────────────────────────────── +Checked files: 111 +✓ No conflict markers found +═══════════════════════════════════════════════════════════════ +``` + +### Failure (Conflicts Found) + +```bash +═══════════════════════════════════════════════════════════════ +Git Conflict Marker Detection +═══════════════════════════════════════════════════════════════ + +✗ Conflict markers detected: + +File: .git/hooks/pre-push + Line 73: <<<<<<< Updated upstream... + +File: src/main.py + Line 42: =======... + +───────────────────────────────────────────────────── +Checked files: 111 +✗ Found conflict markers in files + +Action required: +1. Open the affected files +2. Search for conflict markers: <<<<<<<, =======, >>>>>>> +3. Manually resolve the conflicts +4. Remove all conflict markers +5. Test your changes +6. Commit again + +═══════════════════════════════════════════════════════════════ +``` + +## How to Resolve Conflicts + +1. **Locate the markers** - The script shows file names and line numbers +2. **Review both changes** - Understand code from both branches +3. **Choose or merge** - Keep one version, the other, or combine both +4. **Remove markers** - Delete all `<<<<<<<`, `=======`, `>>>>>>>` lines +5. **Test** - Verify the code works correctly +6. **Commit** - Try committing again + +## Common Scenarios + +### False Positives + +The script only checks lines **starting with** conflict markers, reducing false positives. If you legitimately need these patterns in your code (e.g., documentation), indent them: + +```markdown + + + <<<<<<< This won't trigger (indented) +``` + +### Binary Files + +Binary files are automatically skipped - only text files are checked. + +### .git Directory + +The `.git` directory itself is excluded from checks (uses `git ls-files`). + +## Integration with Other Tools + +### Pre-commit Framework + +```yaml +# .pre-commit-config.yaml +repos: + - repo: local + hooks: + - id: check-conflict-markers + name: Check for conflict markers + entry: ./scripts/check-conflict-markers.sh + language: script + pass_filenames: false +``` + +### CI/CD Pipelines + +```yaml +# GitHub Actions (already included) +- name: Check conflict markers + run: ./scripts/check-conflict-markers.sh +``` + +## Troubleshooting + +### "Permission denied" + +```bash +chmod +x scripts/check-conflict-markers.sh +``` + +### "file: command not found" + +Install the `file` utility: + +```bash +# Ubuntu/Debian +sudo apt install file + +# macOS +brew install file +``` + +## See Also + +- [Preflight Script Documentation](PREFLIGHT.md) - Quality Gate Checks +- [System Requirements Check](CHECK_SYSTEM_REQUIREMENTS.md) - Development Prerequisites +- [Git Merge Conflicts](https://git-scm.com/docs/git-merge#_how_conflicts_are_presented) - Official Git Documentation diff --git a/scripts/check-conflict-markers.sh b/scripts/check-conflict-markers.sh new file mode 100755 index 0000000..b35b87b --- /dev/null +++ b/scripts/check-conflict-markers.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: 2025 SecPal Contributors +# SPDX-License-Identifier: MIT + +# ============================================================================ +# Git Conflict Marker Detection +# ============================================================================ +# Detects unresolved Git merge conflict markers in tracked files to prevent +# accidental commits of broken code. +# +# Exit codes: +# 0 - No conflict markers found +# 1 - Conflict markers detected +# ============================================================================ + +set -euo pipefail + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Conflict marker patterns +MARKERS=( + "<<<<<<< " # Start of conflict (from HEAD) + "=======" # Separator between changes + ">>>>>>> " # End of conflict (from incoming) + "||||||| " # Optional: diff3 style marker +) + +CONFLICTS_FOUND=0 +CHECKED_FILES=0 + +echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" +echo -e "${BLUE}Git Conflict Marker Detection${NC}" +echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" +echo "" + +# Get list of tracked files (excluding .git directory) +while IFS= read -r -d '' file; do + # Skip binary files and non-text files + if file "$file" | grep -q "text"; then + CHECKED_FILES=$((CHECKED_FILES + 1)) + + # Check each conflict marker pattern + for marker in "${MARKERS[@]}"; do + if grep -n "^${marker}" "$file" > /dev/null 2>&1; then + if [ $CONFLICTS_FOUND -eq 0 ]; then + echo -e "${RED}✗ Conflict markers detected:${NC}" + echo "" + fi + + CONFLICTS_FOUND=$((CONFLICTS_FOUND + 1)) + echo -e "${YELLOW}File:${NC} $file" + + # Show lines with conflict markers + grep -n "^${marker}" "$file" | while IFS=: read -r line_num line_content; do + echo -e " ${RED}Line $line_num:${NC} ${line_content:0:60}..." + done + echo "" + break # Only report once per file + fi + done + fi +done < <(git ls-files -z) + +echo -e "${BLUE}─────────────────────────────────────────────────────${NC}" +echo -e "Checked files: ${CHECKED_FILES}" + +if [ $CONFLICTS_FOUND -eq 0 ]; then + echo -e "${GREEN}✓ No conflict markers found${NC}" + echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" + exit 0 +else + echo -e "${RED}✗ Found conflict markers in files${NC}" + echo "" + echo -e "${YELLOW}Action required:${NC}" + echo "1. Open the affected files" + echo "2. Search for conflict markers: <<<<<<<, =======, >>>>>>>" + echo "3. Manually resolve the conflicts" + echo "4. Remove all conflict markers" + echo "5. Test your changes" + echo "6. Commit again" + echo "" + echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" + exit 1 +fi