Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

fix: ListObjects pipeline algorithm enhancements and fix for potential deadlock#3028

Merged
senojj merged 8 commits into
mainopenfga/openfga:mainfrom
poc/token-ringopenfga/openfga:poc/token-ringCopy head branch name to clipboard
Mar 31, 2026
Merged

fix: ListObjects pipeline algorithm enhancements and fix for potential deadlock#3028
senojj merged 8 commits into
mainopenfga/openfga:mainfrom
poc/token-ringopenfga/openfga:poc/token-ringCopy head branch name to clipboard

Conversation

@senojj

@senojj senojj commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

Description

This PR significantly refactors the worker types that underpin the ListObjects pipeline algorithm.

What problem is being solved?

  1. It has been proven that a deadlock is possible in scenarios that involve recursive relationships that produce enough output objects to fill the buffers between workers to capacity.
  2. Currently, intersections do not short-circuit when one input branch returns zero objects.
  3. I have found a scenario where the current Accumulator type could deadlock.
  4. There is a very small window where the current pipeline may observe quiescence while messages remain in-flight.

How is it being solved?

  1. Cyclical senders (edges) now use Accumulator types. This allows the buffer to grow as necessary, without deadlocking the pipeline. However, this comes with a memory tradeoff.
  2. Intersections now short-circuit when any of its senders ends without producing any objects.
  3. The Accumulator implementation was entirely revised to eliminate the potential for deadlocks.
  4. The cycle quiescence detection algorithm has been reworked, fixing bugs within the current in-flight message tracking, ensuring that it is impossible to observe quiescence before in-flight messages have completed, and introducing a reverse topological sort for a stepped shutdown in dependency order.

What changes are made to solve it?

  1. All code is moved into an internal/listobjects directory.
  2. Many of the old types have been removed (such as the resolvers) and have been consolidated into workers.
  3. Workers share as much code as possible.
  4. Several assorted small fixes are also present.

References

Review Checklist

  • I have clicked on "allow edits by maintainers".
  • I have added documentation for new/changed functionality in this PR or in a PR to openfga.dev [Provide a link to any relevant PRs in the references section above]
  • The correct base branch is being used, if not main
  • I have added tests to validate that the change in functionality is working as expected

Summary by CodeRabbit

  • New Features

    • New worker-based list-objects pipeline (Basic, Intersection, Difference), cycle coordination, and message media for cyclical/non-cyclical edges.
    • Generic validation utilities and new concurrency tracking primitives for readiness/quiescence.
  • Bug Fixes

    • Reduced deadlock risk, improved cancellation/error propagation, and added nil-safety in iterator validation.
  • Refactor

    • Large rewrite of pipeline/resolver/worker concurrency and buffering; simplified result streaming.
  • Tests

    • Extensive new and updated unit/integration tests and benchmarks across pipeline, worker, containers, and validation.
  • Docs

    • Package-level documentation added/updated for containers, worker, and validation.

senojj added 3 commits March 30, 2026 15:28
This proved to be an unnecessary backup feature once I was able to
prove that the in-flight message counter worked properly.
@senojj
senojj requested a review from a team as a code owner March 30, 2026 19:59
@senojj senojj added the bug Something isn't working label Mar 30, 2026
Copilot AI review requested due to automatic review settings March 30, 2026 19:59
@senojj senojj added the enhancement New feature or request label Mar 30, 2026
@coderabbitai

coderabbitai Bot commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces the legacy reverse‑expand pipeline with a new internal worker‑based pipeline: introduces worker core, mediums, cycle/tracking, and worker types (Basic/Intersection/Difference); refactors containers (Bag, Accumulator), iterator validation, reader/validation APIs, tests, and server wiring to use the new package.

Changes

