BytesafeDependency Firewall

Maven

Configure Maven and Gradle to resolve dependencies through your firewall. Mirror setup, authentication, CI, publishing, and troubleshooting.

A Maven firewall implements the Maven repository layout. Maven and Gradle both resolve and publish through it.

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 a ready-to-copy Maven snippet with both values already filled in. This page also covers Gradle, whose configuration is not generated in the dashboard.

Repository endpoint

https://eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/maven/<firewall-id>/

The namespace ID and firewall ID are part of the URL. Authentication is a bearer token header for resolution; publishing also accepts HTTP basic auth with the token as the password.

Configure the project

Mirror everything through the firewall in ~/.m2/settings.xml (or a checked-in settings file passed with -s). Maven sends credentials from the <server> whose ID matches the mirror:

settings.xml
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0">
  <mirrors>
    <mirror>
      <id>firewall</id>
      <name>Bytesafe Dependency Firewall</name>
      <url>https://eu-sov-1.bytesafecloud.eu/v1/NAMESPACE_ID/maven/FIREWALL_ID/</url>
      <mirrorOf>*</mirrorOf>
    </mirror>
  </mirrors>
  <servers>
    <server>
      <id>firewall</id>
      <configuration>
        <httpHeaders>
          <property>
            <name>Authorization</name>
            <value>Bearer ${env.BYTESAFE_TOKEN}</value>
          </property>
        </httpHeaders>
      </configuration>
    </server>
  </servers>
</settings>

mirrorOf: * routes every repository, including plugin repositories, through the firewall.

Replace the repository block in build.gradle (or settings.gradle under dependencyResolutionManagement):

build.gradle
repositories {
    maven {
        url = uri('https://eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/maven/<firewall-id>/')
        credentials(HttpHeaderCredentials) {
            name = 'Authorization'
            value = "Bearer ${System.getenv('BYTESAFE_TOKEN')}"
        }
        authentication {
            header(HttpHeaderAuthentication)
        }
    }
}

Remove mavenCentral() and other repository entries. Gradle tries repositories in order, and any direct entry is a firewall bypass.

Each developer exports a personal access token:

export BYTESAFE_TOKEN=<your token>

Verify

mvn dependency:resolve
gradle dependencies

A successful resolution confirms the firewall is serving the artifacts, and every request through that repository 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 a build that breaks no rule leaves no trace. An empty log is not evidence that the build 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 build steps.

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.

Publishing

A firewall can receive mvn deploy and gradle publish. First set a publish target: the upstream that should receive published artifacts. Without one the firewall is install-only and rejects publishes. Then publish with the firewall as the repository. Upload rules run against the publish before it is forwarded.

pom.xml
<distributionManagement>
  <repository>
    <id>firewall</id>
    <url>https://eu-sov-1.bytesafecloud.eu/v1/NAMESPACE_ID/maven/FIREWALL_ID/</url>
  </repository>
</distributionManagement>

With basic-auth credentials on the matching server. The token goes in the password field; the username is not checked, so deploy here is only a label:

settings.xml
<server>
  <id>firewall</id>
  <username>deploy</username>
  <password>${env.BYTESAFE_TOKEN}</password>
</server>
build.gradle
publishing {
    repositories {
        maven {
            url = uri('https://eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/maven/<firewall-id>/')
            credentials {
                username = 'deploy'
                password = System.getenv('BYTESAFE_TOKEN')
            }
        }
    }
}

A blocked publish fails with:

com.acme:app@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 maven-metadata.xml. Maven and Gradle dependencies are usually exact versions, so the practical effects are:

  • Version ranges and LATEST/RELEASE style resolution pick the newest version that passed the rules.
  • An exact dependency on a filtered version fails as not found (Could not find artifact in Maven, Could not resolve in Gradle).

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

com.acme:app@1.0.0 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.

Maven Central caching

Responses from Maven Central (repo1.maven.org, repo.maven.apache.org) are always cached by the firewall, regardless of the upstream's cache setting. Maven Central rate-limits heavy traffic with 429 Too Many Requests; the always-on cache keeps repeat resolutions from counting against that limit. Cache misses are fetched with automatic failover, so a throttling or failing Central does not break the resolution. This is automatic; there is nothing to configure. Other upstreams are cached when the upstream has caching enabled, which applies to internal upstreams. See Upstreams and caching.

Troubleshooting

BYTESAFE_TOKEN is unset, expired, or revoked, or the <server> ID does not match the mirror ID, in which case Maven never attaches the header at all. Confirm the variable is set in the shell that runs the build, that both IDs are identical, and that the token is still listed and unexpired in the dashboard.

A 429 in your build output means the build is talking to Maven Central directly, not through the firewall; Central throttles heavy or unauthenticated traffic. Fix the bypass (see below) and the problem disappears: the firewall always caches Maven Central responses, so repeat resolutions are served from cache instead of hitting Central, and cache misses are fetched with automatic failover when Central throttles.

Most likely a versions rule filtered it. Because Maven dependencies are exact versions, a filtered version fails the build instead of resolving to an older one. Check the firewall logs before assuming an upstream problem.

No log entry does not by itself mean the build 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, check for <repositories> in POMs (a mirrorOf: * mirror catches these, a narrower one may not) and extra repositories blocks in Gradle builds, including settings.gradle plugin management.

Plugin repositories go through the firewall too. With Maven, mirrorOf: * covers them. With Gradle, add the firewall repository to pluginManagement.repositories in settings.gradle as well.

On this page