Andrea Cosentino created CAMEL-26896:
----------------------------------------
Summary: camel-openfga - preserve relationship condition on tuple
write and read
Key: CAMEL-26896
URL: https://issues.apache.org/jira/browse/CAMEL-26896
Project: Camel
Issue Type: Improvement
Reporter: Andrea Cosentino
Assignee: Andrea Cosentino
Fix For: 4.24.0
h3. Background
{{camel-openfga}} lets a Camel route manage relationship tuples in an OpenFGA
store through {{OpenFgaProducer}}. A relationship tuple has a {{user}}, a
{{relation}} and an {{object}}. The OpenFGA SDK type {{ClientTupleKey}} can
additionally carry a *relationship condition*: a condition name plus an
optional context that OpenFGA evaluates to decide when the relationship holds.
The SDK models this by having {{ClientTupleKey}} extend
{{ClientTupleKeyWithoutCondition}}, with {{getCondition()}} present only on the
{{ClientTupleKey}} subtype. On the read side the server returns the condition
on {{dev.openfga.sdk.api.model.TupleKey}} via {{getCondition()}}.
h3. Current behaviour
On the write path {{OpenFgaProducer}} funnels every input through a private
three-field holder {{Tuple}} that keeps only {{user}}, {{relation}} and
{{object}}:
* {{toTuple(Object)}} matches the input against the
{{ClientTupleKeyWithoutCondition}} supertype, so a {{ClientTupleKey}} that
carries a condition still matches, and only {{getUser()}}, {{getRelation()}}
and {{getObject()}} are read. The condition is never looked at.
* The {{Map}} branch of {{toTuple}} reads only the {{user}}, {{relation}} and
{{object}} keys. A {{condition}} key on the map is ignored.
* {{writeTuples}} then rebuilds a new {{ClientTupleKey}} from the three
surviving fields ({{new ClientTupleKey().user(..).relation(..)._object(..)}}),
with no {{.condition(..)}} call.
The result is that when a route passes {{writeTuples}} a tuple that includes a
relationship condition, the component writes an unconditioned tuple instead,
and the caller gets no error and no sign that the condition was not applied.
The read path drops the same information. {{readTuples}} projects each tuple
into a {{Map}} of {{user}}, {{relation}}, {{object}} and {{timestamp}}.
{{readChanges}} projects each change into a {{Map}} of {{user}}, {{relation}},
{{object}}, {{operation}} and {{timestamp}}. Neither includes the condition
that the server returned on the {{TupleKey}}, so a route cannot read it back or
round-trip it.
For reference, {{deleteTuples}} intentionally uses
{{ClientTupleKeyWithoutCondition}}, because OpenFGA deletes by identity and a
condition is not part of a delete key. That path is correct and should stay
unchanged.
h3. Proposed behaviour
Carry the relationship condition through faithfully on both paths:
* Capture the condition in {{toTuple}} when the input is a {{ClientTupleKey}},
and define explicit handling for a {{condition}} key (a map of {{name}} and
{{context}}) in the {{Map}} branch.
* Extend the internal {{Tuple}} holder with an optional condition, and have
{{writeTuples}} set {{.condition(..)}} on the outgoing {{ClientTupleKey}} when
one is present. An unconditioned input still produces an unconditioned write.
* In {{readTuples}} and {{readChanges}}, add a {{condition}} entry to each
result {{Map}} when the server-returned {{TupleKey}} carries one, projected as
a map of {{name}} and {{context}} (mirroring how {{operation}} is projected as
a {{String}} rather than an SDK enum).
* Keep {{deleteTuples}} identity-only, and keep the existing rule that an
endpoint-configured tuple wins over the message body.
h3. Classes and files
*
{{components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaProducer.java}}:
{{toTuple}}, {{writeTuples}}, {{readTuples}}, {{readChanges}} and the private
{{Tuple}} holder.
* {{components/camel-openfga/src/main/docs/openfga-component.adoc}}: document
the condition on write and the new {{condition}} key in read and change
results, then regenerate and commit the catalog doc mirror under
{{catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/}}.
* {{docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc}}: a
short note that {{writeTuples}} now honours a relationship condition on a
{{ClientTupleKey}} or {{Map}} input, and that {{readTuples}} and
{{readChanges}} now include a {{condition}} key when present.
h3. Tests
A new package-private test class (for example {{OpenFgaTupleConditionTest}})
covering:
* {{writeTuples}} preserves a condition on a single {{ClientTupleKey}};
* {{writeTuples}} preserves conditions across a collection of tuples;
* {{writeTuples}} with a {{Map}} {{condition}} key preserves it;
* an unconditioned write stays unconditioned (control);
* {{deleteTuples}} stays identity-only (regression guard);
* {{readTuples}} projects a server-returned condition;
* {{readChanges}} projects a server-returned condition.
Follow the module's existing assertion style (AssertJ is already a test
dependency here) and do not use {{Thread.sleep}}.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)