المستوى المطلوب: محترف. هذا الشرح موجّه لمن يدير مستودعات فريق على Git ولديه خط CI (مثل GitHub Actions). لو أنت مبتدئ، ابدأ بقسم "إزاي بتشتغل الأداة" ففيه مثال مبسّط قبل التفاصيل التقنية.
بوت واحد بيفحص كل commit جديد على GitHub العام، ولو لقى مفتاح AWS بيبدأ يستهلك حسابك قبل ما تخلّص قهوتك. الحل مش تنبيه بشري بيتأخّر، الحل بوّابتان أوتوماتيك بتوقفا المفتاح قبل ما يوصل للمستودع أصلاً — ومجانًا. في نهاية المقال هيكون عندك خطاف محلي وفحص CI شغّالين بالكامل.
أتمتة كشف الأسرار قبل ما تدخل تاريخ Git
المشكلة باختصار
الأسرار (مفاتيح API، توكنات، كلمات سر قواعد البيانات) بتتكتب داخل الكود كل يوم بالغلط. حسب تقرير GitGuardian لعام 2026، ظهر حوالي 29 مليون سر علنًا على GitHub في 2025 وحده. وفي 2023 كان الرقم 12.8 مليون سر جديد بزيادة 28% عن السنة اللي قبلها. المشكلة مش إن السر بيتشاف، المشكلة إن Git بيفتكره.
ركز في النقطة دي: لمّا تمسح المفتاح في commit جديد، هو لسه موجود في التاريخ. أي حد يعمل git log -p بيلاقيه. عشان كده مسح السطر مش كافٍ؛ لازم البوّابة توقفه قبل ما يتسجّل، ولو اتسرّب فعلاً لازم تدوّر المفتاح مش بس تمسحه. الافتراض هنا إن كودك على Git وعندك CI.
ليه الطرق الشائعة بتفشل
الطريقة الشائعة إنك تعتمد على .gitignore ومراجعة الكود البشرية. دي بتفشل في حالتين: الملف اللي فيه السر مش دايمًا في .gitignore، والمراجع البشري بيقرا منطق الكود مش بيدوّر على سلسلة عشوائية بطول 40 حرف وسط 300 سطر. الاعتماد على GitHub Push Protection وحده كمان ناقص: بيغطّي مزوّدين معروفين بس، ومبيشتغلش على كل الأنظمة أو الأسرار الداخلية بتاعتك.
البديل: أداة بتفحص آليًا وبتوقف العملية. gitleaks أداة مفتوحة المصدر بتعمل بالظبط ده، بتفحص بالـ regex والإنتروبيا، وبتديك تقارير بصيغ JSON و SARIF.
إزاي بتشتغل الأداة: regex + إنتروبيا
خلّي بالك من فكرة العشوائية بمثال بسيط. لو طلبت من صاحبك يقول كلمة، هيقول "قلم" أو "بيت" — كلمات متوقّعة. لكن لو فتحت مدير كلمات السر وطلبت مفتاح، هيطلعلك حاجة زي g7Qx2vT9pLmZ — حروف وأرقام بلا نمط. الأداة بتقيس "مقدار المفاجأة" في كل سلسلة نصية؛ السلسلة العشوائية جدًا غالبًا سر، مش كلمة عادية.
علميًا ده اسمه إنتروبيا شانون: كل ما قلّت القابلية للتنبؤ بالحروف، زادت قيمة الإنتروبيا. gitleaks بيدمج إشارتين: قواعد regex لمزوّدين معروفين (شكل مفتاح AWS بيبدأ بـ AKIA، توكن GitHub بيبدأ بـ ghp_)، وحد إنتروبيا للسلاسل اللي مالهاش شكل معروف بس عشوائية بشكل مريب. الدمج ده بيقلّل الإيجابيات الكاذبة مقارنة بأداة بتعتمد على الإنتروبيا لوحدها.
البوّابة الأولى: خطاف pre-commit محلي
الفكرة إن الفحص يشتغل على جهاز المطوّر قبل ما الـ commit يتسجّل. أسرع نقطة توقف ممكنة.
# تثبيت gitleaks
brew install gitleaks # macOS
# أو عبر Docker بدون تثبيت
docker run --rm -v "$(pwd):/repo" zricethezav/gitleaks:latest detect --source=/repo
# فحص التغييرات المُجهّزة فقط قبل الـ commit
gitleaks protect --staged --redact --verboseعشان تخليه تلقائي لكل الفريق، استخدم إطار pre-commit:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.4
hooks:
- id: gitleakspip install pre-commit
pre-commit install # يربط الخطاف بـ .git/hooks
pre-commit run gitleaks --all-filesعلى مستودع متوسط، فحص التغييرات المُجهّزة بياخد أقل من ثانية، فالمطوّر مش بيحس بيه. الـ trade-off هنا: بتكسب توقّف فوري ومجاني، بتخسر إنه قابل للتجاوز. أي مطوّر يقدر يكتب git commit --no-verify ويعدّي الخطاف، أو ببساطة يكون مركّبش الخطاف على جهازه. عشان كده البوّابة دي ضرورية بس مش كافية لوحدها.
البوّابة الثانية: فحص في CI لا يمكن تجاوزه
البوّابة اللي بتتحكّم فعلاً هي اللي بتشتغل على السيرفر، مش على جهاز المطوّر. أي push أو Pull Request بيتفحص، ولو فيه سر الـ PR بيفشل ومبيتدمجش.
# .github/workflows/gitleaks.yml
name: gitleaks
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # لازم لفحص كامل التاريخ
- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}سطر fetch-depth: 0 مهم: من غيره الفحص بيشوف آخر commit بس، وبيفوت أسرار متدفونة في التاريخ. الـ trade-off: فحص كامل التاريخ بياخد من ثوانٍ لدقيقة أو دقيقتين على المستودعات الضخمة، مقابل إنه مرجع لا يقدر أي مطوّر يتجاوزه. ده اللي بيخلّيه البوّابة الحاسمة.
قاعدة مخصّصة وتقليل الإيجابيات الكاذبة
القواعد الافتراضية بتغطّي المزوّدين المشهورين، لكن أسرارك الداخلية ليها شكل خاص. أضِف ملف gitleaks.toml يبني فوق الافتراضي ويستثني أمثلة التوثيق:
# gitleaks.toml
title = "قواعد مخصّصة"
[extend]
useDefault = true # ابنِ فوق القواعد الافتراضية
[[rules]]
id = "internal-api-key"
description = "مفتاح API داخلي بصيغة ACME_"
regex = '''ACME_[0-9a-zA-Z]{32}'''
entropy = 3.5
keywords = ["ACME_"]
[allowlist]
description = "تجاهل أمثلة التوثيق والاختبارات"
paths = ['''docs/.*''', '''.*_test\.go''']الإنتروبيا سيف بحدّين: لو رفعت الحساسية زيادة، هتلاقي "أسرار" في هاشات ملفات أو معرّفات UUID عادية. الـ trade-off: بتكسب تغطية أوسع، بتخسر وقت في ضبط الـ allowlist. ابدأ بالافتراضي، وكل ما طلع إيجابي كاذب ضيفه للـ allowlist بدل ما تطفّي القاعدة كلها.
لو المفتاح اتسرّب فعلاً
لو الفحص كشف سر موجود في التاريخ بالفعل، رتّب الخطوات صح: دوّر المفتاح الأول (ألغِ القديم وأصدر جديد)، لأن أي حد نسخ المستودع بقى عنده نسخة. تنظيف التاريخ بعد كده بأدوات زي git filter-repo أو BFG بيمنع تسريب مستقبلي، لكنه لا يبطل مفعول مفتاح اتشاف. الترتيب الغلط (تنظيف قبل تدوير) بيسيبك مكشوف.
متى لا تستخدم هذه الطريقة
لو مشروعك مستودع شخصي صغير بترمي بعد يوم، الإعداد أكبر من الفايدة. ولو فريقك بالفعل مبيحطش بيانات اعتماد ثابتة في الكود إطلاقًا ويعتمد على توكنات OIDC قصيرة العمر ومدير أسرار، فالبوّابتان بتفضلا شبكة أمان مفيدة لكن عائدها أقل. وافتكر: gitleaks بيمنع ويكشف، لكنه مش بديل عن تدوير المفاتيح المسرّبة.
الخطوة التالية
افتح أكبر مستودع عندك دلوقتي وشغّل gitleaks detect --source . --report-format sarif --report-path leaks.sarif على كامل التاريخ. لو طلع أكتر من صفر، عندك أسرار مكشوفة محتاجة تدوير قبل أي حاجة تانية. بعدها ركّب البوّابتين — الخطاف المحلي وملف CI — واقفل الباب.
المصادر
- gitleaks — المستودع الرسمي والتوثيق (regex + entropy، أوامر detect/protect)
- gitleaks-action — إجراء GitHub Actions الرسمي
- pre-commit — إطار خطافات الـ commit
- GitGuardian — State of Secrets Sprawl 2026 (29 مليون سر على GitHub في 2025)
- GitGuardian — State of Secrets Sprawl 2024 (12.8 مليون سر في 2023، +28%)
- GitHub Docs — إزالة البيانات الحساسة من مستودع وتدوير المفاتيح