Skip to content

add internal remote config patch tool #6380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 21, 2025

Conversation

LukasPaczos
Copy link
Contributor

Task/Issue URL: https://app.asana.com/1/137249556945/project/1208671518894266/task/1210708742763735

Description

Adds tooling to locally patch remote config. Read the details in the new README file in the diff.

Steps to test this PR

  1. Create a privacy-config/privacy-config-internal/local-patch-file/test_patch.json file with this content:
[
  {
    "op": "replace",
    "path": "/features/aiChat/state",
    "value": "disabled"
  }
]
  1. Create a privacy-config/privacy-config-internal/local.properties file with this content:
config_patches=privacy-config/privacy-config-internal/local-config-patches/test_patch.json
  1. Clean install the app.
  2. Verify Duck.ai is disabled and that Settings -> Duck.ai is gone.
  3. Update the patch file to:
[
  {
    "op": "replace",
    "path": "/version",
    "value": "2752244802866"
  },
  {
    "op": "remove",
    "path": "/features/aiChat/hash"
  }
]
  1. Relaunch the app (without clean installing it). This will download the production config and force update the feature because of the bumped version number and mismatching hash.
  2. Verify Duck.ai is enabled and that Settings -> Duck.ai is available.
  3. Update the test_patch.json to disable Duck.ai again and bump version:
[
  {
    "op": "replace",
    "path": "/features/aiChat/state",
    "value": "disabled"
  },
  {
    "op": "remove",
    "path": "/features/aiChat/hash"
  },
  {
    "op": "replace",
    "path": "/version",
    "value": "3752244802866"
  }
]
  1. Relaunch the app (without clean installing it).
  2. Verify Duck.ai is disabled and that Settings -> Duck.ai is gone.

Comment on lines +35 to +39
@ContributesMultibinding(
scope = AppScope::class,
boundType = ApiInterceptorPlugin::class,
)
class DevPrivacyConfigPatchApiInterceptor @Inject constructor(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

All interceptors are currently added in default order, sorted by class name. If I assign a low priority to this interceptor without changing the others, it would run first, since it would be the only one with a defined priority. I tried giving all plugins the same priority (to preserve class name sorting as PriorityKey docs suggest) and setting this interceptor last, but the build fails due to duplicate priority keys, despite what the docs say.

I don’t want to risk changing any production behavior, so it’s fine if this interceptor doesn’t run last for now. If it ever becomes a problem, we can revisit.

@LukasPaczos LukasPaczos force-pushed the feature/lukasz-p/dev-remote-config-patches branch from 4c0a289 to 38a26d8 Compare July 22, 2025 13:51
@LukasPaczos LukasPaczos force-pushed the feature/lukasz-p/dev-remote-config-patches branch from 38a26d8 to 57356ee Compare August 4, 2025 10:00
@joshliebe joshliebe requested a review from Copilot August 12, 2025 07:40
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds local remote config patching tooling for development builds, allowing developers to override production remote config values locally without server deployments. The implementation uses JSON Patch format to apply runtime modifications to privacy config responses.

Key changes:

  • Introduces JSON patch-based remote config modification system for internal builds
  • Adds flexible configuration through command-line parameters or local.properties files
  • Implements asset copying and build-time validation for patch files

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
versions.properties Adds zjsonpatch library dependency for JSON Patch operations
DevPrivacyConfigPatchApiInterceptor.kt New interceptor that applies JSON patches to privacy config API responses
build.gradle Implements patch file discovery, copying, and build configuration logic
README.md Documents the patching system usage and configuration options
.gitignore Excludes local patch files and configuration from version control
Comments suppressed due to low confidence (1)

return response
}

return chain.proceed(chain.request())
Copy link
Preview

Copilot AI Aug 12, 2025

Choose a reason for hiding this comment

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

This line should use the request parameter instead of chain.request() since the request was already extracted on line 46. Using chain.request() creates a new request object unnecessarily.

Suggested change
return chain.proceed(chain.request())
return chain.proceed(request)

Copilot uses AI. Check for mistakes.


android.sourceSets.main.assets.srcDirs += layout.buildDirectory.dir("generated/assets/configPatches").get().asFile.path

afterEvaluate {
Copy link
Preview

Copilot AI Aug 12, 2025

Choose a reason for hiding this comment

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

Adding the build directory path to source sets during configuration time can cause issues with Gradle's build cache and configuration caching. Consider using a different approach such as configuring this in the copyConfigPatches task or using a pre-existing assets directory.

Suggested change
afterEvaluate {
// Moved to afterEvaluate to avoid configuration time issues with Gradle caching
afterEvaluate {
// Add generated configPatches assets directory to source sets at execution time
android.sourceSets.main.assets.srcDirs += layout.buildDirectory.dir("generated/assets/configPatches").get().asFile.path

Copilot uses AI. Check for mistakes.

Copy link
Contributor

@joshliebe joshliebe left a comment

Choose a reason for hiding this comment

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

First testing step should be local-config-patches instead of local-patch-file but works as expected! Nice one 🙂

@LukasPaczos LukasPaczos merged commit 61b3864 into develop Aug 21, 2025
12 checks passed
@LukasPaczos LukasPaczos deleted the feature/lukasz-p/dev-remote-config-patches branch August 21, 2025 15:10
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