Skip to content
Apothem
Reference

Dependency Pinning Manifest

Dependency declaration policy covering Python runtime ranges, dev tooling, release-tool lock files, and ratified version floors for each build surface.

Ratified posture for how Apothem declares, pins, and locks dependencies. Audience: contributors and downstream consumers who need to understand the reproducibility model.

Posture

Apothem is a Python CLI with a small runtime dependency set plus a larger development, audit, release, and documentation toolchain. Runtime dependencies use conservative lower bounds in pyproject.toml; the website commits site/package-lock.json; GitHub Actions are pinned by immutable SHA with version comments and are bumped by Renovate.

ClassDeclarationLock policy
Runtime Python dependencies[project.dependencies] in pyproject.tomlLower-bound ranges; no committed Python runtime lock
Dev / security tooling[project.optional-dependencies] extrasLower-bound ranges; CI installs current matching versions
Release toolingscripts/release/requirements-build-linux.txtHash-locked for release workflows; generated from the release tooling closure
CI-only tools.github/workflows/*.ymlWorkflow-only pip tools use exact pins (pip, bandit, pip-audit, pip-licenses, pyinstaller)
Documentation sitesite/package.jsonsite/package-lock.json committed and consumed by npm ci
GitHub ActionsSHA-pinned uses: refs with version commentsRenovate proposes updates; exceptions carry action-pinning-exempt: markers

Release ratification

SurfaceRatified stateRationale
Runtime depsCurrent lower bounds live in pyproject.toml [project.dependencies]Current stable floors ratified before release; no known runtime CVE blocker
Dev toolingCurrent lower bounds live in pyproject.toml dev extraLatest stable floors ratified before release
Security toolingCurrent lower bounds live in pyproject.toml security extraCurrent scanner floors ratified before release
Release toolingHash-locked closure lives in scripts/release/requirements-build-linux.txtRelease workflow installs with --require-hashes; local scripts require build to already exist instead of silently installing moving dependencies
Docs toolingCurrent ranges live in site/package.json; exact resolution lives in site/package-lock.jsonnpm outdated returns no stale docs dependency after lockfile refresh
GitHub ActionsExisting SHA pins retained for the current release; the SLSA reusable workflow remains the documented tag-pinned exceptionPublic CI rerun is green; broad action-major upgrades are intentionally left to dependency-automation PRs to avoid release-surface churn
npm packagingManual-only publish-npm.yml workflow; no automatic release triggerThe single public npm package is @ahmed-g-gad/apothem; publication runs after release readiness passes

Locking

Python lock files are generated on demand by the contributor. They are not committed because Apothem's runtime closure is small, the CLI supports multiple Python minor versions, and CI intentionally exercises the latest matching tooling versions.

# 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

The website is different: site/package-lock.json is committed and CI uses npm ci, so the rendered documentation site has a reproducible Node closure.

Rationale

  • Why range pins for Python? The CLI supports a broad Python matrix and CI should reveal compatibility issues with current tooling before users hit them.
  • Why a committed Node lock? The website is a deployed static artifact; the lockfile gives deterministic npm ci builds for that public surface.
  • Why SHA-pinned Actions? Tags are mutable; SHAs are immutable. Renovate updates the pinned SHAs, while the release gate records any intentional hold.

On this page