Skip to content

Conversation

@mihai-turdean
Copy link

@mihai-turdean mihai-turdean commented Dec 10, 2025

Description

This PR introduces a new internal gRPC storage service API that provides direct access to OpenFGA's storage backend operations. The service is designed for internal use and is intentionally excluded from public API documentation.

Rationale

The storage service API provides a gRPC interface to OpenFGA's storage layer, enabling custom datastore implementations.

Changes

New Storage Service API (storage/v1beta1/storage.proto)

  • StorageService: A comprehensive gRPC service for storage backend operations

    • Tuple operations: Read, ReadPage, ReadUserTuple, ReadUsersetTuples, ReadStartingWithUser, Write
    • Authorization model operations: ReadAuthorizationModel, ReadAuthorizationModels, FindLatestAuthorizationModel, WriteAuthorizationModel
    • Store operations: CreateStore, DeleteStore, GetStore, ListStores
    • Assertion operations: WriteAssertions, ReadAssertions
    • Changelog operations: ReadChanges
    • Service health: IsReady
  • Key Features:

    • Reuses existing openfga.v1 types for consistency
    • Type-safe enum options for write behavior (OnMissingDelete, OnDuplicateInsert)
    • Comprehensive filter options for tuple queries
    • Pagination support
    • Consistency preferences
    • Standardized error reasons via StorageErrorReason enum

Configuration Changes

  • Split Swagger generation: Created separate buf.gen.swagger.yaml to exclude storage/v1beta1 from public OpenAPI documentation
  • Makefile updates: Modified to use both buf.gen.yaml (for code generation) and buf.gen.swagger.yaml (for docs)

Generated Code

  • Go protobuf bindings
  • Go gRPC service stubs
  • Go validation code

Testing

  • Proto files generate successfully via make
  • Swagger documentation excludes storage service
  • Generated Go code compiles without errors

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

    • Introduced a new Storage Service API with comprehensive operations for data management (read, write with pagination), authorization model operations, store lifecycle management, assertion handling, and change tracking with consistency and pagination options.
  • Chores

    • Restructured code generation configuration to improve documentation generation workflow.

✏️ Tip: You can customize this high-level summary in your review settings.

@mihai-turdean mihai-turdean requested a review from a team as a code owner December 10, 2025 20:59
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 10, 2025

Walkthrough

This PR reorganizes the Buf code generation configuration by separating OpenAPI v2 generation into a dedicated template file (buf.gen.swagger.yaml), removes it from the main buf.gen.yaml, updates the Makefile to invoke both templates, and introduces a new comprehensive gRPC storage service specification defining storage operations for tuples, authorization models, stores, assertions, and changes.

Changes

Cohort / File(s) Summary
Build and configuration
.gitignore, Makefile
Added .devcontainer/ to ignore list; updated buf-gen target to execute two buf generate commands: one with buf.gen.yaml and another with buf.gen.swagger.yaml template excluding storage/v1beta1 path.
Code generation templates
buf.gen.yaml, buf.gen.swagger.yaml
Removed OpenAPI v2 plugin from buf.gen.yaml; introduced new buf.gen.swagger.yaml configuration for OpenAPI v2 generation with simple naming strategy and merge enabled, outputting to docs/openapiv2.
Storage service definition
storage/v1beta1/storage.proto
New comprehensive proto file defining StorageService with 18 RPCs (Read, ReadPage, ReadUserTuple, ReadUsersetTuples, ReadStartingWithUser, Write, authorization model operations, store operations, assertions, changes, and health check). Includes request/response messages, filters (ReadFilter, ReadUsersetTuplesFilter, ReadStartingWithUserFilter, ReadChangesFilter), pagination/consistency options, tuple write options, and StorageErrorReason enum with 9 standardized error codes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • storage/v1beta1/storage.proto: Requires careful review of the 18 RPC definitions, semantic correctness of 40+ message types and filters, error code appropriateness and consistency, and options field behaviors. Each filter and option carries specific semantics (e.g., allowed_user_type_restrictions, continuation tokens, consistency preferences, atomic write semantics) that need verification.
  • Makefile + buf configuration: Verify that the new two-step generation correctly excludes storage/v1beta1 from Swagger generation and doesn't break existing workflows.
  • Proto imports and versioning: Confirm all dependencies (OpenFGA authz model types) are correctly imported and namespace alignment is correct for v1beta1.

Suggested reviewers

  • rhamzeh
  • adriantam

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: introducing an internal gRPC storage service API in v1beta1 namespace, which is the primary purpose of this changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@dosubot
Copy link

dosubot bot commented Dec 10, 2025

Related Documentation

Checked 7 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between feed3db and 172cc1c.

