build(plugin): Add dependency locking and verification to plugin-build (GRADLE-104)#1256
build(plugin): Add dependency locking and verification to plugin-build (GRADLE-104)#1256runningcode wants to merge 5 commits into
plugin-build (GRADLE-104)#1256Conversation
| 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 |
There was a problem hiding this comment.
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.
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.
12fc51b to
86ac005
Compare
86ac005 to
91533ad
Compare
plugin-build (GRADLE-104)
0xadam-brown
left a comment
There was a problem hiding this comment.
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?
|
Yeah those are good points. |
| 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 }} |
There was a problem hiding this comment.
I think we need to add this secret.
| @@ -0,0 +1,65 @@ | |||
| name: Update Dependency Locks | |||
There was a problem hiding this comment.
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.
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>
3c44476 to
92718d0
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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.
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>
92718d0 to
630801b
Compare

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):
dependencyLocking { lockAllConfigurations() }plus agradle.lockfile. STRICT mode (the default) fails the build on unexpected version drift.gradle/verification-metadata.xmlwith 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.yamldeliberately tests compatibility against a matrix of AGP / Kotlin / Gradle versions, set via theVERSION_AGP/VERSION_KOTLINenv vars (read inbuildSrc/.../Dependencies.kt) and thegradle-versionoverride. Those overrides intentionally diverge from the lockfile and the recorded checksums, so pinning and the matrix are fundamentally in conflict:VERSION_KOTLINoverridden,compileClasspathresolves e.g.kotlin-stdlib:2.3.21, but the lockfile pins{strictly 2.0.0}→Dependency version enforced by Dependency Lockingfailure.-p plugin-buildintegration test) resolve artifacts that aren't inverification-metadata.xml(different SDK/AGP versions; the buildscript-classpath.modulefiles) →Dependency verification failed.So we keep pinning on the canonical build and exempt the version-varying jobs:
VERSION_AGP/VERSION_KOTLINoverride is present:--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
resolveAndLockAllhelper task (per the Gradle docs) regenerates the lockfile:./gradlew -p plugin-build resolveAndLockAll --write-locks../gradlew -p plugin-build --write-verification-metadata sha256 ….--write-locks/--write-verification-metadatarefresh.--no-daemon, becauseSystem.getenv()returns the daemon's startup environment (which is why CI, with a fresh daemon per job, behaves correctly).🤖 Generated with Claude Code