Skip to content

Package resolution rules

A package resolution rule changes how one repository resolves the PyPI, npm, or Maven packages the rule matches. Use rules to:

  • Reserve a naming space. Keep names such as acme-*, @acme/*, or com.acme:* to your own repositories, so a public registry can never supply them.
  • Limit a package to reviewed sources. Allow only the upstreams you select.
  • Combine versions from several sources. Let each source add the versions that earlier sources do not have, with Version-level resolution.

An upstream is a source connected to a repository on its Upstreams tab: another private Ravenstash repository, or a private mirror of a public registry or custom package source. The app calls public registries and custom package sources remote sources.

Packages that no rule matches keep the default behavior: the repository’s own packages come first, then the first upstream that has the package supplies all of its versions. See How upstream package resolution works for the source order and for what “shadowed” means.

  • Where: open the repository in the Ravenstash app and select the Rules tab, next to Upstreams.
  • Formats: PyPI, npm, and Maven. The tab appears when the repository has at least one of them. Container images and Helm charts do not use rules.
  • Who can view rules: everyone who can read the repository.
  • Who can change rules: the same people who manage the repository’s upstreams. In an organization, that is the repository Maintainer or Admin role, organization administrators, and namespace administrators in their namespaces. The owner of a personal account can change everything. See Roles and grants.
  • Tools: rules are managed in the web app. The rvs CLI and the Developer API do not create or change rules.

If Add rule is not shown on the Rules tab, ask an organization administrator to add the rule or to review your access.

A rule belongs to one repository and one format. It never changes another repository, and it does not change who can read or publish packages.

  1. On the Rules tab, select Add rule.
  2. Choose the Format when the repository has more than one.
  3. Enter the Match: a package name, or a name followed by * to match every name that starts with it. Below the field, the dialog shows how it reads your entry, as Exact match or Prefix match, and how many known packages a prefix matches.
  4. Choose the Mode: Package-level or Version-level.
  5. Choose the Upstreams that matching packages can use. For Selected upstreams, tick the sources in the list.
  6. Review the rule summary, any warning, and the Impact on known packages. When a warning asks for it, tick the confirmation.
  7. Select Add rule.

You can also start from a package: open the package in the repository and select Add rule for this package in its Resolution panel. The dialog opens with the package’s format and exact name filled in.

The parts of a rule are described under Reference. The sections below walk through the most common rules.

Without a rule, a name your repository does not contain can still be supplied by a connected public registry. That includes names you have not published yet and misspelled names. Someone who registers one of your names on the public registry could then have their package installed in your builds.

Two upstream choices close that gap. With either one, a public package that uses one of your names is never served, an unknown name answers “not found,” and Ravenstash does not ask the public registry about those names at all.

Your packages are published Choose
Only in this repository This repository only
In this repository and in other private repositories it connects to, such as a shared platform repository Ravenstash repositories only

To reserve a naming space:

  1. Select Add rule and enter the beginning of your names followed by *:

    • PyPI: acme-* covers acme-utils, acme-billing-client, and every other name that starts with acme-.
    • npm: @acme/* covers every package in the @acme scope.
    • Maven: com.acme:* covers every artifact in the com.acme group.
  2. Under Upstreams, choose This repository only, or Ravenstash repositories only with Package-level mode.

  3. Check the Impact on known packages, then select Add rule.

A rule can match names that do not exist yet, so you can reserve a naming space before you publish anything in it.

Serve patched versions of a public package

Section titled “Serve patched versions of a public package”

You maintain a few patched builds of a public package and still want the public versions. By default this does not work: once your repository contains the package, it supplies every version, and the public versions are shadowed.

A Version-level rule lets both sources supply versions:

  1. Publish your patched versions to the repository. Give each one a version number the public registry does not use. For example:

    • PyPI: the public example-http-client has 1.4.1, 1.4.2, and 1.5.0. You publish 1.4.2.post1.
    • npm: the public example-queue has 2.8.0, 2.8.1, and 2.9.0. You publish 2.8.1-acme.1.
    • Maven: the public org.example:parser has 3.2.0, 3.2.1, and 3.3.0. You publish 3.2.1-acme-1.
  2. Select Add rule and enter the exact package name: example-http-client, example-queue, or org.example:parser.

  3. Choose Version-level.

  4. Under Upstreams, choose Selected upstreams and tick the mirror of the public registry. Choose All upstreams only when every connected source, including ones you connect later, should supply versions.

  5. Read the Dependency confusion risk warning, tick the confirmation under This broadens the trusted supply chain, and select Add rule.

The repository now serves your patched version together with the public versions. In the PyPI example, 1.4.1, 1.4.2, and 1.5.0 come from the public registry and 1.4.2.post1 comes from your repository. Keep these points in mind:

  • Your repository comes first. If the public registry later publishes a version number you already use, your version keeps being served.
  • Pin the patched version. A version range can select a newer public version. Request your build by its exact version, and keep a lockfile.
  • npm latest. A latest tag in your repository wins over the public one, so a plain npm install <package> can install your patched build. See Tags and latest.
  • Use an exact name. Do not use a prefix for this rule unless every matching name is a public package you intend to mix. Read Dependency confusion and public registries first.

Some packages must come from one reviewed source, for example a vendor’s artifacts that should never be taken from a public registry.

  1. Select Add rule and enter the name or naming space, such as com.vendor:*, @vendor/*, or vendor-sdk.
  2. Choose Package-level.
  3. Under Upstreams, choose Selected upstreams and tick the sources that may supply these packages.
  4. Check the Impact on known packages, then select Add rule.

Matching packages now resolve only from this repository and the upstreams you ticked, in the order they have on the Upstreams tab. The other upstreams stay connected for every other package. An upstream you connect later is not included until you edit the rule.

Combine versions across your own repositories

Section titled “Combine versions across your own repositories”

Several of your repositories publish different versions of the same package, for example a shared platform repository and a team repository.

  1. Select Add rule and enter the name or naming space.
  2. Choose Version-level. The dialog selects Ravenstash repositories only for you.
  3. Tick the confirmation under This broadens the trusted supply chain, then select Add rule.

Each version now comes from the first of your repositories that has it, and no public registry or custom package source can add versions.

After you add a rule, the app shows the result in three places.

Contents list. In the Packages & paths view, the Sources column shows how a package governed by a rule resolves:

Label Meaning
Mixed by version More than one source serves versions of the package.
Version-level · upstream #2, or another single source A Version-level rule applies, and one source serves every known version.
Version-level · no version served A Version-level rule applies, and no source has a version that can be served.
Package-level or This repository only A rule with that setting applies.
2 sources contribute, 3 shadowed versions, 1 excluded source How many sources serve versions, how many copies an earlier source already supplies, and how many upstreams the rule leaves out.
Rule: and a match The rule that applies. Select it to open that rule on the Rules tab.

Package page. The Resolution panel states the mode, which sources serve the package, and the rule that applies. Each source in the version list has a state:

State Meaning
Serving The only source that serves versions of the package here.
Contributing One of several sources that serve versions. The row says how many versions it serves and how many of its copies are shadowed.
Shadowed Earlier sources supply every version this source has.
Excluded The rule does not use this source. Its versions stay listed for reference.
No versions The source has nothing to serve for this package.

Version page. A statement at the top says whether the copy you are viewing is served:

Statement Why
Served here. This source is the first one that has the version.
Shadowed: not served here. An earlier source has the same version, or has it in its trash.
Excluded: not served here. The rule that applies does not use this source.

In version lists, a copy that is not served is marked Shadowed, Reserved (an earlier source has the version in its trash), or Excluded. Select the mark for an explanation and, when a rule applies, a link to it.

Known versions only means the result is based on the versions seen so far. An upstream can hold versions that have not been requested through this repository yet.

Use Edit rule or Remove rule in the rule’s row.

  • Edit changes the match, mode, or upstreams. A rule’s format cannot be changed; remove the rule and add one for the other format.
  • Rename a rule by editing its match. Packages that only the previous match covered go back to the rule that otherwise applies, or to the default. The dialog names the previous match under Which rule governs matching packages.
  • Remove returns matching packages to the rule that otherwise applies, or to the default. Removing a rule is how you undo it; nothing else is changed or deleted.

Before you save, Ravenstash checks what the change does:

The change What you see
Lets more sources supply versions: Version-level mode, a wider upstream choice, more selected upstreams, or removing or renaming a rule that limited sources This broadens the trusted supply chain, naming the sources that become eligible where it can. Tick the confirmation to continue.
Anything else, such as Package-level mode, fewer upstreams, or This repository only Impact on known packages: how many known packages are affected, and how many versions will no longer be installable or will become installable.

A change can do both, for example removing a Version-level rule that allowed only Ravenstash repositories. The dialog then shows the warning and, when known packages are affected, the impact.

Known packages are the ones Ravenstash has already seen: packages in this repository, in connected Ravenstash repositories, and versions from other sources that were already requested through this repository. A count ending in + means there are more than the dialog counts.

A lockfile that pins a version that stops being installable will fail to install. Check the impact before you narrow a rule that builds depend on.

If someone else changes the repository’s upstreams or rules while you are editing, Ravenstash asks you to review the rule and save again.

Dependency confusion and public registries

Section titled “Dependency confusion and public registries”

A Version-level rule that allows a public registry, or another source you do not control, reopens a dependency-confusion risk for the names it matches. Anyone who can publish a package with one of those names on that registry can add new version numbers, and your repository will serve them. A package manager that asks for the newest matching version may then install the outside version instead of yours.

This is why Version-level mode starts with Ravenstash repositories only selected: versions can then only come from repositories your organization controls.

When a rule would include such a source, the dialog shows a Dependency confusion risk warning that names each one before you save. In the rule list, the rule is marked Includes a remote source. To stay safe:

  • Prefer Ravenstash repositories only for names your organization owns.
  • Include a public registry in a Version-level rule only for a package that genuinely exists there, such as a public package for which you publish patched versions privately. Prefer an exact name over a prefix.
  • Keep a minimum package age on the connection and pin versions in lockfiles.

Such a rule also means Ravenstash asks that registry about each matching name that is requested, even when your repository already has the package. Those names become visible to the registry’s operator.

The Package resolution list shows one row per rule:

Column What it shows
Format PyPI, npm, or Maven. A rule belongs to one format.
Match The exact package name, or Starts with and the beginning of a name.
Mode Package-level or Version-level. A dash for This repository only.
Upstreams The upstream choice, or the number of selected upstreams. A Version-level rule that allows a public registry or custom package source is marked Includes a remote source.
Known packages How many packages Ravenstash already knows that the rule matches.
Last change When the rule last changed.

Filter the list by format, or search it by the text of a rule’s match. To find the rule that applies to one package, open the package: its Resolution panel names the rule and links to it.

A match is either one exact package name or the beginning of a name followed by a single *.

Format Examples
PyPI Exact name: acme-utils. Starts with: acme-*.
npm Exact name: acme-ui or @acme/ui. Starts with: @acme/* for a whole scope, or @acme/ui-* for part of it.
Maven Exact name: com.acme:utils, written as groupId:artifactId. Starts with: com.acme:* for one group, com.acme.* for every group below it, or com.acme:util-* for part of a group.
  • The * is allowed once, at the end. A * anywhere else, or more than one, is refused. No other wildcards are supported.
  • At least one character must come before the *, so a rule can never match every package.
  • The name must be valid for the format. A Maven exact name needs both parts, groupId:artifactId, and an npm scope needs a package name after it: @acme/ui or @acme/*, not @acme.
  • Matching ignores letter case. For PyPI, -, _, and . are also the same character, so Acme_Utils and acme-utils are one name and acme-* covers both.
  • A prefix is plain text. acme* also matches acmecorp-tools, and @acme* also matches the scope @acme-labs. End the prefix at a separator, as in acme-*, @acme/*, com.acme:*, or com.acme.*, to match only your own naming space.
  • For Maven, com.acme:* covers the group com.acme only, and com.acme.* covers the groups below it, such as com.acme.billing. Add both rules to cover the group and everything below it.
  • A match can be up to 255 characters, including the *.
Mode What it does
Package-level The first allowed source that has the package supplies all of its versions. This is how packages without a rule resolve.
Version-level Every allowed source adds the versions that no earlier source already provides.

Package-level with All upstreams is the default for every package, so it is not offered as a rule. This repository only has no mode, because matching packages come from one place.

With a Version-level rule, each version comes from the first allowed source, in upstream order, that has that version:

  • Different versions of one package can come from different sources.
  • One version, with all of its files, always comes from exactly one source.
  • When two sources have the same version, the earlier source wins and the later copy is shadowed.

Version-level resolution is not a fallback. Once a source has a version, that version comes from that source or not at all:

  • A version that is held back by package age, quarantined, or blocked is not served from a later source instead.
  • A version that Ravenstash has already recorded from an earlier public registry or custom package source keeps its number there, even if that source later withdraws it.
  • A version in the trash keeps its version number until it is permanently removed, in this repository and in every connected private repository the rule allows. Restore it or publish a new version if you need it back.
  • If an allowed source cannot be checked, the request fails instead of being answered without that source.

For a worked example and for npm tags and latest, see Version-level resolution.

Choice What matching packages can use
All upstreams This repository and every upstream of that format, including upstreams you connect later. Use it with Version-level mode, when you deliberately want versions from every source.
Ravenstash repositories only This repository and every connected private Ravenstash repository, including ones you connect later. Never a public registry or a custom package source. Use it for names your organization owns that are published across several of your repositories.
Selected upstreams This repository and only the upstreams you tick. Upstreams you connect later are not included until you edit the rule. Use it for a fixed, reviewed set of sources.
This repository only Only packages published directly to this repository. Use it for names your organization owns and publishes only here.

This repository is always included and cannot be deselected. The choice filters the upstreams; it never changes their order. Selected upstreams keep the positions they have on the Upstreams tab, and reordering upstreams or changing their package age does not change a rule.

An upstream that a rule leaves out is not consulted at all for matching packages. It stays connected for every other package, and a problem with that upstream does not affect the packages it is left out of.

A connected private repository contributes only the packages published directly to it. Its own upstreams and its own rules are not used.

Exactly one rule applies to a package:

  1. A rule for the exact name wins over any prefix.
  2. Among prefixes, the longest one wins.

With rules for @acme/*, @acme/ui-*, and @acme/ui-icons:

Package Rule that applies
@acme/ui-icons @acme/ui-icons
@acme/ui-forms @acme/ui-*
@acme/cli @acme/*

The whole winning rule applies. Nothing is combined from the other rules, and there is no rule order to maintain.

A format has one rule per match. If you add a rule whose match already exists, the dialog says that it replaces the existing rule. Changing a rule’s match to one that another rule already uses is refused; edit that rule instead.

When another rule also covers the packages you are matching, the dialog shows Which rule governs matching packages. A package page names the rule that applies to it and links to that rule.

You cannot remove an upstream while a Selected upstreams rule names it. On the Upstreams tab, Ravenstash keeps your unsaved changes and lists the rules under Rules still select an upstream you removed. Change or remove those rules on the Rules tab, then save the upstream change again.

An upstream that rules select shows a link such as 2 rules on the Upstreams tab.

A rule is never widened automatically. If a selected source is itself deleted for good, the rule loses that selection and keeps the others; a rule left with no selected upstream resolves from this repository only until you edit it.

All upstreams and Ravenstash repositories only rules do not block removing an upstream. They follow whatever is connected.

Change Takes effect
Adding, changing, or removing a rule Usually within a minute.
Publishing, deleting, restoring, or tagging a version in this repository or a connected private repository Usually within a minute.
A new, removed, or re-tagged version at a public registry or custom package source Up to about 20 minutes.

Package managers also keep their own caches, which Ravenstash cannot clear. Refresh them when you test a rule change:

Tool What to do
pip Add --no-cache-dir, or run pip cache purge.
uv Add --refresh, or run uv cache clean.
npm Add --prefer-online, or run npm cache clean --force.
Maven Run the build with -U. Artifacts already in ~/.m2/repository are reused.

A lockfile records the exact file it installed. If a rule change makes a different source supply a version number that a lockfile already pins, the file can differ and the package manager reports a checksum or integrity mismatch. Update the lockfile after you confirm the new source is the one you intend.

  • Up to 50 rules for each format in a repository.
  • One rule per match in a format.
  • A match can be up to 255 characters.
  • Up to four upstreams for each format, so a rule can select at most four.
  • Rules apply to PyPI, npm, and Maven. Container images and Helm charts do not use them.
  • Rules are managed in the web app only.
  1. Open the package in the repository and find the version. A copy marked Shadowed, Reserved, or Excluded exists in a source but is not served through this repository; select the mark to see why.
  2. Excluded: the rule that applies leaves that upstream out. Edit the rule, or add a more specific rule for this package.
  3. Shadowed without a Version-level rule: an earlier source has the package and supplies all of its versions. Add a Version-level rule if several sources should supply versions.
  4. Shadowed or Reserved under a Version-level rule: an earlier source has the same version number, possibly in its trash. Restore that version or publish a new version number.
  5. Not listed at all: check the connection’s minimum and maximum package age on the Upstreams tab, and whether the version is quarantined or blocked on the Protection tab.
  6. Refresh the package manager’s cache and retry. See When changes take effect.

Open the version in the repository to see which source serves it. If a public registry supplies versions of a name you own, a Version-level rule includes that registry, or no rule reserves the name. See Reserve a naming space you own. For npm, also check which source owns the latest tag.

That is the rule working: the name is not published in the sources the rule allows, and public registries are not asked. If the package lives in a connected Ravenstash repository, change the rule from This repository only to Ravenstash repositories only.

Message What to do
Use * only once, at the end of the name. Put a single * at the end. Patterns such as *-utils or acme-*-client are not supported.
Add at least one character before *. A rule cannot match every package. Enter the beginning of a name.
This match isn’t valid. Enter a name that is valid for the format; see Match.
A rule for this match already exists. Edit that rule instead. Another rule already uses the match you are renaming this rule to.
Package-level over all upstreams is already the default. Choose different upstreams, or Version-level mode.
Select at least one upstream. Tick a source under Selected upstreams, or connect one on the Upstreams tab first.
This format has reached its rule limit. A format holds up to 50 rules. Remove a rule, or replace several exact rules with one prefix.
A selected upstream is no longer attached. The upstream was removed while you were editing. Review the selection and save again.
This repository’s upstreams or rules changed while you were editing. Someone else saved a change. Review the rule and save again.

I changed a rule and my build has not changed

Section titled “I changed a rule and my build has not changed”

A rule change usually takes effect within a minute. After that, the package manager’s own cache or a lockfile is the usual cause. See When changes take effect.

Does a rule in a connected repository apply here?

Section titled “Does a rule in a connected repository apply here?”

No. A connected private repository contributes only the packages published directly to it. Each repository uses its own rules.

Can I use rules for container images or Helm charts?

Section titled “Can I use rules for container images or Helm charts?”

No. Rules apply to PyPI, npm, and Maven.