Skip to content

security: hash-lock what ships (image, release and audit tooling) - #23

Merged
mojtaba-py-code merged 1 commit into
mainfrom
security/hash-locked-installs
Oct 3, 2026
Merged

mojtaba-py-code merged 1 commit into
mainfrom
security/hash-locked-installs

Conversation

@mojtaba-py-code

Copy link
Copy Markdown
Owner

What and why

OpenSSF Scorecard reported 11 pipCommand not pinned by hash alerts: the container image, the release tooling and the dependency audit installed whatever PyPI served at build time, with no hash check. A package replaced or tampered with on the index would have entered the image.

  • requirements/: hash-locked files made by make lock (uv pip compile --universal --generate-hashes):
    • runtime.txt: what the image ships;
    • audit.txt: every optional extra;
    • build.txt: setuptools and wheel;
    • tools.txt: build, cyclonedx-bom and pip-audit.
  • Image: installs runtime.txt and build.txt with --require-hashes, then builds the project with --no-deps --no-build-isolation, so nothing unpinned is downloaded. .dockerignore admits exactly those two files.
  • Security workflow: audits the locked set; pip check fails the job when the lock no longer satisfies pyproject.toml.
  • Release workflow: build and cyclonedx-bom come from tools.txt.
  • CI test jobs still install the newest versions on purpose (IronFlow is also a library, see dependabot.yml); ci.yml now says so. Their 4 Scorecard alerts will be dismissed with that reason.
  • Dependabot waits 7 days before proposing a new release (cooldown); security updates are not delayed.
  • Hygiene tests: the image installs only hash-locked packages, the build context admits the locks, and every locked requirement carries hashes.

Verification

  • Hash-checked install of audit.txt into a clean venv, then pip check: no broken requirements.
  • pip-audit of all four locks: no known vulnerabilities.
  • tests/test_repo_hygiene.py: 50 passed. ruff clean. zizmor: no findings.
  • The Docker build and smoke test run in CI on this PR.

Security impact

Supply chain only; no application code changes.

🤖 Generated with Claude Code

The container image, the release tooling and the dependency audit installed
whatever PyPI served at build time, with no hash check (11 OpenSSF Scorecard
"pipCommand not pinned by hash" alerts).

- requirements/ holds hash-locked files made by `make lock` (uv pip compile
  --universal --generate-hashes): runtime.txt (what the image ships),
  audit.txt (every optional extra), build.txt (setuptools, wheel) and
  tools.txt (build, cyclonedx-bom, pip-audit).
- The image installs runtime.txt and build.txt with --require-hashes and
  builds the project with --no-deps --no-build-isolation, so nothing
  unpinned is downloaded; .dockerignore admits exactly those two files.
- The Security workflow audits the locked set, and `pip check` fails the
  job when the lock no longer satisfies pyproject.toml.
- CI test jobs keep installing the newest versions on purpose (IronFlow is
  also a library); a comment in ci.yml says why.
- Dependabot waits 7 days before proposing a new release (cooldown);
  security updates are not delayed. zizmor: no findings.
- New hygiene tests: the image installs only hash-locked packages, the build
  context admits the locks, and every locked requirement carries hashes.

Verified locally: hash-checked install of audit.txt plus `pip check`,
pip-audit of all four locks (no known vulnerabilities), 50 hygiene tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mojtaba-py-code
mojtaba-py-code merged commit 64c03d7 into main Oct 3, 2026
16 checks passed
@mojtaba-py-code
mojtaba-py-code deleted the security/hash-locked-installs branch October 3, 2026 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant