What this integration does
Maven and Gradle resolve through mShield instead of talking to Maven Central directly. Every
artifact download — POM, JAR, or other file — is evaluated against your policies before it
reaches the machine. Metadata and listings behave normally; an artifact that fails policy stops with an
HTTP 403 naming the check that refused it.
The integration is one mirror in Maven's settings.xml, or one repository URL in Gradle.
Nothing is installed on the developer's machine, and in egress-interception mode there is no client
change at all.
For SaaS and on-prem. This guide uses client configuration. DNS mode is an alternative available only on-prem; see deployment models.
Point Maven and Gradle at your mShield repository
Your deployment provides the hostname and the credentials to use. Replace
maven.example.mshield.dev below with your own.
Maven
<settings>
<mirrors>
<mirror>
<id>mshield</id>
<url>https://maven.example.mshield.dev/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
<servers>
<server>
<id>mshield</id>
<username>token</username>
<password><your-token></password>
</server>
</servers>
</settings>
mirrorOf is * so no repository declared in a POM can route around mShield.
The server id must match the mirror id.
For a project-scoped setup, keep the file in the repository's tooling directory and pass it
explicitly: mvn -s settings.xml <goals>. Only builds run that way go through
mShield.
Gradle
repositories {
maven {
url = uri("https://maven.example.mshield.dev/")
credentials {
username = "token"
password = providers.environmentVariable("MSHIELD_TOKEN").get()
}
}
}
Use it for pluginManagement and dependencyResolutionManagement too, and remove
mavenCentral(), google() and gradlePluginPortal() — each one is
a second, ungated path to the same artifacts. To apply it to every project for an account, place the same
block in an init script under ~/.gradle/init.d/.
On tokens. Anyone who can read settings.xml can use the token. Keep the
file out of version control, and have Gradle read the token from the environment rather than writing it
into build.gradle. Rotate the token if it is shared or committed.
Java trust store. The JVM uses its own certificate store, not the operating system's. If your deployment uses a private CA, import it into the JDK trust store used by the build.
Verify it took effect
rm -rf ~/.m2/repository/junit
mvn -s settings.xml dependency:get -Dartifact=junit:junit:4.13.2
Maven prints the repository each artifact is downloaded from; it should be your mShield host and
nothing else. Remove the artifact from the local repository first — Maven does not fetch what it
already has. For Gradle, run a build with --refresh-dependencies and check the same.
CI runners
- Write
settings.xmlin the job from a secret, or mount it from the runner's secret store. Both are discarded with the workspace. - Bake it into the build image so every job is covered without editing pipelines.
A persisted ~/.m2/repository or Gradle cache hides the proxy: anything already cached is
never fetched again and so is never evaluated. Version ranges are read from metadata at resolve time, so
a build can pull a different version than last week's — which is exactly what the gate is for.
What a blocked download looks like
[ERROR] Failed to execute goal on project app: Could not resolve dependencies:
Could not transfer artifact org.apache.logging.log4j:log4j-core:pom:2.14.1 from/to mshield
(https://maven.example.mshield.dev/): status code: 403
org.apache.logging.log4j:log4j-core 2.14.1 was refused by policy "Production dependencies"
| More details: https://mshield.example.com/...
The build fails the way it fails any rejected download, and the refusal names the artifact and the rule behind it.
The refusal also carries a link to a page that explains the block in full — what was refused, why, the version that would satisfy the policy, and a way to request an exclusion. It needs no login, and it is scoped to that single refusal. See what the developer opens.
If the block is wrong for a case your team has accepted, the developer requests an exclusion from that page; an operator grants or refuses it, and a granted exclusion is package-scoped, time-boxed, and recorded like any other decision.
Rolling back
Remove the mshield mirror and server from settings.xml (or stop passing
-s), and remove the mShield repository block from your Gradle files or init script.
Decisions already recorded stay in the dashboard.