Skip to content

feat: let Gradle component metadata resolve distribution URLs on a warm cache - #7049

Open
calhar-snyk wants to merge 1 commit into
mainfrom
feat/gradle-include-component-metadata
Open

feat: let Gradle component metadata resolve distribution URLs on a warm cache#7049
calhar-snyk wants to merge 1 commit into
mainfrom
feat/gradle-include-component-metadata

Conversation

@calhar-snyk

@calhar-snyk calhar-snyk commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Pull Request Submission Checklist

  • Follows CONTRIBUTING guidelines
  • Commit messages
    are release-note ready, emphasizing
    what was changed, not how.
  • Includes detailed description of changes
  • Contains risk assessment (Low | Medium | High)
  • Highlights breaking API changes (if applicable) — N/A, no API changes
  • Links to automated tests covering new functionality
  • Includes manual testing instructions (if necessary)
  • Updates relevant GitBook documentation (PR link: ___) — N/A, --gradle-refresh-dependencies is deliberately undocumented and kept off SupportedUserReachableFacingCliArgs
  • Includes product update to be announced in the next stable release notes — N/A, internal flag with no user-facing surface

What does this PR do?

Lets Gradle component metadata resolve distribution:url provenance on a warm Gradle cache.

Component metadata reads artifact provenance as Gradle resolves dependencies. On a warm cache Gradle
skips the resolution work, so nothing observes the downloads and distribution:url comes back empty.
--gradle-refresh-dependencies is the opt-in that forces Gradle to refresh so those reads fire.

Three changes:

  1. Thread the flag to the plugin (get-single-plugin-result.ts, types.ts) —
    cli-extension-dep-graph already forwards --gradle-refresh-dependencies down the legacy
    resolution path, but the legacy CLI dropped it. Recognise it off its dashed key and pass it as
    gradleRefreshDependencies, mirroring how include-component-metadata is handled. The spread is
    conditional so the default plugin-options shape is unchanged for the overwhelming majority of
    scans that never set it. Deliberately kept off SupportedUserReachableFacingCliArgs so it stays
    internal.
  2. Bump cli-extension-dep-graph v2.7.2 → v2.8.1 — v2.7.2 has no knowledge of the flag, so it
    would be parsed and then silently dropped before ever reaching the legacy CLI. v2.8.1 is the first
    released version whose legacy resolution forwards it. The delta is two commits: the flag itself
    (https://github.com/snyk/snyk/issues/225 #226) and a CODEOWNERS chore (fix: bump gradle plugin to fix dep tree annotations #227).
  3. Add unit coverage for the threading — forwarded when true, forwarded when explicitly
    false, and absent from the plugin options entirely when unset.

Where should the reviewer start?

src/lib/plugins/get-single-plugin-result.ts — the eight added lines are the whole behavioural
change. Then test/jest/unit/lib/plugins/get-single-plugin-result.spec.ts for the three states, and
the go.mod/go.sum bump last.

How should this be manually tested?

⚠️ Not end-to-end testable from this PR alone — see the pending bumps below. The published
snyk-gradle-plugin (7.0.2 is latest) does not yet read gradleRefreshDependencies, so today the
flag reaches the plugin and the plugin ignores it. This PR is correct and inert in isolation.

Once snyk-gradle-plugin is released and bumped here, against a Gradle project with an already-warm
Gradle cache:

snyk test --print-graph --include-component-metadata --gradle-refresh-dependencies

Expect distribution:url node labels to be populated, where the same command without
--gradle-refresh-dependencies leaves them empty on a warm cache. Gradle should be invoked with
--refresh-dependencies (visible with -d).

Risk assessment (Low | Medium | High)?

Low.

  • The flag is internal, undocumented, and unset for every existing scan; the conditional spread means
    the plugin-options shape is byte-identical when it is absent.
  • Network cost (--refresh-dependencies forces Gradle to hit the network) is opt-in per invocation
    rather than implied by --include-component-metadata.

Any background context you want to provide?

Pending version bumps — these must follow before the feature works end to end. This PR
intentionally does not contain the local replace / file: pins used for cross-repo development.

Dependency Pinned here Action
cli-extension-dep-graph v2.8.1 ✅ bumped in this PR; released and contains the flag
snyk-gradle-plugin 7.0.0 ⏳ needs a release containing gradleRefreshDependencies, then a bump here. No published version (7.0.0–7.0.2) has it yet. This is what gates end-to-end behaviour.
cli-extension-sbom v0.0.0-20260722102401-3c3af28e7b93 ⏳ needs a bump once the sbom PR registering --gradle-refresh-dependencies on snyk sbom merges

Full chain, for orientation:

snyk sbom / snyk test flag → cli-extension-sbom (registers, hidden) → config clone →
cli-extension-dep-graph legacy resolution (appends --gradle-refresh-dependencies) → legacy CLI
(this PR)
snyk-gradle-plugin (adds --refresh-dependencies) → Gradle.

What are the relevant tickets?

CMPA-649

@snyk-io

snyk-io Bot commented Jul 28, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@cjheppell
cjheppell force-pushed the feat/gradle-include-component-metadata branch 2 times, most recently from 0174740 to 5f0bc39 Compare July 30, 2026 10:01
Component metadata reads artifact provenance as Gradle resolves
dependencies. On a warm cache Gradle skips that work, so nothing observes
the downloads and distribution:url comes back empty.
--gradle-refresh-dependencies is the opt-in that forces a refresh so those
reads fire.

- Thread the flag through the legacy CLI. cli-extension-dep-graph already
  forwards --gradle-refresh-dependencies down the legacy resolution path,
  but the legacy CLI dropped it. Recognise it off its dashed key and pass
  it as gradleRefreshDependencies, mirroring include-component-metadata.
  The spread is conditional so the default plugin-options shape is
  unchanged for scans that never set it. Kept off
  SupportedUserReachableFacingCliArgs so it stays internal.
- Bump cli-extension-dep-graph to v2.8.1, the first release whose legacy
  resolution forwards the flag rather than dropping it.
- Bump cli-extension-sbom, which registers the hidden flag on sbom create
  so it survives the config clone into that resolution path.
- Bump snyk-gradle-plugin to 7.1.0, which reads gradleRefreshDependencies
  and appends --refresh-dependencies.
- Cover the threading in all three states: forwarded when true, forwarded
  when explicitly false, and absent from the options entirely when unset.

The plugin only appends --refresh-dependencies inside its
includeComponentMetadata branch, so the flag needs
--include-component-metadata alongside it to have any effect.

Co-authored-by: Chris Heppell <christopher.heppell@snyk.io>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cjheppell
cjheppell force-pushed the feat/gradle-include-component-metadata branch from 5f0bc39 to fa6391c Compare July 30, 2026 14:15
@cjheppell
cjheppell marked this pull request as ready for review July 30, 2026 14:16
@cjheppell
cjheppell requested a review from a team as a code owner July 30, 2026 14:16
@snyk-pr-review-bot

Copy link
Copy Markdown

PR Reviewer Guide 🔍

🧪 PR contains tests
🔒 No security concerns identified
⚡ No major issues detected
📚 Repository Context Analyzed

This review considered 14 relevant code sections from 6 files (average relevance: 0.63)

🤖 Repository instructions applied (from AGENTS.md)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant