Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions docs/guide/coverage/language/java.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,38 @@ The vulnerability database will be downloaded anyway.
!!! Warning
Trivy may skip some dependencies (that were not found on your local machine) when the `--offline-scan` flag is passed.

### mirrors
Trivy supports several ways to set up mirrors for Maven repositories:

- `<mirrors>` in your Maven [`settings.xml`][maven-mirror-settings] — both the global and the user file.
- The Trivy [config file][config-file] — see [config-file mirrors](#config-file-mirrors) below.

#### resolving priority
For each package that needs to be fetched from a remote repository, Trivy applies the following order:

1. mirror from `settings.xml`;
2. mirrors[^10] from the config file.

!!! note
Trivy supports chained resolution across the two sources: if `settings.xml` maps `repo1 -> repo2` and the config file maps `repo2 -> repo3`, then `repo1` resolves to `repo3`.

#### config-file mirrors
`scan.maven.mirrors` maps each source repository URL to an ordered list of mirror URLs, tried in turn. Use it to avoid modifying `settings.xml` (for example in CI) and to configure several fallback mirrors[^10] for a single repository:

```yaml
scan:
maven:
mirrors:
https://repo.maven.apache.org/maven2/:
- https://my-internal-mirror/maven2/
- https://backup-mirror/maven2/
```

To mirror Maven Central, use `https://repo.maven.apache.org/maven2/` as the source repository URL.

!!! warning "Credentials"
Config-file mirrors do not read credentials from `settings.xml` `<server>` entries. To authenticate, embed them in the mirror URL (`https://user:password@host/...`), which stores the password in plaintext in the config file. For a secure setup, configure the mirror in `settings.xml` instead.

### supported scopes
Trivy only scans `import`, `compile`, `runtime` and empty [maven scopes][maven-scopes]. Other scopes and `Optional` dependencies are not currently being analyzed.

Expand Down Expand Up @@ -142,11 +174,14 @@ Make sure that you have cache[^8] directory to find licenses from `*.pom` depend
[^7]: To avoid confusion, Trivy only finds locations for direct dependencies from the base pom.xml file.
[^8]: The supported directories are `$GRADLE_USER_HOME/caches` and `$HOME/.gradle/caches` (`%HOMEPATH%\.gradle\caches` for Windows).
[^9]: License detection is limited. See [Licenses](#licenses) for details.
[^10]: The mirrors are tried in order, falling back to the next one when the requested POM is not found.

[dependency-graph]: ../../configuration/reporting.md#show-origins-of-vulnerable-dependencies
[maven-invoker-plugin]: https://maven.apache.org/plugins/maven-invoker-plugin/usage.html
[maven-central]: https://repo.maven.apache.org/maven2/
[maven-pom-repos]: https://maven.apache.org/settings.html#repositories
[maven-mirror-settings]: https://maven.apache.org/guides/mini/guide-mirror-settings.html
[config-file]: ../../references/configuration/config-file.md
[maven-scopes]: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope
[sbt-dependency-lock]: https://stringbean.github.io/sbt-dependency-lock
[detection-priority]: ../../scanner/vulnerability.md#detection-priority
Expand Down
3 changes: 3 additions & 0 deletions docs/guide/references/configuration/config-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,9 @@ scan:
# Same as '--file-patterns'
file-patterns: []

maven:
mirrors:

# Same as '--offline-scan'
offline: false

Expand Down
1 change: 1 addition & 0 deletions pkg/commands/artifact/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ func (r *runner) initScannerConfig(ctx context.Context, opts flag.Options) (Scan
AWSEndpoint: opts.Endpoint,
FileChecksum: fileChecksum,
DetectionPriority: opts.DetectionPriority,
MavenMirrors: opts.MavenMirrors,

// For image scanning
ImageOption: ftypes.ImageOptions{
Expand Down
63 changes: 54 additions & 9 deletions pkg/dependency/parser/java/pom/mirror.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"net/url"
"strings"

"github.com/samber/lo"

"github.com/aquasecurity/trivy/pkg/log"
)

Expand All @@ -17,14 +19,21 @@ type mirror struct {
url url.URL // parsed URL with userinfo from the matching <server>
}

// resolveMirrors converts <mirror> entries from settings.xml into the runtime
// mirror form: split and trim the mirrorOf patterns, parse the URL, and embed
// credentials from the <server> whose id equals the mirror id. Mirrors with
// no usable pattern or an unparsable URL are dropped.
func resolveMirrors(mirrors []Mirror, servers []Server) []mirror {
// mirrors holds the resolved mirrors from settings.xml and from the config file.
type mirrors struct {
settings []mirror // settings.xml mirrors
configFile map[string][]url.URL // config-file mirrors; key: mirrorKey(source), value: ordered parsed mirror URL
}

// resolveMirrors resolves and validates both mirror sources into their runtime form:
// it parses every URL — embedding <server> credentials into settings.xml mirrors and
// normalizing config-file keys via mirrorKey — and drops any entry with an unusable
// pattern or an unparsable URL.
func resolveMirrors(settingsMirrors []Mirror, servers []Server, configFileMirrors map[string][]string) mirrors {
logger := log.WithPrefix("pom")
var result []mirror
for _, m := range mirrors {

var resolved mirrors
for _, m := range settingsMirrors {
var patterns []string
for p := range strings.SplitSeq(m.MirrorOf, ",") {
p = strings.TrimSpace(p)
Expand Down Expand Up @@ -55,13 +64,49 @@ func resolveMirrors(mirrors []Mirror, servers []Server) []mirror {
}

logger.Debug("Adding mirror", log.String("id", m.ID), log.String("url", u.Redacted()))
result = append(result, mirror{
resolved.settings = append(resolved.settings, mirror{
id: m.ID,
patterns: patterns,
url: *u,
})
}
return result

for src, targets := range configFileMirrors {
// Config-file mirror URLs are validated when the config file is parsed (fail-fast).
srcURL, err := url.Parse(src)
if err != nil {
continue
}

var mirrorURLs []url.URL
for _, target := range targets {
mirrorURL, err := url.Parse(target)
if err != nil {
continue
}
mirrorURLs = append(mirrorURLs, *mirrorURL)
}
if len(mirrorURLs) == 0 {
continue
}
logger.Debug("Added config-file mirror", log.String("source", srcURL.Redacted()),
log.Any("mirrors", lo.Map(mirrorURLs, func(u url.URL, _ int) string {
return u.Redacted()
})))
if resolved.configFile == nil {
resolved.configFile = make(map[string][]url.URL)
}
resolved.configFile[mirrorKey(*srcURL)] = mirrorURLs
}

return resolved
}

// mirrorKey normalizes a repository URL to the key used for config-file mirror
// lookup: its string form with any trailing slash trimmed, so that
// "https://host/maven2/" and "https://host/maven2" resolve to the same key.
func mirrorKey(u url.URL) string {
return strings.TrimRight(u.String(), "/")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: TrimRight only removes trailing slashes; it does not normalize ./, ../, or repeated slashes, and it can also remove a slash from the query or fragment. Would normalizing u.Path with path.Clean, or using u.JoinPath("."), be appropriate here? Trivy already normalizes the repository base with path.Join when constructing artifact URLs, so applying the same path semantics to mirror keys seems reasonable. This is not general URL canonicalization, since servers may distinguish /repo from /repo/, as well as repeated slashes. RawPath and percent-encoding may also need a quick check, but this may be more than this PR needs, so I'll leave the final decision to you.

}

// matches reports whether this mirror should serve the given repository.
Expand Down
Loading