⛔ Files ignored due to path filters (2)
  • proto/storage/v1beta1/storage.pb.go is excluded by !**/*.pb.go
  • proto/storage/v1beta1/storage_grpc.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (5)
  • .gitignore (1 hunks)
  • Makefile (1 hunks)
  • buf.gen.swagger.yaml (1 hunks)
  • buf.gen.yaml (0 hunks)
  • storage/v1beta1/storage.proto (1 hunks)
💤 Files with no reviewable changes (1)
  • buf.gen.yaml
🔇 Additional comments (6)
storage/v1beta1/storage.proto (3)

11-81: Comprehensive and well-documented service definition.

The StorageService organization, RPC signatures, and documentation are clear and logically structured. The separation into tuple operations, model operations, store operations, assertions, and health checks is intuitive. Stream semantics (e.g., Read) and pagination patterns (ReadPage) are appropriately chosen.


327-382: StorageErrorReason enum provides structured error handling.

The StorageErrorReason enum with mappings to gRPC status codes and the example in the comments (lines 335–341) is a solid pattern for domain-specific error reporting. This enables clients to distinguish storage-layer failures from generic gRPC errors.


5-20: Remove unused import or clarify visibility approach — current suggestion is not valid protobuf syntax.

The google/api/visibility.proto import is unused. Visibility restrictions for gRPC services are configured in external service config files using VisibilityRule entries with selectors, not as proto option statements. The suggested syntax option (google.api.visibility).restriction = "INTERNAL" is invalid—google.api.Visibility is a service config message, not a proto option.

If marking StorageService as internal-only is required, use a service config YAML file (not a proto option). Otherwise, remove the unused import.

Likely an incorrect or invalid review comment.

.gitignore (1)

5-5: Minor addition; no concerns.

Adding .devcontainer/ to the ignore list is standard practice for development environment configurations.

buf.gen.swagger.yaml (1)

1-15: Well-configured OpenAPI v2 template.

The configuration cleanly separates Swagger/OpenAPI v2 generation into a dedicated template, enabling the two-generation flow defined in the Makefile. Plugin version is pinned, output path aligns with downstream processing (patch-swagger-doc), and allow_merge=true is appropriate for multi-proto specifications.

Makefile (1)

3-5: Two-step Buf generation correctly excludes internal service from public docs.

The split into two buf generate commands—one with buf.gen.yaml (for Go bindings, gRPC, validation, gateway) and one with buf.gen.swagger.yaml using --exclude-path storage/v1beta1—is a sound strategy to keep the internal StorageService out of public OpenAPI documentation while still generating its bindings for internal use. Public-facing proto files in openfga/v1/ do not import types from storage/v1beta1, so the --exclude-path approach is safe and won't create documentation inconsistencies.

Comment on lines +291 to +299
// PaginationOptions controls pagination behavior.
message PaginationOptions {
// page_size is the maximum number of items to return per page.
// Must be greater than 0. Default is determined by the storage backend.
int32 page_size = 1;
// from is a continuation token from a previous response.
// Empty string starts from the beginning.
string from = 2;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Does protobuf proto3 support field-level validation constraints for numeric ranges?

💡 Result:

Short answer: Not in core proto3 itself — but you can add field-level numeric-range constraints using widely used annotation-based plugins and option sets (e.g., protoc-gen-validate / (validate.rules) or Spine/other custom options).

Details (concise):

  • proto3 language/spec does not include built‑in validation options for ranges; it only defines types and literals. [1]
  • The common approach is to annotate .proto fields with custom options provided by validation plugins (protoc‑gen‑validate supports lt/lte/gt/gte, in/not_in, const, etc., for numeric types). Generated code enforces the constraints. [2]
  • Other projects (e.g., Spine) also provide range/min/max options as proto field options you can use. [3]

References:

  • Protobuf language/spec (no built-in validation options). [1]
  • protoc‑gen‑validate numeric rules docs/examples (lt/lte/gt/gte, in/not_in, const). [2]
  • Spine validation options (range/min/max examples). [3]

Document page_size validation and enforce it at runtime or via protoc-gen-validate

proto3 does not enforce field-level constraints; ensure the server rejects page_size <= 0 or add a validation rule such as:
int32 page_size = 1 [(validate.rules).int32 = {gt: 0}];

🤖 Prompt for AI Agents
In storage/v1beta1/storage.proto around lines 291 to 299, the
PaginationOptions.page_size field lacks validation and proto3 won't enforce >0;
update the .proto to add a protoc-gen-validate rule such as int32 page_size = 1
[(validate.rules).int32 = {gt: 0}]; and/or ensure the server-side handler
rejects page_size <= 0 (returning an appropriate validation error) and applies
the backend default when page_size is omitted or zero.

@rhamzeh
Copy link
Member

rhamzeh commented Dec 10, 2025

Re:

Created separate buf.gen.swagger.yaml to exclude storage/v1beta1 from public OpenAPI documentation

I don't think we need to - we can use VisibilityRule to hide them from the OpenAPI output

@mihai-turdean
Copy link
Author

mihai-turdean commented Dec 11, 2025

Re:

Created separate buf.gen.swagger.yaml to exclude storage/v1beta1 from public OpenAPI documentation

I don't think we need to - we can use VisibilityRule to hide them from the OpenAPI output

@rhamzeh I've tried using VisibilityRules and the service itself does not make it into the swagger.json, but all the messages, enums in the proto definition still modify the swagger output.

Copy link
Member

@DanCech DanCech left a comment

Choose a reason for hiding this comment

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

Nice

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