Skip to content

feat: add GCP Secret Manager OpenFeature provider#1772

Open
mahpatil wants to merge 1 commit intoopen-feature:mainfrom
mahpatil:feat/gcp-secret-manager
Open

feat: add GCP Secret Manager OpenFeature provider#1772
mahpatil wants to merge 1 commit intoopen-feature:mainfrom
mahpatil:feat/gcp-secret-manager

Conversation

@mahpatil
Copy link
Copy Markdown

@mahpatil mahpatil commented Apr 9, 2026

Summary

  • Adds a new OpenFeature provider for GCP Secret Manager that reads feature flags from GCP Secret Manager secrets
  • Includes flag caching, value conversion for all OpenFeature types (bool, string, int, double, object), and background polling for updates
  • Adds a sample application under samples/gcp-secret-manager-sample/ with setup/teardown scripts

Provider Details

  • Package: providers/gcp-secret-manager
  • Class: GcpSecretManagerProvider
  • Supports all OpenFeature flag types via structured or plain-text secret values
  • Configurable poll interval and GCP project settings

Test plan

  • Unit tests for FlagCache, FlagValueConverter, and GcpSecretManagerProvider
  • Integration test (GcpSecretManagerProviderIntegrationTest) requires a real GCP project — set GCP_PROJECT_ID env var to run
  • Sample app: follow samples/gcp-secret-manager-sample/README.md to run end-to-end

Adds a new OpenFeature provider for GCP Secret Manager that enables
reading feature flags from GCP Secret Manager secrets. Includes the
provider implementation with flag caching, value conversion, unit tests,
integration tests, and a sample application demonstrating usage.
@mahpatil mahpatil requested a review from a team as a code owner April 9, 2026 05:18
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new OpenFeature provider for Google Cloud Secret Manager, enabling feature flags to be managed as GCP secrets. The changes include the core provider implementation with caching and value conversion, along with comprehensive unit and integration tests, and a sample application. Feedback suggests adding an initial entry to the new module's CHANGELOG.md, refining the spotbugs-exclusions.xml to only include relevant exclusions, and improving the testability of FlagCache by injecting a Clock instance instead of relying on Instant.now() and Thread.sleep().

@@ -0,0 +1 @@

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.

medium

A new module should have an initial entry in its CHANGELOG.md to document its creation and initial version. This helps maintain a clear history of changes from the very beginning.

Suggested change
# Changelog
## 0.0.1
### ✨ New Features
* Initial release of the GCP Secret Manager OpenFeature provider.

Comment on lines +4 to +38
<!-- Ignore generated dev.openfeature.flagd.grpc schemas -->
<Match>
<Package name="~dev\.openfeature\.flagd\.grpc.*" />
</Match>

<!-- Ignore generated dev.openfeature.flagd.sync schemas -->
<Match>
<Package name="~dev\.openfeature\.flagd\.sync.*" />
</Match>

<!-- Allow predictable random for backoff jitter generation -->
<Match>
<Class name="dev.openfeature.contrib.providers.flagd.resolver.common.backoff.BackoffService" />
<Bug pattern="PREDICTABLE_RANDOM" />
</Match>

<!-- Suppress: EI_EXPOSE_REP2 in ModuleMachine -->
<Match>
<Class name="dev.openfeature.contrib.providers.gofeatureflag.wasm.ModuleMachine"/>
<Bug pattern="EI_EXPOSE_REP2"/>
</Match>

<!-- Suppress: SKIPPED_CLASS_TOO_BIG in ModuleMachineFuncGroup_0 -->
<Match>
<Class name="dev.openfeature.contrib.providers.gofeatureflag.wasm.ModuleMachineFuncGroup_0"/>
<Bug pattern="SKIPPED_CLASS_TOO_BIG"/>
</Match>

<!-- All bugs in test classes, except for JUnit-specific bugs -->
<Match>
<Class name="~.*\.*Test" />
<Not>
<Bug code="IJU" />
</Not>
</Match>
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.

medium

This spotbugs-exclusions.xml file is specific to the gcp-secret-manager provider. It should ideally only contain exclusions relevant to this module. The current file includes exclusions for other modules, which indicates a copy-paste error and makes the configuration less maintainable.

<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter xmlns="https://github.com/spotbugs/filter/3.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubusercontent.com/spotbugs/spotbugs/3.1.0/spotbugs/etc/findbugsfilter.xsd">

    <!-- All bugs in test classes, except for JUnit-specific bugs -->
    <Match>
        <Class name="~.*\.*Test" />
        <Not>
            <Bug code="IJU" />
        </Not>
    </Match>
</FindBugsFilter>

Comment on lines +83 to +87
}

boolean isExpired() {
return Instant.now().isAfter(expiresAt);
}
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.

medium

Using Instant.now() directly within CacheEntry makes time-sensitive logic harder to test deterministically. Consider injecting a Clock instance into FlagCache and subsequently into CacheEntry to allow for better testability and control over time.

        CacheEntry(String value, Duration ttl, Clock clock) {
            this.value = value;
            this.expiresAt = Instant.now(clock).plus(ttl);
        }

        boolean isExpired() {
            return Instant.now(clock).isAfter(expiresAt);
        }


@Test
@DisplayName("get() returns empty after TTL expires")
void getAfterTtlExpiry() throws InterruptedException {
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.

medium

Using Thread.sleep() in tests can lead to flaky tests and slow down the test suite. For time-sensitive logic like cache expiry, it's better to use a Clock abstraction (e.g., java.time.Clock) that can be mocked or controlled in tests. This would make tests deterministic and faster.

// Simulate time passing using a mocked Clock if FlagCache is refactored to accept one

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