Skip to content

build(plugin): Add dependency locking and verification to plugin-build (GRADLE-104)#1256

Open
runningcode wants to merge 5 commits into
mainfrom
no/gradle-104-version-pinning
Open

build(plugin): Add dependency locking and verification to plugin-build (GRADLE-104)#1256
runningcode wants to merge 5 commits into
mainfrom
no/gradle-104-version-pinning

Conversation

@runningcode

@runningcode runningcode commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Hardens the published plugin build against supply-chain risk by pinning its transitive dependencies, scoped to plugin-build/ (the build that produces the shipped artifact). Part of GRADLE-104 / SDK-1316.

Two complementary controls, both enforced automatically by existing CI (no workflow changes):

  • Gradle dependency lockingdependencyLocking { lockAllConfigurations() } plus a gradle.lockfile. STRICT mode (the default) fails the build on unexpected version drift.
  • Gradle dependency verificationgradle/verification-metadata.xml with a SHA-256 checksum for every resolved artifact (verify-metadata=true, verify-signatures=false — no PGP keyring to maintain).

The verification metadata captures the formatter (spotless), docs (dokka), and publish tooling in addition to the project configurations.

Why the version-matrix tests are exempt

Pinning protects the canonical build (the default versions that ship). But test-matrix-agp-gradle.yaml deliberately tests compatibility against a matrix of AGP / Kotlin / Gradle versions, set via the VERSION_AGP / VERSION_KOTLIN env vars (read in buildSrc/.../Dependencies.kt) and the gradle-version override. Those overrides intentionally diverge from the lockfile and the recorded checksums, so pinning and the matrix are fundamentally in conflict:

  • Locking: with VERSION_KOTLIN overridden, compileClasspath resolves e.g. kotlin-stdlib:2.3.21, but the lockfile pins {strictly 2.0.0}Dependency version enforced by Dependency Locking failure.
  • Verification: the matrix (and the standalone -p plugin-build integration test) resolve artifacts that aren't in verification-metadata.xml (different SDK/AGP versions; the buildscript-classpath .module files) → Dependency verification failed.

So we keep pinning on the canonical build and exempt the version-varying jobs:

  • Locking is guarded to only apply when no VERSION_AGP / VERSION_KOTLIN override is present:
    val isVersionOverrideBuild =
      System.getenv("VERSION_AGP") != null || System.getenv("VERSION_KOTLIN") != null
    if (!isVersionOverrideBuild) {
      dependencyLocking { lockAllConfigurations() }
    }
  • Verification is turned off on the version-matrix and standalone integration-test steps via --dependency-verification=off.

Canonical jobs (pre-merge, publish, the distribution build) keep strict locking and verification, so the protection that matters for the shipped artifact is fully enforced.

Notes for reviewers

  • A resolveAndLockAll helper task (per the Gradle docs) regenerates the lockfile: ./gradlew -p plugin-build resolveAndLockAll --write-locks.
  • Regenerate verification metadata with ./gradlew -p plugin-build --write-verification-metadata sha256 ….
  • Dependabot's gradle updater does not always rewrite these files on a bump — dependency PRs may need a follow-up --write-locks / --write-verification-metadata refresh.
  • Local gotcha: version overrides only take effect with --no-daemon, because System.getenv() returns the daemon's startup environment (which is why CI, with a fresh daemon per job, behaves correctly).

🤖 Generated with Claude Code

@linear-code

linear-code Bot commented Jun 3, 2026

Copy link
Copy Markdown

GRADLE-104

io.grpc:grpc-stub:1.69.1=testRuntimeClasspath
io.grpc:grpc-util:1.69.1=testRuntimeClasspath
io.netty:netty-buffer:4.1.110.Final=testRuntimeClasspath
io.netty:netty-codec-http2:4.1.110.Final=testRuntimeClasspath

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

High severity vulnerability introduced by a package you're using:
Line 100 lists a dependency (io.netty:netty-codec-http2) with a known High severity vulnerability. Fixing requires upgrading or replacing the dependency.

ℹ️ Why this matters

Affected versions of io.grpc:grpc-netty-shaded and io.netty:netty-codec-http2 are vulnerable to Allocation of Resources Without Limits or Throttling. Netty's HTTP/2 implementation fails to correctly track active streams when sending RST_STREAM in response to certain malformed control frames. An attacker can send, for example, WINDOW_UPDATE frames with a zero or overflow increment, HEADERS/DATA on a half-closed stream, or PRIORITY frames with invalid length to trigger RST_STREAMs; each reset decrements Netty's concurrent-stream counter even though the request is still processed. By repeating this on a single connection, the attacker can open an unbounded number of streams, exhausting CPU and memory and causing a denial of service. This is a protocol level attack.

References: GHSA, CVE

To resolve this comment:
Upgrade this dependency to at least version 4.1.124.Final at plugin-build/gradle.lockfile.

💬 Ignore this finding

To ignore this, reply with:

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

You can view more details on this finding in the Semgrep AppSec Platform here.

Comment thread plugin-build/build.gradle.kts
@runningcode runningcode force-pushed the no/gradle-104-version-pinning branch from 12fc51b to 86ac005 Compare June 4, 2026 12:26
Comment thread plugin-build/build.gradle.kts
@runningcode runningcode force-pushed the no/gradle-104-version-pinning branch from 86ac005 to 91533ad Compare June 4, 2026 12:49
Comment thread .github/workflows/integration-tests-sentry-cli.yml
@runningcode runningcode changed the title build(plugin): Add dependency locking and verification (GRADLE-104) build(plugin): Add dependency locking and verification to plugin-build (GRADLE-104) Jun 4, 2026

@0xadam-brown 0xadam-brown left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice! Coordinate + content locks look great.

m: Two high-level suggestions:

[1] Could be nice to include a pre-merge workflow that warns folks if their lock file needs updating, ie, regenerate the lock file, diff against what's in the PR, and fail if changed.

[2] Have dependabot PRs self-heal w/r/t the lock file.

Eg, i) extract lock file generation into a script, ii) trigger a small workflow on pull_request from dependabot/* when gradle/, plugin-build/, or buildSrc/** change, and iii) re-run the script from (i). (Or whatever makes sense...)

[1] is optional, but I think we should do [2], lest our dependabot life become even busier. Either here or in a fast-follow is fine by me. Thoughts?

@runningcode

runningcode commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Yeah those are good points.
For 1, I will update and add this
For 2, Dependabot supports Gradle lock files but not dependency verification.
I wonder if we should consider switching to Renovate since it supports lock files and dependency verification out of the box and is free on open source repos: https://docs.renovatebot.com/modules/manager/gradle/
Or otherwise drop the dependency verification from this PR.

ref: ${{ github.head_ref }}
# Pushing with the deploy key (rather than GITHUB_TOKEN) re-triggers CI
# so the regenerated files are validated.
ssh-key: ${{ secrets.CI_DEPLOY_KEY }}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think we need to add this secret.

@@ -0,0 +1,65 @@
name: Update Dependency Locks

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is generated by claude and not tested. We'll just need to merge this and adjust as needed since there isn't really a way to testing the full integration and secrets.

runningcode and others added 3 commits June 9, 2026 13:24
Pin the transitive dependencies of the published plugin build to harden
against supply-chain risk. Gradle dependency locking records resolved
versions in a lockfile and fails the build (STRICT mode) on unexpected
drift, while dependency verification checks a SHA-256 checksum for every
resolved artifact.

Scoped to plugin-build only, the build that produces the shipped artifact.
The metadata captures the formatter (spotless), docs (dokka), and publish
tooling in addition to the project configurations, so the existing CI
enforces both controls without new workflow steps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…DLE-104)

The compatibility test matrix overrides AGP/Kotlin/Gradle versions, which
deliberately diverges from the lockfile and verification metadata of the
canonical build. Guard dependency locking so it only applies when no
VERSION_AGP/VERSION_KOTLIN override is set, and disable dependency
verification on the matrix and standalone integration-test steps.

Canonical builds (pre-merge, publish, distribution) keep strict locking
and verification.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@runningcode runningcode force-pushed the no/gradle-104-version-pinning branch from 3c44476 to 92718d0 Compare June 9, 2026 11:26

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 92718d0. Configure here.

Comment thread .github/workflows/update-dependency-locks.yml
runningcode and others added 2 commits June 9, 2026 15:45
Adding, removing, or bumping a dependency in plugin-build invalidates the
lockfile and verification metadata, and STRICT-mode locking fails the build
until both are regenerated. Document the single command that rewrites them
and point the dependencyLocking block at the new section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dependabot bumps versions in the catalog but cannot regenerate the
plugin-build lockfile or verification metadata, so its Gradle PRs fail
STRICT-mode locking and checksum verification. Run resolveAndLockAll with
--write-locks and --write-verification-metadata on those PRs and push the
regenerated files back via the deploy key so CI revalidates them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@runningcode runningcode force-pushed the no/gradle-104-version-pinning branch from 92718d0 to 630801b Compare June 9, 2026 13:46
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.

2 participants