
يحمي من هجمات سلسلة التوريد، والانزلاق الإملائي، والانتحال الإملائي من التبعيات والكود.
cargo install sloppy-joe
هجوم سلسلة التوريد LiteLLM (مارس 2026) اخترق حزمة تحمل 97 مليون تنزيل شهريًا. سرق المهاجمون بيانات اعتماد النشر، ودفعوا إصدارات خبيثة سرقت مفاتيح SSH وبيانات اعتماد السحابة وأسرار K8s. كانت بوابة عمر الإصدار الافتراضية لمدة 72 ساعة في sloppy-joe لتمنع كلا الإصدارين المسمومين — فقد تم اكتشافهما في غضون ساعات، قبل وقت طويل من فتح البوابة. إذا قمت بتشغيل
sloppy-joe checkفي CI، فإن هذا الهجوم يفشل. التحليل الكامل
المولدات الكودية بالذكاء الاصطناعي تهلوس أسماء الحزم بنسبة ~20% من الوقت. يسجل المهاجمون تلك الأسماء وينتظرون. يكتشف sloppy-joe هذه الحزم في CI قبل تشغيل npm install أو pip install.
cargo install sloppy-joe
sloppy-joe check
sloppy-joe check --full
sloppy-joe check --ci
sloppy-joe check --dir ./my-project
sloppy-joe check --type npm
sloppy-joe check --python-groups dev,test --python-version 3.12 sloppy-joe check --python-extras docs --python-platform linux --python-version 3.12
sloppy-joe check --config /etc/sloppy-joe/config.json
sloppy-joe check --config https://raw.githubusercontent.com/yourorg/security-configs/main/sloppy-joe.json
sloppy-joe check --json
sloppy-joe check --review-exceptions
sloppy-joe init --register
sloppy-joe init --greenfield --ecosystem npm
sloppy-joe init --from-current
sloppy-joe init --from-current --register
sloppy-joe init > /secure/location/sloppy-joe.json
### Nix```bash
nix profile install github:brennhill/sloppy-joe
أوضاع المسح:
sloppy-joe check بتشغيل الحاجز المحلي السريع. يفرض دائمًا تحليل ملفات البيان، ومزامنة ملفات القفل، والإثبات، وسياسة المصادر غير المدعومة. إذا تغيرت حالة التبعية أو السياسة، أو كان آخر مسح كامل ناجح أقدم من 24 ساعة، فإنه يوصي باستخدام sloppy-joe check --full.sloppy-joe check --full بتشغيل المسح الصارم عبر الإنترنت ويقوم بتحديث حالة المسح الكامل الناجح المسجلة.sloppy-joe check --ci بتشغيل نفس التغطية الصارمة مثل --full، مع نية موجهة للتكامل المستمر.sloppy-joe check بتقييم ملف runtime الشخصي افتراضيًا. إذا كانت هناك تبعيات نطاقية، فإنه يحذر ويطلب منك تمرير علامات --python-groups و--python-extras و--python-platform و/أو --python-version الصريحة لتحقيق التكافؤ مع CI/build.sloppy-joe check النصية القابلة للقراءة البشرية دائمًا باستخدام أو لأغراض CI والإنتاج.رموز الخروج: 0 = لم يتم العثور على مشكلات مانعة في الوضع المحدد، 1 = تم العثور على مشكلات مانعة، 2 = خطأ وقت التشغيل.
يدعم: JavaScript (npm، pnpm، Yarn، Bun)، Python، Rust، Go، Ruby، PHP، JVM (Gradle/Maven)، و.NET — يتم الكشف عنها تلقائيًا من ملفات البيان.
أدلة الأنظمة البيئية: راجع docs/ecosystems/README.md للحصول على نموذج الثقة الحالي والميزات المدعومة والحدود المغلقة عند الفشل لكل نظام بيئي.
مصادر التكوين: مسار ملف محلي، رابط HTTPS، أو متغير البيئة SLOPPY_JOE_CONFIG. لا تتم قراءة التكوين أبدًا من دليل المشروع (راجع CONFIG.md لمعرفة السبب).
الإعداد المبدئي: استخدم وضع التمهيد الذي يتطابق مع المستودع:
sloppy-joe init --greenfield --ecosystem <eco> سياسة بدء خاصة بالنظام البيئي للمشاريع الجديدة. حاليًا، تم تنفيذ الإعدادات المسبقة للـ greenfield لـ npm وpypi وcargo؛ تفشل الأنظمة البيئية الأخرى مع خطأ “غير مدعوم بعد”. أضف --register لكتابتها خارج المستودع وتسجيلها بأمان.sloppy-joe init --from-current المستودع الحالي ويطبع اقتراحات تمهيد للمراجعة فقط. حاليًا، تم تنفيذ --from-current فقط للمستودعات التي يكون كودها من الطرف الأول هو npm و/أو cargo؛ تفشل الأنظمة البيئية الأخرى بشكل مغلق مع خطأ “غير مطبق بعد”. أضف --register لكتابة وتسجيل التكوين المُنشأ.sloppy-joe init بدون وضع قالبًا يدويًا محايدًا.ملف ثنائي واحد. 8 أنظمة بيئية. 16 نوع هجوم. صفر نتائج إيجابية خاطئة في الفحوصات التوليدية. تكوين لا تستطيع عوامل AI العبث به.
تتحقق معظم أدوات أمان التبعيات من شيئين أو اثنين — الوجود، أو مسافة التحرير. يتحقق sloppy-joe من 16 ناقل هجوم في تمريرة واحدة: الحزم المُهلوسة، 10 أنواع من انتحال التشابه (تجانسات الحروف، احتلال النطاق، الأحرف المكررة، ارتباك الفاصل، إعادة ترتيب الكلمات، التبديلات المتجاورة، الأحرف المحذوفة، الأشكال المربكة، متغيرات الحالة، لاحقات الإصدار)، فرض القواعد الأساسية، التحكم في عمر الإصدار، تضخيم سكريبت التثبيت، انفجار التبعيات، تغييرات الصيانة، والثغرات المعروفة عبر OSV.dev.
يعمل كملف ثنائي Rust واحد بدون تبعيات وقت التشغيل. يدعم جميع الأنظمة البيئية الثمانية الرئيسية للحزم. وتصميم تكوينه من أجل الأمان: لا يُقرأ أبدًا من دليل المشروع، يمكن تحميله من رابط لـ CI، مع رسائل خطأ واضحة عند وجود خطأ ما.
🔶 = تجريبي/اختباري
الهجوم: يولد AI تعليمة import ai_json_helper. الحزمة غير موجودة. يقوم مهاجم بتسجيل ai-json-helper على PyPI مع برمجيات خبيثة. في المرة التالية التي يقوم فيها شخص ما بتشغيل pip install، يحصل على الحزمة الخبيثة.
كيف يحجبه sloppy-joe: يضرب فحص الوجود واجهة PyPI API ويحصل على 404. يتم حظر البناء.``` ERROR ai-json-helper [existence] Package 'ai-json-helper' does not exist on the pypi registry. It may be hallucinated by an AI code generator. Fix: Remove 'ai-json-helper' from your dependencies.
### 2. التصيد الإملائي (فحوصات توليدية + احتياطي مسافة التحرير)
**الهجوم:** يُسجِّل مهاجم الحزمة `expresz` على npm — حرف واحد مختلف عن `express`. قد تُنشئها الذكاء الاصطناعي، أو قد يخطئ المطور في كتابتها. الحزمة موجودة، وتجتاز فحص الوجود، وتُثبّت برامج ضارة.
**كيف يمنعها sloppy-joe:** يقوم sloppy-joe بتشغيل 10 فحوصات توليدية قبل اللجوء إلى احتياطي مسافة التحرير. يُنتِج كل فحص توليدي تحويرًا محددًا لاسم التبعية (تبديل الأحرف، تكرار الأحرف المتجاورة، إزالة اللواحق، إعادة ترتيب الكلمات، توحيد الفواصل، استبدال الحروف المتشابهة شكليًا، فحص النطاقات) ويختبر التطابق التام مع الحزم الشائعة المعروفة. هذا الأسلوب، المستوحى من مكتبة [Typomania لمؤسسة Rust](https://github.com/rustfoundation/typomania)، يتمتع باحتمال ضئيل جدًا للإيجابيات الكاذبة لأنه يعمل فقط على التطابقات التامة بعد التحوير.
تعمل مسافة التحرير لـ Levenshtein في النهاية كشبكة أمان للتحويرات الجديدة التي لم يتوقعها أي فحص محدد. معًا، تغطي أنماط الهجوم المعروفة (بدقة) وغير المعروفة (على نطاق واسع).```
ERROR expresz [similarity/edit-distance]
'expresz' is 1 character away from 'express'. This could be a typosquat.
Fix: If you meant 'express', fix the name in your manifest.
الهجوم: expresss (حرف s زائد) أو reeact (حرف e زائد). هذه أنماط هلوسة شائعة في الذكاء الاصطناعي — حيث يُنتج النموذج أسماءً تبدو معقولة ولكن بها أحرف متكررة.
كيف يحجبها sloppy-joe: يقوم فحص الأحرف المتكررة بإزالة نسخة مكررة واحدة في كل مرة ويتحقق مما إذا كانت النتيجة تطابق حزمة معروفة. expresss → إزالة حرف s واحد → express → تطابق.```
ERROR expresss [similarity/repeated-chars]
'expresss' matches 'express' after removing a repeated character.
Fix: Use 'express' — remove the repeated characters.
### 4. الارتباك في الفاصل
**الهجوم:** `python-dateutil` مقابل `python_dateutil` مقابل `pythondateutil`. في بعض السجلات، هذه حزم مختلفة. يسجل المهاجم المتغير.
**كيف يحجبها sloppy-joe:** يقوم بتطبيع جميع الفواصل (`-`, `_`, `.`) قبل المقارنة. إذا تطابق الشكل المُطبّع مع حزمة معروفة، يتم وضع علامة عليها.```
ERROR socket_io [similarity/separator-confusion]
'socket_io' matches 'socket.io' after normalizing separators.
Fix: Use the canonical name 'socket.io' with the correct separators.
الهجوم: parse-json مقابل json-parse. مسافة ليفنشتاين هي 8 — غير مرئية لفحوصات مسافة التحرير. لكن يمكن للمهاجم تسجيل الاسم المُعاد ترتيبه.
كيف يحجب sloppy-joe ذلك: يقسم على الفواصل، ويُولّد جميع التباديل للمقاطع، ويتحقق من كل منها مقابل المجموعة. parse-json → permute → json-parse → match.```
ERROR parse-json [similarity/word-reorder]
'parse-json' is a reordering of 'json-parse'.
Fix: Use 'json-parse' — the segments are in the wrong order.
### 6. تبديل الأحرف المتجاورة
**الهجوم:** `reqeust` بدلاً من `request`. حرفان متجاوران تم قلبهما — خطأ إملائي شائع يستغله المهاجمون.
**كيف يمنعه sloppy-joe:** يقوم بتوليد جميع متغيرات التبادل المتجاور لاسم التبعية ويتحقق من كل منها مقابل المجموعة.```
ERROR reqeusts [similarity/char-swap]
'reqeusts' matches 'requests' with two adjacent characters swapped.
Fix: Use 'requests' — two characters are transposed.
الهجوم: reqests (حرف u مفقود) بدلاً من requests. يقوم الذكاء الاصطناعي بإسقاط حرف واحد مما ينتج عنه اسم يبدو صحيحًا.
كيف يحجبه sloppy-joe: يُدرج كل حرف من a-z في كل موضع في الاسم ويتحقق مما إذا كانت أي نتيجة تطابق حزمة معروفة. reqests + u في الموضع 3 → requests → تطابق.```
ERROR reqests [similarity/omitted-char]
'reqests' matches 'requests' with one character inserted.
Fix: Use 'requests' — a character appears to be missing.
### 8. الهوموغليف (المتشابهات البصرية)
**الهجوم:** `rеquests` بحرف `е` سيريلي (U+0435) بدلاً من الحرف اللاتيني `e` (U+0065). متطابقة بصريًا. يبدو اسم الحزمة تمامًا مثل `requests` لكنه يشير إلى حزمة ضارة مختلفة.
**كيف يمنعه sloppy-joe:** يستبدل 17 حرفًا هوموغليفيًا معروفًا (سيريلية، عريضة، متغيرات خطية) بنظيراتها اللاتينية ويتحقق مما إذا كانت النتيجة تطابق حزمة معروفة.```
ERROR rеquests [similarity/homoglyph]
'rеquests' contains characters that look identical to 'requests'
but are different Unicode codepoints (homoglyphs).
Fix: Replace the lookalike characters with standard ASCII.
الهجوم: py-utils مقابل python-utils. على PyPI، هذان حزمان مختلفان. الذكاء الاصطناعي يولد أحدهما بينما كنت تقصد الآخر. بالمثل، github.com مقابل gitlab.com في وحدات Go.
كيف يقوم sloppy-joe بحظره: يطبق قواعد استبدال خاصة بالنظام البيئي (py↔python لـ PyPI، github↔gitlab لـ Go) ويتحقق مما إذا كان أي متغير يطابق حزمة معروفة.``` ERROR py-flask [similarity/confused-form] 'py-flask' is a confused form of 'flask'. Fix: Use the canonical name 'flask'.
### 10. هجمات تباين الحالة (سجلات حساسة لحالة الأحرف)
**الهجوم:** في Go و Maven و Ruby، فإن `Rails` و `rails` هما حزمتان مختلفتان. يقوم المهاجم بتسجيل المتغير الذي يحتوي على حرف كبير.
**كيف يمنعه sloppy-joe:** في السجلات الحساسة لحالة الأحرف، يتم وضع علامة على أي تباين في حالة حزمة معروفة كخطأ. في السجلات غير الحساسة لحالة الأحرف (npm, PyPI, Cargo, NuGet, PHP)، تكون تباينات الحالة آمنة ويتم تخطيها.```
ERROR Rails [similarity/case-variant]
'Rails' differs from 'rails' only in letter casing.
On case-sensitive registries (ruby) these resolve to different packages.
Fix: Use the exact casing 'rails' in your manifest.
الهجوم: requests2 أو lodash-4. يضيف الذكاء الاصطناعي رقم إصدار إلى اسم الحزمة بدلاً من تحديد الإصدار بشكل صحيح.
كيف يمنعه sloppy-joe: يزيل الأرقام والفواصل اللاحقة ويتحقق مما إذا كان الاسم الأساسي يطابق حزمة معروفة.``` ERROR requests2 [similarity/version-suffix] 'requests2' looks like 'requests' with a version suffix appended. Fix: Use 'requests' and specify the version in your manifest's version field.
### 12. احتلال النطاق (npm, PHP, Go, JVM)
**الهجوم:** يسجِّل المهاجم `@typos/lodash` على npm — بفارق حرف واحد عن `@types/lodash`. أو `larvael/framework` على Packagist — بفارق حرفين عن `laravel/framework`. أو `github.com/gooogle/protobuf` على Go — بحرف `o` زائد. يبدو النطاق شرعيًا للوهلة الأولى. يتم تحميل الحزمة. يتم تثبيت البرنامج الضار.
هذا نادر ولكنه محتمل — و"نادر ولكنه محتمل" هو تحديدًا ما وُجد من أجله sloppy-joe. حادثة `ua-parser-js` في عام 2021 كانت متعلقة بالنطاق. إذا كان يمكن أن يحدث لحزمة بملايين التنزيلات الأسبوعية، فيمكن أن يحدث لحزمتك.
**كيف يمنعه sloppy-joe:** يستخرج النطاق/الاسم الفضائي من اسم التبعية ويقارنه بقائمة النطاقات المعروفة الموثوقة باستخدام مسافة التعديل. يعمل على npm (`@scope`)، وPHP (`vendor/`)، وGo (`github.com/org`)، وJVM (`com.group`).```
ERROR @typos/lodash [similarity/scope-squatting]
Scope '@typos' is 1 character away from the known scope '@types'.
Scope squatting is a known supply chain attack vector.
Fix: If you meant '@types/lodash', fix the scope in your manifest.
projectdiscovery وobservers وdoc-*packet-capture (راجع)### 13. الحزم غير القانونية (ليست هجومًا — بوابة اتساق)
**الهجوم:** ليس هجومًا — مشكلة اتساق. تختار الذكاء الاصطناعي `moment` لأنه كان شائعًا في بيانات التدريب، لكن فريقك يستخدم `dayjs`. استخدام فرق مختلفة لحزم مختلفة لنفس المهمة يخلق دينًا صيانةً وتضخمًا في التبعيات.
**كيف يحجب sloppy-joe ذلك:** يقوم تكوينك بتعيين كل حزمة قانونية إلى بدائلها المرفوضة. إذا تطابقت تبعية مع بديل، يفشل البناء.```
ERROR moment [canonical]
'moment' is not the approved package for this purpose.
Your team uses 'dayjs'.
Fix: Replace 'moment' with 'dayjs' in your manifest file.
الهجوم: يخترق المهاجم حساب أحد صانعي الحزم (أو ينحرف صانع الحزمة عن المسار) وينشر إصدارًا خبيثًا من التصحيح. يبدو وكأنه تحديث عادي. إذا قامت بيئة التكامل المستمر (CI) الخاصة بك بتثبيته فورًا، فستكون مخترقًا قبل أن يلاحظ أحد.
كيف يمنعه sloppy-joe: تعمل بوابة عمر الإصدار على حظر أي تبعية تم نشر إصدارها منذ أقل من min_version_age_hours ساعة (الافتراضي: 72 ساعة). وهذا يمنح المجتمع و Socket.dev وأدوات المسح الأخرى الوقت الكافي للإبلاغ عن الإصدارات الخبيثة.```
ERROR react [metadata/version-age]
Version '^19.0.0' of 'react' was published 6 hours ago (minimum: 72 hours).
New versions need time for the community and security scanners to review them.
Fix: Wait until the version is at least 72 hours old, or pin to an older version.
### 15. الحزم الجديدة تمامًا
**الهجوم:** حزمة تم إنشاؤها أمس مع 3 تنزيلات ولها اسم مشابه لحزمة شائعة. احتمال كبير أنها انتحال اسم أو عنصر نائب لهجوم مستقبلي.
**كيف يمنعها sloppy-joe:** يشير إلى أي حزمة تم إنشاؤها منذ أقل من 30 يومًا.```
ERROR sketchy-lib [metadata/new-package]
'sketchy-lib' was first published 2 days ago.
New packages are higher risk.
Fix: Verify 'sketchy-lib' at its registry page and source repository.
الهجوم: حزمة بعدد تنزيلات 12 والتي تبعد حرفًا واحدًا عن requests. بالتأكيد تقريبًا هجوم تشابه إملائي.
كيف يمنعه sloppy-joe: يضع علامة على الحزم التي يقل عدد تنزيلاتها عن 100 (حيث يوفر السجل بيانات التنزيل — حاليًا npm و crates.io و RubyGems).``` ERROR requsets [metadata/low-downloads] 'requsets' has only 12 downloads. Fix: Verify 'requsets' is the package you intend to use.
---
## الأنظمة البيئية المدعومة
| النظام البيئي | الملف الدال (Manifest) | سياسة ملف القفل (Lockfile Policy) | الوجود (Existence) | البيانات الوصفية (Metadata) | بوابة العمر (Age Gate) |
|-----------|----------|-----------------|:---------:|:--------:|:--------:|
| npm | package.json | `package-lock.json` أو `npm-shrinkwrap.json` مطلوب | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| PyPI | `pyproject.toml`, `requirements*.txt`, `Pipfile`, `setup.cfg`, `setup.py` | يتم الوثوق بـ Poetry مع `poetry.lock`، ويتم الوثوق بـ uv مع `uv.lock`، ويتم الوثوق بـ pip-tools المقيد بالتجزئة الكاملة فقط عندما يربط رسم التبعيات الملتزم `--index-url` وقيم `--extra-index-url` المسموح بها بالضبط، ويمكن الوثوق بفهارس Poetry/uv المخصصة المرئية في المستودع فقط بواسطة قائمة السماح `trusted_indexes.pypi` بالضبط؛ الملفات الدالة القديمة تحذر في كل تشغيل ما لم يكن `python_enforcement` هو `poetry_only` | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Cargo | Cargo.toml | `Cargo.lock` مطلوب | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Go | go.mod | `go.sum` مطلوب للتبعيات الخارجية؛ غير مطلوب للمكتبة القياسية فقط أو `replace` المحلية بالكامل | :white_check_mark: | :x: | :x: |
| Ruby | Gemfile | `Gemfile.lock` مطلوب | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| PHP | composer.json | `composer.lock` مطلوب | :white_check_mark: | :x: | :x: |
| JVM (Gradle) | build.gradle / build.gradle.kts | `gradle.lockfile` مطلوب | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| JVM (Maven) | pom.xml | تحذير فقط: لا يوجد تطبيق صارم لملف القفل | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| .NET | *.csproj | `packages.lock.json` مطلوب | :white_check_mark: | :x: | :x: |
جميع الأنظمة البيئية تحصل على فحوصات الوجود + التشابه + القانونية. تعتمد البيانات الوصفية وبوابة العمر على ما يعرضه واجهة برمجة تطبيقات السجل. يدعم ملف القفل فحص التبعيات العابرة وحل الإصدارات الدقيق حيث يوفر النظام البيئي نموذج ملف قفل موثوق به على مستوى المستودع.
## بدء الاستخدام السريع```bash
# Install
cargo install sloppy-joe
# Check current project (auto-detects ecosystem)
sloppy-joe check
# Check with canonical enforcement and age gate
sloppy-joe check --config /etc/sloppy-joe/config.json
# Output as JSON for CI
sloppy-joe check --json
| الرمز | المعنى |
|---|---|
0 | تم اجتياز جميع الفحوصات |
1 | تم العثور على مشكلات |
2 | خطأ في وقت التشغيل |
{ "canonical": { "npm": { "lodash": ["underscore", "ramda", "lazy.js"], "dayjs": ["moment", "luxon"], "axios": ["request", "got", "node-fetch", "superagent"] }, "pypi": { "httpx": ["urllib3", "requests"], "ruff": ["flake8", "pylint"] } }, "internal": { "go": ["github.com/yourorg/"], "npm": ["@yourorg/"] }, "allowed": { "npm": ["some-vetted-external-pkg"] }, "similarity_exceptions": { "cargo": [ { "package": "serde_json", "candidate": "serde", "generator": "segment-overlap" } ] }, "metadata_exceptions": { "cargo": [ { "package": "colored", "check": "metadata/maintainer-change", "version": "2.2.0", "previous_publisher": "kurtlawrence", "current_publisher": "hwittenborn" } ] }, "min_version_age_hours": 72, "allow_legacy_npm_v1_lockfile": false, "python_enforcement": "prefer_poetry" }
**`canonical`** — المفاتيح هي حزم معتمدة؛ القيم هي بدائل مرفوضة.
**`internal`** — حزم مؤسستك. تخطي جميع الفحوصات. هذه تتغير باستمرار.
**`allowed`** — حزم خارجية مدققة. تخطي فحص الوجود والتشابه، ولكن لا تزال تخضع لشرط عمر الإصدار.
**`similarity_exceptions`** — إلغاءات دقيقة للحزمة/المرشح/المولد للإيجابيات الكاذبة للتشابه التي تمت مراجعتها. استخدم هذا عندما تكون حالة تشابه واحدة خاطئة ولكنك لا تزال ترغب في الفحوصات العادية على الحزمة.
**`metadata_exceptions`** — إلغاءات دقيقة للبيانات الوصفية التي تمت مراجعتها. حالياً هذا يدعم فقط `metadata/maintainer-change`، ويتطلب تطابقاً دقيقاً للحزمة/الإصدار/الناشر السابق/الناشر الحالي.
استخدم `sloppy-joe check --review-exceptions` عندما تحتاج إلى مراجعة حاصرات تغيير الصيانة. لا يزال المسح يحظر بشكل طبيعي، لكن الإخراج البشري يضيف قسم `REVIEW EXCEPTIONS` مع المالكين، رابط المستودع، ومقتطف `metadata_exceptions` جاهز للصق. `--json` يتضمن نفس البيانات في حقل `review_candidates` على المستوى الأعلى.
**`min_version_age_hours`** — حظر أي إصدار نُشر قبل أقل من هذا العدد من الساعات. الافتراضي: 72 (3 أيام). اضبط على 0 لتعطيله. الحزم الداخلية مستثناة.
**`allow_legacy_npm_v1_lockfile`** — السماح بملفات قفل npm `lockfileVersion: 1` من npm v5/v6 في وضع الثقة المنخفضة. الافتراضي: `false`. أبقه مغلقاً إلا إذا كنت عالقاً عمداً في npm القديم وتقبل التحذيرات الصاخبة بالإضافة إلى تغطية npm الانتقالية الموثوقة المنخفضة.
**`python_enforcement`** — يتحكم في سياسة الثقة في بايثون. `prefer_poetry` (الافتراضي) يثق في مشاريع Poetry ومشاريع uv، ويثق في متطلبات pip-tools المقفلة بالكامل بالتجزئة فقط عندما يربط رسم المتطلبات الملتزمة القيم `--index-url` وأي `--extra-index-url` غير PyPI بالضبط، وبخلاف ذلك يخفض pip-tools إلى ثقة منخفضة. الملفات القديمة مثل `requirements*.txt` غير المجزأة، `Pipfile`، `setup.cfg`، `setup.py`، و `pyproject.toml` غير Poetry/uv تحذر في كل تشغيل. `poetry_only` يحظر تلك سير عمل بايثون غير Poetry ويتطلب Poetry.
### أمان التكوين
لا **يُقرأ التكوين أبداً من دليل المشروع**. يمكن لوكيل ذكاء اصطناعي مع وصول إلى شل إعادة كتابة تكوين داخل المستودع لإدراج ما يريد في القائمة البيضاء.
حل التكوين:
1. `--config /path/to/config.json` — ملف محلي (علم CLI، أعلى أولوية)
2. `--config https://example.com/config.json` — جلب من URL
3. `SLOPPY_JOE_CONFIG=...` — متغير بيئة (مسار ملف أو URL)
4. لا تكوين = فحوصات الوجود والتشابه والبيانات الوصفية فقط
التكوينات التالفة **تفشل بشدة** مع رسائل خطأ قابلة للتنفيذ — لا يتراجع التكوين المعطل بصمت إلى عدم وجود حماية.
راجع [CONFIG.md](https://github.com/brennhill/sloppy-joe/blob/HEAD/CONFIG.md) للمرجع الكامل للتنسيق، وأنماط تكامل CI، والأمثلة.
تكوين التمهيد:```bash
sloppy-joe init --greenfield --ecosystem npm
sloppy-joe init --from-current
sloppy-joe init --from-current --register
sloppy-joe init --register
أسرع طريقة لإضافة sloppy-joe إلى خط أنابيب CI الخاص بك — يقوم بتنزيل ملف ثنائي مبني مسبقًا من GitHub Releases (لا حاجة لـ Rust toolchain):```yaml
name: Dependency Check on: [push, pull_request]
jobs: sloppy-joe: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: brennhill/[email protected] with: config: https://raw.githubusercontent.com/yourorg/configs/main/sloppy-joe.json
#### مدخلات الإجراء
| المدخل | الوصف | الافتراضي |
|-------|-------------|---------|
| `config` | مسار ملف التكوين أو رابط HTTPS | *(لا شيء)* |
| `dir` | دليل المشروع المراد مسحه | `.` |
| `type` | النظام البيئي (`npm`, `pypi`, `cargo`, `go`, `ruby`, `php`, `jvm`, `dotnet`) | اكتشاف تلقائي |
| `deep` | تمكين فحوصات تشابه التبعيات المتعدية | `false` |
| `paranoid` | تمكين تغييرات bitflip | `false` |
| `args` | وسائط سطر أوامر إضافية | *(لا شيء)* |
| `version` | إصدار sloppy-joe المراد تثبيته | `latest` |
#### أمثلة```yaml
# Minimal — CI-oriented scan, auto-detect ecosystem, no config
- uses: brennhill/[email protected]
# With org config from a URL
- uses: brennhill/[email protected]
with:
config: https://raw.githubusercontent.com/yourorg/configs/main/sloppy-joe.json
# Deep scan with paranoid mode
- uses: brennhill/[email protected]
with:
config: ${{ secrets.SLOPPY_JOE_CONFIG }}
deep: true
paranoid: true
# Scan a subdirectory, pin to a specific version
- uses: brennhill/[email protected]
with:
dir: ./packages/api
version: '1.1.0'
dependency-guard: script: - cargo install sloppy-joe - sloppy-joe check --ci --config $SLOPPY_JOE_CONFIG
### pre-commit
يعمل sloppy-joe مع إطار [pre-commit](https://pre-commit.com).
أضفه إلى ملف `.pre-commit-config.yaml` الخاص بك:```yaml
# .pre-commit-config.yaml
repos:
- repo: https://github.com/brennhill/sloppy-joe
rev: v1.1.0
hooks:
- id: sloppy-joe
يقوم الخطاف بتشغيل sloppy-joe check على كل commit (واختياريًا على push). يكتشف تلقائيًا النظام البيئي الخاص بك من ملفات البيان. قم بتمرير وسائط إضافية عبر args:```yaml
- id: sloppy-joe
args: [--config, "https://example.com/config.json"]
أو استخدم ربط شل بسيط دون الإطار:```bash
#!/bin/sh
sloppy-joe check || exit 1
يستخدم sloppy-joe نهجاً توليدياً قائماً على السجل للكشف عن التشابه. بدلاً من مقارنة كل تبعية مع مجموعة ثابتة باستخدام مسافة التحرير (التي تنتج نتائج إيجابية خاطئة)، يقوم بتوليد طفرات محددة لكل اسم تبعية، ويستعلم السجل للتحقق من وجود الطفرة، ويضع علامة على التطابقات التامة.``` Pipeline (in order):
تشغيل التشابه على 4 مراحل:
- **Phase 0: Scope squatting** — فحص محلي، بدون اتصال بالشبكة. يقارن النطاق/الفضاء الاسمي مع نطاقات معروفة جيدة عبر مسافة ليفنشتاين.
- **Phase 1: Intra-manifest** — فحص محلي. يشير إلى وجود تبعيتين في نفس المانيفست تكونان طفرات من بعضهما البعض.
- **Phase 2: Registry query** — يولد الطفرات، ويستعلم السجل بشكل دفعاتي لوجودها، ويخزن النتائج مؤقتًا (7 أيام TTL).
- **Phase 3: Metadata enrichment** — يجلب أعداد التحميلات وتواريخ النشر للمطابقات لإضافة أدلة إلى التقارير.
كل مولد طفرة يوسم مخرجاته، لذلك فإن نوع الفحص المُبلَّغ عنه (مثل `similarity/homoglyph`) حتمي — المولد ذو الخطورة الأعلى يفوز عندما تنتج مولدات متعددة نفس المرشح.
## موثوقية التكامل المستمر
صمم sloppy-joe لخطوط أنابيب التكامل المستمر حيث الفشل المتقلب غير مقبول.
**إعادة المحاولة مع التباطؤ.** جميع استدعاءات HTTP للسجل تعيد المحاولة 3 مرات مع تباطؤ أسي (200ms، 400ms، 800ms) عند الفشل المؤقت (5xx، مهلات، أخطاء اتصال). خلل شبكة واحد لن يعطل بناءك.
**الإغلاق عند الفشل في أخطاء الاستعلام.** إذا فشلت استعلامات السجل أو OSV، يُصدر sloppy-joe خطأ حظرًا `registry-unreachable` بدلاً من تخطي الفحوصات بصمت. لم يعد الفحص يعتمد على عتبات لكل نظام بيئي أو عتبات حجم العينة قبل الحظر.
**ذاكرة تشابه مؤقتة.** تُخزَّن نتائج وجود الطفرات مؤقتًا لمدة 7 أيام. بعد أول فحص، تُخدم معظم الاستعلامات من الذاكرة المؤقتة بدون استدعاءات شبكة. فقط التبعيات الجديدة تؤدي إلى استعلامات السجل.
**تحليل واعي بملف القفل.** عندما يكون ملف القفل المدعوم موجودًا وجديرًا بالثقة (`package-lock.json`, `npm-shrinkwrap.json`, `Cargo.lock`, `Gemfile.lock`, `poetry.lock` لمشاريع Poetry, `uv.lock` لمشاريع uv, `composer.lock`, `gradle.lockfile`, `packages.lock.json`), يحلل sloppy-joe الإصدارات الدقيقة منه بدلاً من التخمين من النطاقات. كما يمكن لـ `requirements*.txt` المغلقة بالهاش بالكامل توفير إصدارات مثبتة دقيقة، وتصبح موثوقة تمامًا عندما يربط رسم التبعيات المُلتزَم به قيم `--index-url` الخاصة وقيم `--extra-index-url` المسموح بها بدقة.
## الاختبارات
تغطي مجموعة الاختبارات فحوصات التشابه، إشارات البيانات الوصفية، سلوك OSV، تحليل الإعدادات والتحقق منها، تحليل ملف القفل، سياسة الفحص المسبق للمانيفست وملف القفل، تنسيق التقارير، ومنطق إعادة محاولة HTTP.```bash
cargo test
حيث يكون الآخرون أقوى: يقوم Socket.dev بتحليل عميق لسكريبتات التثبيت مع كشف سلوكي يتجاوز بكثير النهج القائم على العلامات في sloppy-joe. cargo-deny لديه أفضل فحص للامتثال للتراخيص، ولكن هذا خارج نطاق sloppy-joe عن قصد لأن سياسة الترخيص هي مشكلة امتثال وليست تحكمًا أمنيًا في التبعيات. npm audit و pip-audit هما خياران بدون تثبيت لفحص الثغرات في نظام بيئي واحد.
حيث يختلف sloppy-joe: إنها الأداة الوحيدة التي تتحقق من وجود الحزم فعليًا في السجلات (لكشف تخيلات AI)، وتشغل 11 مولدًا للتصيد التشابهي مع أخطاء إيجابية تقترب من الصفر، وتفرض اختيارات الحزم القانونية، وتحتفظ بإعداداتها خارج المستودع حتى لا يتمكن وكلاء AI من إضعاف فحوصاتهم الخاصة.
Apache 2.0
--ci--full| النظام البيئي | ملف البيان المطلوب | ملف القفل / حالة المشروع الموثوقة |
|---|
| JavaScript / npm | package.json | package-lock.json أو npm-shrinkwrap.json؛ إصدار npm v1 القديم محظور افتراضيًا |
| JavaScript / pnpm | package.json | pnpm-lock.yaml |
| JavaScript / Yarn | package.json | yarn.lock |
| JavaScript / Bun | package.json | bun.lock |
| Python | pyproject.toml، requirements*.txt، Pipfile، setup.cfg، أو setup.py | مسار Poetry الموثوق يستخدم poetry.lock، مسار uv الموثوق يستخدم uv.lock، يتم الوثوق بأدوات pip-tools ذات القفل الكامل للتجزئة فقط عندما يربط رسم بياني متطلبات ملتزم بقيم --index-url وأي --extra-index-url بالضبط؛ يمكن السماح لمؤشرات Python المرئية في المستودع عبر trusted_indexes.pypi؛ الأوضاع الموثوقة لـ Python تقيم ملف تثبيت واحد محدد في كل مرة (runtime افتراضيًا، مجموعات/إضافات/منصة/بنية/إصدار صريحة عبر CLI)؛ يُسمح بملفات البيان القديمة مع تحذيرات افتراضيًا |
| Rust | Cargo.toml | Cargo.lock |
| Go | go.mod | go.sum مطلوب للتبعيات الخارجية |
| Ruby | Gemfile | Gemfile.lock |
| PHP / Composer | composer.json | composer.lock |
| JVM / Gradle | build.gradle أو build.gradle.kts | gradle.lockfile |
| JVM / Maven | pom.xml | تحذير فقط: لا يوجد مسار لملف قفل موثوق به محلي في المشروع حتى الآن |
| .NET / NuGet | .csproj | packages.lock.json |
| sloppy-joe | Socket.dev | GuardDog | Phantom Guard | antislopsquat |
|---|
| فحص الوجود | ✅ | ✅ | ❌ | ✅ | ✅ |
| التشابه / انتحال التشابه | ✅ | ✅ | ✅ | ✅ | ❌ |
| كشف تجانس الحروف | ✅ | ❌ | ❌ | ❌ | ❌ |
| احتلال النطاق | ✅ | ❌ | ❌ | ❌ | ❌ |
| فرض القواعد الأساسية | ✅ | ❌ | ❌ | ❌ | ❌ |
| التحكم في عمر الإصدار | ✅ | ❌ | ❌ | ❌ | ❌ |
| تضخيم سكريبت التثبيت | ✅ | ✅ | ❌ | ❌ | ❌ |
| انفجار التبعيات | ✅ | ❌ | ❌ | ❌ | ❌ |
| تغيير الصيانة | ✅ | ✅ | ❌ | ❌ | ❌ |
| فحص ثغرات OSV | ✅ | ✅ | ❌ | ❌ | ❌ |
| أمان التكوين (خارج المستودع) | ✅ | N/A | ❌ | ❌ | ❌ |
| القوائم الداخلية + المسموح بها | ✅ | ❌ | ❌ | ❌ | ❌ |
| npm | ✅ | ✅ | ✅ | ✅ | ❌ |
| PyPI | ✅ | ✅ | ✅ | ✅ | ✅ |
| Cargo | ✅ | ✅ | ❌ | ✅ | ❌ |
| Go | ✅ | ✅ | ✅ | ❌ | ❌ |
| Ruby | ✅ | ✅ | ✅ | ❌ | ❌ |
| PHP | ✅ | 🔶 | ❌ | ❌ | ❌ |
| JVM (Gradle/Maven) | ✅ | ✅ | ❌ | ❌ | ❌ |
| .NET (NuGet) | ✅ | ✅ | ❌ | ❌ | ❌ |
| ملف ثنائي واحد | ✅ | ❌ | ❌ | ❌ | ❌ |
| مفتوح المصدر | Apache 2.0 | تجاري | Apache 2.0 | MIT | OSS |
| اللغة | Rust | SaaS | Python | Python | Python |
| الميزة | sloppy-joe | Socket.dev | cargo-deny | pip-audit | npm audit |
|---|
| كشف الحزم المتخيلة | ✅ | ❌ | ❌ | ❌ | ❌ |
| كشف التصيد التشابهي | ✅ 11 مولدًا | جزئي | ❌ | ❌ | ❌ |
| فرض الاسم القانوني | ✅ | ❌ | ❌ | ❌ | ❌ |
| فحص الثغرات المعروفة | ✅ عبر OSV | ✅ | ✅ | ✅ | ✅ |
| تحليل سكريبت التثبيت | أساسي (علامة + لا مستودع) | ✅ تحليل عميق | ❌ | ❌ | ❌ |
| الامتثال للتراخيص | خارج النطاق: الامتثال، ليس أمانًا | ✅ | ✅ ممتاز | خارج النطاق: الامتثال، ليس أمانًا | خارج النطاق: الامتثال، ليس أمانًا |
| متعدد الأنظمة البيئية | 8 أنظمة بيئية | npm, PyPI, Go, Ruby, Java, .NET | Rust فقط | Python فقط | npm فقط |
| سلامة وكيل AI (إعداد خارج المستودع) | ✅ | ❌ | ❌ | ❌ | ❌ |
| مناسب للاستخدام دون اتصال/CI | ✅ يعمل في أي مكان | يتطلب منصة Socket | ✅ | ✅ | ✅ |
| مجاني / مفتوح المصدر | Apache 2.0 | طبقة مجانية + مدفوعة | Apache 2.0 | Apache 2.0 | مدمج |