Skip to content

fix(opal-client): apply scoped data updates published through /scopes/{scope_id}/data/update - #981

Closed
folarinmartins wants to merge 1 commit into
permitio:masterfrom
folarinmartins:fix/scoped-data-update-entry-topics
Closed

folarinmartins wants to merge 1 commit into
permitio:masterfrom
folarinmartins:fix/scoped-data-update-entry-topics

Conversation

@folarinmartins

Copy link
Copy Markdown

Problem

Data updates published to a scoped client through POST /scopes/{scope_id}/data/update are silently dropped by the client. The scoped client only receives its data through the initial load and the periodic refresh, so real-time push and broadcast never take effect for scopes.

Why:

  • The scoped client subscribes to <scope_id>:data:<topic> (DataUpdater.__init__, "Namespacing the data topics for the specific scope").
  • The scope's data sources config entries are expected in that same form, which is why the initial load works.
  • The scope update endpoint (opal_server/scopes/api.py) rewrites entry.topics = [f"data:{topic}" ...] and publishes through ScopedServerSideTopicPublisher, which prefixes the scope on the published topic only (<scope_id>:data:<topic>).
  • The client therefore receives the event, but the entry inside it carries data:<topic>. DataUpdater._update_policy_data skips it because set(entry.topics).isdisjoint(set(self._data_topics)).

Observed (opal-server and opal-client 0.9.9; the same code is on master):

  • The server logs Publishing to topics: ['document-access:data:documents'] for an update whose entry has 'topics': ['data:documents'].
  • The scoped client (OPAL_SCOPE_ID=document-access, OPAL_DATA_TOPICS=documents) never applies it.
  • The same data appears only at the next periodic refresh.

Fix

The topic check moves into a small DataUpdater._entry_matches_data_topics(). For a non-default scope, it normalises an entry topic without the scope prefix to <scope_id>:<topic> before comparing.

  • Scoped config entries (<scope_id>:data:<topic>): unchanged.
  • Scoped push entries (data:<topic>): now match.
  • Another scope's topic (other:data:<topic>): still doesn't match.
  • Clients in the default scope: unchanged; no rewriting.

This is the smallest change that keeps both the config-entry form and the push-entry form valid. A server-side alternative would rewrite the entries' topics in the scope endpoint to the full scoped form. That needs the publisher to stop prefixing the scope again, and it changes the wire format for any other subscriber, so I kept the fix on the client side. Happy to move it if you prefer.

Tests

The new packages/opal-client/opal_client/tests/data_updater_scoped_topics_test.py covers:

  • scoped/scoped-config match;
  • scoped/pushed match;
  • other-scope rejection;
  • unsubscribed-topic rejection;
  • default-scope behaviour unchanged.

8 cases, all passing locally.

…/{scope_id}/data/update

A scoped client subscribes to "<scope_id>:data:<topic>", and the entries of
its scope's data sources config carry that form, so the initial load and the
periodic refresh apply. An update published through
POST /scopes/{scope_id}/data/update is delivered on the scoped topic
(ScopedServerSideTopicPublisher prefixes the scope), but its entries keep
"data:<topic>" (the endpoint rewrites entry.topics to f"data:{topic}" only).
DataUpdater then finds the entry's topics disjoint from its own and skips the
entry, so every pushed update to a scoped client is dropped silently and the
data only arrives with the next periodic refresh.

Normalise unscoped entry topics to the client's scope before the topic check.
Entries that already carry the scoped form, and clients in the default scope,
are unchanged; a topic of another scope still does not match.

Signed-off-by: Martins Folarin <folarin@engineer.com>
@netlify

netlify Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for opal-docs canceled.

Name Link
🔨 Latest commit 8c50250
🔍 Latest deploy log https://app.netlify.com/projects/opal-docs/deploys/6adfcbde6912dd3fb60f75f8

@zeevmoney

Copy link
Copy Markdown
Member

Thank you for the clear write-up and the fix.

We're fixing this on the server side in #949. With it, the entries carry the scoped topic that clients already match. That works for every client, older ones included, without a client change.

Closing in favour of #949. Thanks again.

@zeevmoney zeevmoney closed this Nov 6, 2026
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