BytesafeDependency Firewall

NuGet

Configure dotnet, nuget.exe, and Visual Studio to install through your firewall. Source setup, authentication, CI, publishing, and troubleshooting.

A NuGet firewall implements the NuGet v3 API. Clients discover everything through the service index, so dotnet, nuget.exe, and Visual Studio all work against one URL.

The examples use <namespace-id> and <firewall-id> placeholders. Replace them with IDs, not with namespace or firewall names. XML examples use NAMESPACE_ID and FIREWALL_ID so the files stay valid XML before you replace them. The firewall's Setup tab shows ready-to-copy NuGet.Config and dotnet snippets with both values already filled in. This page also covers nuget.exe.

Source endpoint

https://eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/nuget/<firewall-id>/index.json

The namespace ID and firewall ID are part of the URL. Authentication is HTTP basic auth with the access token as the password (any username), or the token as the API key when pushing.

Configure the project

Commit a NuGet.Config at the repository root. <clear /> removes nuget.org from the source list, which is what prevents installs from bypassing the firewall:

NuGet.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <clear />
    <add key="firewall" value="https://eu-sov-1.bytesafecloud.eu/v1/NAMESPACE_ID/nuget/FIREWALL_ID/index.json" />
  </packageSources>
  <packageSourceCredentials>
    <firewall>
      <add key="Username" value="firewall" />
      <add key="ClearTextPassword" value="%BYTESAFE_TOKEN%" />
      <add key="ValidAuthenticationTypes" value="basic" />
    </firewall>
  </packageSourceCredentials>
</configuration>

%BYTESAFE_TOKEN% reads the token from the environment, keeping credentials out of git. Each developer exports a personal access token:

export BYTESAFE_TOKEN=<your token>

Visual Studio uses the same NuGet.Config; the Browse tab in Manage NuGet Packages works because the firewall implements the search service.

Verify

dotnet add package Newtonsoft.Json
nuget.exe install Newtonsoft.Json

A successful install confirms the firewall is serving the package, and every request through that source is evaluated against your rules.

Do not expect a log entry from this. A request is logged only when it matches a rule with log: true or a logging exception, so an install that breaks no rule leaves no trace. An empty log is not evidence that the client bypassed the firewall. To see the requests while verifying setup, add a log-only rule that matches all packages. See What is logged when.

CI

Use a Service Access Token (SAT) instead of a PAT. Set it as a secret in your CI system and export it as BYTESAFE_TOKEN before restore steps. The committed NuGet.Config does the rest.

To correlate all requests from one pipeline run, append an interaction ID to the token:

export BYTESAFE_TOKEN="${BYTESAFE_TOKEN}::${CI_PIPELINE_ID}"

The ID shows up on every log entry from that run.

Vulnerability audit

dotnet restore audit warnings (NU1901 to NU1904) work through the firewall. The vulnerability info resource is served from the firewall's advisory data, so restore-time audits keep working without a direct connection to nuget.org.

Publishing

A firewall can receive push. First set a publish target: the upstream that should receive published packages. Without one the firewall is install-only and rejects pushes. Then push with the token as the API key:

dotnet nuget push Acme.Utils.1.0.0.nupkg \
  --source https://eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/nuget/<firewall-id>/index.json \
  --api-key $BYTESAFE_TOKEN
nuget.exe push Acme.Utils.1.0.0.nupkg \
  -Source https://eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/nuget/<firewall-id>/index.json \
  -ApiKey $BYTESAFE_TOKEN

Upload rules run against the push before it is forwarded. Unlisting a version (dotnet nuget delete) goes through upload rules the same way.

A blocked push fails with:

Acme.Utils@1.0.0 upload blocked. Check firewall log entries for request <request-id> for details

What a blocked install looks like

Rules on the versions phase filter versions out of the flat container index and registration pages. The effect depends on how the dependency is declared:

  • A version range or floating version (1.*) resolves to the newest version that passed the rules.
  • An exact PackageReference to a filtered version fails as not found (NuGet error NU1102, unable to find package with the requested version).

Rules on the download phase block the package fetch. The firewall returns a 404 with:

Newtonsoft.Json@13.0.1 is blocked. Check firewall log entries for request <request-id> for details

Take the request ID to the logs to see which rule fired. See Investigate a blocked install.

Deprecated and unlisted versions

Two selector functions are useful with NuGet specifically:

  • deprecated matches versions their publisher has marked deprecated.
  • unlisted matches versions hidden from search (listed: false). Unlisted versions remain installable for existing consumers on nuget.org; a rule with this selector blocks them.

See the selector functions reference.

Troubleshooting

BYTESAFE_TOKEN is unset, expired, or revoked. Confirm the variable is set for the process that runs the restore, not only in your own shell profile, and that the token is still listed and unexpired in the dashboard. %BYTESAFE_TOKEN% in the config file is only substituted if the variable exists in that environment, and a missing variable looks the same as a wrong token.

Most likely a versions rule filtered it. Check the firewall logs before assuming an upstream problem.

No log entry does not by itself mean the client bypassed the firewall. Approved packages that match no logging rule pass through without an entry. First test with a log-only rule matching the package or all packages. If that rule still does not produce an entry, another source may be active. NuGet merges config files from the machine, user, and project levels; run dotnet nuget list source and confirm only the firewall source is enabled. Keep the <clear /> element in the committed config.

The credential key inside <packageSourceCredentials> must match the source key exactly (firewall in the examples). Keep ValidAuthenticationTypes set to basic so the client does not stall trying other schemes.

On this page