بيان تثبيت الاعتماديات
سياسة الإعلان عن الاعتماديات تغطي نطاقات بيئة تشغيل Python، وأدوات التطوير، وملفات قفل أدوات الإصدار، والحدود الدنيا للإصدارات المُصادَق عليها لكل سطح بناء.
الموقف المُصادَق عليه لكيفية إعلان Apothem عن الاعتماديات وتثبيتها وقفلها. الجمهور: المساهمون والمستهلكون في المصبّ ممّن يحتاجون إلى فهم نموذج قابلية إعادة الإنتاج.
الموقف
Apothem هو واجهة سطر أوامر Python بمجموعة صغيرة من اعتماديات وقت التشغيل،
إضافةً إلى سلسلة أدوات أكبر للتطوير والتدقيق والإصدار والتوثيق. تستخدم اعتماديات
وقت التشغيل حدودًا دنيا متحفظة في pyproject.toml؛ ويُودِع الموقع
site/package-lock.json؛ وتُثبَّت GitHub Actions بـSHA غير قابل للتغيير
مع تعليقات الإصدار، وتُرقَّى عبر Dependabot.
| الصنف | الإعلان | سياسة القفل |
|---|---|---|
| اعتماديات وقت تشغيل Python | [project.dependencies] في pyproject.toml | نطاقات بحد أدنى للمستخدمين؛ ولا يأتي مع الحزمة أي قفل لوقت تشغيل Python. ويُثبِّت CI إغلاقًا مقفولًا بالتجزئة لهذه الاعتماديات (انظر أقفال اعتماديات CI) |
| أدوات التطوير / الأمان | extras الخاصة بـ[project.optional-dependencies] | نطاقات بحد أدنى، باستثناء ruff وmypy، إذ يُثبِّت extra dev كلًّا منهما تثبيتًا دقيقًا على الإصدار الذي يُشغِّله CI (انظر أقفال أدوات CI بخصوص ruff)؛ ويُثبِّت CI مكوّنات extra dev من إغلاق مقفول بالتجزئة (انظر أقفال اعتماديات CI) |
| أدوات الإصدار | scripts/release/requirements-build-linux.txt لسير عمل الإصدار؛ وextra release في [project.optional-dependencies] لعمليات البناء المحلية | مقفولة بالتجزئة لسير عمل الإصدار؛ مُولَّدة من إغلاق أدوات الإصدار. أما extra release فنطاق بحد أدنى |
| pip في CI | scripts/ci/requirements-ci-pip.txt | مقفول بالتجزئة: تثبيت واحد pip==X.Y.Z مع تجزئتَي حزمتَي wheel وsdist، ويُثبِّته بـ--require-hashes -r كلُّ سير عمل يُرقّي pip. يقترح Dependabot الترقيات ويعيد كتابة التجزئات؛ ويُبقي scripts/dev/check_pip_pin_drift.py التثبيت على pip 26.2 أو أحدث |
| أقفال اعتماديات CI | scripts/ci/requirements-ci-dev.txt و-runtime.txt و-test.txt و-prereqs.txt | إغلاقات موحَّدة لكل المنصات مقفولة بالتجزئة، تُولَّد بـuv pip compile من pyproject.toml (ومن متطلبات المضيف المسبقة للمحرّك في حالة -prereqs.txt) بحسب تاريخ قفل مطروحًا منه مهلة انتظار مدتها 7 أيام، ويُسجَّل كلاهما في كل ملف، وتُثبَّت بـ--require-hashes -r (والحزمة نفسها بـ--no-deps -e .). يختبر CI الإصدارات المقفولة إلى أن يعيد scripts/dev/refresh_ci_locks.py توليدها؛ ويدقّق pip-audit.yml أسبوعيًا أحدث الإصدارات المسموح بها، ويدقّق الأقفال أيضًا. ويفشل tests/scripts/test_ci_locks_fresh.py عندما يكفّ قفل عن تلبية مدخلاته |
| أقفال أدوات CI | scripts/ci/requirements-ci-ruff.txt و-bandit.txt و-pip-audit.txt و-pip-licenses.txt و-pre-commit.txt | إغلاق واحد مقفول بالتجزئة لكل أداة يُشغِّلها سير العمل، يُولِّده السكربت نفسه من مواصفة دقيقة في scripts/dev/ci_lock_table.py، بتاريخ القفل ومهلة الانتظار نفسيهما، ويُثبَّت بـ--require-hashes -r. ولا يذكر أي سير عمل إصدارَ أداة. يحتاج pre-commit إلى Python 3.11 أو أحدث، وكذلك قفله، ويُولَّد قفل pip-audit لـ3.11 أيضًا، لأن أحدث إصدار من filelock يدعم 3.10 عليه تنبيهات أمنية لم تُصلَح. ولا يُثبِّت pip أيُّ قفل سوى قفل pip في CI |
| موقع التوثيق | site/package.json | site/package-lock.json مُودَع ويستهلكه npm ci |
| مُحزِّم VS Code | tools/vsce/package.json | tools/vsce/package-lock.json مُودَع؛ وتُشغِّل مهام الإصدار والنشر npm ci --ignore-scripts |
| واجهات سطر أوامر الأدوات المضيفة لاختبار القنوات السريع | tools/channel-smoke/package.json | tools/channel-smoke/package-lock.json مُودَع ويستهلكه npm ci |
| GitHub Actions | مراجع uses: مُثبَّتة بـSHA مع تعليقات الإصدار | يقترح Dependabot تحديثات أسبوعية؛ وتحمل الاستثناءات علامات action-pinning-exempt: |
مصادقة الإصدار
| السطح | الحالة المُصادَق عليها | المسوّغ |
|---|---|---|
| اعتماديات وقت التشغيل | تعيش الحدود الدنيا الحالية في pyproject.toml ضمن [project.dependencies] | حدود دنيا مستقرّة حالية مُصادَق عليها قبل الإصدار؛ ولا يوجد مُعيق CVE معروف لوقت التشغيل |
| أدوات التطوير | تعيش الحدود الدنيا الحالية في الإضافة dev من pyproject.toml؛ وفيها التثبيتان الدقيقان لـruff وmypy | أحدث الحدود الدنيا المستقرّة المُصادَق عليها قبل الإصدار؛ ويُثبَّت كلٌّ من ruff وmypy على إصدار واحد للخطافات وCI والمساهمين، ويُثبِّت خطاف mypy المكتباتِ التي يسردها على إصداراتها في قفل dev، ويفشل tests/scripts/test_ci_tool_locks.py عند أي اختلاف بينها |
| أدوات الأمان | تعيش الحدود الدنيا الحالية في الإضافة security من pyproject.toml | حدود دنيا حالية للماسحات مُصادَق عليها قبل الإصدار |
| أدوات الإصدار | يعيش الإغلاق المقفول بالتجزئة في scripts/release/requirements-build-linux.txt | يُثبِّت سير عمل الإصدار بـ--require-hashes؛ وتشترط السكربتات المحلية وجود build مسبقًا بدلًا من تثبيت اعتماديات متحركة بصمت |
| pip في CI | يعيش التثبيت المقفول بالتجزئة في scripts/ci/requirements-ci-pip.txt | يسدّ pip 26.2 أو أحدث الثغرة CVE-2026-13346؛ ويُثبِّته سير العمل بـ--require-hashes، فيُطابَق التنزيل مع تجزئته المنشورة |
| أقفال اعتماديات CI | تعيش الإغلاقات المقفولة بالتجزئة في scripts/ci/requirements-ci-{dev,runtime,test,prereqs}.txt | يُثبِّتها سير العمل بـ--require-hashes؛ ويُسجِّل كلٌّ منها تاريخ قفله ومهلة الانتظار والتاريخ الفاصل، ويُبقيها اختبار الحداثة متوافقة مع pyproject.toml |
| أقفال أدوات CI | تعيش الإغلاقات المقفولة بالتجزئة في scripts/ci/requirements-ci-{ruff,bandit,pip-audit,pip-licenses,pre-commit}.txt | يُثبِّتها سير العمل بـ--require-hashes دون أن يذكر أي إصدار للأدوات؛ وتعيش المواصفات في scripts/dev/ci_lock_table.py، ويطابق تاريخ القفل ومهلة الانتظار والتاريخ الفاصل ما في أقفال الاعتماديات |
| أدوات التوثيق | تعيش النطاقات الحالية في site/package.json، ويعيش الحلّ الدقيق في site/package-lock.json | لا يُرجِع npm outdated أي اعتمادية توثيق متقادمة بعد تحديث ملف القفل |
| GitHub Actions | تُستبقى تثبيتات SHA الموجودة للإصدار الحالي؛ ويبقى سير عمل SLSA القابل لإعادة الاستخدام الاستثناءَ الموثَّق المُثبَّت بوسم، ويحمل تعليقَ action-pinning-exempt: في release.yml | إعادة تشغيل CI العام خضراء؛ وتُترَك عمدًا ترقيات الإصدارات الرئيسية الواسعة لـactions إلى طلبات سحب أتمتة الاعتماديات، لتفادي اضطراب سطح الإصدار |
| تحزيم npm | يعمل سير عمل publish-npm.yml عند دفع الوسم v*.*.*، مع workflow_dispatch بديلًا احتياطيًا | الحزمة npm العامة الوحيدة هي @ahmed-g-gad/apothem؛ وينتظر النشر موافقة المُشغِّل على بيئة release، وتُمنَح هذه الموافقة بعد اجتياز scripts/release/check-release-ready.sh |
القفل
تُولَّد ملفات قفل Python الخاصة بالمساهمين عند الطلب ولا تُودَع، لأن إغلاق وقت
تشغيل Apothem صغير، ولأن واجهة سطر الأوامر تدعم عدة إصدارات فرعية من Python.
ويُستثنى CI من ذلك، إذ يُثبِّت الملفات المقفولة بالتجزئة في scripts/ci/: أربعة
أقفال اعتماديات (requirements-ci-dev.txt و-runtime.txt و-test.txt
و-prereqs.txt)، وقفل واحد لكل أداة يُشغِّلها سير العمل (-ruff.txt
و-bandit.txt و-pip-audit.txt و-pip-licenses.txt
و-pre-commit.txt). ويُولِّد python scripts/dev/refresh_ci_locks.py الملفات
التسعة كلها بحسب تاريخ قفل مطروحًا منه مهلة انتظار مدتها 7 أيام تطابق مهلة Dependabot،
فيختبر CI الإصدارات التي مضى على نشرها أسبوع على الأقل في تاريخ القفل، ويُقدِّمها
تحديث الملفات إلى إصدارات أحدث. ويُسجِّل كل ملف تاريخ القفل ومهلة الانتظار والتاريخ الفاصل
الناتج، ويُعيد --check إنتاج ذلك التاريخ الفاصل. ويحتاج إصلاح أمني عاجل أحدث من
مهلة الانتظار إلى تشغيل تحديث بـ--cooldown-days 0، أو إلى استثناء من مهلة الانتظار
لحزمته في scripts/dev/ci_lock_table.py يرفع المهلة عن تلك الحزمة وحدها. ويدقّق
التشغيل الأسبوعي لـpip-audit.yml أحدث الإصدارات التي يسمح بها pyproject.toml
إضافةً إلى الأقفال التسعة، ويستعلم خدمة OSV عن التنبيهات الأمنية. ويواصل المساهمون
التثبيت بـpip install -e ".[dev]".
# Astral uv:
uv pip install -e ".[dev,security,release]"
uv pip freeze > requirements.dev.lock
# pip-tools:
pip-compile --extra=dev --extra=security --extra=release -o requirements.dev.lock pyproject.toml
# Plain pip:
pip install -e ".[dev,security,release]"
pip freeze > requirements.dev.lockأما الموقع فمختلف: يُودَع site/package-lock.json ويستخدم CI الأمر
npm ci، فيكون لموقع التوثيق الناتج إغلاق Node قابل لإعادة الإنتاج.
المسوّغ
- لماذا تثبيت بالنطاقات لـPython؟ تدعم واجهة سطر الأوامر مصفوفة Python واسعة،
لذا يحتفظ
pyproject.tomlبحدود دنيا متحفظة. ويُثبِّت CI إغلاقات مقفولة بالتجزئة لهذه النطاقات، يُحدِّثها القائم على صيانة المشروع بـscripts/dev/refresh_ci_locks.py(والوتيرة المقصودة أسبوعية)، ويحلّ التشغيل الأسبوعي لـpip-audit.ymlأحدث الإصدارات المسموح بها ليكشف المشكلات مع الأدوات الحالية. - لماذا قفل Node مُودَع؟ الموقع مُنتَج ساكن منشور؛ ويمنح ملف القفل عمليات بناء
npm ciحتمية لذلك السطح العام. - لماذا Actions مُثبَّتة بـSHA؟ الوسوم قابلة للتغيير؛ أما SHA فغير قابلة للتغيير. يقترح Dependabot ترقيات SHA ويعيد كتابة كل تعليق إصدار، بينما تُسجِّل بوابة الإصدار أي تأجيل مقصود.
- ما لا تلمسه أداة التحديث الآلية. تغطي تحديثات الإصدارات في Dependabot
(
.github/dependabot.yml) تثبيتات GitHub Actions، وملف قفل الموقع، وملف قفل مُحزِّم vsce (tools/vsce)، وملف قفل واجهات سطر أوامر الأدوات المضيفة الذي يُثبِّته اختبار القنوات السريع (tools/channel-smoke)، وpip المقفول بالتجزئة الذي يُثبِّته CI (scripts/ci/requirements-ci-pip.txt)، وخطافات pre-commit. والملفات التسعة الأخرى فيscripts/ciإغلاقاتٌ يُعاد توليدها كاملةً بـscripts/dev/refresh_ci_locks.py، ولا يُثبِّت أيٌّ منها pip، وتقتصر تحديثات الإصدارات في Dependabot لذلك المجلد على pip. أما الحدود الدنيا لوقت التشغيل فيpyproject.toml، ومتطلبات الإصدار المقفولة بالتجزئة، والإغلاق المُضمَّن فيsrc/apothem/_vendor/vendor.txt، وخطافات pre-commit المُثبَّتة بالتوازي معpyproject.toml، فتُحدَّث يدويًا، لأن ترقية تثبيت منفرد ستكسر الملفات التي تتوافق معها. وخطافا ruff وmypy اثنان منها: يفشلtests/scripts/test_ci_tool_locks.pyإلى أن يحمل التثبيت الدقيق لـruff فيpyproject.tomlوrev الخطاف وقفل ruff وقفل dev إصدارًا واحدًا، وإلى أن يطابق التثبيت الدقيق لـmypy وrev خطاف mypy والمكتبات التي يسردها ذلك الخطاف قفلَ dev. لذا يُكيَّف يدويًا أي طلب سحب أمني من Dependabot لأيٍّ من الأداتين. يتبع الإصدار الرئيسي لـ@types/nodeفي الموقع الحدَّ الأدنى لـNode (enginesو.nvmrc، Node 22)، فلا يقترح Dependabot إلا تحديثاته الفرعية والتصحيحية؛ ارفع ذلك الإصدار الرئيسي مع الحد الأدنى معًا. تترك تحديثات الإصدارات كتلoverridesفي npm دون مساس. أما تحديثات الأمان في Dependabot فتظل تغطي كل بيان، لذا قد يقترح طلب سحب أمني أحد هذه التثبيتات، أو ينقل تجاوزًا؛ فكيِّفه يدويًا أو أغلقه. - دمج طلب سحب من Dependabot. يأخذ الدمج الافتراضي بالضغط (squash) في
المستودع عنوانَ طلب السحب. وبعض عناوين Dependabot، ومعظمها عناوين مُجمَّعة تُسمّي
مجلدًا، تتجاوز سطر موضوع الضغط البالغ 72 حرفًا؛ ويُسمّيها فحص PR Title، ويُصلحها
تغيير العنوان. ولا يُشغِّل طلب السحب الذي يغيّر ملف قفل أداة أي مهمة من
ci.yml، لذا يدقّقه سير عمل تدقيق npm ويُثبِّته، ويُحزِّم امتداد VS Code لملف قفل vsce ويُشغِّل اختبارات إصدار vsce، ويعمل سير عمل اختبار القنوات السريع لملف قفل channel-smoke. ويُشغِّل سير عمل Markdown Lint خطاف markdownlint على طلب سحب خطافات pre-commit؛ أما الخطافات الأخرى فلا تُختبَر في CI، لذا شغِّلpre-commit run --all-filesعلى فرعه قبل دمجه.
ترويسة التأليف — سطر رخصة SPDX لكل ملف
تعريف علامات مُعرِّف رخصة SPDX لكل ملف وفرضها باستخدام ترويسات مرجعية أحادية السطر بصيغة التعليق المناسبة لكل نوع ملف.
انضباط الخطط — ذاكرة عمل عابرة محلية للمشروع
إدارة ذاكرة عمل عابرة محلية للمشروع في .apothem/plans/ (تُرقَّى شجرة .plans/ القديمة عبر apothem migrate-workspace) مع مخطط الواجهة الأمامية وانتقالات دورة الحياة والترقية إلى سجلات قرار معمارية والفرض عبر الخطافات والمُتحقِّقات.