Safeguard
Developer Tools•

Should a library test its lowest supported dependency versions?

Declare a lower bound only if you test it. Add a CI job that installs the lowest allowed versions so your range promise matches what you ship. Steps.

Safeguard Security Team
3 min read

Yes. A lower bound in your manifest is a promise that your library works with that version, so test it. Add one CI job that installs the lowest allowed versions and runs your tests, next to the job that installs the latest.

Why the floor needs testing

Python's packaging guide says to give dependencies known lower and upper bounds, such as A>=1,<2. A bound is only known if you have run your code against it. Many libraries raise their code to use a newer feature, forget to raise the declared floor, and ship a range that does not work at its low end. Users who resolve to the minimum version, which happens when other packages constrain them, hit errors you never saw.

There is a security side too. If the floor allows a version with a known advisory that affects you, your users can end up there. Testing the floor makes you look at it.

Two jobs, two ends of every range

JobInstallsCatches
LowestThe minimum allowed version of each dependencyFloors that are too low, missing feature checks
LatestThe newest allowed versionsBreakage from new releases

The Cargo guide documents the latest side: run cargo update, build and test, in a job marked to continue on failure. The lowest job is the mirror image, and tooling for it varies by ecosystem, so check what your package manager offers.

Making a lowest job

The method depends on your ecosystem, but the pattern is the same:

  1. Install the dependencies at the declared minimum. Some package managers have a resolution option for this, and in others you generate a constraints file from your declared lower bounds.
  2. Run the same tests as normal.
  3. Fix failures by raising the floor, not by adding workarounds, unless the older version is important to users.
  4. Keep the job required, because a failing floor is a real bug in your promise.

Unlike the latest job, a lowest job usually should block merges. It tests something you control.

Raise the floor on purpose

There are three good reasons to raise a floor:

  • Your code uses a feature from a newer release.
  • An advisory affects older versions and your code reaches the flaw.
  • Supporting the old version costs you more than it helps users.

Say so in your release notes. A raised floor is a visible change for users with older environments.

Choosing floors for security

When an advisory affects versions below a fixed release, and you are affected, set your floor at or above the fix. If you are not affected, you may keep a lower floor, but expect scanner questions. A short statement helps, and so does raising the floor anyway if it costs little.

Keep the matrix small

You do not need every combination. Test lowest, latest and whatever lockfile you use for development. Add more only where you have seen real failures.

Quick check

Do I need a lowest job for every dependency?

Run it on the whole set at once. Split it only if failures are hard to attribute.

Should the lowest job block merges?

Usually yes. It tests the promise your manifest makes.

Safeguard shows which dependency versions a project resolves and which have known advisories, which helps when choosing floors. Start with the free scan.

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.