Manifeste d'épinglage des dépendances
Politique de déclaration des dépendances couvrant les plages du runtime Python, l'outillage de développement, les fichiers de verrouillage de l'outillage de publication et les planchers de version ratifiés pour chaque surface de build.
Posture ratifiée sur la manière dont Apothem déclare, épingle et verrouille ses dépendances. Public : contributeurs et consommateurs en aval qui doivent comprendre le modèle de reproductibilité.
Posture
Apothem est une CLI Python avec un petit ensemble de dépendances d'exécution,
auxquelles s'ajoute une chaîne d'outils plus vaste de développement, d'audit, de
publication et de documentation. Les dépendances d'exécution utilisent des
bornes inférieures prudentes dans pyproject.toml ; le site web commite
site/package-lock.json ; les GitHub Actions sont épinglées par SHA immuable
avec des commentaires de version et sont mises à niveau par Dependabot.
| Classe | Déclaration | Politique de verrouillage |
|---|---|---|
| Dépendances d'exécution Python | [project.dependencies] dans pyproject.toml | Plages à borne inférieure pour les utilisateurs ; aucun verrou d'exécution Python n'est livré avec le paquet. La CI installe une fermeture verrouillée par hash de ces dépendances (voir Verrous de dépendances de la CI) |
| Outillage de développement / sécurité | extras de [project.optional-dependencies] | Plages à borne inférieure, sauf ruff et mypy, que l'extra dev épingle exactement aux versions qu'exécute la CI (pour ruff, voir Verrous d'outils de la CI) ; la CI installe l'extra dev à partir d'une fermeture verrouillée par hash (voir Verrous de dépendances de la CI) |
| Outillage de publication | scripts/release/requirements-build-linux.txt pour les flux de travail de publication ; l'extra release de [project.optional-dependencies] pour les builds locaux | Verrouillé par hash pour les flux de travail de publication ; généré à partir de la fermeture de l'outillage de publication. L'extra release est une plage à borne inférieure |
| pip de la CI | scripts/ci/requirements-ci-pip.txt | Verrouillé par hash : un seul épinglage pip==X.Y.Z avec les hashs de son wheel et de son sdist, installé avec --require-hashes -r par chaque flux de travail qui met pip à niveau. Dependabot propose les mises à niveau et réécrit les hashs ; scripts/dev/check_pip_pin_drift.py maintient l'épinglage à pip 26.2 ou plus récent |
| Verrous de dépendances de la CI | scripts/ci/requirements-ci-dev.txt, -runtime.txt, -test.txt et -prereqs.txt | Fermetures universelles verrouillées par hash, compilées avec uv pip compile à partir de pyproject.toml (ou, pour -prereqs.txt, des prérequis d'hôte du moteur) à une date de verrouillage moins un délai d'attente de 7 jours, tous deux consignés dans chaque fichier, et installées avec --require-hashes -r (le paquet lui-même avec --no-deps -e .). La CI teste les versions verrouillées jusqu'à ce que scripts/dev/refresh_ci_locks.py les régénère ; pip-audit.yml audite chaque semaine les versions autorisées les plus récentes, ainsi que les verrous. tests/scripts/test_ci_locks_fresh.py échoue quand un verrou ne satisfait plus ses entrées |
| Verrous d'outils de la CI | scripts/ci/requirements-ci-ruff.txt, -bandit.txt, -pip-audit.txt, -pip-licenses.txt et -pre-commit.txt | Une fermeture verrouillée par hash par outil qu'exécutent les flux de travail, compilée par le même script à partir d'une spécification exacte dans scripts/dev/ci_lock_table.py, avec la même date de verrouillage et le même délai d'attente, et installée avec --require-hashes -r. Aucun flux de travail n'écrit de version d'outil. pre-commit exige Python 3.11 ou plus récent, donc son verrou aussi, et le verrou pip-audit est lui aussi compilé pour 3.11, car le filelock le plus récent qui prend en charge 3.10 a des avis de sécurité non corrigés. Seul le verrou pip de la CI épingle pip |
| Site de documentation | site/package.json | site/package-lock.json commité et consommé par npm ci |
| Empaqueteur VS Code | tools/vsce/package.json | tools/vsce/package-lock.json commité ; les tâches de publication et de mise en ligne exécutent npm ci --ignore-scripts |
| CLI des harnais du channel-smoke | tools/channel-smoke/package.json | tools/channel-smoke/package-lock.json commité et consommé par npm ci |
| GitHub Actions | Références uses: épinglées par SHA avec commentaires de version | Dependabot propose des mises à jour hebdomadaires ; les exceptions portent des marqueurs action-pinning-exempt: |
Ratification de publication
| Surface | État ratifié | Justification |
|---|---|---|
| Dépendances d'exécution | Les bornes inférieures actuelles vivent dans pyproject.toml [project.dependencies] | Planchers stables actuels ratifiés avant la publication ; aucune CVE d'exécution connue ne bloque |
| Outillage de développement | Les bornes inférieures actuelles vivent dans l'extra dev de pyproject.toml ; ruff et mypy y sont épinglés exactement | Derniers planchers stables ratifiés avant la publication ; ruff et mypy sont chacun épinglés à une seule version pour les hooks, la CI et les contributeurs, le hook mypy épingle les bibliothèques qu'il liste aux versions du verrou dev, et tests/scripts/test_ci_tool_locks.py échoue en cas d'écart |
| Outillage de sécurité | Les bornes inférieures actuelles vivent dans l'extra security de pyproject.toml | Planchers de scanner actuels ratifiés avant la publication |
| Outillage de publication | La fermeture verrouillée par hash vit dans scripts/release/requirements-build-linux.txt | Le flux de travail de publication installe avec --require-hashes ; les scripts locaux exigent que build existe déjà au lieu d'installer silencieusement des dépendances mouvantes |
| pip de la CI | L'épinglage verrouillé par hash vit dans scripts/ci/requirements-ci-pip.txt | pip 26.2 ou plus récent corrige la CVE-2026-13346 ; les flux de travail l'installent avec --require-hashes, si bien que le téléchargement est vérifié par rapport à son hash publié |
| Verrous de dépendances de la CI | Les fermetures verrouillées par hash vivent dans scripts/ci/requirements-ci-{dev,runtime,test,prereqs}.txt | Les flux de travail les installent avec --require-hashes ; chacune consigne sa date de verrouillage, son délai d'attente et sa date limite, et le test de fraîcheur les maintient en phase avec pyproject.toml |
| Verrous d'outils de la CI | Les fermetures verrouillées par hash vivent dans scripts/ci/requirements-ci-{ruff,bandit,pip-audit,pip-licenses,pre-commit}.txt | Les flux de travail les installent avec --require-hashes et ne mentionnent aucune version d'outil ; les spécifications vivent dans scripts/dev/ci_lock_table.py, et la date de verrouillage, le délai d'attente et la date limite sont ceux des verrous de dépendances |
| Outillage de documentation | Les plages actuelles vivent dans site/package.json ; la résolution exacte vit dans site/package-lock.json | npm outdated ne renvoie aucune dépendance de documentation obsolète après l'actualisation du fichier de verrouillage |
| GitHub Actions | Les épinglages SHA existants sont conservés pour la publication actuelle ; le flux de travail réutilisable SLSA reste l'exception documentée épinglée par étiquette, signalée par un commentaire action-pinning-exempt: dans release.yml | La réexécution de la CI publique est au vert ; les mises à niveau larges de version majeure des actions sont intentionnellement laissées aux pull requests d'automatisation des dépendances, pour éviter les remaniements de la surface de publication |
| Empaquetage npm | Le flux de travail publish-npm.yml s'exécute au push de l'étiquette v*.*.*, avec workflow_dispatch comme solution de repli | Le seul paquet npm public est @ahmed-g-gad/apothem ; la publication attend l'approbation de l'environnement release par l'opérateur, donnée après que scripts/release/check-release-ready.sh a réussi |
Verrouillage
Les fichiers de verrouillage Python propres aux contributeurs sont générés à la
demande et ne sont pas commités : la fermeture d'exécution d'Apothem est petite
et la CLI prend en charge plusieurs versions mineures de Python. La CI fait
exception. Elle installe les fichiers verrouillés par hash de scripts/ci/ :
quatre verrous de dépendances (requirements-ci-dev.txt, -runtime.txt,
-test.txt et -prereqs.txt) et un verrou par outil qu'exécutent les flux de
travail (-ruff.txt, -bandit.txt, -pip-audit.txt, -pip-licenses.txt et
-pre-commit.txt). python scripts/dev/refresh_ci_locks.py compile les neuf à
une date de verrouillage moins un délai d'attente de 7 jours, aligné sur celui
de Dependabot : la CI teste donc les versions publiées depuis au moins une
semaine à la date de verrouillage, et l'actualisation des fichiers les fait
avancer. Chaque fichier consigne la date de verrouillage, le délai d'attente et
la date limite qui en résulte, et --check reproduit cette date limite. Un
correctif de sécurité urgent plus récent que le délai d'attente exige une
actualisation avec --cooldown-days 0, ou une exception au délai d'attente
pour son paquet dans scripts/dev/ci_lock_table.py, qui lève le délai pour ce
seul paquet. L'exécution hebdomadaire de pip-audit.yml audite les versions
les plus récentes qu'autorise pyproject.toml ainsi que les neuf verrous, en
interrogeant le service OSV sur les avis de sécurité. Les contributeurs
continuent d'installer avec 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.lockLe site web est différent : site/package-lock.json est commité et la CI utilise
npm ci, de sorte que le site de documentation rendu possède une fermeture Node
reproductible.
Justification
- Pourquoi des épinglages par plage pour Python ? La CLI prend en charge une
large matrice Python, donc
pyproject.tomlgarde des planchers prudents. La CI installe des fermetures verrouillées par hash de ces plages, que le mainteneur actualise avecscripts/dev/refresh_ci_locks.py(le rythme prévu est hebdomadaire), et l'exécution hebdomadaire depip-audit.ymlrésout les versions autorisées les plus récentes pour révéler les problèmes avec l'outillage actuel. - Pourquoi un verrou Node commité ? Le site web est un artefact statique
déployé ; le fichier de verrouillage donne des builds
npm cidéterministes pour cette surface publique. - Pourquoi des Actions épinglées par SHA ? Les étiquettes sont mutables ; les SHA sont immuables. Dependabot propose les mises à niveau de SHA et réécrit chaque commentaire de version, tandis que le portail de publication consigne toute retenue intentionnelle.
- Ce que le robot de mise à jour ne touche pas. Les mises à jour de version
de Dependabot (
.github/dependabot.yml) couvrent les épinglages des GitHub Actions, le fichier de verrouillage du site web, le fichier de verrouillage de l'empaqueteur vsce (tools/vsce), le fichier de verrouillage des CLI de harnais qu'installe le channel smoke (tools/channel-smoke), le pip verrouillé par hash qu'installe la CI (scripts/ci/requirements-ci-pip.txt) et les hooks pre-commit. Les neuf autres fichiers descripts/cisont des fermetures régénérées en entier avecscripts/dev/refresh_ci_locks.py; aucun n'épingle pip, et les mises à jour de version de Dependabot pour ce dossier se limitent à pip. Les planchers d'exécution depyproject.toml, les exigences de publication verrouillées par hash, la fermeture vendorisée desrc/apothem/_vendor/vendor.txtet les hooks pre-commit épinglés en phase avecpyproject.tomlévoluent à la main, car la mise à niveau d'un seul épinglage casserait les fichiers avec lesquels ils concordent. Les hooks ruff et mypy en font partie :tests/scripts/test_ci_tool_locks.pyéchoue tant que l'épinglage exact de ruff danspyproject.toml, la rev du hook, le verrou ruff et le verrou dev ne portent pas une seule et même version, et tant que l'épinglage exact de mypy, la rev du hook mypy et les bibliothèques que liste ce hook ne correspondent pas au verrou dev. Une pull request de sécurité Dependabot pour l'un ou l'autre outil s'adapte donc à la main. La version majeure de@types/nodedu site web suit son plancher Node (engineset.nvmrc, Node 22) ; Dependabot ne propose donc que ses mises à jour mineures et correctives ; relevez cette version majeure en même temps que le plancher. Les mises à jour de version laissent intacts les blocs npmoverrides. Les mises à jour de sécurité de Dependabot couvrent toujours chaque manifeste, de sorte qu'une pull request de sécurité peut proposer l'un de ces épinglages, ou déplacer une surcharge ; adaptez-la à la main ou fermez-la. - Fusionner une pull request Dependabot. Le squash par défaut du dépôt
reprend le titre de la PR. Certains titres Dependabot, surtout des titres
groupés qui nomment un répertoire, dépassent le sujet de squash de
72 caractères ; la vérification PR Title les signale, et un changement de
titre les corrige. Une pull request qui modifie le fichier de verrouillage
d'un outil n'exécute aucune tâche
ci.yml; le flux de travail d'audit npm l'audite et l'installe, empaquette l'extension VS Code pour le fichier de verrouillage vsce et exécute les tests de publication vsce, et le flux de travail channel smoke s'exécute pour le fichier de verrouillage channel-smoke. Le flux de travail Markdown Lint exécute le hook markdownlint sur une pull request de hooks pre-commit ; les autres hooks ne sont pas exercés en CI, alors exécutezpre-commit run --all-filessur sa branche avant de la fusionner.
En-tête de paternité — Ligne de licence SPDX par fichier
Définir et faire respecter des marqueurs d'identifiant de licence SPDX par fichier à l'aide d'en-têtes canoniques d'une seule ligne, dans la syntaxe de commentaire appropriée à chaque type de fichier.
Discipline des plans — Mémoire de travail éphémère et locale au projet
Gérez la mémoire de travail éphémère et locale au projet dans .apothem/plans/ (un arbre hérité .plans/ se met à niveau via apothem migrate-workspace) avec un schéma de frontmatter, des transitions de cycle de vie, la promotion vers des ADR et l'application via des hooks et des validateurs.