From c00bdcf19458f5d88eaa443f82ff6439412d5e0c Mon Sep 17 00:00:00 2001 From: Uditha Atukorala Date: Mon, 21 Oct 2024 20:38:31 +0100 Subject: [PATCH 1/8] (docs) skeleton structure for api docs --- docs/README.md | 1 + docs/api/README.md | 6 ++++ docs/api/v1/principals.md | 64 +++++++++++++++++++++++++++++++++++++++ docs/api/v1/relations.md | 7 +++++ 4 files changed, 78 insertions(+) create mode 100644 docs/api/README.md create mode 100644 docs/api/v1/principals.md create mode 100644 docs/api/v1/relations.md diff --git a/docs/README.md b/docs/README.md index 8c2f957..1c5512a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,3 +3,4 @@ ## Table of contents * [ReBAC](rebac.md) +* [API Documentation](api/README.md) diff --git a/docs/api/README.md b/docs/api/README.md new file mode 100644 index 0000000..08fde23 --- /dev/null +++ b/docs/api/README.md @@ -0,0 +1,6 @@ +# API Documentation + +## V1 (`ruek.api.v1`) + +* [Principals (`ruek.api.v1.Principals`)](v1/principals.md) +* [Relations (`ruek.api.v1.Relations`)](v1/relations.md) diff --git a/docs/api/v1/principals.md b/docs/api/v1/principals.md new file mode 100644 index 0000000..ffaec0a --- /dev/null +++ b/docs/api/v1/principals.md @@ -0,0 +1,64 @@ +# Principals (`ruek.api.v1.Principals`) + +```proto +package ruek.api.v1; + +service Principals {} +``` + +## [RPC] Create (`ruek.api.v1.Principals.Create`) + +Create a new principal. + +```proto +rpc Create(PrincipalsCreateRequest) returns (Principal) { + option (google.api.http) = { + post : "/v1/principals" + body : "*" + }; +} +``` + +### Request message + +[`PrincipalsCreateRequest`](#PrincipalsCreateRequest) + + +### Response message + +[`Principal`](#Principal) + + +### Example + +``` +❯ grpcurl \ + -import-path proto \ + -import-path ./.build/_deps/googleapis-src \ + -proto proto/ruek/api/v1/principals.proto \ + -plaintext \ + localhost:8080 ruek.api.v1.Principals/Create + +{ + "id": "cn7qtdu56a1cqrj8kur0" +} +``` + + +## Messages + +### Principal + +| Field | Type | Description | +| ------- | ------------------- | ----------- | +| id | `string` | | +| attrs | (optional) [google.protobuf.Struct](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | +| segment | (optional) `string` | | + +### PrincipalsCreateRequest + +| Field | Type | Description | +| ------- | ------------------- | ----------- | +| id | (optional) `string` | | +| attrs | (optional) [google.protobuf.Struct](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | +| segment | (optional) `string` | | diff --git a/docs/api/v1/relations.md b/docs/api/v1/relations.md new file mode 100644 index 0000000..24f1260 --- /dev/null +++ b/docs/api/v1/relations.md @@ -0,0 +1,7 @@ +# Relations (`ruek.api.v1.Relations`) + +```proto +package ruek.api.v1; + +service Relations {} +``` From bb38c43bd3edf4556f91aa9eaaecbff6030e4b4c Mon Sep 17 00:00:00 2001 From: Uditha Atukorala Date: Mon, 21 Oct 2024 20:55:25 +0100 Subject: [PATCH 2/8] (docs) tidy-up Acknowledgments on the `gatekeeper` branch aren't necessary anymore since the contributors are now `main` branch contributors as well. --- README.md | 7 +------ docs/README.md | 2 +- docs/api/README.md | 2 +- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 93f3810..8d72c86 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![discussions](https://img.shields.io/github/discussions/uatuko/ruek)](https://github.com/uatuko/ruek/discussions) [![release](https://img.shields.io/github/v/release/uatuko/ruek)](https://github.com/uatuko/ruek/releases) -Lightning fast, global scale authorization service without the overhead of yet another DSL[^1]. +Lightning fast, global scale authorization service without the overhead of a yet another DSL[^1]. ## What is Ruek? @@ -230,11 +230,6 @@ Listening on [127.0.0.1:8080] ... * [libxid](https://github.com/uatuko/libxid) - For globally unique IDs. -## Acknowledgments - -* Thanks to [@kw510](https://github.com/kw510), [@neculalaura](https://github.com/neculalaura) and [@td0m](https://github.com/td0m) -for their contributions on the `gatekeeper` branch. - [^1]: [Domain-Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language) [^2]: [Zero trust architecture (ZTA)](https://en.wikipedia.org/wiki/Zero_trust_security_model) [^3]: Authorization check using ReBAC `set` (**O(1+n+m)**) and `graph` (**O(1+v+e)**) strategies are not constant time. diff --git a/docs/README.md b/docs/README.md index 1c5512a..ba3c61d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,5 +2,5 @@ ## Table of contents -* [ReBAC](rebac.md) * [API Documentation](api/README.md) +* [ReBAC](rebac.md) diff --git a/docs/api/README.md b/docs/api/README.md index 08fde23..b9268f9 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -1,6 +1,6 @@ # API Documentation -## V1 (`ruek.api.v1`) +## `ruek.api.v1` * [Principals (`ruek.api.v1.Principals`)](v1/principals.md) * [Relations (`ruek.api.v1.Relations`)](v1/relations.md) From bd9dfdefd1220b4499f6352ccf354559ad667d2f Mon Sep 17 00:00:00 2001 From: Uditha Atukorala Date: Wed, 23 Oct 2024 18:31:58 +0100 Subject: [PATCH 3/8] (docs) principals api docs stubs --- docs/api/v1/principals.md | 126 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/docs/api/v1/principals.md b/docs/api/v1/principals.md index ffaec0a..399f16a 100644 --- a/docs/api/v1/principals.md +++ b/docs/api/v1/principals.md @@ -45,6 +45,92 @@ rpc Create(PrincipalsCreateRequest) returns (Principal) { ``` +## [RPC] Delete (`ruek.api.v1.Principals.Delete`) + +Delete an existing principal. + +```proto +rpc Delete(PrincipalsDeleteRequest) returns (PrincipalsDeleteResponse) { + option (google.api.http) = { + delete : "/v1/principals/{id}" + body : "*" + }; +} +``` + +### Request message + +[`PrincipalsDeleteRequest`](#PrincipalsDeleteRequest) + +### Response message + +[`PrincipalsDeleteResponse`](#PrincipalsDeleteResponse) + + +## [RPC] List (`ruek.api.v1.Principals.List`) + +List principals. + +```proto +rpc List(PrincipalsListRequest) returns (PrincipalsListResponse) { + option (google.api.http) = { + get : "/v1/principals?segment={segment}&_limit={pagination_limit}&_start={pagination_token}" + }; +} +``` + +### Request message + +[`PrincipalsListRequest`](#PrincipalsListRequest) + +### Response message + +[`PrincipalsListResponse`](#PrincipalsListResponse) + + +## [RPC] Retrieve (`ruek.api.v1.Principals.Retrieve`) + +Retrieve a principal. + +```proto +rpc Retrieve(PrincipalsRetrieveRequest) returns (Principal) { + option (google.api.http) = { + get : "/v1/principals/{id}" + }; +} +``` + +### Request message + +[`PrincipalsRetrieveRequest`](#PrincipalsRetrieveRequest) + +### Response message + +[`Principal`](#Principal) + + +## [RPC] Update (`ruek.api.v1.Principals.Update`) + +Update a principal. + +```proto + rpc Update(PrincipalsUpdateRequest) returns (Principal) { + option (google.api.http) = { + put : "/v1/principals/{id}" + body : "*" + }; + } +``` + +### Request message + +[`PrincipalsUpdateRequest`](#PrincipalsUpdateRequest) + +### Response message + +[`Principal`](#Principal) + + ## Messages ### Principal @@ -62,3 +148,43 @@ rpc Create(PrincipalsCreateRequest) returns (Principal) { | id | (optional) `string` | | | attrs | (optional) [google.protobuf.Struct](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | | segment | (optional) `string` | | + +### PrincipalsDeleteRequest + +| Field | Type | Description | +| ------- | --------- | ----------- | +| id | `string` | | + +### PrincipalsDeleteResponse + +| Field | Type | Description | +| ------- | ------------------- | ----------- | + +### PrincipalsListRequest + +| Field | Type | Description | +| ---------------- | ------------------- | ----------- | +| segment | (optional) `string` | | +| pagination_limit | (optional) `uint32` | | +| pagination_token | (optional) `string` | | + +### PrincipalsListResponse + +| Field | Type | Description | +| ---------------- | ------------------- | ----------- | +| principals | `[]Principal` | | +| pagination_token | (optional) `string` | | + +### PrincipalsRetrieveRequest + +| Field | Type | Description | +| ------- | --------- | ----------- | +| id | `string` | | + +### PrincipalsUpdateRequest + +| Field | Type | Description | +| ------- | ------------------- | ----------- | +| id | `string` | | +| attrs | (optional) [google.protobuf.Struct](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | +| segment | (optional) `string` | | From cfa49330ab6fc7477022de125f9ac1220c7ec27a Mon Sep 17 00:00:00 2001 From: Uditha Atukorala Date: Wed, 23 Oct 2024 18:32:46 +0100 Subject: [PATCH 4/8] (docs) tidy-up --- docs/api/v1/principals.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/api/v1/principals.md b/docs/api/v1/principals.md index 399f16a..20e6d6d 100644 --- a/docs/api/v1/principals.md +++ b/docs/api/v1/principals.md @@ -23,12 +23,10 @@ rpc Create(PrincipalsCreateRequest) returns (Principal) { [`PrincipalsCreateRequest`](#PrincipalsCreateRequest) - ### Response message [`Principal`](#Principal) - ### Example ``` From 637b4e440578bd30f5b1dc06a2995421f1153853 Mon Sep 17 00:00:00 2001 From: Uditha Atukorala Date: Sun, 3 Nov 2024 21:32:39 +0000 Subject: [PATCH 5/8] (docs) relations api docs stubs --- docs/api/v1/relations.md | 236 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) diff --git a/docs/api/v1/relations.md b/docs/api/v1/relations.md index 24f1260..59a76b1 100644 --- a/docs/api/v1/relations.md +++ b/docs/api/v1/relations.md @@ -5,3 +5,239 @@ package ruek.api.v1; service Relations {} ``` + +## [RPC] Check (`ruek.api.v1.Relations.Check`) + +Check if a relation exists. + +```proto +rpc Check(RelationsCheckRequest) returns (RelationsCheckResponse) { + option (google.api.http) = { + post : "/v1/relations:check" + body : "*" + }; +} +``` + +### Request message + +[`RelationsCheckRequest`](#relationscheckrequest) + +### Response message + +[`RelationsCheckResponse`](#relationscreateresponse) + + +## [RPC] Create (`ruek.api.v1.Relations.Create`) + +Create a new relation. + +```proto +rpc Create(RelationsCreateRequest) returns (RelationsCreateResponse) { + option (google.api.http) = { + post : "/v1/relations" + body : "*" + }; +} +``` + +### Request message + +[`RelationsCreateRequest`](#relationscreaterequest) + +### Response message + +[`RelationsCreateResponse`](#relationscreateresponse) + + +## [RPC] Delete (`ruek.api.v1.Relations.Delete`) + +Delete an existing relation. + +```proto +rpc Delete(RelationsDeleteRequest) returns (RelationsDeleteResponse) { + option (google.api.http) = { + post : "/v1/relations:delete" + body : "*" + }; +} +``` + +### Request message + +[`RelationsDeleteRequest`](#relationsdeleterequest) + +### Response message + +[`RelationsDeleteResponse`](#relationsdeleteresponse) + + +## [RPC] ListLeft (`ruek.api.v1.Relations.ListLeft`) + +List relations to the left of a relation. + +```proto +rpc ListLeft(RelationsListLeftRequest) returns (RelationsListLeftResponse) { + option (google.api.http) = { + get : "/v1/relations:left?_limit={pagination_limit}&_start={pagination_token}" + }; +} +``` + +### Request message + +[`RelationsListLeftRequest`](#relationslistleftrequest) + +### Response message + +[`RelationsListLeftResponse`](#relationslistleftresponse) + + +## [RPC] ListRight (`ruek.api.v1.Relations.ListRight`) + +List relations to the right of a relation. + +```proto +rpc ListRight(RelationsListRightRequest) returns (RelationsListRightResponse) { + option (google.api.http) = { + get : "/v1/relations:right?_limit={pagination_limit}&_start={pagination_token}" + }; +} +``` + +### Request message + +[`RelationsListRightRequest`](#relationslistrightrequest) + +### Response message + +[`RelationsListRightResponse`](#relationslistrightresponse) + + +## Messages + +### Entity + +| Field | Type | Description | +| ------ | -------- | ----------- | +| id | `string` | | +| type | `string` | | + +### Tuple + +| Field | Type | Description | +| ------------------------------ | -------------------- | ----------- | +| space_id | `string` | | +| id | `string` | | +| `left` | (oneof) | | +| [ `left` ] left_entity | [`Entity`](#entity) | | +| [ `left` ] left_principal_id | `string` | | +| relation | `string` | | +| `right` | (oneof) | | +| [ `right` ] right_entity | [`Entity`](#entity) | | +| [ `right` ] right_principal_id | `string` | | +| strand | (optional) `string` | | +| attrs | (optional) [`google.protobuf.Struct`](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | +| ref_id_left | (optional) `string` | | +| ref_id_right | (optional) `string` | | + +### RelationsCheckRequest + +| Field | Type | Description | +| ------------------------------ | -------------------- | ----------- | +| `left` | (oneof) | | +| [ `left` ] left_entity | [`Entity`](#entity) | | +| [ `left` ] left_principal_id | `string` | | +| relation | `string` | | +| `right` | (oneof) | | +| [ `right` ] right_entity | [`Entity`](#entity) | | +| [ `right` ] right_principal_id | `string` | | +| strategy | (optional) `uint32` | | +| cost_limit | (optional) `uint32` | | + +### RelationsCheckResponse + +| Field | Type | Description | +| ------ | ---------------------------- | ----------- | +| found | `bool` | | +| cost | `int32` | | +| tuple | (optional) [`Tuple`](#tuple) | | +| path | `[]`[`Tuple`](#tuple) | | + +### RelationsCreateRequest + +| Field | Type | Description | +| ------------------------------ | -------------------- | ----------- | +| `left` | (oneof) | | +| [ `left` ] left_entity | [`Entity`](#entity) | | +| [ `left` ] left_principal_id | `string` | | +| relation | `string` | | +| `right` | (oneof) | | +| [ `right` ] right_entity | [`Entity`](#entity) | | +| [ `right` ] right_principal_id | `string` | | +| strand | (optional) `string` | | +| attrs | (optional) [`google.protobuf.Struct`](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | +| optimize | (optional) `uint32` | | +| cost_limit | (optional) `uint32` | | + +### RelationsCreateResponse + +| Field | Type | Description | +| --------------- | --------------------- | ----------- | +| tuple | [`Tuple`](#tuple) | | +| cost | `int32` | | +| computed_tuples | `[]`[`Tuple`](#tuple) | | + +### RelationsDeleteRequest + +| Field | Type | Description | +| ------------------------------ | -------------------- | ----------- | +| `left` | (oneof) | | +| [ `left` ] left_entity | [`Entity`](#entity) | | +| [ `left` ] left_principal_id | `string` | | +| relation | `string` | | +| `right` | (oneof) | | +| [ `right` ] right_entity | [`Entity`](#entity) | | +| [ `right` ] right_principal_id | `string` | | +| strand | (optional) `string` | | + +### RelationsDeleteResponse + +| Field | Type | Description | +| ------ | ---- | ----------- | + +### RelationsListLeftRequest + +| Field | Type | Description | +| ------------------------------ | -------------------- | ----------- | +| `right` | (oneof) | | +| [ `right` ] right_entity | [`Entity`](#entity) | | +| [ `right` ] right_principal_id | `string` | | +| relation | (optional) `string` | | +| pagination_limit | (optional) `uint32` | | +| pagination_token | (optional) `string` | | + +### RelationsListLeftResponse + +| Field | Type | Description | +| ---------------- | -------------------- | ----------- | +| tuples | `[]`[`Tuple`](#tuple) | | +| pagination_token | (optional) `string` | | + +### RelationsListRightRequest + +| Field | Type | Description | +| ---------------------------- | -------------------- | ----------- | +| `left` | (oneof) | | +| [ `left` ] left_entity | [`Entity`](#entity) | | +| [ `left` ] left_principal_id | `string` | | +| relation | (optional) `string` | | +| pagination_limit | (optional) `uint32` | | +| pagination_token | (optional) `string` | | + +### RelationsListRightResponse + +| Field | Type | Description | +| ---------------- | --------------------- | ----------- | +| tuples | `[]`[`Tuple`](#tuple) | | +| pagination_token | (optional) `string` | | From 4b06f3ad73022c4ae06e53c273ab8772eec26050 Mon Sep 17 00:00:00 2001 From: Uditha Atukorala Date: Sun, 3 Nov 2024 21:33:18 +0000 Subject: [PATCH 6/8] (docs) tidy-up --- docs/api/v1/principals.md | 56 +++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/docs/api/v1/principals.md b/docs/api/v1/principals.md index 20e6d6d..27e87a3 100644 --- a/docs/api/v1/principals.md +++ b/docs/api/v1/principals.md @@ -21,11 +21,11 @@ rpc Create(PrincipalsCreateRequest) returns (Principal) { ### Request message -[`PrincipalsCreateRequest`](#PrincipalsCreateRequest) +[`PrincipalsCreateRequest`](#principalscreaterequest) ### Response message -[`Principal`](#Principal) +[`Principal`](#principal) ### Example @@ -58,11 +58,11 @@ rpc Delete(PrincipalsDeleteRequest) returns (PrincipalsDeleteResponse) { ### Request message -[`PrincipalsDeleteRequest`](#PrincipalsDeleteRequest) +[`PrincipalsDeleteRequest`](#principalsdeleterequest) ### Response message -[`PrincipalsDeleteResponse`](#PrincipalsDeleteResponse) +[`PrincipalsDeleteResponse`](#principalsdeleteresponse) ## [RPC] List (`ruek.api.v1.Principals.List`) @@ -79,11 +79,33 @@ rpc List(PrincipalsListRequest) returns (PrincipalsListResponse) { ### Request message -[`PrincipalsListRequest`](#PrincipalsListRequest) +[`PrincipalsListRequest`](#principalslistrequest) ### Response message -[`PrincipalsListResponse`](#PrincipalsListResponse) +[`PrincipalsListResponse`](#principalslistresponse) + +### Example + +``` +❯ grpcurl \ + -import-path proto \ + -import-path ./.build/_deps/googleapis-src \ + -proto proto/ruek/api/v1/principals.proto \ + -plaintext \ + localhost:8080 ruek.api.v1.Principals/List + +{ + "principals": [ + { + "id": "cn7qtim56a1cqrj8kurg" + }, + { + "id": "cn7qtdu56a1cqrj8kur0" + } + ] +} +``` ## [RPC] Retrieve (`ruek.api.v1.Principals.Retrieve`) @@ -100,11 +122,11 @@ rpc Retrieve(PrincipalsRetrieveRequest) returns (Principal) { ### Request message -[`PrincipalsRetrieveRequest`](#PrincipalsRetrieveRequest) +[`PrincipalsRetrieveRequest`](#principalsretrieverequest) ### Response message -[`Principal`](#Principal) +[`Principal`](#principal) ## [RPC] Update (`ruek.api.v1.Principals.Update`) @@ -122,11 +144,11 @@ Update a principal. ### Request message -[`PrincipalsUpdateRequest`](#PrincipalsUpdateRequest) +[`PrincipalsUpdateRequest`](#principalsupdaterequest) ### Response message -[`Principal`](#Principal) +[`Principal`](#principal) ## Messages @@ -136,7 +158,7 @@ Update a principal. | Field | Type | Description | | ------- | ------------------- | ----------- | | id | `string` | | -| attrs | (optional) [google.protobuf.Struct](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | +| attrs | (optional) [`google.protobuf.Struct`](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | | segment | (optional) `string` | | ### PrincipalsCreateRequest @@ -144,7 +166,7 @@ Update a principal. | Field | Type | Description | | ------- | ------------------- | ----------- | | id | (optional) `string` | | -| attrs | (optional) [google.protobuf.Struct](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | +| attrs | (optional) [`google.protobuf.Struct`](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | | segment | (optional) `string` | | ### PrincipalsDeleteRequest @@ -168,10 +190,10 @@ Update a principal. ### PrincipalsListResponse -| Field | Type | Description | -| ---------------- | ------------------- | ----------- | -| principals | `[]Principal` | | -| pagination_token | (optional) `string` | | +| Field | Type | Description | +| ---------------- | ----------------------------- | ----------- | +| principals | `[]`[`Principal`](#principal) | | +| pagination_token | (optional) `string` | | ### PrincipalsRetrieveRequest @@ -184,5 +206,5 @@ Update a principal. | Field | Type | Description | | ------- | ------------------- | ----------- | | id | `string` | | -| attrs | (optional) [google.protobuf.Struct](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | +| attrs | (optional) [`google.protobuf.Struct`](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | | segment | (optional) `string` | | From 5e6c9bff24ccbf2379227693d14b1a0c6103a285 Mon Sep 17 00:00:00 2001 From: Uditha Atukorala Date: Sat, 9 Nov 2024 09:13:34 +0000 Subject: [PATCH 7/8] (docs) update docs --- docs/api/v1/principals.md | 47 ++++++++++++---- docs/api/v1/relations.md | 109 +++++++++++++++++++++++++++++--------- docs/rebac.md | 25 --------- 3 files changed, 121 insertions(+), 60 deletions(-) diff --git a/docs/api/v1/principals.md b/docs/api/v1/principals.md index 27e87a3..82e8636 100644 --- a/docs/api/v1/principals.md +++ b/docs/api/v1/principals.md @@ -1,3 +1,4 @@ + # Principals (`ruek.api.v1.Principals`) ```proto @@ -6,7 +7,35 @@ package ruek.api.v1; service Principals {} ``` -## [RPC] Create (`ruek.api.v1.Principals.Create`) +- [(rpc) Create (`ruek.api.v1.Principals.Create`)](#rpc-create-ruekapiv1principalscreate) + - [Request message](#request-message) + - [Response message](#response-message) + - [Example](#example) +- [(rpc) Delete (`ruek.api.v1.Principals.Delete`)](#rpc-delete-ruekapiv1principalsdelete) + - [Request message](#request-message-1) + - [Response message](#response-message-1) +- [(rpc) List (`ruek.api.v1.Principals.List`)](#rpc-list-ruekapiv1principalslist) + - [Request message](#request-message-2) + - [Response message](#response-message-2) + - [Example](#example-1) +- [(rpc) Retrieve (`ruek.api.v1.Principals.Retrieve`)](#rpc-retrieve-ruekapiv1principalsretrieve) + - [Request message](#request-message-3) + - [Response message](#response-message-3) +- [(rpc) Update (`ruek.api.v1.Principals.Update`)](#rpc-update-ruekapiv1principalsupdate) + - [Request message](#request-message-4) + - [Response message](#response-message-4) +- [Messages](#messages) + - [Principal](#principal) + - [PrincipalsCreateRequest](#principalscreaterequest) + - [PrincipalsDeleteRequest](#principalsdeleterequest) + - [PrincipalsDeleteResponse](#principalsdeleteresponse) + - [PrincipalsListRequest](#principalslistrequest) + - [PrincipalsListResponse](#principalslistresponse) + - [PrincipalsRetrieveRequest](#principalsretrieverequest) + - [PrincipalsUpdateRequest](#principalsupdaterequest) + + +## (rpc) Create (`ruek.api.v1.Principals.Create`) Create a new principal. @@ -43,7 +72,7 @@ rpc Create(PrincipalsCreateRequest) returns (Principal) { ``` -## [RPC] Delete (`ruek.api.v1.Principals.Delete`) +## (rpc) Delete (`ruek.api.v1.Principals.Delete`) Delete an existing principal. @@ -65,7 +94,7 @@ rpc Delete(PrincipalsDeleteRequest) returns (PrincipalsDeleteResponse) { [`PrincipalsDeleteResponse`](#principalsdeleteresponse) -## [RPC] List (`ruek.api.v1.Principals.List`) +## (rpc) List (`ruek.api.v1.Principals.List`) List principals. @@ -108,7 +137,7 @@ rpc List(PrincipalsListRequest) returns (PrincipalsListResponse) { ``` -## [RPC] Retrieve (`ruek.api.v1.Principals.Retrieve`) +## (rpc) Retrieve (`ruek.api.v1.Principals.Retrieve`) Retrieve a principal. @@ -129,7 +158,7 @@ rpc Retrieve(PrincipalsRetrieveRequest) returns (Principal) { [`Principal`](#principal) -## [RPC] Update (`ruek.api.v1.Principals.Update`) +## (rpc) Update (`ruek.api.v1.Principals.Update`) Update a principal. @@ -190,10 +219,10 @@ Update a principal. ### PrincipalsListResponse -| Field | Type | Description | -| ---------------- | ----------------------------- | ----------- | -| principals | `[]`[`Principal`](#principal) | | -| pagination_token | (optional) `string` | | +| Field | Type | Description | +| ---------------- | --------------------------- | ----------- | +| principals | [`[]Principal`](#principal) | | +| pagination_token | (optional) `string` | | ### PrincipalsRetrieveRequest diff --git a/docs/api/v1/relations.md b/docs/api/v1/relations.md index 59a76b1..890fa0f 100644 --- a/docs/api/v1/relations.md +++ b/docs/api/v1/relations.md @@ -1,3 +1,4 @@ + # Relations (`ruek.api.v1.Relations`) ```proto @@ -6,7 +7,40 @@ package ruek.api.v1; service Relations {} ``` -## [RPC] Check (`ruek.api.v1.Relations.Check`) +- [(rpc) Check (`ruek.api.v1.Relations.Check`)](#rpc-check-ruekapiv1relationscheck) + - [Request message](#request-message) + - [Response message](#response-message) +- [(rpc) Create (`ruek.api.v1.Relations.Create`)](#rpc-create-ruekapiv1relationscreate) + - [Request message](#request-message-1) + - [Response message](#response-message-1) +- [(rpc) Delete (`ruek.api.v1.Relations.Delete`)](#rpc-delete-ruekapiv1relationsdelete) + - [Request message](#request-message-2) + - [Response message](#response-message-2) +- [(rpc) ListLeft (`ruek.api.v1.Relations.ListLeft`)](#rpc-listleft-ruekapiv1relationslistleft) + - [Request message](#request-message-3) + - [Response message](#response-message-3) +- [(rpc) ListRight (`ruek.api.v1.Relations.ListRight`)](#rpc-listright-ruekapiv1relationslistright) + - [Request message](#request-message-4) + - [Response message](#response-message-4) +- [Messages](#messages) + - [Entity](#entity) + - [Tuple](#tuple) + - [RelationsCheckRequest](#relationscheckrequest) + - [RelationsCheckResponse](#relationscheckresponse) + - [RelationsCreateRequest](#relationscreaterequest) + - [RelationsCreateResponse](#relationscreateresponse) + - [RelationsDeleteRequest](#relationsdeleterequest) + - [RelationsDeleteResponse](#relationsdeleteresponse) + - [RelationsListLeftRequest](#relationslistleftrequest) + - [RelationsListLeftResponse](#relationslistleftresponse) + - [RelationsListRightRequest](#relationslistrightrequest) + - [RelationsListRightResponse](#relationslistrightresponse) +- [Appendix A. Strategies](#appendix-a-strategies) + - [A.1. Lookup strategies](#a1-lookup-strategies) + - [A.2. Optimization strategies](#a2-optimization-strategies) + + +## (rpc) Check (`ruek.api.v1.Relations.Check`) Check if a relation exists. @@ -28,7 +62,7 @@ rpc Check(RelationsCheckRequest) returns (RelationsCheckResponse) { [`RelationsCheckResponse`](#relationscreateresponse) -## [RPC] Create (`ruek.api.v1.Relations.Create`) +## (rpc) Create (`ruek.api.v1.Relations.Create`) Create a new relation. @@ -50,7 +84,7 @@ rpc Create(RelationsCreateRequest) returns (RelationsCreateResponse) { [`RelationsCreateResponse`](#relationscreateresponse) -## [RPC] Delete (`ruek.api.v1.Relations.Delete`) +## (rpc) Delete (`ruek.api.v1.Relations.Delete`) Delete an existing relation. @@ -72,7 +106,7 @@ rpc Delete(RelationsDeleteRequest) returns (RelationsDeleteResponse) { [`RelationsDeleteResponse`](#relationsdeleteresponse) -## [RPC] ListLeft (`ruek.api.v1.Relations.ListLeft`) +## (rpc) ListLeft (`ruek.api.v1.Relations.ListLeft`) List relations to the left of a relation. @@ -93,7 +127,7 @@ rpc ListLeft(RelationsListLeftRequest) returns (RelationsListLeftResponse) { [`RelationsListLeftResponse`](#relationslistleftresponse) -## [RPC] ListRight (`ruek.api.v1.Relations.ListRight`) +## (rpc) ListRight (`ruek.api.v1.Relations.ListRight`) List relations to the right of a relation. @@ -152,17 +186,17 @@ rpc ListRight(RelationsListRightRequest) returns (RelationsListRightResponse) { | `right` | (oneof) | | | [ `right` ] right_entity | [`Entity`](#entity) | | | [ `right` ] right_principal_id | `string` | | -| strategy | (optional) `uint32` | | -| cost_limit | (optional) `uint32` | | +| strategy | (optional) `uint32` | Lookup strategy to use (default `2`). See [lookup strategies](#a1---lookup-strategies). | +| cost_limit | (optional) `uint32` | A value between `1` and `65535` to limit the lookup cost (default `1000`). | ### RelationsCheckResponse | Field | Type | Description | | ------ | ---------------------------- | ----------- | -| found | `bool` | | -| cost | `int32` | | -| tuple | (optional) [`Tuple`](#tuple) | | -| path | `[]`[`Tuple`](#tuple) | | +| found | `bool` | Flag to indicate if a relation exists or could be derived using the lookup strategy. | +| cost | `int32` | Lookup cost. A negative cost indicates the lookup cost exceeded the limit and the lookup _may_ have been abandoned without computing all possible derivations. | +| tuple | (optional) [`Tuple`](#tuple) | Tuple containing relation data that matched the query. An empty tuple `id` indicates a computed tuple which isn't stored. | +| path | [`[]Tuple`](#tuple) | Path that derived the relation between entities when using the _graph_ (`4`) lookup strategy. | ### RelationsCreateRequest @@ -177,16 +211,16 @@ rpc ListRight(RelationsListRightRequest) returns (RelationsListRightResponse) { | [ `right` ] right_principal_id | `string` | | | strand | (optional) `string` | | | attrs | (optional) [`google.protobuf.Struct`](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | -| optimize | (optional) `uint32` | | -| cost_limit | (optional) `uint32` | | +| optimize | (optional) `uint32` | Optimization strategy to use (default `4`). See [optimization strategies](#a2-optimization-strategies). | +| cost_limit | (optional) `uint32` | A value between `1` and `65535` to limit the cost of creating a new relation (default `1000`). | ### RelationsCreateResponse -| Field | Type | Description | -| --------------- | --------------------- | ----------- | -| tuple | [`Tuple`](#tuple) | | -| cost | `int32` | | -| computed_tuples | `[]`[`Tuple`](#tuple) | | +| Field | Type | Description | +| --------------- | ------------------- | ----------- | +| tuple | [`Tuple`](#tuple) | Tuple containing the relation data. | +| cost | `int32` | Cost of creating the relation. A negative cost indicates only the relation was created but computing and storing derived relations was aborted. | +| computed_tuples | [`[]Tuple`](#tuple) | Computed and _maybe_ stored derived relation tuples. If the `cost` returned is negative, this _may_ contain a partial list. Any tuple with an empty id indicates it's only computed but not stored (i.e. dirty). | ### RelationsDeleteRequest @@ -219,10 +253,10 @@ rpc ListRight(RelationsListRightRequest) returns (RelationsListRightResponse) { ### RelationsListLeftResponse -| Field | Type | Description | -| ---------------- | -------------------- | ----------- | -| tuples | `[]`[`Tuple`](#tuple) | | -| pagination_token | (optional) `string` | | +| Field | Type | Description | +| ---------------- | ------------------- | ----------- | +| tuples | [`[]Tuple`](#tuple) | | +| pagination_token | (optional) `string` | | ### RelationsListRightRequest @@ -237,7 +271,30 @@ rpc ListRight(RelationsListRightRequest) returns (RelationsListRightResponse) { ### RelationsListRightResponse -| Field | Type | Description | -| ---------------- | --------------------- | ----------- | -| tuples | `[]`[`Tuple`](#tuple) | | -| pagination_token | (optional) `string` | | +| Field | Type | Description | +| ---------------- | ------------------- | ----------- | +| tuples | [`[]Tuple`](#tuple) | | +| pagination_token | (optional) `string` | | + + +## Appendix A. Strategies + +Refer to [ReBAC strategies](../../rebac.md#strategies) documentation for more information. + +### A.1. Lookup strategies + +Lookup strategies are used when checking + +| Strategy | Description | +| ------------ | ----------- | +| `2` (direct) | Only check if there's a direct relation exists between the entities. | +| `4` (graph) | If a direct relation cannot be found between the entities, use a graph traversal algorithm to derive a relation. | +| `8` (set) | Check if there's a direct relation exists between the entities and if not, use a set intersection algorithm to derive a relation between the entities. | + +### A.2. Optimization strategies + +| Strategy | Description | +| ------------ | ----------- | +| `2` (direct) | Optimize for direct lookups. Best for lookup speeds but can produce large numbers of computed relations resulting in expensive write operations. | +| `4` (graph) | Don't optimize. Lookups will need to use a graph traversal algorithm to derive relations. | +| `8` (set) | Optimize by computing derived relations between principals, which the lookups can utilise in a set intersection algorithm. | diff --git a/docs/rebac.md b/docs/rebac.md index 40e4123..572ef7f 100644 --- a/docs/rebac.md +++ b/docs/rebac.md @@ -130,29 +130,4 @@ look for all the groups `user:jane` is a member of and compare that list with al a `reader` relation to `doc:notes.txt` using the _spot_ algorithm. -## Appendix A1: Protobuf Message Types - -### A1.1 Entity - -| Field | Type | Description | -| -------| ---------- | ----------- | -| `id` | **string** | Entity ID | -| `type` | **string** | Entity Type | - -### A1.2 Tuple - -| Field | Type | Description | -| -------------------- | ----------------------- | ----------- | -| `space_id` | **string** | | -| `id` | **string** | | -| `left_entity` | _(optional)_ [Entity](#a11-entity) | | -| `left_principal_id` | _(optional)_ **string** | | -| `relation` | **string** | | -| `right_entity` | _(optional)_ [Entity](#a11-entity) | | -| `right_principal_id` | _(optional)_ **string** | | -| `strand` | _(optional)_ **string** | | -| `attrs` | [google.protobuf.Struct](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | | -| `ref_id_left` | _(optional)_ **string** | | -| `ref_id_right` | _(optional)_ **string** | | - [^bfs]: [Breadth-first search](https://en.wikipedia.org/wiki/Breadth-first_search) From f00e1c3c9b60e2c514c77a4a325f8aea24ed4465 Mon Sep 17 00:00:00 2001 From: Uditha Atukorala Date: Tue, 12 Nov 2024 00:21:55 +0000 Subject: [PATCH 8/8] (docs) update docs --- README.md | 180 ++++----------------------------------- docs/README.md | 91 ++++++++++++++++++++ docs/api/v1/relations.md | 2 +- docs/rebac.md | 12 ++- 4 files changed, 117 insertions(+), 168 deletions(-) diff --git a/README.md b/README.md index 8d72c86..a757d2b 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Ruek lean on well known API design principals to provide an authorization servic integrate, quick to master and flexible enough to handle complex requirements. -## Features +## 🔥 Features * ABAC, RBAC & ReBAC * Schema-less fine-grained authorization (FGA) @@ -42,180 +42,34 @@ integrate, quick to master and flexible enough to handle complex requirements. * Built using the fastest gRPC server implementation[^5] -## Documentation +## 📜 Documentation You can find a bit more detailed documentation in [docs/](docs/README.md). -## Getting started +## 🚀 Quickstart (with `docker`) -### Prerequisites - -* [CMake](https://cmake.org) (>= 3.23) -* [Protobuf](https://protobuf.dev) (>= 3.15) -* [libpq](https://www.postgresql.org/docs/current/libpq.html) -* [PostgreSQL](https://www.postgresql.org) (or [PostgreSQL protocol](https://www.postgresql.org/docs/current/protocol.html) compatible server) - -### Compiling - -``` -❯ cmake -B .build -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DPostgreSQL_ADDITIONAL_VERSIONS=16 \ - -Druek_ENABLE_COVERAGE=OFF -``` - -``` -❯ cmake --build .build --target ruek +### Create a docker network +```sh +docker network create ruek-net ``` -### Setting-up - +### Run PostgreSQL +```sh +docker run --net=ruek-net --name=pg -e POSTGRES_PASSWORD=postgres -d postgres:16-alpine ``` -❯ psql --dbname=postgres -psql (16.1) -Type "help" for help. - -postgres=# create user ruek; -CREATE ROLE -postgres=# create database ruek owner ruek; -CREATE DATABASE -``` - -``` -❯ psql --username=ruek --dbname=ruek < db/schema.sql -``` - -### Running - -``` -❯ PGDATABASE=ruek PGUSER=ruek ./.build/bin/ruek -Listening on [127.0.0.1:8080] ... -``` - - -## Usage - -### Creating a user +### Setup PostgreSQL user and database for Ruek +```sh +echo "create user ruek with password 'ruek'; create database ruek owner ruek;" | docker run --rm -i --network=ruek-net -e PGPASSWORD=postgres postgres:16-alpine psql --host=pg --username=postgres ``` -❯ grpcurl \ - -import-path proto \ - -import-path ./.build/_deps/googleapis-src \ - -proto proto/ruek/api/v1/principals.proto \ - -plaintext \ - localhost:8080 ruek.api.v1.Principals/Create - -{ - "id": "cn7qtdu56a1cqrj8kur0" -} +```sh +curl -sL https://raw.githubusercontent.com/uatuko/ruek/refs/heads/main/db/schema.sql | docker run --rm -i --network=ruek-net -e PGPASSWORD=ruek postgres:16-alpine psql --host=pg --username=ruek --dbname=ruek ``` -### Granting access - -``` -❯ grpcurl \ - -import-path proto \ - -import-path ./.build/_deps/googleapis-src \ - -proto proto/ruek/api/v1/authz.proto \ - -plaintext \ - -d '{ - "principal_id": "cn7qtdu56a1cqrj8kur0", - "entity_type": "documents", - "entity_id": "65bd28aaa076ee8c8463cff8" - }' \ - localhost:8080 ruek.api.v1.Authz/Grant - -{} -``` - -### Checking access - -``` -❯ grpcurl \ - -import-path proto \ - -import-path ./.build/_deps/googleapis-src \ - -proto proto/ruek/api/v1/authz.proto \ - -plaintext \ - -d '{ - "principal_id": "cn7qtdu56a1cqrj8kur0", - "entity_type": "documents", - "entity_id": "65bd28aaa076ee8c8463cff8" - }' \ - localhost:8080 ruek.api.v1.Authz/Check - -{ - "ok": true -} -``` - -### Listing users - -``` -❯ grpcurl \ - -import-path proto \ - -import-path ./.build/_deps/googleapis-src \ - -proto proto/ruek/api/v1/principals.proto \ - -plaintext \ - localhost:8080 ruek.api.v1.Principals/List - -{ - "principals": [ - { - "id": "cn7qtim56a1cqrj8kurg" - }, - { - "id": "cn7qtdu56a1cqrj8kur0" - } - ] -} -``` - -### Listing entities a user can access - -``` -❯ grpcurl \ - -import-path proto \ - -import-path ./.build/_deps/googleapis-src \ - -proto proto/ruek/api/v1/entities.proto \ - -plaintext \ - -d '{ - "principal_id": "cn7qtdu56a1cqrj8kur0", - "entity_type": "documents" - }' \ - localhost:8080 ruek.api.v1.Entities/List - -{ - "entities": [ - { - "id": "65bd28aaa076ee8c8463cff8", - "type": "documents" - } - ] -} -``` - -### Listing users that has access to an entity - -``` -❯ grpcurl \ - -import-path proto \ - -import-path ./.build/_deps/googleapis-src \ - -proto proto/ruek/api/v1/entities.proto \ - -plaintext \ - -d '{ - "entity_type": "documents", - "entity_id": "65bd28aaa076ee8c8463cff8" - }' \ - localhost:8080 ruek.api.v1.Entities/ListPrincipals - -{ - "principals": [ - { - "id": "cn7qtdu56a1cqrj8kur0" - } - ] -} +### Run Ruek +```sh +docker run --network=ruek-net --name=ruek -e PGHOST=pg -e PGUSER=ruek -e PGPASSWORD=ruek -p 8080:8080 -d uatuko/ruek:latest ``` diff --git a/docs/README.md b/docs/README.md index ba3c61d..84f3f4a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,5 +2,96 @@ ## Table of contents +* [Getting started](#getting-started) * [API Documentation](api/README.md) * [ReBAC](rebac.md) + + +## Getting started + +### Prerequisites + +Ruek require [PostgreSQL](https://www.postgresql.org) (or [PostgreSQL protocol](https://www.postgresql.org/docs/current/protocol.html) compatible server) to run. + +
+Example - setting up PostgreSQL in docker + +```sh +# create a docker network to connect postgres and ruek containers +docker network create ruek-net + +# run postgres in the 'ruek-net' network +docker run --net=ruek-net --name=pg -e POSTGRES_PASSWORD=postgres -d postgres:16-alpine + +# wait until postgres starts up +while ! $(docker run --rm --network=ruek-net postgres:16-alpine pg_isready --host=pg | grep -q 'accepting connections'); do sleep 1; done + +# setup postgres user and db for ruek +echo "create user ruek with password 'ruek'; create database ruek owner ruek;" | docker run --rm -i --network=ruek-net -e PGPASSWORD=postgres postgres:16-alpine psql --host=pg --username=postgres + +# initialize ruek db +curl -sL https://raw.githubusercontent.com/uatuko/ruek/refs/heads/main/db/schema.sql | docker run --rm -i --network=ruek-net -e PGPASSWORD=ruek postgres:16-alpine psql --host=pg --username=ruek --dbname=ruek +``` +
+ +### Using pre-built containers + +The quickest way to run Ruek is by using pre-built containers. There are `linux/amd64` and `linux/arm64` containers published to [`docker.io/uatuko/ruek`](https://hub.docker.com/r/uatuko/ruek) and [`ghcr.io/uatuko/ruek`](https://github.com/uatuko/ruek/pkgs/container/ruek). + +> [!IMPORTANT] +> In the following example, Ruek is connecting to a PostgreSQL server running on host `pg` using the username `ruek` and password `ruek`. If you are running PostgreSQL in docker, you probably will need to specify the `--network` option to connect to a container network (e.g. `--network=ruek-net`) + +e.g. +```sh +docker run --name=ruek -e PGHOST=pg -e PGUSER=ruek -e PGPASSWORD=ruek -p 8080:8080 -d uatuko/ruek:latest +``` + +### Compiling from source + +#### Prerequisites + +* [CMake](https://cmake.org) (>= 3.23) +* [Protobuf](https://protobuf.dev) (>= 3.15) +* [libpq](https://www.postgresql.org/docs/current/libpq.html) + +#### Build with CMake + +> [!NOTE] +> The following should result in a Ruek executable at `.build/bin/ruek`. + +```sh +# generate build files +cmake -B .build \ + -DCMAKE_BUILD_TYPE=Release \ + -DPostgreSQL_ADDITIONAL_VERSIONS=16 \ + -DRUEK_ENABLE_COVERAGE=OFF \ + -DRUEK_BUILD_TESTING=OFF + +# compile +cmake --build .build --target ruek +``` + + +### Setting-up PostgreSQL + +``` +❯ psql --dbname=postgres +psql (16.1) +Type "help" for help. + +postgres=# create user ruek; +CREATE ROLE +postgres=# create database ruek owner ruek; +CREATE DATABASE +``` + +``` +❯ psql --username=ruek --dbname=ruek < db/schema.sql +``` + +### Running + +``` +❯ PGDATABASE=ruek PGUSER=ruek ./.build/bin/ruek +Listening on [127.0.0.1:8080] ... +``` diff --git a/docs/api/v1/relations.md b/docs/api/v1/relations.md index 890fa0f..bc39e93 100644 --- a/docs/api/v1/relations.md +++ b/docs/api/v1/relations.md @@ -186,7 +186,7 @@ rpc ListRight(RelationsListRightRequest) returns (RelationsListRightResponse) { | `right` | (oneof) | | | [ `right` ] right_entity | [`Entity`](#entity) | | | [ `right` ] right_principal_id | `string` | | -| strategy | (optional) `uint32` | Lookup strategy to use (default `2`). See [lookup strategies](#a1---lookup-strategies). | +| strategy | (optional) `uint32` | Lookup strategy to use (default `2`). See [lookup strategies](#a1-lookup-strategies). | | cost_limit | (optional) `uint32` | A value between `1` and `65535` to limit the lookup cost (default `1000`). | ### RelationsCheckResponse diff --git a/docs/rebac.md b/docs/rebac.md index 572ef7f..08c8523 100644 --- a/docs/rebac.md +++ b/docs/rebac.md @@ -61,7 +61,8 @@ To derive the relation `[]user:jane/reader/doc:notes.txt` using a BFS[^bfs] grap (which has **O(v+e)** complexity), we will need to read 10,003 tuples. This can be really slow depending on DB load and number of concurrent requests. -> 💡 This is only an illustrative example. In reality, Ruek traverse the relations graphs from right +> [!TIP] +> This is only an illustrative example. In reality, Ruek traverse the relations graphs from right > to left which will result in only 3 reads in this instance. ![Relations Graph #02](./assets/rebac-relations-graph-02.svg) @@ -71,7 +72,8 @@ strategies to suite different shapes of relations graphs. ### Direct -> 💡 Best for reads (**O(1)**), _can be_ worst for writes (**O(1+l+r)**). +> [!TIP] +> Best for reads (**O(1)**), _can be_ worst for writes (**O(1+l+r)**). _Direct_ strategy optimise for **O(1)** relations checks at the expense of computing and storing derived relations during creation. @@ -88,7 +90,8 @@ the relations graph and compute and store the derived tuple `t2-1`. This ensures ### Graph -> 💡 Best for writes (**O(1)**), _can be_ worst for reads (**O(1+v+e)**). +> [!TIP] +> Best for writes (**O(1)**), _can be_ worst for reads (**O(1+v+e)**). _Graph_ strategy does not perform any additional computations when creating relations resulting in **O(1)** writes. When checking relations, if a direct relation does not exists Ruek will use a graph traversal @@ -97,7 +100,8 @@ of the relations graph. ### Set -> 💡 A balance between reads and writes (**O(1+n+m)**), best for large datasets. +> [!TIP] +> A balance between reads and writes (**O(1+n+m)**), best for large datasets. _Set_ strategy require relations to be defined between principals (e.g. users, groups) and entities. When creating relations, Ruek will analyse the relations graph and compute and store derived relations