BytesafeDependency Firewall

Configure upstreams

Add, edit, and remove the registries a firewall fetches packages from, including private registries with credentials and a publish target.

Upstreams are the registries a firewall fetches packages from. A new firewall typically starts with the ecosystem's public registry; this guide covers adding more, wiring in private registries, and choosing where publishes go.

Add an upstream

In the dashboard, open the firewall, go to Upstreams, and add an upstream:

  • Endpoint: the registry URL, for example https://registry.npmjs.org
  • Internal registry: on if this is your private registry (see below)
  • Cache upstream: on to let the firewall cache responses from this upstream. Available only while Internal registry is on; the switch is disabled otherwise
  • Credentials: username/password or a token, if the registry requires authentication

As JSON, an upstream inside the firewall config:

{
  "id": "npmjs",
  "endpoint": "https://registry.npmjs.org",
  "credentials": {},
  "internal": false,
  "cached": false
}

The cached flag applies to internal upstreams: set cached: true on the registries you own, so repeat requests are served from the firewall's copy instead of the registry. An external upstream with cached: true is rejected with 400, in the dashboard and on import alike. The flag is not the whole caching story; Upstreams and caching describes what the firewall keeps in either case.

To apply JSON without the dashboard: export the config with bsfw config export, edit the upstreams array, and import it back. See config import. Imports must not contain plaintext credentials. For an existing upstream, keep its exported placeholders to preserve the stored values. A new upstream has no stored value to preserve, so set its credentials separately.

How multiple upstreams behave

The firewall queries all upstreams for package metadata and merges the results, with one exception: when an upstream marked internal knows a package, only internal upstreams' versions are served for it. External copies of that package name disappear. That is the dependency confusion defense.

Rules can also target specific upstreams with the upstreamId and internal selector fields; see Rules and selectors.

Private registries and credentials

For a registry that requires authentication, set the upstream's credentials. They are encrypted at rest, and API responses never return them; edits in the dashboard show a placeholder that means "keep the stored value".

Mark your private registry internal if it hosts your own packages. Internal here is a statement about trust and package ownership, not network location.

Choose a publish target

If developers publish through the firewall, set publishTarget to the ID of the upstream that should receive published packages:

{
  "id": "3e7f5cb806f26e3beae2",
  "ecosystem": "npm",
  "upstreams": [
    { "id": "npmjs", "endpoint": "https://registry.npmjs.org", "internal": false, "cached": false },
    { "id": "e2de947a", "endpoint": "https://npm.acme.internal", "internal": true, "cached": true }
  ],
  "publishTarget": "e2de947a"
}

Publishes pass the firewall's upload rules first, then are forwarded to the publish target with that upstream's credentials.

Verify

Install a package through a rule with logging enabled, then open Logs. The table is a summary and does not have an upstream column. Select the row and confirm its detail shows the expected upstream value.

bsfw logs --firewall <firewall-id>

For client-side install commands, see your ecosystem page.

Troubleshoot

If the internal upstream claims a package name, external versions of that name are no longer served. If the internal registry has the name but not the versions you need, that is working as designed; publish the versions internally or unmark the upstream as internal.

Caching applies to internal upstreams. Turn on Internal registry to enable the switch; turning it back off clears the cache setting. On import, an external upstream with cached: true is rejected with upstream <id>: caching is only allowed on internal upstreams.

Fetch failures from an upstream are skipped, so a misconfigured credential looks like missing packages rather than an error. Nothing in the client output points at the upstream. If packages you know exist upstream are not served, check that upstream's credentials first.

bsfw config import refuses plaintext credentials in the config file. Keep exported placeholder values as-is in config files under version control. They preserve credentials already stored for the same firewall and upstream; for a new firewall or upstream, set credentials separately after import.

On this page