Skip to content

fix!: Stop serving payload filters - #867

Merged
keelerm84 merged 1 commit into
v9from
mk/sdk-3082/remove-payload-filters
Sep 14, 2026
Merged

keelerm84 merged 1 commit into
v9from
mk/sdk-3082/remove-payload-filters

Conversation

@keelerm84

@keelerm84 keelerm84 commented Sep 11, 2026

Copy link
Copy Markdown
Member

Warning

Breaking change. Payload filter support is removed. The [Filters] config section and LD_FILTER_KEYS_ environment variables no longer configure anything, and the two /status routes that took a filter key are gone. The option never had any effect on this version, so nothing that worked before stops working. A filter query parameter on a request is accepted and ignored.

Summary

The Flag Delivery network does not support payload filters on FDv2. This version of Relay connects only through FDv2, so a configured filter never had any effect -- Relay sent ?filter=<key> upstream and the upstream ignored it. Because the option never worked, removing it changes no behavior anyone could have depended on, and v9 has had no non-rc release, so the configuration surface is fair game.

Relay created filtered environments on two paths, and both are gone.

Manual configuration. makeFilteredEnvironments fanned each environment out once per configured filter key, set the filter on the copy, appended /<key> to its store prefix, and registered it as <env>/<filterKey>. That goes, along with Config.Filters, FiltersConfig and EnvConfig.FilterKey. A [Filters] file section is now rejected as an unknown section (gcfg does this for free), and a LD_FILTER_KEYS_ variable is ignored like any other unrecognized variable. I confirmed both behaviors empirically rather than assuming them.

Auto-configuration. LaunchDarkly sends filter entities over the RPAC stream, and Relay turned each into an extra environment per filter. The put, patch and delete handling is removed, along with the filter receiver and the dispatch into the handler. Filter entities now fall through to the branch the stream already had for unrecognized entities -- deliberately a debug log, per its own comment -- so LaunchDarkly can keep sending them with no restart and no log noise. The prefix substitution in envfactory no longer appends a filter key either; that was what made this path produce the same suffixed prefix as manual config.

The two /status routes carrying a filter key are removed, since nothing can create a filtered environment for them to report on. The status handler needs no change: the filter key it reads is simply absent from the remaining routes.

