Each policy shows what it would do before you pick it
Safest
The highest stable release that Safe Harbour clears.
Chosen by version order. A pre-release is never picked.
Stable
The stable release closest to the one you run.
Closest by major, then minor, then patch, with a tie going to the higher version. It can be lower than the version you run.
Latest
The highest stable release by the ecosystem's own version rules.
A pre-release is never picked. Where versions follow SemVer, the highest version wins whatever its date. Where versions cannot be ordered by number, the most recent release by date wins. A point release on an old branch is newer by date but is not the latest.
Rolling
What shipped most recently, closest to the one you run.
Takes every version published on the release day of the highest version, pre-releases included and malware removed, and picks the one closest to your version.
Every pick comes from versions Safe Harbour clears: no known vulnerability, exploit or malware report. The database works each one out with the ecosystem's own version rules. Safest and Latest are worked out separately, so they can name different versions. Today they usually agree.
Only the packages that need you ask for you
Packages fall into three groups: needs your decision, ready to ship, and no change. Fixes and routine updates the policy picked go straight into the change set. Anything riskier waits, and a pull request never includes it until you say so.
- Major versions: A jump to a new major version waits until you accept it, one package at a time or all together.
- Downgrades: Stable can pick a version lower than the one you run. That needs a yes too.
- No safe version: When Safe Harbour has no clean version of a package, nothing is picked and the row says so.
Fix a problem where it is cheapest to fix
A vulnerable package three levels down is rarely in your manifest. The curator shows it under the direct dependency that pulls it in, and offers three routes: pin it in the section your package manager uses for overrides, upgrade the parent, or leave it.
When accepting a parent brings a clean copy of the child, the child needs no override and drops out of the change set. Pins stay inside the versions the parents accept, so an override cannot break the resolve.
- npm, Yarn, pnpm: overrides, resolutions or pnpm.overrides in package.json
- Python: a pinned line in requirements.txt or requirements.in, or override-dependencies for uv
- Go: an indirect require in go.mod
- Rust: the lockfile only, so Cargo.toml does not change
- Maven: dependencyManagement in pom.xml
- PHP: the child added to require in composer.json
- Ruby: a pinned gem line in the Gemfile
Lockfiles are generated, never edited
The curator edits only your manifests. We generate the lockfile from them on our servers, with install scripts switched off, and show it to you read only with the packages the resolver moved. Generation covers npm, Yarn, pnpm, Go, Cargo, Poetry, uv, Bundler and Composer. pip and Maven have no lockfile, so there is nothing extra to commit. If the resolver cannot satisfy your choices, it tells you which package conflicts with which, and the pull request waits until the lockfile matches.
The same change, read three ways
- Workflow: Packages grouped by what needs you. Each one opens into its version history, the problems in its resolved tree and the routes for fixing them.
- Text: The final content of every file: the manifests as they will be committed and the lockfiles generated from them.
- Diff: What changed in each file, with a reason beside each line and unchanged stretches folded away.
A pull request that carries on from the last one
- Update the pull request we started: Branches that begin with vulnetix/, opened by the Vulnetix bot or labelled safe-harbour are found for you, with their failing checks. Pushing replaces their changes with your selection.
- Or open a new one: The base branch is detected, the branch name follows the pattern of your earlier ones, and the title, description and labels are filled in for you to edit.
- See the checks that read your manifests first: After you push, the checks about manifests and lockfiles lead the list, so a failing lockfile check is the first thing you see.
- Or take the files: Without the GitHub App, on another host, or with read-only access, you download the edited manifests and the lockfiles and carry on curating.
Which manifests it writes
The editor writes package.json, requirements.txt and requirements.in, pyproject.toml, go.mod, Cargo.toml, pom.xml, composer.json and Gemfile. Every other manifest we read is shown and listed as not edited yet.