Safeguard
Developer Tools•

Requirements or constraints file: which one should a scan read?

A pip constraints file limits versions but installs nothing. Learn which Python files describe what you ship in a monorepo and which a scanner should read.

Safeguard Security Team
3 min read

Read the requirements files, and read the constraints file as a version cap, not as a list of what is installed. The pip guide says a constraints file controls which version is installed, not whether anything is installed. A package listed only in constraints may never ship.

What pip says

The pip user guide describes a requirements file as a list of install arguments placed in a file, used with the dash r option. A constraints file, used with the dash c option, restricts the versions that may be installed. In the guide's words, including a package in a constraints file does not trigger installation of the package. It is installed only when requested directly or pulled in as a dependency. Constraints use a subset of requirements syntax, with names required and no extras or editable entries.

python -m pip install -r requirements.txt -c constraints.txt

Why monorepos use both

A Python monorepo has no single workspace standard, so teams build their own pattern. A common one is a shared constraints file at the root, so every service uses the same versions of common libraries, and a requirements file per service that lists what that service needs.

FileSaysScanner should treat it as
requirements.txt in a serviceWhat this service installsInventory input
constraints.txt at rootVersion caps for everythingVersion source, not inventory
Lock file such as poetry.lock or uv.lockResolved setPreferred inventory input if present

Scan mistakes to avoid

  1. Scanning constraints as inventory. You then report vulnerabilities in packages no service installs. Noise erodes trust.
  2. Ignoring constraints for versions. A requirements line without a version resolves to the cap in the constraints file. A scanner that reads only the requirements file sees no version.
  3. Unpinned requirements. If nothing pins the version, results depend on when you resolve. See does pip-audit work on unpinned requirements.

Find the real set

The most reliable approach is to resolve per service, using the same arguments as the deployment, and export the result. Then scan the resolved list.

python -m venv .venv-scan
.venv-scan/bin/python -m pip install -r requirements.txt -c constraints.txt
.venv-scan/bin/python -m pip freeze

The frozen list names each package and version that was actually installed, which is what you want to scan. Do this in a throwaway environment, not on a developer machine.

Group by service

Keep one resolved list per deployable service, and report findings per service. A shared constraints file can make one vulnerable pin appear in every service. That is useful to know, and fixing it once in the shared file is the right move.

Where Safeguard fits

Safeguard scans Python dependencies and builds SBOMs per project, and can open fix pull requests when you turn autonomous remediation on. It is off by default. Try one service with the free scan at https://gold.safeguard.sh/scan.

Quick check

Does a constraints file install packages?

No. It limits the allowed versions of packages that are requested elsewhere.

What should I scan for each service?

The resolved package list produced with that service's own requirements and constraints.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.