Cohort / File(s) Summary
Worker Core & Abstractions
internal/listobjects/pipeline/internal/worker/core.go, internal/listobjects/pipeline/internal/worker/core_test.go, internal/listobjects/pipeline/internal/worker/doc.go
Adds worker runtime, message/Item types, BufferPool, Worker/Interpreter interfaces, Subscribe/Broadcast/ProcessSender semantics and tests.
Message Mediums
internal/listobjects/pipeline/internal/worker/medium.go, internal/listobjects/pipeline/internal/worker/medium_test.go
Introduces Medium/Sender/Listener and two implementations: AccumulatorMedium (accumulator-backed) and ChannelMedium (channel-backed) with Close/Recv/Send semantics and tests.
Workers & Processors
internal/listobjects/pipeline/internal/worker/basic.go, internal/listobjects/pipeline/internal/worker/intersection.go, internal/listobjects/pipeline/internal/worker/difference.go, internal/listobjects/pipeline/internal/worker/basic.go (tests), internal/listobjects/pipeline/internal/worker/worker_test.go
Adds Basic, Intersection, Difference workers (preprocessing, dedupe, bag materialization, execution, cycle handling) and extensive unit/integration tests.
Cycle Coordination & Tracking
internal/listobjects/pipeline/internal/worker/cycle.go, internal/listobjects/pipeline/internal/track/reporting.go, internal/listobjects/pipeline/internal/track/doc.go, internal/listobjects/pipeline/internal/track/reporting_test.go
New CycleGroup/Membership and StatusPool/Reporter for readiness and quiescence tracking; adds Reporter/StatusPool APIs and tests.
Worker Utilities & Tests
internal/listobjects/pipeline/internal/worker/util.go, internal/listobjects/pipeline/internal/worker/util_test.go
Adds EdgeLabels, DrainSender, IsCyclical helpers and unit tests for utilities.
Containers (Bag & Accumulator)
internal/containers/bag.go, internal/containers/mpsc/accumulator.go, internal/containers/mpsc/accumulator_test.go, internal/containers/doc.go
Bag docs updated and new Bag.Clear(); mpsc.Accumulator API changed from variadic Add to single-item Send, added Recv(ctx) and context-aware Seq(ctx), Close/done coordination; tests updated.
Iterator Validation
internal/iterator/validate.go
Adds nil-checks for optional validator in validatingIterator.Head/Next to avoid panics.
Validation Utilities
internal/validation/validate.go, internal/validation/validate_test.go, internal/validation/doc.go
Adds generic Validator[T], ValidatorFunc, MakeFallible, CombineValidators plus tests and docs.
Pipeline Reader & Config
internal/listobjects/pipeline/reader.go, internal/listobjects/pipeline/reader_test.go, internal/listobjects/pipeline/config.go, internal/listobjects/pipeline/config_test.go
Moves/refactors reader into the internal pipeline package, renames options to ReaderOption, adds NewValidator helper and config docs/tests.
Pipeline Integration & API
internal/listobjects/pipeline/pipeline.go, internal/listobjects/pipeline/pipeline_test.go
Rewires pipeline to build worker graph, use worker.Interpreter/Worker, cycle coordination and mediums; changes tracing and result iteration to worker message semantics; tests updated.
Server Integration
pkg/server/commands/list_objects.go, pkg/server/server.go
Switches imports/wiring to internal/listobjects/pipeline, filters errored items before appending/streaming, updates pipeline config usage.
Worker Medium & Core Tests
internal/listobjects/pipeline/internal/worker/core_test.go, internal/listobjects/pipeline/internal/worker/medium_test.go
Comprehensive tests covering message lifecycle, buffer pool, chunking, medium semantics, and cycle membership primitives.
Removed Legacy Pipeline
pkg/server/commands/reverseexpand/pipeline/* (multiple files removed)
Removes legacy reverse‑expand pipeline implementation (resolvers, messaging, buffer pools, old track/cycle primitives and tests).
Changelog & Docs
CHANGELOG.md, multiple doc.go files
Changelog updated; package docs added/updated for containers and validation.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Pipeline
    participant Worker as Worker (Basic/Intersection/Difference)
    participant Interpreter
    participant Medium as Medium (Accumulator/Channel)
    participant Downstream

    Client->>Pipeline: Expand(ctx, spec)
    Pipeline->>Pipeline: build workers & mediums
    Pipeline->>Worker: Subscribe(edge, bufferCapacity)
    Worker->>Medium: create Sender/Listener
    loop node execution
        Pipeline->>Worker: Execute(ctx)
        Worker->>Medium: Recv(ctx)
        Medium-->>Worker: *Message
        Worker->>Interpreter: Interpret(ctx, edge, values)
        Interpreter-->>Worker: iter.Seq[Item]
        Worker->>Worker: filter / deduplicate / materialize
        Worker->>Medium: Send(ctx, message)
        Medium-->>Downstream: queue message
    end
    alt cyclical
        Worker->>Worker: SignalReady / WaitForAllReady(ctx)
    end
    Worker->>Medium: Close()
    Downstream->>Medium: Recv(ctx)
    Medium-->>Client: results
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested labels

refactor

Suggested reviewers

  • adriantam
  • justincoh

Poem

🐰 I hopped through code with nimble paws,

Workers hum, and mediums pause,
Bags now clear with single sweep,
Accumulators wake from sleep,
A rabbit cheers this tidy cause.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main purpose: fixing a deadlock issue in the ListObjects pipeline algorithm while also including enhancements.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch poc/token-ring

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

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.

Pull request overview

This PR significantly refactors the ListObjects pipeline algorithm to address deadlock scenarios in recursive relationships. The key improvements include:

  1. Code Reorganization: Moves pipeline code from pkg/server/commands/reverseexpand/pipeline/ to internal/listobjects/pipeline/, with worker implementations isolated in internal/listobjects/pipeline/internal/worker/.

  2. Deadlock Prevention: Cyclical edges now use Accumulator types with unbounded buffers instead of fixed-size channels, eliminating deadlock scenarios from buffer exhaustion. Intersections now short-circuit when any sender produces zero objects.

  3. Quiescence Detection Overhaul: The cycle detection algorithm has been completely reworked with improved in-flight message tracking, preventing premature quiescence observation and implementing reverse topological sort for ordered shutdown.

Changes:

  • New internal/validation/validate.go provides generic validator combinators
  • Reader functionality refactored with improved naming (e.g., WithReaderConsistency, WithReaderValidator)
  • Worker types (Basic, Intersection, Difference) consolidated and moved to internal package
  • Accumulator API changed: Send() now returns bool, Seq() requires context parameter
  • Comprehensive test coverage added for new worker implementations and tracking primitives

Reviewed changes

Copilot reviewed 43 out of 44 changed files in this pull request and generated no comments.

Show a summary per file
File Description
pkg/server/commands/list_objects.go Updated imports and error handling logic for pipeline results
internal/validation/validate.go New generic validator combinators
internal/listobjects/pipeline/reader.go Reader moved with improved API naming and validation integration
internal/listobjects/pipeline/pipeline.go Major refactoring of worker graph construction and streaming logic
internal/listobjects/pipeline/internal/worker/* New worker types (Basic, Intersection, Difference) and core infrastructure
internal/listobjects/pipeline/internal/track/reporting.go New StatusPool for quiescence detection and coordination
internal/containers/mpsc/accumulator.go API changes: Send() returns bool, Seq() requires context
internal/containers/bag.go Added Clear() method for cleanup

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 7

🧹 Nitpick comments (9)
internal/listobjects/pipeline/config.go (1)

3-4: Rename this option type to match the repo's Go option pattern.

Option func(*Config) does not follow the <Type>Option func(*<Type>) convention, and the new comment says it configures a Pipeline even though it mutates Config. ConfigOption would line up with both the signature and the actual target.

As per coding guidelines, "Use <Type>Option func(*<Type>) type signature for option functions in Go".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/listobjects/pipeline/config.go` around lines 3 - 4, Rename the
exported type Option to ConfigOption and update its doc comment to correctly
describe that it configures a Config (not a Pipeline); change the type
definition from Option func(*Config) to ConfigOption func(*Config) and update
all usages/signatures that reference Option (e.g., functions that accept or
return Option, variables, and tests) to use ConfigOption so the name follows the
<Type>Option func(*<Type>) pattern and matches the actual target type (Config).
internal/listobjects/pipeline/edge.go (1)

30-37: Reuse the scratch slice instead of allocating mutated.

Interpret is already called with a per-message scratch slice, so this extra copy shows up on every direct-edge hop. Updating objects[i] in place keeps the same query input and removes one hot-path allocation.

♻️ Proposed refactor
 	if exists {
-		mutated := make([]string, len(objects))
-		for i, obj := range objects {
-			obj += "#" + userRelation
-			mutated[i] = obj
-		}
-		objects = mutated
+		for i := range objects {
+			objects[i] += "#" + userRelation
+		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/listobjects/pipeline/edge.go` around lines 30 - 37, The code
allocates a new slice mutated when adding the "#"+userRelation suffix; instead
reuse the existing objects scratch slice to avoid the hot-path allocation. In
the block guarded by exists in internal/listobjects/pipeline/edge.go, replace
the mutated allocation and loop with an in-place update (e.g., update objects[i]
= objects[i] + "#" + userRelation) so the Interpret caller's per-message scratch
buffer is reused; remove the mutated variable and assign directly to objects.
Ensure any references to mutated are removed and tests still pass.
pkg/server/commands/list_objects.go (1)

585-592: Extract the pipeline reader wiring once.

The validator/reader setup is identical in both execution paths, and listObjectsRequest already gives you a shared request shape. A small helper here would keep future reader options from drifting between unary and streamed ListObjects.

Also applies to: 753-760

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/server/commands/list_objects.go` around lines 585 - 592, Extract the
duplicated validator/reader wiring into a small helper that takes the shared
listObjectsRequest (and ds/timeoutCtx/typesys) and returns a configured reader
(and/or validator) so both unary and streamed paths reuse it; specifically move
the pipeline.NewValidator(...) and pipeline.NewReader(...,
pipeline.WithReaderConsistency(req.GetConsistency()),
pipeline.WithReaderValidator(validator)) into a function (e.g.,
buildListObjectsReader or newListObjectsPipelineReader) and replace the
duplicated blocks in listObjectsRequest handling and the other path with calls
to that helper.
internal/listobjects/pipeline/reader_test.go (1)

203-235: This test doesn't currently prove the no-leak behavior.

Breaking after the first yielded item only shows that one value can be produced. If you want this to guard the cleanup path, use an iterator stub that records cleanup (or a goroutine completion signal) and assert it after the break.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/listobjects/pipeline/reader_test.go` around lines 203 - 235, Replace
the static iterator with a custom iterator stub that records/ signals cleanup so
the test actually verifies resources are released: implement a small iterator
(implementing the same interface used by ReadStartingWithUser) that yields the
three tuples but also has a Close() (or equivalent) which sets a flag or closes
a channel; have the mock store.Return(...) return that stub from
ReadStartingWithUser, consume one item from reader.Read(...) and break, then
assert that the stub’s cleanup flag/channel was signaled (or Close was called)
after the break. Use the existing symbols ReadStartingWithUser,
pipeline.NewReader/reader.Read and your stub in place of
storage.NewStaticTupleIterator(tuples) so the test validates the no-leak
behavior.
internal/containers/mpsc/accumulator_test.go (1)

173-188: Missing test coverage for Seq context cancellation.

All tests pass context.Background() to Seq(), which never exercises the <-ctx.Done() path in Recv(). Consider adding a test that cancels the context mid-iteration to verify proper early termination.

📝 Example test
func TestAccumulator_SeqContextCancellation(t *testing.T) {
	acc := mpsc.NewAccumulator[int]()

	ctx, cancel := context.WithCancel(context.Background())

	go func() {
		for i := range 10 {
			acc.Send(i)
			time.Sleep(10 * time.Millisecond)
		}
		acc.Close()
	}()

	var got []int
	for v := range acc.Seq(ctx) {
		got = append(got, v)
		if len(got) >= 3 {
			cancel()
		}
	}

	// Should have stopped early due to cancellation
	require.LessOrEqual(t, len(got), 5)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/containers/mpsc/accumulator_test.go` around lines 173 - 188, Add a
test that verifies Seq(ctx) respects context cancellation by creating an
accumulator via mpsc.NewAccumulator[int](), producing values with acc.Send in a
goroutine, iterating over acc.Seq(ctx) with a cancellable context
(context.WithCancel), canceling the context after a few receives, and asserting
the loop stops early (e.g., len(got) is bounded or less than full stream);
reference the Seq method and Accumulator behavior (Send/Close) to locate where
to exercise the <-ctx.Done() path in Recv/Seq.
internal/listobjects/pipeline/internal/worker/difference.go (1)

25-29: AccumulatorAdder.Add silently drops values after close.

The Send return value is ignored. If the accumulator is closed mid-processing, subsequent values are silently dropped. This may be intentional (context already cancelled), but consider logging or tracking dropped values for observability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/listobjects/pipeline/internal/worker/difference.go` around lines 25
- 29, AccumulatorAdder.Add currently ignores the return value from
(*mpsc.Accumulator[T])(a).Send and therefore silently drops values if the
accumulator is closed; update Add to check Send's boolean/err return and handle
drops (e.g., increment a dropped counter, emit a processLogger warning with
context, or return/report an error) so dropped values are observable. Locate the
Add method on type AccumulatorAdder[T] and change the loop to capture the Send
result and take one of the above actions (logging/metrics/reporting) when Send
indicates the value was not accepted.
internal/validation/validate.go (1)

5-7: ValidatorFunc is redundant.

The adapter function simply performs a type conversion that Go already allows directly:

validator := Validator[T](fn)

Unless this is intended for future extension or documentation purposes, consider removing it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/validation/validate.go` around lines 5 - 7, The ValidatorFunc
wrapper is redundant — remove the function ValidatorFunc[T any](fn func(T)
(bool, error)) Validator[T] from validate.go and replace its usages with the
direct type conversion Validator[T](fn). Search for all call sites referencing
ValidatorFunc and update them to use Validator[T](fn) (or adjust to construct a
Validator directly) so compilation remains correct; no other logic changes are
needed.
internal/listobjects/pipeline/internal/worker/core.go (1)

162-169: Rename the context key to match the repo convention.

BufferKey is a context key, but the repo rule here is <name>CtxKey. Renaming this to something like bufferCtxKey/BufferCtxKey would also avoid exporting an implementation detail that's only used inside worker.

As per coding guidelines, "Use context keys named <name>CtxKey for context value keys in Go".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/listobjects/pipeline/internal/worker/core.go` around lines 162 -
169, Rename the exported context key BufferKey to follow repo convention and
avoid exporting implementation detail: change BufferKey to bufferCtxKey (or
BufferCtxKey if exported is required) and update its declaration of type Key and
all usages (e.g., where Core.ProcessSender stores/loads the reusable []string
scratch buffer) to use the new symbol; ensure references to type Key remain
unchanged and update any tests or packages that reference BufferKey to the new
name.
internal/listobjects/pipeline/internal/worker/worker_test.go (1)

273-288: Cover the cyclical cancellation path in the worker tests.

These cases only use nil-edge senders, so they never hit the new Membership.WaitForAllReady / Sleep teardown path. A small cycle-backed regression test that asserts Execute returns promptly on context cancellation would lock in the deadlock fix and catch the one-minute stall path.

Also applies to: 415-430, 572-587

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/listobjects/pipeline/internal/worker/worker_test.go` around lines
273 - 288, Add a regression test that exercises the cyclical cancellation path
so Execute returns promptly when the context is canceled even if
Membership.WaitForAllReady / Sleep teardown is used: create a test similar to
TestBasic_Execute_ContextCancelled but construct the worker.Core via newCore
with an interpreter or sender configuration that triggers the membership cycle
path (the code paths invoking Membership.WaitForAllReady and Sleep), call
w.Listen(...) (e.g., using sendItems or another non-nil sender that triggers the
cycle), cancel the context before Execute, call w.Execute(ctx), and assert that
output is empty and no errors were produced; ensure the test references
worker.Basic.Execute, newCore, passthroughInterpreter/sendItems, and
Membership.WaitForAllReady/Sleep so it covers the one-minute stall regression.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/containers/bag.go`:
- Around line 68-69: Update the package docs and method comments to reflect the
new destructive API: revise the type-level comment for Bag to remove the
assertion that values cannot be removed and instead document that Clear()
drains/resets the bag, potentially invalidating active iterators or references;
add a GoDoc comment on the exported method Clear describing its behavior (it
resets internal head, is destructive, concurrency/visibility guarantees if any,
and intended usage). Ensure references to Bag[T] and the Clear method are
updated so users see the new drain/reset semantics.

In `@internal/listobjects/pipeline/internal/track/reporting_test.go`:
- Around line 232-250: BenchmarkStatusPool currently creates the StatusPool and
reporters once, causing later iterations to be measuring idempotent Report()
calls and letting goroutines overlap; fix by moving sp := track.NewStatusPool()
and the reporters allocation/registration (reporters[i] = sp.Register()) inside
the b.Loop() iteration so a fresh pool is used each iteration, ensure each
spawned goroutine correctly captures the loop index (use i := i inside the loop)
and wait for all goroutines to finish before the next iteration (either rely on
sp.Wait(context.Background()) if that guarantees all reporter goroutines
complete or add a sync.WaitGroup around Reporter.Report calls), and keep the
calls to Reporter.Report and sp.Wait in the same iteration to avoid overlap.

In `@internal/listobjects/pipeline/internal/track/reporting.go`:
- Around line 79-89: Update the Register() doc comment on StatusPool to clearly
require that all registrations complete before any Reporter methods are used
(e.g., before any call to Reporter.Report or Reporter.set or any access that may
close ready), not just before StatusPool.Wait; mention that late Register()
calls race with Report()/set() and can mark ready too early so callers must
treat Register as a pre-use setup step (alternatively protect sp.pool
append/index computation with the same mutex used by Report/set if you prefer to
allow concurrent registration).

In `@internal/listobjects/pipeline/internal/worker/basic.go`:
- Around line 165-188: The teardown code is detaching from the caller context by
using context.Background() — change it to derive the timeout from the caller
context so cancellation propagates. Replace
context.WithTimeout(context.Background(), time.Minute) with
context.WithTimeout(parentCtx, time.Minute) (use the incoming ctx parameter or
w.ctx that represents the pipeline caller context) and use that timeoutCtx for
WaitForAllReady and Sleep; remove any calls to context.Background() in these
calls so WaitForAllReady, Membership.Sleep and related teardown (W.Cleanup,
Membership.Next().Wake) honor caller cancellation.

In `@internal/listobjects/pipeline/internal/worker/difference.go`:
- Around line 92-122: The goroutines running ProcessSender (the wgBase and
wgSubtract closures) record panics/errors via w.error and
concurrency.RecoverFromPanic but do not cancel the parent context; update both
goroutine error handling so that if the local err becomes non-nil (after
RecoverFromPanic/w.error), they call cancel() to stop the other worker and avoid
partial processing—i.e., in the wgBase closure (which already defers base.Close)
and in the wgSubtract closure, add a deferred check that calls cancel() when err
!= nil (keep existing defer order: base.Close, w.error(&err),
concurrency.RecoverFromPanic(&err), then a final defer that calls cancel() if
err != nil), ensuring ProcessSender, w.error, and concurrency.RecoverFromPanic
remain referenced.

In `@internal/listobjects/pipeline/internal/worker/doc.go`:
- Around line 7-8: Update the package doc comment to accurately describe both
communication mechanisms: keep the original description for the acyclic/acyclic
path that uses bounded, unidirectional Medium instances (symbol: Medium) but
also mention the cyclical transport that uses accumulator-backed senders which
may grow to avoid deadlock; alternatively, narrow the sentence to explicitly
state it applies only to the acyclic path and add a brief sentence noting the
cycle path uses accumulator-backed senders instead of bounded Mediums so readers
can find both behaviors.

In `@internal/listobjects/pipeline/internal/worker/intersection.go`:
- Around line 79-96: The worker goroutines may record errors via w.error and
RecoverFromPanic without cancelling ctx, allowing wg.Wait() to return and
intersection logic to run on partially populated bags; modify the flow so that
when a goroutine sets err (inside the goroutine around ProcessSender, or in the
deferred w.error/RecoverFromPanic handling) it calls cancel() (the cancel tied
to ctx) or otherwise signals failure, and/or after wg.Wait() check for errors by
inspecting len(w.Errors)>0 (or ctx.Err()) and return early instead of proceeding
to the intersection computation; update the goroutine body around ProcessSender,
the deferred error handlers, and the post-wg.Wait() branch to implement one of
these fixes (use ProcessSender, w.error, RecoverFromPanic, cancel, wg.Wait, and
w.Errors as reference points).

---

Nitpick comments:
In `@internal/containers/mpsc/accumulator_test.go`:
- Around line 173-188: Add a test that verifies Seq(ctx) respects context
cancellation by creating an accumulator via mpsc.NewAccumulator[int](),
producing values with acc.Send in a goroutine, iterating over acc.Seq(ctx) with
a cancellable context (context.WithCancel), canceling the context after a few
receives, and asserting the loop stops early (e.g., len(got) is bounded or less
than full stream); reference the Seq method and Accumulator behavior
(Send/Close) to locate where to exercise the <-ctx.Done() path in Recv/Seq.

In `@internal/listobjects/pipeline/config.go`:
- Around line 3-4: Rename the exported type Option to ConfigOption and update
its doc comment to correctly describe that it configures a Config (not a
Pipeline); change the type definition from Option func(*Config) to ConfigOption
func(*Config) and update all usages/signatures that reference Option (e.g.,
functions that accept or return Option, variables, and tests) to use
ConfigOption so the name follows the <Type>Option func(*<Type>) pattern and
matches the actual target type (Config).

In `@internal/listobjects/pipeline/edge.go`:
- Around line 30-37: The code allocates a new slice mutated when adding the
"#"+userRelation suffix; instead reuse the existing objects scratch slice to
avoid the hot-path allocation. In the block guarded by exists in
internal/listobjects/pipeline/edge.go, replace the mutated allocation and loop
with an in-place update (e.g., update objects[i] = objects[i] + "#" +
userRelation) so the Interpret caller's per-message scratch buffer is reused;
remove the mutated variable and assign directly to objects. Ensure any
references to mutated are removed and tests still pass.

In `@internal/listobjects/pipeline/internal/worker/core.go`:
- Around line 162-169: Rename the exported context key BufferKey to follow repo
convention and avoid exporting implementation detail: change BufferKey to
bufferCtxKey (or BufferCtxKey if exported is required) and update its
declaration of type Key and all usages (e.g., where Core.ProcessSender
stores/loads the reusable []string scratch buffer) to use the new symbol; ensure
references to type Key remain unchanged and update any tests or packages that
reference BufferKey to the new name.

In `@internal/listobjects/pipeline/internal/worker/difference.go`:
- Around line 25-29: AccumulatorAdder.Add currently ignores the return value
from (*mpsc.Accumulator[T])(a).Send and therefore silently drops values if the
accumulator is closed; update Add to check Send's boolean/err return and handle
drops (e.g., increment a dropped counter, emit a processLogger warning with
context, or return/report an error) so dropped values are observable. Locate the
Add method on type AccumulatorAdder[T] and change the loop to capture the Send
result and take one of the above actions (logging/metrics/reporting) when Send
indicates the value was not accepted.

In `@internal/listobjects/pipeline/internal/worker/worker_test.go`:
- Around line 273-288: Add a regression test that exercises the cyclical
cancellation path so Execute returns promptly when the context is canceled even
if Membership.WaitForAllReady / Sleep teardown is used: create a test similar to
TestBasic_Execute_ContextCancelled but construct the worker.Core via newCore
with an interpreter or sender configuration that triggers the membership cycle
path (the code paths invoking Membership.WaitForAllReady and Sleep), call
w.Listen(...) (e.g., using sendItems or another non-nil sender that triggers the
cycle), cancel the context before Execute, call w.Execute(ctx), and assert that
output is empty and no errors were produced; ensure the test references
worker.Basic.Execute, newCore, passthroughInterpreter/sendItems, and
Membership.WaitForAllReady/Sleep so it covers the one-minute stall regression.

In `@internal/listobjects/pipeline/reader_test.go`:
- Around line 203-235: Replace the static iterator with a custom iterator stub
that records/ signals cleanup so the test actually verifies resources are
released: implement a small iterator (implementing the same interface used by
ReadStartingWithUser) that yields the three tuples but also has a Close() (or
equivalent) which sets a flag or closes a channel; have the mock
store.Return(...) return that stub from ReadStartingWithUser, consume one item
from reader.Read(...) and break, then assert that the stub’s cleanup
flag/channel was signaled (or Close was called) after the break. Use the
existing symbols ReadStartingWithUser, pipeline.NewReader/reader.Read and your
stub in place of storage.NewStaticTupleIterator(tuples) so the test validates
the no-leak behavior.

In `@internal/validation/validate.go`:
- Around line 5-7: The ValidatorFunc wrapper is redundant — remove the function
ValidatorFunc[T any](fn func(T) (bool, error)) Validator[T] from validate.go and
replace its usages with the direct type conversion Validator[T](fn). Search for
all call sites referencing ValidatorFunc and update them to use Validator[T](fn)
(or adjust to construct a Validator directly) so compilation remains correct; no
other logic changes are needed.

In `@pkg/server/commands/list_objects.go`:
- Around line 585-592: Extract the duplicated validator/reader wiring into a
small helper that takes the shared listObjectsRequest (and
ds/timeoutCtx/typesys) and returns a configured reader (and/or validator) so
both unary and streamed paths reuse it; specifically move the
pipeline.NewValidator(...) and pipeline.NewReader(...,
pipeline.WithReaderConsistency(req.GetConsistency()),
pipeline.WithReaderValidator(validator)) into a function (e.g.,
buildListObjectsReader or newListObjectsPipelineReader) and replace the
duplicated blocks in listObjectsRequest handling and the other path with calls
to that helper.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: aa855211-1881-4879-90cb-6a833cb70c5d

📥 Commits

Reviewing files that changed from the base of the PR and between 1a44a05 and c685b61.

📒 Files selected for processing (44)
  • internal/containers/bag.go
  • internal/containers/mpsc/accumulator.go
  • internal/containers/mpsc/accumulator_test.go
  • internal/containers/mpsc/doc.go
  • internal/iterator/validate.go
  • internal/listobjects/pipeline/config.go
  • internal/listobjects/pipeline/config_test.go
  • internal/listobjects/pipeline/doc.go
  • internal/listobjects/pipeline/edge.go
  • internal/listobjects/pipeline/internal/track/doc.go
  • internal/listobjects/pipeline/internal/track/reporting.go
  • internal/listobjects/pipeline/internal/track/reporting_test.go
  • internal/listobjects/pipeline/internal/worker/basic.go
  • internal/listobjects/pipeline/internal/worker/core.go
  • internal/listobjects/pipeline/internal/worker/core_test.go
  • internal/listobjects/pipeline/internal/worker/cycle.go
  • internal/listobjects/pipeline/internal/worker/difference.go
  • internal/listobjects/pipeline/internal/worker/doc.go
  • internal/listobjects/pipeline/internal/worker/intersection.go
  • internal/listobjects/pipeline/internal/worker/medium.go
  • internal/listobjects/pipeline/internal/worker/medium_test.go
  • internal/listobjects/pipeline/internal/worker/util.go
  • internal/listobjects/pipeline/internal/worker/util_test.go
  • internal/listobjects/pipeline/internal/worker/worker_test.go
  • internal/listobjects/pipeline/pipeline.go
  • internal/listobjects/pipeline/pipeline_test.go
  • internal/listobjects/pipeline/reader.go
  • internal/listobjects/pipeline/reader_test.go
  • internal/validation/validate.go
  • internal/validation/validate_test.go
  • pkg/server/commands/list_objects.go
  • pkg/server/commands/reverseexpand/pipeline/cycle.go
  • pkg/server/commands/reverseexpand/pipeline/messaging.go
  • pkg/server/commands/reverseexpand/pipeline/obj/validate.go
  • pkg/server/commands/reverseexpand/pipeline/processor_operator.go
  • pkg/server/commands/reverseexpand/pipeline/resolver_base.go
  • pkg/server/commands/reverseexpand/pipeline/resolver_core.go
  • pkg/server/commands/reverseexpand/pipeline/resolver_exclusion.go
  • pkg/server/commands/reverseexpand/pipeline/resolver_intersection.go
  • pkg/server/commands/reverseexpand/pipeline/track/reporting.go
  • pkg/server/commands/reverseexpand/pipeline/track/reporting_test.go
  • pkg/server/commands/reverseexpand/pipeline/util.go
  • pkg/server/commands/reverseexpand/pipeline/worker.go
  • pkg/server/server.go
💤 Files with no reviewable changes (12)
  • pkg/server/commands/reverseexpand/pipeline/util.go
  • pkg/server/commands/reverseexpand/pipeline/track/reporting_test.go
  • pkg/server/commands/reverseexpand/pipeline/processor_operator.go
  • pkg/server/commands/reverseexpand/pipeline/messaging.go
  • pkg/server/commands/reverseexpand/pipeline/resolver_exclusion.go
  • pkg/server/commands/reverseexpand/pipeline/resolver_intersection.go
  • pkg/server/commands/reverseexpand/pipeline/obj/validate.go
  • pkg/server/commands/reverseexpand/pipeline/resolver_base.go
  • pkg/server/commands/reverseexpand/pipeline/cycle.go
  • pkg/server/commands/reverseexpand/pipeline/worker.go
  • pkg/server/commands/reverseexpand/pipeline/track/reporting.go
  • pkg/server/commands/reverseexpand/pipeline/resolver_core.go

Comment thread internal/containers/bag.go
Comment thread internal/listobjects/pipeline/internal/track/reporting_test.go
Comment thread internal/listobjects/pipeline/internal/track/reporting.go
Comment thread internal/listobjects/pipeline/internal/worker/basic.go Outdated
Comment thread internal/listobjects/pipeline/internal/worker/difference.go
Comment thread internal/listobjects/pipeline/internal/worker/doc.go
Comment thread internal/listobjects/pipeline/internal/worker/intersection.go

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/containers/mpsc/accumulator.go`:
- Around line 27-28: Update the comment on Accumulator.Close to refer to the
current producer method name Send instead of the old Add; e.g., change
"completed their Add calls" to "completed their Send calls" (keep the
surrounding explanation about the sentinel node intact). Ensure any other
mentions of "Add" in comments near the Accumulator.Close declaration or its doc
header are updated to "Send" so docs match the code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 09a4b6b2-62da-48ab-a313-ece0ee360626

📥 Commits

Reviewing files that changed from the base of the PR and between ca43f68 and a081b70.

📒 Files selected for processing (6)
  • internal/containers/bag.go
  • internal/containers/doc.go
  • internal/containers/mmap.go
  • internal/containers/mpsc/accumulator.go
  • internal/validation/doc.go
  • internal/validation/validate.go
✅ Files skipped from review due to trivial changes (3)
  • internal/containers/doc.go
  • internal/validation/doc.go
  • internal/containers/mmap.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/containers/bag.go
  • internal/validation/validate.go

Comment thread internal/containers/mpsc/accumulator.go Outdated
@codecov

codecov Bot commented Mar 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.54434% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.68%. Comparing base (1a44a05) to head (e5b8938).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
internal/listobjects/pipeline/edge.go 76.20% 5 Missing ⚠️
internal/listobjects/pipeline/pipeline.go 95.97% 5 Missing ⚠️
internal/containers/mpsc/accumulator.go 95.75% 1 Missing and 1 partial ⚠️
internal/iterator/validate.go 50.00% 1 Missing and 1 partial ⚠️
...rnal/listobjects/pipeline/internal/worker/basic.go 97.37% 1 Missing and 1 partial ⚠️
pkg/server/commands/list_objects.go 87.50% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3028      +/-   ##
==========================================
+ Coverage   90.51%   90.68%   +0.17%     
==========================================
  Files         188      186       -2     
  Lines       20324    20444     +120     
==========================================
+ Hits        18395    18538     +143     
+ Misses       1267     1257      -10     
+ Partials      662      649      -13     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

if a user sets their request timeout to an arbitrarily high value,
the hard-coded timeout could conflict, causing partial results.
@senojj

senojj commented Mar 31, 2026

Copy link
Copy Markdown
Contributor Author

@claude

@senojj
senojj merged commit c75b5f0 into main Mar 31, 2026
22 checks passed
@senojj
senojj deleted the poc/token-ring branch March 31, 2026 21:24
@coderabbitai coderabbitai Bot mentioned this pull request Apr 6, 2026
4 tasks
@coderabbitai coderabbitai Bot mentioned this pull request Apr 19, 2026
4 tasks
fredrikaverpil added a commit to fredrikaverpil/openfga that referenced this pull request Jul 12, 2026
Add support for exporting logs via OTLP, allowing integration with any
OpenTelemetry-compatible backend (Grafana Loki, Datadog, GCP Cloud
Logging, etc.).

When log.otlp.enabled is set, logs are exported via OTLP in addition to
stdout. The otelzap bridge attaches span context (trace ID, span ID) to
each log record, enabling log-trace correlation in backends that
support it.

Configuration mirrors the trace configuration shape: the standard OTel
env vars (OTEL_EXPORTER_OTLP_LOGS_ENDPOINT, OTEL_EXPORTER_OTLP_ENDPOINT)
only answer where logs are sent, while the explicit OpenFGA flag
(log.otlp.enabled / --log-otlp-enabled / OPENFGA_LOG_OTLP_ENABLED)
answers whether to export at all — so a cluster that injects the
generic endpoint variable for tracing does not silently start exporting
logs on upgrade.

zap's production sampling is applied outside the tee, so the keep/drop
decision is made once, before fan-out: stdout and OTLP receive the same
deterministically sampled stream and collector egress stays bounded
during log storms.

Changes:
- Add otelzap bridge core backed by an OTLP log provider
  (internal/telemetry/logging.go)
- Add WithOTELCore logger option that tees log entries to the bridge.
  The bridge core is capped to the configured log level, the stdout
  core strips the bridge-only context field via contextFilterCore, and
  the sampler wraps the tee (pkg/logger/logger.go)
- Attach the context field in the *WithContext logging methods only
  when an OTEL core is configured, and use those methods in the gRPC
  logging interceptor so the bridge can extract span context
  (pkg/middleware/logging/logging.go)
- Add config: log.otlp.enabled, log.otlp.endpoint, log.otlp.tls.enabled
  with OPENFGA_LOG_OTLP_* env vars and OTEL_EXPORTER_OTLP_* endpoint
  fallbacks (pkg/server/config/config.go, cmd/run/, .config-schema.json)

feat: add potential v2 breaking change logs for Expand and ListUsers (openfga#3182)
release: update changelog for release 1.18.1 (openfga#3188)
release: Update changelog to prep for 1.18.1 release (openfga#3186)
test: fix flaky TestV2CheckWithIteratorCache_HigherConsistencyBypassesCache (openfga#3061)

Co-authored-by: Joshua Jones <joshua.jones.software@gmail.com>
Merge commit from fork

* test reproducing ListUsers report

* implement fix

* additional test with 3 operands
fix: match IPv4-mapped IPv6 addresses in the in_cidr condition (openfga#3181)

Signed-off-by: kanywst <niwatakuma@icloud.com>
fix: use deterministic proto marshaling for stored authorization models (openfga#3171)
chore: create draft release and publish after provenance succeeds for immutable tags/releases (openfga#3178)
docs: fix changelog entry (openfga#3177)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
feat: add v2Check logs for resolution breaking change (openfga#3149)
feat: BatchCheck uses v2Check when ExperimentalWeightedGraphCheck is enabled (openfga#3154)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
chore: update changelog to add CVE identifiers for recent fixes (openfga#3176)
chore: update todo comment string in migration guide (openfga#3175)
release: update changelog for release `v1.18.0` (openfga#3174)

Co-authored-by: adriantam <adrian.tam@okta.com>
Merge commit from fork

* fix(authn): require issuer and audience when OIDC authn is enabled

Enforce configuration authn.oidc.audience and authn.oidc.issuer when
`authn.method` is set to `oidc`.

* fixed based on code review feedback

* fix: adding comments + test case on empty space for audience

* update based on code review feedback

* Update CHANGELOG.md

Co-authored-by: Joshua Jones <joshua.jones.software@gmail.com>

* update changelog

* Update CHANGELOG.md

---------

Co-authored-by: Joshua Jones <joshua.jones.software@gmail.com>
Merge commit from fork

* fix(mysql): collate identifier columns as utf8mb4_bin

* fix: add operator note to changelog

* fix: move tests to shared storage

* fix: separate migrations for each table

* fix: add runbook for migrations

* fix: set lock_wait_timeout

* fix: add docker instructions

* fix: add docker instructions

* fix: combine the migrations back into one, fix documentation for this

* fix: include details about table copy and

* Update CHANGELOG.md

Co-authored-by: Adrian Tam <adrian.tam@okta.com>

---------

Co-authored-by: Adrian Tam <adrian.tam@okta.com>
fix: use constant-time comparison for preshared key authentication (openfga#3168)
chore(deps): bump the dependencies group with 2 updates (openfga#3166)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Justin Cohen <justincoh@gmail.com>
chore(deps): bump the dependencies group with 2 updates (openfga#3167)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
release: update changelog for release `v1.17.1` (openfga#3165)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
chore: bump grpc-health-probe to v0.4.52 (openfga#3164)

Co-authored-by: Saad Hussain <saad.hussain@okta.com>
docs: update caching docs (openfga#3163)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
fix: continuation token deserializer - handle `|` in type names (openfga#3152)
chore(deps): bump the dependencies group across 1 directory with 13 updates (openfga#3162)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Justin Cohen <justincoh@gmail.com>
chore(deps): bump the dependencies group across 1 directory with 10 updates (openfga#3156)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Justin Cohen <justincoh@gmail.com>
fix: use query start time as iterator cache entry LastModified to prevent stale-read survival (openfga#3155)
chore(deps): bump grpc-ecosystem/grpc-health-probe from v0.4.50 to v0.4.51 in the dependencies group (openfga#3157)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Saad Hussain <saad.hussain@okta.com>
Co-authored-by: Justin Cohen <justincoh@gmail.com>
chore: Bump go toolchain to 1.26.4 (openfga#3159)
fix: prevent v2Check from falling back for throttling and validation (openfga#3150)
ci: make pr benchmark comparisons less fragile (openfga#3153)

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
release: update changelog for release `v1.17.0` (openfga#3151)

Co-authored-by: Vic-Dev <vmichellej@gmail.com>
refactor: redesign cache key generation, making it more secure and consistent (openfga#3148)
feat: add configurable trace sampler with ParentBased support (openfga#3072)
release: update changelog for release `v1.16.1` (openfga#3147)
chore: update grpc-health-probe to latest to addres std lib CVEs (openfga#3146)
fix: skip v2Check weight2 pruning if iterator is unordered (openfga#3145)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
chore: add concurrency-group to PR-related CI steps (openfga#3140)
docs: move OIDC JWKS refresh entry from v1.15.1 to v1.16.0 (openfga#3142)
fix: when v2Check is primary algorithm, fix fallback condition and emit metrics (openfga#3141)
release: update changelog for release `v1.16.0` (openfga#3139)
Merge commit from fork

* fix: Standardize cache key generation everywhere

* Revert "fix: Standardize cache key generation everywhere"

This reverts commit ce60c6f9ae48a310a4dea2b824b5993520c8ba1c.

* length-encoded approach

* Revert "length-encoded approach"

This reverts commit b94637c187c57a2d3f3904247267bbc8ad21a41a.

* implement Hexer() and use in some cache keys

* appendConditionsHash -> generateConditionsHash

* mv Hexer -> BuildKey

* BuildKey -> BuildCacheKey

refactor to BuildCacheKey on each individual prefix component to remove collision risk

* make v2 cacheKey functions the standard

* make cache key prefixes consistent

* generateConditionsHash -> generateConditionsString

* delimit condition name string

* remove extra empty check

* relocate and reuse existing userTypeRestrictions function

* replace hashing of conditions for brevity

* fix tests

* cleanup, add test file

* remove unused slice capacity

* make prefix treatments consistent

* add nil-byte separator in object ids

* hash user type restrictions for brevity

* update comment string, use nil-byte separator for future-proofing

* remove call to xxhash.new

* adjustments for performance, consistency, and interface ergonomics.

* make condition hash generation more efficient.

* add clarifying comments for size caluculations

* fix builder growth calculations to match original intentions

* update outdated comment

* don't hash potentially zero values

* Revert "don't hash potentially zero values"

This reverts commit 2ad6c5b796bc20a82c1414c5146c3c708330eefa.

* add condition key separator unconditionally

* patch test expectations for new key structure

* export V2IteratorCachePrefix, use in tests

---------

Co-authored-by: justin <justin.cohen@okta.com>
Co-authored-by: Joshua Jones <joshua.jones@okta.com>
fix: unintentional zeroing of slice values by setting slice to nil (openfga#3135)
increase the check v2 trace information fidelity (openfga#3134)
feat: add datastore ping and ping retry configurations (openfga#3113)
fix: prevent v2Check strategies returning spurious false on context cancellation (openfga#3128)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
fix(authn/oidc): refresh JWKS on unknown kid to handle key rotation (openfga#3101)
fix: v2Check falls back to v1 on errors (openfga#3126)
fix: don't cache false results from cancelled-context goroutines in v2Check (openfga#3125)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
make union cache key unique by including the node input's label (openfga#3117)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
Co-authored-by: Saad Hussain <saad.hussain@okta.com>
fix: shadow v2check and check use the same trace (openfga#3118)
fix: bump go toolchain version to 1.26.3 (openfga#3115)
chore: add more spans/attributes to v1 and v2 Check (openfga#3116)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
fix: add matches attribute to shadowv2Check and Check spans (openfga#3114)
fix: use the same `request_id` for shadow traces in v2Check (openfga#3110)
release: update changelog for release `v1.15.1` (openfga#3112)
feat: reuse MySQL container across tests (openfga#3042)
fix: close all channels opened thus far, before return on error (openfga#3111)
chore: Add more spans/attributes to v2Check (openfga#3102)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
fix: ensure acquired limiter token is released on throttle context cancelation (openfga#3106)
fix: cancel context before waiting on worker pool in ResolveUnionEdges (openfga#3105)
fix: replace golang.org/x/exp/maps with stdlib maps to resolve govet inline errors (openfga#3104)
fix: v2Check EdgeCacheKey collisions (openfga#3097)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
fix: expose context errors when they can be the potential cause of an underlying datastore error (openfga#3096)
chore(deps): bump the dependencies group across 1 directory with 2 updates (openfga#3093)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
fix: move subproblem cache lookup from ResolveUnionEdges into ResolveUnion (openfga#3095)
chore(deps): bump the dependencies group with 4 updates (openfga#3092)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
fix: error handler panic (openfga#3091)
release: update changelog for release `v1.15.0` (openfga#3090)
chore(deps): bump the dependencies group across 1 directory with 4 updates (openfga#3087)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
fix: v2Check correctly uses query cache even when cache controller is disabled (openfga#3086)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
chore(deps): bump the dependencies group across 1 directory with 7 updates (openfga#3081)

Signed-off-by: dependabot[bot] <support@github.com>
chore(deps): bump github.com/jackc/pgx/v5 from 5.9.1 to 5.9.2 (openfga#3085)

Signed-off-by: dependabot[bot] <support@github.com>
chore(deps): bump grpc-ecosystem/grpc-health-probe from v0.4.47 to v0.4.48 in the dependencies group across 1 directory (openfga#3065)

Signed-off-by: dependabot[bot] <support@github.com>
feat: try to use UDS internally between HTTP server and gRPC server (openfga#2937)
feat: add jitter to internal cache TTLs to prevent thundering herd effects (openfga#3033)

Signed-off-by: Asish Kumar <officialasishkumar@gmail.com>
list objects pipeline edge pruning (openfga#3075)
update toolchain go to 1.26.2 to address stdlib CVEs (openfga#3084)
chore: add store ID and datastore query/item count to shadowV2Check log (openfga#3073)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
CI speed up (openfga#3062)

Co-authored-by: Joshua Jones <joshua.jones.software@gmail.com>
Co-authored-by: Joshua Jones <joshua.jones@okta.com>
Add tracing to v2 Check planner strategy selection (openfga#3077)
fix: v2Check honours `check-query-cache-enabled` flag (openfga#3070)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
feat: reuse PostgreSQL container across tests (openfga#3018)
chore: fix reporter links in changelog (openfga#3069)
release: update changelog for release `v1.14.2` (openfga#3068)
fix: add null byte delimiter in contextual tuple cache keys and validation in v2Check (openfga#3064)
release: update changelog for release `v1.14.1` (openfga#3060)
chore(deps): bump the dependencies group across 1 directory with 7 updates (openfga#3056)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Adrian Tam <adrian.tam@okta.com>
fix: use a baseURL for AuthZEN configuration endpoint (openfga#3057)
chore: replace docker with moby (openfga#3047)
Iterator Cache V2: Storage Wrapper Pattern with Lock-Free Design (openfga#3016)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
Co-authored-by: Saad Hussain <saad.hussain@okta.com>
Co-authored-by: Joshua Jones <joshua.jones.software@gmail.com>
test: fix flaky condition test (openfga#3058)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
chore(deps): bump the dependencies group across 1 directory with 6 updates (openfga#3045)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
chore(deps): bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp from 1.41.0 to 1.43.0 (openfga#3054)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Adrian Tam <adrian.tam@okta.com>
feat: add graceful shutdown timeout configuration (openfga#2976)
chore: update changelog to reflect playground off-by-default behavior (openfga#3053)
chore: decouple Error() and Unwrap() (openfga#3051)
perf: remove `fmt` from cache key generation (openfga#3006)
perf: enhancements for list objects (openfga#3043)
chore: remove stale notice file (openfga#3050)
docs: update 1.14.0 for CVE fix (openfga#3046)
feat: Add datastore throttling & concurrency limiting to v2Check (openfga#3035)

Signed-off-by: Saad Hussain <saad.hussain@okta.com>
release: update changelog for release `v1.14.0` (openfga#3040)
batch check cache (openfga#3025)
Merge commit from fork

Also prevent enabling playground when the server requires authentication
feat: add stats on tuple iterator query (openfga#3030)
fix: remove unnecessary non-deterministic test (openfga#3038)
remove unnecessary import (openfga#3032)
perf: improve the intersection algorithm, reducing latency and memory use (openfga#3031)
fix: ListObjects pipeline algorithm enhancements and fix for potential deadlock (openfga#3028)
chore: Also update openfga/helm-charts in release script (openfga#3010)
chore: update CICD to enforce GRPC healthprobe changes (openfga#2990)
fix: SQL `TupleOperation` serialization and `pgx.ErrNoRows` error handling (openfga#3014)
docs: update changelog for CVE-2026-33729 (openfga#3017)
chore: output the diff after running keep-a-changelog (openfga#3015)
chore(deps): bump the dependencies group across 1 directory with 11 updates (openfga#2998)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
chore(deps): bump the dependencies group across 1 directory with 10 updates (openfga#2999)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
release: update changelog for release `v1.13.1` (openfga#3002)
Merge commit from fork

* strip unicode control characters, encode context key length in cache key

* add cache_key tests to ensure we escape control characters and encode context key length

* run linter

* docs: update changelog

* Apply suggestion from @adriantam

Co-authored-by: Adrian Tam <adrian.tam@okta.com>

* Apply suggestion from @adriantam

Co-authored-by: Adrian Tam <adrian.tam@okta.com>

---------

Co-authored-by: Saad Hussain <saad.hussain@okta.com>
Co-authored-by: Saad Hussain <saad.h@outlook.com>
Co-authored-by: Adrian Tam <adrian.tam@okta.com>
release: update changelog for release `v1.13.0` (openfga#2997)
refactor: Separate caches for v1 and v2 Check (openfga#2968)

Co-authored-by: Justin Cohen <justincoh@gmail.com>
docs: fix typos in comments (openfga#2972)

Signed-off-by: Artem Muterko <artem@sopho.tech>
Co-authored-by: Adrian Tam <adrian.tam@okta.com>
observability: aggregate message statistics for each list-objects sender into a single span (openfga#2993)

Co-authored-by: Justin Cohen <justincoh@gmail.com>
fix: capture panics in pipeline's base resolver, and return as errors. (openfga#2994)
docs: fix typos in RELEASES.md and Makefile (openfga#2980)

Co-authored-by: Adrian Tam <adrian.tam@okta.com>
AuthZen v1.0 Implementation (openfga#2875)

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Rokibul Hasan <mdrokibulhasan@appscode.com>
Signed-off-by: Vihang Mehta <vihang@gimletlabs.ai>
Co-authored-by: Karl Persson <kalle.persson92@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Maria Ines Parnisari <maria.inesparnisari@okta.com>
Co-authored-by: Rokibul Hasan <mdrokibulhasan18@gmail.com>
Co-authored-by: José Padilla <jose.padilla@okta.com>
Co-authored-by: Adrian Tam <adrian.tam@okta.com>
Co-authored-by: Vihang Mehta <vihang@gimletlabs.ai>
Co-authored-by: Joshua Jones <joshua.jones.software@gmail.com>
Co-authored-by: Justin Cohen <justincoh@gmail.com>
release: update changelog for release `v1.12.1` (openfga#2992)
chore(deps): bump google.golang.org/grpc from 1.79.1 to 1.79.3 (openfga#2988)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Adrian Tam <adrian.tam@okta.com>
chore: enforce minor version upgrade rule (openfga#2978)

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
perf: tuple validation performance tweaks (openfga#2984)
fix: support URI schemes in OTLP endpoint configuration (openfga#2981)
refactor: remove custom pipes and replace with channels (openfga#2977)
chore(docs): added caching  docs (openfga#2664)

Co-authored-by: Saad Hussain <saad.hussain@okta.com>
release: update changelog for release `v1.12.0` (openfga#2974)
chore: update toolchain go to 1.26.1 (openfga#2975)
fix: update toolchain go to 1.25.8 to address stdlib CVEs (openfga#2971)
fix: correct swapped format args in DecodeParameterType error message (openfga#2961)

Signed-off-by: Artem Muterko <artem@sopho.tech>
Co-authored-by: Adrian Tam <adrian.tam@okta.com>
perf: small tweaks to tuple validation functions (openfga#2963)

Co-authored-by: Vic-Dev <vmichellej@gmail.com>
test: add tests for condition parameter type any with complex context structures (openfga#2959)

Signed-off-by: Artem Muterko <artem@sopho.tech>
test: add functional test for ReadAssertions API endpoint (openfga#2960)

Signed-off-by: Artem Muterko <artem@sopho.tech>
Co-authored-by: Adrian Tam <adrian.tam@okta.com>
make configurable the maximum received grpc message size (openfga#2952)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
fix: set ExperimentalPipelineListObjects in experimentals by default (openfga#2957)

fix: `cache_item_count` metric overcounting (openfga#2950)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
chore(deps): bump the dependencies group across 1 directory with 7 updates (openfga#2953)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Adrian Tam <adrian.tam@okta.com>
refactor: Make shadowV2Check final log clearer (openfga#2946)

Move telemetry package to internal/telemetry (openfga#2938)

Signed-off-by: Oleksandr Shestopal <ar.shestopal-oshegithub@gmail.com>
Co-authored-by: Adrian Tam <adrian.tam@okta.com>
chore(deps): bump the dependencies group across 1 directory with 3 updates (openfga#2956)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
fix: Resolve race condition in check reducers (openfga#2947)

Co-authored-by: Adrian Tam <adrian.tam@okta.com>
fix: gateway grpc client tls cert rotation (openfga#2951)

Signed-off-by: Shashank Goel <goelshashank13@gmail.com>
fix: disable LO pipeline if ff has it set for a store (openfga#2945)

chore(deps): bump the dependencies group across 1 directory with 4 updates (openfga#2949)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
fix: various random fixes (openfga#2942)

refactor: check using weighted graph (openfga#2816)

Co-authored-by: Yissell Garma <yissell.garma@okta.com>
release: update changelog for release `v1.11.6` (openfga#2939)

feat: enable pipeline algorithm by default (openfga#2921)

add tests to exercise reported bug (openfga#2934)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Adrian Tam <adrian.tam@okta.com>
refine AGENTS.md to make it more concise with higher value. (openfga#2936)

Co-authored-by: Justin Cohen <justincoh@gmail.com>
migrate grpc dial context to NewClient (openfga#2714)

Co-authored-by: Adrian Tam <adrian.tam@okta.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
chore(deps): bump filippo.io/edwards25519 from 1.1.0 to 1.1.1 (openfga#2935)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.