The PayloadFilter calls on the data source builders are gone, with the nolint directives that suppressed their deprecation warnings (added in #862).

A filter query parameter is accepted and ignored. Authentication no longer reads it, so it cannot affect which environment a request resolves to. The secondary Unscope() lookup that distinguished "credential valid but filter unknown" is gone with it, along with errPayloadFilterNotFound, IsPayloadFilterNotFound and the 404 they produced.

This needed fixing after review: I had claimed the parameter was ignored while authentication still read it, so an SDK sending one got 404 on every request. Cursor Bugbot flagged it and I reproduced it independently. Ignoring is the right behavior rather than rejecting, because such an SDK was already being served the environment's full data (the upstream ignores the filter on FDv2), so refusing it now would break a client that was working.

Filter documentation is removed rather than rewritten to say the feature is unsupported; the release notes cover the removal. That includes the [Filters "PROJECT-KEY"] section in configuration.md, the filtered status routes and their examples in endpoints.md, and the " (<filterKey>)" display-name clause. No dangling links remain -- endpoints.md had linked to the configuration.md#payload-filtering anchor.

Side effect worth having

Removing the /<filterKey> prefix on both paths removes a silent data-loss hazard on Consul. A filtered view's keys lived under the unfiltered view's subtree, because the separator is / and Consul treats that as a path separator. go-server-sdk-consul's Init does kv.List(prefix) and deletes every key not in the payload it writes, so the unfiltered environment's init deleted the filtered view's flags and its $inited sentinel with nothing logged. Fixing only the manual path would have left this live under auto-config. The hazard remains on v8, where FDv1 filtering genuinely works, and needs its own ticket.

Tests

Tests covering the removed behavior are replaced by tests covering the new behavior:

  • TestFilterEventsAreIgnored pins the RPAC contract: a filter patch, a filter delete and a malformed filter patch each reach no handler and cause no restart. Because "nothing happened" would also hold for a dead stream, each case then sends an environment patch and requires it through, proving the connection survived.
  • TestNewRelayDoesNotCreateFilteredEnvironments asserts the environment set matches the declared configuration.
  • TestStrayFilterQueryParameterIsIgnored sends the same request with and without ?filter=, requires 200 for both, and compares the set of objects returned. It compares object sets rather than raw bytes because serializeBasisV2 walks a map of data kinds, so Go randomizes flag-versus-segment ordering; a byte comparison passed in isolation then failed in the full suite. I confirmed it fails when the query-parameter lookup is restored.
  • The middleware subtests that registered environments under filtered credentials are removed, along with buildPreRoutedRequestWithFilter and returns 404 if key is correct but filter is unrecognized. Two of them hung rather than failed once the lookup stopped matching, because they block on a channel the handler never reaches.
  • TestWellFormedJSONThatIsNotWellFormedEventDataCausesStreamRestart/patch/filters is removed. It asserted a malformed filter patch restarts the stream; a filter path is now an unrecognized entity, so it is ignored instead. That is the intended consequence, not a regression.
  • The tracing test used the filtered status route as a generic "path with no context variable" example. It now uses /status/{projKey}/{envKey}, so the case survives without referencing a dead route.
  • Removed as covering the removed feature: the three TestMakeFilteredEnvironments_*, the three TestNewRelayDisallowsFilters*, TestFilterPutEvent / TestFilterPatchEvent / TestFilterDeleteEvent, and the filtered-status 404 subtest.

Net: 578 deletions against 54 insertions.

Follow-ups

The filter machinery in projmanager (AddFilter, DeleteFilter, the filtered map) is now unreachable but still compiled; it comes out next along with internal/sdkauth, which exists solely because of payload filtering, and finally config.FilterKey / FilterID / DefaultFilter once nothing references them.


Note

Overview
Breaking change: Payload filtering is removed end-to-end. The [Filters] config section, LD_FILTER_KEYS_* env vars, filtered environment fan-out, auto-config filter stream handling, /status/.../filters/{filterKey} routes, and SDK PayloadFilter wiring are all gone.

Relay now registers only environments declared in config (or from auto-config environments), without <env>/<filterKey> copies or filter-key suffixes on datastore prefixes. Auto-config filter SSE events are treated like unknown entities (debug log, no handler, no stream restart) so upstream can keep sending them quietly.

Client behavior: The filter query parameter is ignored—requests still authenticate and receive the full environment payload instead of 404. Middleware and relay no longer expose IsPayloadFilterNotFound.

Docs drop the Filters section, filtered status examples, and filter-related display-name notes. Tests replace filter-specific coverage with checks that filter events are ignored, filtered envs are not created, and ?filter= returns the same data as unfiltered poll.

Reviewed by Cursor Bugbot for commit 77ce3a5. Bugbot is set up for automated code reviews on this repo. Configure here.

@keelerm84 keelerm84 changed the title fix: Stop serving payload filters and reject them in config fix: Stop serving payload filters Sep 11, 2026
@keelerm84
keelerm84 force-pushed the mk/sdk-3082/remove-payload-filters branch 2 times, most recently from 96ed95d to c7d1d79 Compare September 11, 2026 18:25
@keelerm84 keelerm84 changed the title fix: Stop serving payload filters fix!: Stop serving payload filters Sep 11, 2026
@keelerm84
keelerm84 force-pushed the mk/sdk-3082/remove-payload-filters branch from c7d1d79 to 0741b79 Compare September 11, 2026 18:41
@keelerm84
keelerm84 marked this pull request as ready for review September 11, 2026 18:42
@keelerm84
keelerm84 requested a review from a team as a code owner September 11, 2026 18:42

@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 using default effort and found 1 potential issue.

Fix All in Cursor

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

Reviewed by Cursor Bugbot for commit 0741b79. Configure here.

Comment thread relay/relay.go
The Flag Delivery network does not support payload filters on FDv2. This
version of Relay connects only through FDv2, so a configured filter never
had any effect: Relay sent ?filter=<key> upstream and the upstream ignored
it. Because the option never worked, removing it changes no behavior that
anyone could have depended on, and v9 has not had a non-rc release, so the
configuration surface can change.

Relay created filtered environments on two paths, and both are gone.

Manual configuration fanned each environment out once per configured filter
key in makeFilteredEnvironments, setting the filter on the copy, appending
/<key> to its store prefix, and registering it as <env>/<filterKey>.
Config.Filters, FiltersConfig and EnvConfig.FilterKey are removed with it. A
[Filters] file section is now rejected as an unknown section, and a
LD_FILTER_KEYS_ variable is ignored like any other unrecognized variable.

Auto-configuration received filter entities over the RPAC stream and turned
each one into an extra environment per filter. The put, patch and delete
handling for those entities is removed, along with the filter receiver and
the dispatch into the handler. Filter entities now fall through to the same
silent branch that the stream already used for unrecognized entities, so
LaunchDarkly can keep sending them without a restart or a noisy log. The
prefix substitution in envfactory no longer appends a filter key either,
which is what made the auto-config path produce the same suffixed prefix as
manual configuration.

Removing the /<filterKey> prefix on both paths also removes a silent
data-loss hazard on Consul, where the filtered view's keys lived under the
unfiltered view's subtree and the unfiltered environment's init deleted
them.

The two /status routes carrying a filter key are removed. Nothing can
create a filtered environment for them to report on. The status handler
needs no change, because the filter key it reads is simply absent from the
remaining routes.

The PayloadFilter calls on the data source builders are gone, with the
nolint directives that suppressed their deprecation warnings.

Documentation for filters is removed rather than rewritten to say the
feature is unsupported. The release notes cover the removal.

A filter query parameter is accepted and ignored. Authentication no longer
reads it, so it cannot affect which environment a request resolves to. The
secondary lookup that used to distinguish "credential valid but filter
unknown" is gone with it, along with errPayloadFilterNotFound and the 404 it
produced. Without this, an SDK that still sends a filter would match no
environment and receive 404 on every request. Such an SDK was previously
served the environment's full data, because the upstream ignored the filter,
so refusing it now would break a client that was working.

The filter machinery in projmanager is now unreachable but still present;
it comes out in a follow-up along with the remaining types.

BREAKING CHANGE: Payload filter support is removed. The [Filters] config
section and LD_FILTER_KEYS_ environment variables no longer configure
anything, and the two /status routes that took a filter key are gone. The
option never had any effect on this version, because the Flag Delivery
network does not support payload filters on FDv2. A filter query parameter
on a request is accepted and ignored.
@keelerm84
keelerm84 merged commit 80d86a8 into v9 Sep 14, 2026
17 checks passed
@keelerm84
keelerm84 deleted the mk/sdk-3082/remove-payload-filters branch September 14, 2026 17:56
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.

3 participants