سلسلة التوريد — التحقق من إصدار كاظمه
سلسلة التوريد — التحقق من إصدار كاظمه
Section titled “سلسلة التوريد — التحقق من إصدار كاظمه”كاظمه ذاتية الاستضافة. تشغّلها على جهازك أنت، غالبًا مقابل خزنتك الخاصة، ومسموح لها لمس ملفاتك وصدفتك ومستودعك. والإصدار الذي لا تستطيع التحقق منه إصدار تأخذه على الثقة، و«ثق بي» هو الشيء الوحيد الذي ليس هذا المشروع مستعدًا لطلبه.
لذلك كل قطعة إصدار موقَّعة، وتحمل إثبات منشأ البناء (build provenance)، وتُشحن معها SBOM. هذه الصفحة هي كيف تتحقق من الثلاثة. ولا شيء من ذلك يتطلب حسابًا ولا مورّدًا ولا خدمة مدفوعة.
ما يحتويه الإصدار
Section titled “ما يحتويه الإصدار”| الملف | ما هو |
|---|---|
kazma-<version>-py3-none-any.whl | حزمة wheel |
kazma-<version>.tar.gz | التوزيعة المصدرية |
kazma-<version>.cdx.json | SBOM بصيغة CycloneDX 1.6 لمجموعة التبعيات المثبّتة |
SHA256SUMS | بصمات تحقق (checksums) للملفات الثلاثة أعلاه |
*.sigstore.json | حزمة Sigstore لكل قطعة — التوقيع |
شهادات إثبات المنشأ ليست ملفات في الإصدار؛ GitHub يخزنها ويجلبها لك
gh attestation verify.
كاظمه ليست على PyPI
Section titled “كاظمه ليست على PyPI”تُوزَّع كاظمه عبر إصدارات Mubder/kazma على GitHub وعبر المستودع نفسه، ولا
شيء غيرهما. وعلى PyPI يحجز المشروع kazma وkazma-core والأسماء التي حولها
بحزم محجوزة: الإصدار 0.0.1 من كل منها، بلا شيفرة، وفيها صفحة فقط تحيل القارئ
إلى إصدارات GitHub. فتثبيت إحداها لا يثبّت شيئًا، ولا يستطيع أحد غير المشروع أن
ينشر تحت الاسم. لا تثبّت أبدًا kazma (أو kazma[...]) بالاسم من PyPI لتحصل
على كاظمه. ثبّت الإضافة من مجلد كاظمه لديك (pip install -e ".[web]"، أو
الإعدادات ← الحزم) وحدّث باستخدام kazma update.
في التثبيت المأخوذ من حزمة wheel لإصدار، يقرأ kazma update أحدث إصدار من
واجهة GitHub البرمجية، وينزّل حزمة wheel الخاصة به من ذلك الإصدار، ولا يثبّتها
إلا إذا طابقت بصمةُ SHA-256 للملف ملفَّ SHA256SUMS في الإصدار، وبصمةَ GitHub
نفسه للملف حين يذكرها؛ وإلا توقف وذكر صفحة الإصدار. ولا يتحقق هو نفسه من توقيع
Sigstore: شغّل gh attestation verify (أدناه) حين تريد هذا الإثبات. ويقرأ فحص
التحديثات في الإعدادات الإصدار نفسه. حتى 2026-09-30 كان كلاهما يسأل PyPI، ثم
كان kazma update يطلب من pip ترقية kazma بالاسم.
كيف تُحجز الأسماء
Section titled “كيف تُحجز الأسماء”الأسماء هي kazma وkazma-cli وkazma-core وkazma-gateway وkazma-memory
(المتقاعد) وkazma-skills وkazma-tui وkazma-ui (يبني الحزم المحجوزة
scripts/pypi_reserve.py). ونُشرت الثمانية كلها في 2026-10-01: الإصدار 0.0.1 من
كلٍّ منها، بحزمة wheel وأرشيف مصدر. ورفعها سير العمل .github/workflows/pypi-reserve.yml
عبر النشر الموثوق (Trusted Publishing) في PyPI، فلا يوجد أي توكن لـPyPI في أي
مكان. ولا يعمل إلا يدويًا (Actions ← Reserve PyPI names)، ودون خانة «publish»
يكتفي ببناء الحزم وفحصها.
ولا يقبل PyPI أول رفع لاسم إلا من ناشر مسجَّل له، ثم يبقى الناشر مع المشروع. ولحجز
اسم آخر، أضفه إلى قائمة السكربت (يُبقي الفحص في tests/test_no_pypi_kazma.py تلك
القائمة مطابقة لأسماء حزم كاظمه)، ثم سجّله في pypi.org، من Account ← Publishing ←
Add a new pending publisher ← GitHub، بما يلي:
| الحقل | القيمة |
|---|---|
| PyPI Project Name | الاسم (kazma، ثم kazma-cli، …) |
| Owner | Mubder |
| Repository name | kazma |
| Workflow name | pypi-reserve.yml |
| Environment name | pypi- والاسم (pypi-kazma، ثم pypi-kazma-cli، …) |
ولكل اسم بيئته الخاصة لأن PyPI لا يُبقي الإعداد الواحد منتظرًا إلا لمشروع جديد واحد في الوقت نفسه. فإن تشاركت الأسماء البيئة نفسها قبل الأول ورفض الباقي: “A pending trusted publisher matching this configuration has already been registered for a different project name”.
ثم شغّل سير العمل مع تحديد «publish» وكتابة الاسم الجديد في خانة «names». يُرفع كل اسم في مهمة خاصة به، تحت بيئته الخاصة، فإن غاب ناشر اسمٍ ما أو لم يطابق فشل وحده (“invalid-publisher”)، ويمكن إعادة التشغيل لذلك الاسم وحده. ولا يحتفظ الحساب بأكثر من ثلاثة ناشرين منتظرين في وقت واحد، ولهذا رُفعت الأسماء الثمانية الأولى على أربع دفعات.
1. إثبات المنشأ — هل بُني هذا من هذا المستودع؟
Section titled “1. إثبات المنشأ — هل بُني هذا من هذا المستودع؟”هذا هو الفحص الأهم، وهو أمر واحد:
gh attestation verify kazma-0.11.0-py3-none-any.whl --repo Mubder/kazmaوالنجاح يعني أن سجلّ شفافية GitHub يقرّ بأن الملف أنتجه سير عمل Release في
Mubder/kazma، من إيداع محدد، في تشغيلة يمكنك الذهاب إليها وقراءتها. والملف الذي
أعاد أحدهم بناءه أو رقّعه أو أدخله يفشل هنا — فلا يمكن إعادة الشهادة له دون صلاحية
كتابة على هذا المستودع.
2. التوقيع — Sigstore بلا مفاتيح
Section titled “2. التوقيع — Sigstore بلا مفاتيح”التوقيع بلا مفاتيح (keyless): لا مفتاح خاص يحتفظ به المشرف، فلا مفتاح يتسرب أو يُدار أو يُفقد. والهوية المشهَد لها هي سير عمل GitHub Actions نفسه، والشهادة مدوَّنة في سجلّ شفافية Sigstore العام.
pip install sigstore
python -m sigstore verify github \ --repository Mubder/kazma \ --bundle kazma-0.11.0-py3-none-any.whl.sigstore.json \ kazma-0.11.0-py3-none-any.whlوالصيغة الصريحة، إن أردت تثبيت الهوية الدقيقة بدل ترك الأمر الفرعي github
يبنيها:
python -m sigstore verify identity \ --cert-identity "https://github.com/Mubder/kazma/.github/workflows/release.yml@refs/tags/v0.11.0" \ --cert-oidc-issuer "https://token.actions.githubusercontent.com" \ --bundle kazma-0.11.0-py3-none-any.whl.sigstore.json \ kazma-0.11.0-py3-none-any.whlاللاحقة @refs/... هي مرجع git الذي بُني منه الإصدار. راجع التشغيلة إن لم تكن
متأكدًا أيها ينطبق.
3. بصمات التحقق
Section titled “3. بصمات التحقق”sha256sum -c SHA256SUMSأضعف الثلاثة وهي وحدها — إذ يمكن استبدال ملف البصمات مع القطع. ويستحق التشغيل
لأن SHA256SUMS موقَّع أيضًا، فالتحقق من حزمة Sigstore الخاصة به أولًا يجعل
البصمات ذات معنى.
4. الـ SBOM — ما فيه فعلًا
Section titled “4. الـ SBOM — ما فيه فعلًا”kazma-<version>.cdx.json بصيغة CycloneDX 1.6، مولَّد من uv.lock لا من بيئة
آلة البناء. وهذا التمييز مهم: فهو يصف المجموعة المثبّتة الدقيقة التي يثبّتها لك
uv sync، لا ما صادف أن حلّه مشغّل CI في ذلك اليوم.
أطعمه لما تستخدمه مؤسستك أصلًا. ولنظرة سريعة:
# Component count and licencespython - <<'PY'import jsond = json.load(open("kazma-0.11.0.cdx.json", encoding="utf-8"))comps = d.get("components") or []print(f"{len(comps)} components, CycloneDX {d['specVersion']}")PY
# Known vulnerabilities, via any CycloneDX-aware scannergrype sbom:kazma-0.11.0.cdx.jsontrivy sbom kazma-0.11.0.cdx.jsonإعادة بناء الأصول المضمَّنة
Section titled “إعادة بناء الأصول المضمَّنة”أصلان من طرف ثالث مُدرجان في المستودع بدل جلبهما، لأن الواجهة يجب أن تُصيَّر على جهاز لا طريق له إلى الإنترنت:
- CodeMirror 5 (MIT) —
kazma-ui/kazma_ui/static/vendor/codemirror/. أعِد البناء بـpython scripts/vendor_codemirror.py؛ والنسخة المثبّتة تعيش في ذلك السكربت وفي ملفVERSIONبجوار الحزمة. - IBM Plex Sans Arabic (OFL) —
kazma-ui/kazma_ui/static/fonts/.
يفشل tests/test_editor_assets_offline.py البناء إن بدأ أي قالب بتحميل سكربت أو
أوراق أنماط بعيدة مجددًا.
ما لا يثبته هذا
Section titled “ما لا يثبته هذا”يستحق القول بصراحة، لأن صفحة سلسلة توريد تبالغ في الوعود أسوأ من عدم وجودها أصلًا.
- ليست بناءات قابلة لإعادة الإنتاج. إثبات المنشأ يثبت من بنى القطعة ومن أي إيداع. وهو لا يمكّنك من إعادة بنائها باستقلال والحصول على نتيجة متطابقة بايتًا-ببايت. ذلك عمل أكبر ولا يُدَّعى.
- إثبات المنشأ ليس مراجعة كود. يثبت أن القطعة جاءت من هذا المستودع. ولا يقول شيئًا عن إن كان الكود في ذلك المستودع جيدًا أو آمنًا أو خاليًا من العلل. اقرأه؛ فلهذا هو مفتوح.
- الـ SBOM يسرد التبعيات، لا الثغرات. هو مدخل لماسح، لا شهادة سلامة.
- سجلّ Sigstore عام. التحقق لا يسرّب شيئًا، لكن كون إصدارًا موجودًا معلومة عامة بالتصميم.