Skip to content

build: vendor secrets-gradle-plugin with an Isolated-Projects fix - #6595

Open
jamesarich wants to merge 1 commit into
mainfrom
fix/vendor-secrets-gradle-plugin
Open

build: vendor secrets-gradle-plugin with an Isolated-Projects fix#6595
jamesarich wants to merge 1 commit into
mainfrom
fix/vendor-secrets-gradle-plugin

Conversation

@jamesarich

@jamesarich jamesarich commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Why

Gradle 9.7.0 (Renovate #6589) hard-fails every androidApp build: Google's secrets-gradle-plugin 2.0.1 reads its properties files through project.rootProject.file(), which Isolated Projects forbids and 9.7+ enforces. There is no upstream escape hatch — 2.0.1 is the latest release (Feb 2022), the tagged 2.0.2 was never published, and the one-line fix has sat unmerged in google/secrets-gradle-plugin#104 since March on a repo with no release in four years. This unblocks #6589 without giving up Isolated Projects.

🛠️ Improvements

  • Vendor the plugin (Apache-2.0, ~180 lines) into build-logic as meshtastic.android.secrets, byte-identical to upstream v2.0.1 except:
    • property files resolve via isolated.rootProject — the IP-safe idiom the rest of build-logic already uses
    • legacy Variant API helpers (AppExtension/InternalBaseVariant) dropped — dead code paths here, and the classes no longer exist in AGP 9
    • buildConfigFields made null-safe (nullable since AGP 9)
  • The vendored files keep Google's license header and are excluded from spotless/detekt so they stay trivially diffable against upstream; delete the copy if upstream ever ships a release > 2.0.1 with the fix.

🧹 Cleanup

  • Drop the secrets plugin from the version catalog and the root apply false line; androidApp now applies meshtastic.android.secrets.

Testing Performed

  • spotlessApply spotlessCheck detekt assembleDebug test allTests — green (the sole allTests failure is BleAddressLoggingTest's scope guard, which pre-exists on a clean main tree when run from a .claude/worktrees checkout and is unrelated; tracked separately).
  • Injection verified byte-for-byte against the binary plugin: merged googleDebug manifest carries com.google.android.geo.API_KEY from local.properties, and BuildConfig carries MAPS_API_KEY / datadogApplicationId / datadogClientToken.
  • On the Gradle 9.7.0 branch, :androidApp configuration passes with this plugin where 2.0.1 failed.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added Android secrets configuration support for securely loading property values.
    • Supports default, build-type, and flavor-specific property files.
    • Injects configured values into app builds and manifests.
  • Bug Fixes

    • Missing optional configuration files are now handled gracefully.
    • Improved compatibility with newer Android build tooling.

Google's secrets-gradle-plugin 2.0.1 reads properties via
project.rootProject.file(), which Isolated Projects forbids — Gradle 9.7+
fails every androidApp build over it. Upstream is dormant (no release since
2022) and the one-line fix has sat unmerged in google/secrets-gradle-plugin#104
since March, so waiting is not a strategy and this blocks the Gradle 9.7 bump.

Vendor the plugin (Apache-2.0, ~180 lines) into build-logic as
meshtastic.android.secrets, byte-identical except:
- property files resolve via isolated.rootProject (the IP-safe idiom)
- legacy Variant API helpers dropped (classes removed in AGP 9; dead paths)
- buildConfigFields made null-safe (nullable since AGP 9)

The vendored files keep Google's license header and are excluded from
spotless/detekt so they stay diffable against upstream.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added bugfix PR tag build Build system changes labels Aug 8, 2026
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The build replaces the external Google Secrets plugin alias with a vendored convention plugin. The plugin loads property files and injects values into Android variant BuildConfig fields and manifest placeholders.

Changes

Android secrets integration

Layer / File(s) Summary
Secrets configuration and injection helpers
build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPluginExtension.kt, build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/Extensions.kt
Adds plugin configuration, isolated root-project property loading, variant injection, and string quoting helpers.
Secrets plugin implementation
build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPlugin.kt
Adds the vendored plugin, property-file fallback handling, and default, configured, build-type, and flavor-specific property injection.
Convention plugin registration and application
build-logic/convention/build.gradle.kts, gradle/libs.versions.toml, build.gradle.kts, androidApp/build.gradle.kts
Registers meshtastic.android.secrets, excludes vendored sources from Spotless and Detekt, removes the external alias, and applies the new alias in androidApp.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AndroidApp
  participant SecretsPlugin
  participant RootProject
  participant AndroidVariant
  participant BuildConfig
  participant Manifest
  AndroidApp->>SecretsPlugin: apply meshtastic.android.secrets
  SecretsPlugin->>RootProject: load configured property files
  SecretsPlugin->>AndroidVariant: inject variant properties
  AndroidVariant->>BuildConfig: write string fields
  AndroidVariant->>Manifest: populate placeholders
Loading
🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: vendoring the secrets Gradle plugin to fix Isolated Projects compatibility.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Sibling Call Sites And Presence Semantics ✅ Passed Only one buildConfigFields access exists and it uses ?.put; the PR adds no physical metric fields or zero defaults, and neither NodeItem sibling changes.
Tests Prove The Path, Not The End State ✅ Passed The PR changes only build/configuration and production Kotlin files; no test files or test declarations were added or changed, so this check is not applicable.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@build-logic/convention/build.gradle.kts`:
- Around line 81-82: Remove the secrets_gradle_plugin exclusion from Spotless at
build-logic/convention/build.gradle.kts:81-82 and from Detekt at
build-logic/convention/build.gradle.kts:106-107, then update the vendored Kotlin
sources under secrets_gradle_plugin so both quality checks pass.

In
`@build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPluginExtension.kt`:
- Line 31: Update the ignoreList initializer in SecretsPluginExtension so each
extension receives an independent mutable copy by using
defaultIgnoreList.toMutableList(), preventing changes in one plugin application
from affecting others.
- Line 17: Move the vendored Secrets Gradle Plugin classes from the Google
package to the org.meshtastic package: update the package declarations in
SecretsPluginExtension.kt, Extensions.kt, and SecretsPlugin.kt, and relocate
their source directories accordingly. In
build-logic/convention/build.gradle.kts, update the androidSecrets plugin
registration implementationClass to reference the new org.meshtastic
SecretsPlugin path.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cc349f16-90d4-46f6-8b13-db8faff75c89

📥 Commits

Reviewing files that changed from the base of the PR and between a885127 and 90d101f.

📒 Files selected for processing (7)
  • androidApp/build.gradle.kts
  • build-logic/convention/build.gradle.kts
  • build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/Extensions.kt
  • build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPlugin.kt
  • build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPluginExtension.kt
  • build.gradle.kts
  • gradle/libs.versions.toml
💤 Files with no reviewable changes (1)
  • build.gradle.kts

Comment on lines +81 to +82
// secrets_gradle_plugin is vendored third-party code (Apache-2.0) keeping Google's header.
targetExclude("**/build/**/*.kt", "**/secrets_gradle_plugin/**")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo files matching build-logic/convention/build.gradle.kts =="
git ls-files | grep -F 'build-logic/convention/build.gradle.kts' || true

echo "== relevant lines =="
if [ -f build-logic/convention/build.gradle.kts ]; then
  nl -ba build-logic/convention/build.gradle.kts | sed -n '65,115p'
fi

echo "== secrets_gradle_plugin locations =="
git ls-files | grep -E 'secrets_gradle_plugin' || true

echo "== spotless/detekt config references =="
rg -n "targetExclude|secrets_gradle_plugin|dev\\.detekt\\.gradle\\.Detekt|tasks\\.withType<dev\\.detekt\\.gradle\\.Detekt>" -S .

Repository: meshtastic/Meshtastic-Android

Length of output: 334


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== relevant lines =="
if [ -f build-logic/convention/build.gradle.kts ]; then
  sed -n '65,115p' build-logic/convention/build.gradle.kts | awk '{printf "%7d  %s\n", NR+64, $0}'
fi

echo "== secrets_gradle_plugin locations =="
git ls-files | grep -E 'secrets_gradle_plugin' || true

echo "== spotless/detekt config references =="
grep -RInE "targetExclude|secrets_gradle_plugin|dev\.detekt\.gradle\.Detekt|tasks\.withType<dev\.detekt\.gradle\.Detekt>" . || true

echo "== changed files/stat =="
git diff --name-status -- build-logic/convention/build.gradle.kts || true
git status --short

Repository: meshtastic/Meshtastic-Android

Length of output: 4598


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== vendored files =="
for f in \
  build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/Extensions.kt \
  build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPlugin.kt \
  build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPluginExtension.kt
do
  echo "--- $f ---"
  head -60 "$f"
done

echo "== build-root spotless/detekt files =="
git ls-files ':!build-logic' | \
  xargs -r grep -l -E 'spotless|detekt|targetExclude|secrets_gradle_plugin' | \
  head -50

Repository: meshtastic/Meshtastic-Android

Length of output: 10594


Keep vendored Kotlin sources in the quality gates.

Remove the Spotless and Detekt exclusions for secrets_gradle_plugin, then update these Kotlin sources until both checks pass.

  • build-logic/convention/build.gradle.kts#L82: remove the Spotless exclusion for **/secrets_gradle_plugin/**.
  • build-logic/convention/build.gradle.kts#L107: remove the Detekt exclusion for **/secrets_gradle_plugin/**.
📍 Affects 1 file
  • build-logic/convention/build.gradle.kts#L81-L82 (this comment)
  • build-logic/convention/build.gradle.kts#L106-L107
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build-logic/convention/build.gradle.kts` around lines 81 - 82, Remove the
secrets_gradle_plugin exclusion from Spotless at
build-logic/convention/build.gradle.kts:81-82 and from Detekt at
build-logic/convention/build.gradle.kts:106-107, then update the vendored Kotlin
sources under secrets_gradle_plugin so both quality checks pass.

Source: Coding guidelines

//
// Vendored unmodified from google/secrets-gradle-plugin v2.0.1 — see SecretsPlugin.kt for why.

package com.google.android.libraries.mapsplatform.secrets_gradle_plugin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== candidate files =="
git ls-files 'build-logic/convention/src/main/kotlin/**/*' | rg 'Secrets|Extensions|build.gradle.kts$|gradle/libs.versions.toml$' || true

echo "== relevant package declarations and implementation refs =="
for f in \
  build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPluginExtension.kt \
  build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/Extensions.kt \
  build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPlugin.kt \
  build-logic/convention/build.gradle.kts
do
  if [ -f "$f" ]; then
    echo "--- $f"
    nl -ba "$f" | sed -n '1,220p'
  else
    echo "missing: $f"
  fi
done

echo "== build-logic convention source package usage search =="
rg -n "package (com\.google|org\.meshtastic|.*secrets_gradle_plugin|.*androidSecrets|implementationClass|meshtastic\.android\.secrets)" build-logic/convention src build.gradle.kts settings.gradle.kts || true

echo "== kotlin imports/usages of vendored classes =="
rg -n "com\.google\.android\.libraries\.mapsplatform\.secrets_gradle_plugin|SecretsPlugin|SecretsPluginExtension|androidSecrets" . || true

Repository: meshtastic/Meshtastic-Android

Length of output: 875


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== candidate line content =="
for f in \
  build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPluginExtension.kt \
  build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/Extensions.kt \
  build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPlugin.kt \
  build-logic/convention/build.gradle.kts
do
  if [ -f "$f" ]; then
    echo "--- $f"
    grep -nE '^(package|register\("androidSecrets"\) \{|id\s*=|implementationClass\s*=)' "$f" || true
  else
    echo "missing: $f"
  fi
done

echo "== build.gradle.kts relevant section =="
grep -nE 'androidSecrets|implementationClass|com\.google\.android\.libraries\.mapsplatform\.secrets_gradle_plugin|meshtastic\.android\.secrets' build-logic/convention/build.gradle.kts || true

echo "== broader usage/import search =="
rg -n "com\.google\.android\.libraries\.mapsplatform\.secrets_gradle_plugin|SecretsPlugin|SecretsPluginExtension|androidSecrets|meshtastic\.android\.secrets" . || true

Repository: meshtastic/Meshtastic-Android

Length of output: 5152


Move the vendored Secrets Gradle Plugin classes to an org.meshtastic.* package.

The new Kotlin files still declare com.google.android.libraries.mapsplatform.secrets_gradle_plugin, and the androidSecrets plugin registration points to that Google package. Relocate the sources with the package declarations, then update one implementationClass entry in build-logic/convention/build.gradle.kts to the new SecretsPlugin path.

📍 Affects 4 files
  • build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPluginExtension.kt#L17-L17 (this comment)
  • build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/Extensions.kt#L25-L25
  • build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPlugin.kt#L23-L23
  • build-logic/convention/build.gradle.kts#L135-L139
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPluginExtension.kt`
at line 17, Move the vendored Secrets Gradle Plugin classes from the Google
package to the org.meshtastic package: update the package declarations in
SecretsPluginExtension.kt, Extensions.kt, and SecretsPlugin.kt, and relocate
their source directories accordingly. In
build-logic/convention/build.gradle.kts, update the androidSecrets plugin
registration implementationClass to reference the new org.meshtastic
SecretsPlugin path.

Source: Coding guidelines

/**
* A list of keys this plugin should ignore and not inject. Defaults to $defaultIgnoreList
*/
var ignoreList: MutableList<String> = defaultIgnoreList

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Create an independent ignore list for each extension.

Line 31 assigns the shared mutable defaultIgnoreList to every plugin application. If one project changes secrets.ignoreList, later projects receive the changed list. Initialize this value with defaultIgnoreList.toMutableList().

Proposed fix
-    var ignoreList: MutableList<String> = defaultIgnoreList
+    var ignoreList: MutableList<String> = defaultIgnoreList.toMutableList()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var ignoreList: MutableList<String> = defaultIgnoreList
var ignoreList: MutableList<String> = defaultIgnoreList.toMutableList()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@build-logic/convention/src/main/kotlin/com/google/android/libraries/mapsplatform/secrets_gradle_plugin/SecretsPluginExtension.kt`
at line 31, Update the ignoreList initializer in SecretsPluginExtension so each
extension receives an independent mutable copy by using
defaultIgnoreList.toMutableList(), preventing changes in one plugin application
from affecting others.

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

Labels

bugfix PR tag build Build system changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant