skip to content

How are per-component <artifact> entries structured in verification-metadata.xml, and why does a single component list multiple artifacts?

level: middleimportance: should knowfreq 38%

answer

  1. component = group/name/version
  2. one <artifact> per file (jar, pom, module, sources)
  3. matched by coordinates + filename
  4. <sha256 value> + <also-trust>
  5. <pgp value> for key trust

basics

~10 s

Each <component> identifies a group/name/version and contains one <artifact> per concrete file (the jar, the .pom, the .module, sources/javadoc). Each <artifact> carries the trusted checksum(s) like <sha256> for that exact file.

solid answer

~40 s

Inside `<components>`, each `<component group="" name="" version="">` represents one coordinate (a GAV). Within it, every physical file Gradle downloads for that coordinate gets its own `<artifact name="...">` entry, keyed by the exact filename. A single component lists multiple artifacts because one coordinate produces several files: the main `guava-32.1.3-jre.jar`, its `guava-32.1.3-jre.pom`, the `guava-32.1.3-jre.module` Gradle Module Metadata, and possibly classified artifacts like `-sources.jar` or `-javadoc.jar`. Each `<artifact>` then contains the trusted hash(es) — `<sha256 value="..."/>`, optionally `<sha512>`, `<md5>`, `<sha1>` — and/or a `<pgp value="keyId"/>` entry when trusting by signature. Gradle matches a downloaded file by component coordinates **and** filename, recomputes the listed algorithm, and fails on mismatch or on any file with no matching entry (unless trusted by a `<trusted-artifacts>`/`<trusted-keys>` rule).

code

xml · 13 lines
xml
<component group="com.google.guava" name="guava" version="32.1.3-jre">
   <artifact name="guava-32.1.3-jre.jar">
      <sha256 value="6d4e7d...">
         <also-trust value="olderknowngoodhash..."/>
      </sha256>
   </artifact>
   <artifact name="guava-32.1.3-jre.module">
      <sha256 value="91f0bd..."/>
   </artifact>
   <artifact name="guava-32.1.3-jre.pom">
      <sha256 value="7c2e44..."/>
   </artifact>
</component>

go deeper

for a junior

Know each component holds artifacts and each artifact has a checksum.

for a middle

Explain the component→artifact hierarchy, why multiple artifacts appear, and that matching uses coordinates plus filename.

for a senior

Discuss also-trust for migrations, pgp vs checksum per artifact, and how verify-metadata changes which artifacts are listed.

for a principal

Reason about file growth/maintainability at scale and policies for reviewing also-trust additions (avoid silently widening trust).

## The component → artifact hierarchy `<components>` is a flat list of `<component>` elements. A component is identified by three attributes: ```xml <component group="com.fasterxml.jackson.core" name="jackson-databind" version="2.17.1"> ``` This maps to one Maven coordinate (GAV). But Gradle never downloads just "the dependency" — it downloads concrete **files**. So inside the component sits one `<artifact>` per file: ```xml <component group="com.fasterxml.jackson.core" name="jackson-databind" version="2.17.1"> <artifact name="jackson-databind-2.17.1.jar"> <sha256 value="aaaa...."/> </artifact> <artifact name="jackson-databind-2.17.1.pom"> <sha256 value="bbbb...."/> </artifact> <artifact name="jackson-databind-2.17.1.module"> <sha256 value="cccc...."/> </artifact> </component> ``` ## Why multiple <artifact> entries One coordinate resolves to many files: - the **main binary** jar (or aar, zip, etc.), - the **POM** (`.pom`) — Maven metadata, - the **Gradle Module Metadata** (`.module`) when published, - **classified** artifacts: `-sources.jar`, `-javadoc.jar`, native classifiers like `-linux-x86_64`. Gradle verifies each file independently, so each needs its own entry. The metadata files (`.pom`, `.module`) only appear when `<verify-metadata>` is true; with it false you'd typically see only the jar. ## How an <artifact> is matched and checked Gradle identifies the file by **component coordinates plus the `name` attribute** (the exact filename). On download it: 1. finds the matching `<component>` by group/name/version, 2. finds the matching `<artifact>` by filename, 3. recomputes each declared algorithm and compares to the `value`, 4. fails the build if any value mismatches, or if there is *no* matching entry and no trust rule covers it. ## Checksum elements and the also-trust pattern An `<artifact>` may carry several hash elements: ```xml <artifact name="foo-1.0.jar"> <sha256 value="primary..."> <also-trust value="alternate..."/> </sha256> </artifact> ``` `<sha256>` is the canonical value; nested `<also-trust>` entries let you accept a second known-good checksum (handy during migrations or when a repo re-publishes identical content with a different hash). For signature-based trust the element is `<pgp value="<key-fingerprint>"/>` instead of (or alongside) a checksum, declaring which key must have signed that file. ## Takeaway The structure is two levels deep: component (the coordinate) → artifact (each concrete file). Multiple artifacts per component is the norm, not the exception, because verification operates at the file level.

  • Why might one component contain a .module and a .pom artifact entry?
    Modern libraries publish both Gradle Module Metadata (.module) and a Maven POM; Gradle downloads and (with verify-metadata) verifies whichever it consumes, so both get entries.
  • What is the <also-trust> element for?
    It records an additional acceptable checksum for the same artifact, so Gradle accepts either value — useful during migrations or when a repository serves a content-identical but differently hashed file.

saying these in an interview costs you the question

  • Assuming one component = one file; a coordinate yields several files (jar, pom, module, classifiers).
  • Thinking artifacts are matched only by coordinates — the filename in the name attribute is part of the match.

context