From 09a25b4063abcfdcd4c0de315a2ef088d6d4e72e Mon Sep 17 00:00:00 2001 From: Patrik Date: Mon, 22 Mar 2021 16:12:28 +0100 Subject: [PATCH] docs: add check- and expand-API guides (#493) --- .schema/swagger.json | 2 +- .../00-create-tuples/cli.sh | 23 ++++ .../00-create-tuples/curl.sh | 24 ++++ .../00-create-tuples/expected_output.txt | 1 + .../00-create-tuples/index.js | 91 +++++++++++++ .../00-create-tuples/main.go | 125 +++++++++++++++++ .../01-expand-beach/cli.sh | 6 + .../01-expand-beach/curl.sh | 10 ++ .../01-expand-beach/expected_output.txt | 30 ++++ .../01-expand-beach/index.js | 53 ++++++++ .../01-expand-beach/main.go | 47 +++++++ .../99-cleanup/cli.sh | 13 ++ .../99-cleanup/curl.sh | 21 +++ .../99-cleanup/expected_output.txt | 0 .../99-cleanup/index.js | 44 ++++++ .../99-cleanup/main.go | 57 ++++++++ .../expand-api-display-access/keto.yml | 9 ++ .../00-create-tuples/cli.sh | 20 +++ .../00-create-tuples/curl.sh | 21 +++ .../00-create-tuples/expected_output.txt | 1 + .../00-create-tuples/index.js | 40 ++++++ .../00-create-tuples/main.go | 72 ++++++++++ .../01-list-PM/cli.sh | 7 + .../01-list-PM/curl.sh | 9 ++ .../01-list-PM/expected_output.txt | 3 + .../01-list-PM/index.js | 33 +++++ .../01-list-PM/main.go | 36 +++++ .../02-list-coffee-break/cli.sh | 7 + .../02-list-coffee-break/curl.sh | 9 ++ .../02-list-coffee-break/expected_output.txt | 4 + .../02-list-coffee-break/index.js | 30 ++++ .../02-list-coffee-break/main.go | 34 +++++ .../99-cleanup/cli.sh | 9 ++ .../99-cleanup/curl.sh | 13 ++ .../99-cleanup/expected_output.txt | 0 .../99-cleanup/index.js | 39 ++++++ .../99-cleanup/main.go | 52 +++++++ .../list-api-display-objects/keto.yml | 7 + .../00-write-direct-access/cli.sh | 2 + .../00-write-direct-access/index.js | 2 +- .../01-check-direct-access/cli.sh | 2 + .../01-check-direct-access/index.js | 2 +- .../99-cleanup/cli.sh | 2 + contrib/docs-code-samples/test.sh | 10 +- .../expand-api-display-who-has-access.mdx | 102 ++++++++++++++ docs/docs/guides/list-api-display-objects.mdx | 128 ++++++++++++++++++ docs/docs/index.md | 21 ++- docs/package-lock.json | 12 +- docs/package.json | 2 +- docs/sidebar.json | 4 +- docs/src/theme/CodeFromRemote.js | 6 +- docs/src/theme/CodeTabs/index.js | 66 +++++---- internal/e2e/http_client_test.go | 2 +- internal/e2e/rest_client_test.go | 2 +- internal/expand/handler.go | 4 +- internal/expand/handler_test.go | 6 +- .../client/read/get_expand_parameters.go | 32 ++--- 57 files changed, 1323 insertions(+), 86 deletions(-) create mode 100755 contrib/docs-code-samples/expand-api-display-access/00-create-tuples/cli.sh create mode 100755 contrib/docs-code-samples/expand-api-display-access/00-create-tuples/curl.sh create mode 100644 contrib/docs-code-samples/expand-api-display-access/00-create-tuples/expected_output.txt create mode 100644 contrib/docs-code-samples/expand-api-display-access/00-create-tuples/index.js create mode 100644 contrib/docs-code-samples/expand-api-display-access/00-create-tuples/main.go create mode 100755 contrib/docs-code-samples/expand-api-display-access/01-expand-beach/cli.sh create mode 100755 contrib/docs-code-samples/expand-api-display-access/01-expand-beach/curl.sh create mode 100644 contrib/docs-code-samples/expand-api-display-access/01-expand-beach/expected_output.txt create mode 100644 contrib/docs-code-samples/expand-api-display-access/01-expand-beach/index.js create mode 100644 contrib/docs-code-samples/expand-api-display-access/01-expand-beach/main.go create mode 100755 contrib/docs-code-samples/expand-api-display-access/99-cleanup/cli.sh create mode 100755 contrib/docs-code-samples/expand-api-display-access/99-cleanup/curl.sh create mode 100644 contrib/docs-code-samples/expand-api-display-access/99-cleanup/expected_output.txt create mode 100644 contrib/docs-code-samples/expand-api-display-access/99-cleanup/index.js create mode 100644 contrib/docs-code-samples/expand-api-display-access/99-cleanup/main.go create mode 100644 contrib/docs-code-samples/expand-api-display-access/keto.yml create mode 100755 contrib/docs-code-samples/list-api-display-objects/00-create-tuples/cli.sh create mode 100755 contrib/docs-code-samples/list-api-display-objects/00-create-tuples/curl.sh create mode 100644 contrib/docs-code-samples/list-api-display-objects/00-create-tuples/expected_output.txt create mode 100644 contrib/docs-code-samples/list-api-display-objects/00-create-tuples/index.js create mode 100644 contrib/docs-code-samples/list-api-display-objects/00-create-tuples/main.go create mode 100755 contrib/docs-code-samples/list-api-display-objects/01-list-PM/cli.sh create mode 100755 contrib/docs-code-samples/list-api-display-objects/01-list-PM/curl.sh create mode 100644 contrib/docs-code-samples/list-api-display-objects/01-list-PM/expected_output.txt create mode 100644 contrib/docs-code-samples/list-api-display-objects/01-list-PM/index.js create mode 100644 contrib/docs-code-samples/list-api-display-objects/01-list-PM/main.go create mode 100755 contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/cli.sh create mode 100755 contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/curl.sh create mode 100644 contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/expected_output.txt create mode 100644 contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/index.js create mode 100644 contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/main.go create mode 100755 contrib/docs-code-samples/list-api-display-objects/99-cleanup/cli.sh create mode 100755 contrib/docs-code-samples/list-api-display-objects/99-cleanup/curl.sh create mode 100644 contrib/docs-code-samples/list-api-display-objects/99-cleanup/expected_output.txt create mode 100644 contrib/docs-code-samples/list-api-display-objects/99-cleanup/index.js create mode 100644 contrib/docs-code-samples/list-api-display-objects/99-cleanup/main.go create mode 100644 contrib/docs-code-samples/list-api-display-objects/keto.yml create mode 100644 docs/docs/guides/expand-api-display-who-has-access.mdx create mode 100644 docs/docs/guides/list-api-display-objects.mdx diff --git a/.schema/swagger.json b/.schema/swagger.json index 5bd56ba89..8832546ae 100755 --- a/.schema/swagger.json +++ b/.schema/swagger.json @@ -290,7 +290,7 @@ { "type": "integer", "format": "int64", - "name": "depth", + "name": "max-depth", "in": "query" } ], diff --git a/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/cli.sh b/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/cli.sh new file mode 100755 index 000000000..2f5bdd1b2 --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/cli.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -euo pipefail + +export KETO_WRITE_REMOTE="127.0.0.1:4467" + +echo '// ownership +directories:/photos#owner@maureen +files:/photos/beach.jpg#owner@maureen +files:/photos/mountains.jpg#owner@laura + +// maureen granted access to /photos to laura +directories:/photos#access@laura + +// the following tuples are defined implicitly through subject set rewrites (not supported yet) +directories:/photos#access@(directories:/photos#owner) +files:/photos/beach.jpg#access@(files:/photos/beach.jpg#owner) +files:/photos/beach.jpg#access@(directories:/photos#access) +files:/photos/mountains.jpg#access@(files:/photos/mountains.jpg#owner) +files:/photos/mountains.jpg#access@(directories:/photos#access)' | \ + keto relation-tuple parse - --format json | \ + keto relation-tuple create - >/dev/null \ + && echo "Successfully created tuples" \ + || echo "Encountered error" diff --git a/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/curl.sh b/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/curl.sh new file mode 100755 index 000000000..7b8a427d3 --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/curl.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -euo pipefail + +echo '// ownership +directories:/photos#owner@maureen +files:/photos/beach.jpg#owner@maureen +files:/photos/mountains.jpg#owner@laura + +// maureen granted access to /photos to laura +directories:/photos#access@laura + +// the following tuples are defined implicitly through subject set rewrites (not supported yet) +directories:/photos#access@(directories:/photos#owner) +files:/photos/beach.jpg#access@(files:/photos/beach.jpg#owner) +files:/photos/beach.jpg#access@(directories:/photos#access) +files:/photos/mountains.jpg#access@(files:/photos/mountains.jpg#owner) +files:/photos/mountains.jpg#access@(directories:/photos#access)' | \ + keto relation-tuple parse - --format json | \ + jq "[ .[] | { relation_tuple: . , action: \"insert\" } ]" -c | \ + curl -X PATCH --silent --fail \ + --data @- \ + http://127.0.0.1:4467/relationtuple + +echo "Successfully created tuples" diff --git a/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/expected_output.txt b/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/expected_output.txt new file mode 100644 index 000000000..6306203bb --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/expected_output.txt @@ -0,0 +1 @@ +Successfully created tuples diff --git a/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/index.js b/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/index.js new file mode 100644 index 000000000..777e03131 --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/index.js @@ -0,0 +1,91 @@ +import grpc from '@ory/keto-acl/node_modules/@grpc/grpc-js/build/src/index.js' +import acl from '@ory/keto-acl/acl_pb.js' +import writeService from '@ory/keto-acl/write_service_grpc_pb.js' +import writeData from '@ory/keto-acl/write_service_pb.js' + +const writeClient = new writeService.WriteServiceClient( + '127.0.0.1:4467', + grpc.credentials.createInsecure() +) + +const writeRequest = new writeData.TransactRelationTuplesRequest() + +const insert = (tuple) => { + const tupleDelta = new writeData.RelationTupleDelta() + tupleDelta.setAction(writeData.RelationTupleDelta.Action.INSERT) + tupleDelta.setRelationTuple(tuple) + + writeRequest.addRelationTupleDeltas(tupleDelta) +} + +const addSimpleTuple = (namespace, object, relation, user) => { + const relationTuple = new acl.RelationTuple() + relationTuple.setNamespace(namespace) + relationTuple.setObject(object) + relationTuple.setRelation(relation) + + const sub = new acl.Subject() + sub.setId(user) + relationTuple.setSubject(sub) + + insert(relationTuple) +} + +// ownership +addSimpleTuple('directories', '/photos', 'owner', 'maureen') +addSimpleTuple('files', '/photos/beach.jpg', 'owner', 'maureen') +addSimpleTuple('files', '/photos/mountains.jpg', 'owner', 'laura') +// granted access +addSimpleTuple('directories', '/photos', 'access', 'laura') + +// should be subject set rewrite +// owners have access +;[ + ['files', '/photos/beach.jpg'], + ['files', '/photos/mountains.jpg'], + ['directories', '/photos'] +].forEach(([namespace, object]) => { + const relationTuple = new acl.RelationTuple() + relationTuple.setNamespace(namespace) + relationTuple.setObject(object) + relationTuple.setRelation('access') + + const subjectSet = new acl.SubjectSet() + subjectSet.setNamespace(namespace) + subjectSet.setObject(object) + subjectSet.setRelation('owner') + + const sub = new acl.Subject() + sub.setSet(subjectSet) + relationTuple.setSubject(sub) + + insert(relationTuple) +}) + +// should be subject set rewrite +// access on parent means access on child +;['/photos/beach.jpg', '/photos/mountains.jpg'].forEach((file) => { + const relationTuple = new acl.RelationTuple() + relationTuple.setNamespace('files') + relationTuple.setObject(file) + relationTuple.setRelation('access') + + const subjectSet = new acl.SubjectSet() + subjectSet.setNamespace('directories') + subjectSet.setObject('/photos') + subjectSet.setRelation('access') + + const sub = new acl.Subject() + sub.setSet(subjectSet) + relationTuple.setSubject(sub) + + insert(relationTuple) +}) + +writeClient.transactRelationTuples(writeRequest, (error) => { + if (error) { + console.log('Encountered error', error) + } else { + console.log('Successfully created tuples') + } +}) diff --git a/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/main.go b/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/main.go new file mode 100644 index 000000000..07046dc44 --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/00-create-tuples/main.go @@ -0,0 +1,125 @@ +package main + +import ( + "context" + "fmt" + + "google.golang.org/grpc" + + acl "github.com/ory/keto/proto/ory/keto/acl/v1alpha1" +) + +func main() { + conn, err := grpc.Dial("127.0.0.1:4467", grpc.WithInsecure()) + if err != nil { + panic("Encountered error: " + err.Error()) + } + + client := acl.NewWriteServiceClient(conn) + + //directories:/photos#owner@maureen + //files:/photos/beach.jpg#owner@maureen + //files:/photos/mountains.jpg#owner@laura + //directories:/photos#access@laura + //directories:/photos#access@(directories:/photos#owner) + //files:/photos/beach.jpg#access@(files:/photos/beach.jpg#owner) + //files:/photos/beach.jpg#access@(directories:/photos#access) + //files:/photos/mountains.jpg#access@(files:/photos/mountains.jpg#owner) + //files:/photos/mountains.jpg#access@(directories:/photos#access) + + tupleDeltas := []*acl.RelationTupleDelta{ + // ownership + { + Action: acl.RelationTupleDelta_INSERT, + RelationTuple: &acl.RelationTuple{ + Namespace: "directories", + Object: "/photos", + Relation: "owner", + Subject: &acl.Subject{Ref: &acl.Subject_Id{ + Id: "maureen", + }}, + }, + }, + { + Action: acl.RelationTupleDelta_INSERT, + RelationTuple: &acl.RelationTuple{ + Namespace: "files", + Object: "/photos/beach.jpg", + Relation: "owner", + Subject: &acl.Subject{Ref: &acl.Subject_Id{ + Id: "maureen", + }}, + }, + }, + { + Action: acl.RelationTupleDelta_INSERT, + RelationTuple: &acl.RelationTuple{ + Namespace: "files", + Object: "/photos/mountains.jpg", + Relation: "owner", + Subject: &acl.Subject{Ref: &acl.Subject_Id{ + Id: "laura", + }}, + }, + }, + // granted access + { + Action: acl.RelationTupleDelta_INSERT, + RelationTuple: &acl.RelationTuple{ + Namespace: "directories", + Object: "/photos", + Relation: "access", + Subject: &acl.Subject{Ref: &acl.Subject_Id{ + Id: "laura", + }}, + }, + }, + } + // should be subject set rewrite + // owners have access + for _, o := range []struct{ n, o string }{ + {"files", "/photos/beach.jpg"}, + {"files", "/photos/mountains.jpg"}, + {"directories", "/photos"}, + } { + tupleDeltas = append(tupleDeltas, &acl.RelationTupleDelta{ + Action: acl.RelationTupleDelta_INSERT, + RelationTuple: &acl.RelationTuple{ + Namespace: o.n, + Object: o.o, + Relation: "access", + Subject: &acl.Subject{Ref: &acl.Subject_Set{Set: &acl.SubjectSet{ + Namespace: o.n, + Object: o.o, + Relation: "owner", + }}}, + }, + }) + } + // should be subject set rewrite + // access on parent means access on child + for _, obj := range []string{"/photos/beach.jpg", "/photos/mountains.jpg"} { + tupleDeltas = append(tupleDeltas, &acl.RelationTupleDelta{ + Action: acl.RelationTupleDelta_INSERT, + RelationTuple: &acl.RelationTuple{ + Namespace: "files", + Object: obj, + Relation: "access", + Subject: &acl.Subject{Ref: &acl.Subject_Set{Set: &acl.SubjectSet{ + Namespace: "directories", + Object: "/photos", + Relation: "access", + }}}, + }, + }) + } + + _, err = client.TransactRelationTuples(context.Background(), &acl.TransactRelationTuplesRequest{ + RelationTupleDeltas: tupleDeltas, + }) + if err != nil { + panic("Encountered error: " + err.Error()) + } + + fmt.Println("Successfully created tuples") +} diff --git a/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/cli.sh b/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/cli.sh new file mode 100755 index 000000000..bd70fadc5 --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/cli.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -euo pipefail + +export KETO_READ_REMOTE="127.0.0.1:4466" + +keto expand access files /photos/beach.jpg --format json-pretty --max-depth 3 diff --git a/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/curl.sh b/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/curl.sh new file mode 100755 index 000000000..709813adb --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/curl.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -euo pipefail + +curl -G --silent \ + --data-urlencode "namespace=files" \ + --data-urlencode "relation=access" \ + --data-urlencode "object=/photos/beach.jpg" \ + --data-urlencode "max-depth=3" \ + http://127.0.0.1:4466/expand | \ + jq diff --git a/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/expected_output.txt b/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/expected_output.txt new file mode 100644 index 000000000..550b1ac47 --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/expected_output.txt @@ -0,0 +1,30 @@ +{ + "type": "union", + "subject": "files:/photos/beach.jpg#access", + "children": [ + { + "type": "union", + "subject": "directories:/photos#access", + "children": [ + { + "type": "leaf", + "subject": "directories:/photos#owner" + }, + { + "type": "leaf", + "subject": "laura" + } + ] + }, + { + "type": "union", + "subject": "files:/photos/beach.jpg#owner", + "children": [ + { + "type": "leaf", + "subject": "maureen" + } + ] + } + ] +} diff --git a/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/index.js b/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/index.js new file mode 100644 index 000000000..d846ae47c --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/index.js @@ -0,0 +1,53 @@ +import grpc from '@ory/keto-acl/node_modules/@grpc/grpc-js/build/src/index.js' +import expandService from '@ory/keto-acl/expand_service_grpc_pb.js' +import expandData from '@ory/keto-acl/expand_service_pb.js' +import acl from '@ory/keto-acl/acl_pb.js' + +const expandClient = new expandService.ExpandServiceClient( + '127.0.0.1:4466', + grpc.credentials.createInsecure() +) + +const subjectSet = new acl.SubjectSet() +subjectSet.setNamespace('files') +subjectSet.setRelation('access') +subjectSet.setObject('/photos/beach.jpg') + +const sub = new acl.Subject() +sub.setSet(subjectSet) + +const expandRequest = new expandData.ExpandRequest() +expandRequest.setSubject(sub) +expandRequest.setMaxDepth(3) + +// helper to get a nice result +const subjectString = (subject) => { + if (subject.hasId()) { + return subject.getId() + } + const set = subject.getSet() + return set.getNamespace() + ':' + set.getObject() + '#' + set.getRelation() +} + +// helper to get a nice result +const prettyTree = (tree) => { + const [nodeType, subject, children] = [ + tree.getNodeType(), + subjectString(tree.getSubject()), + tree.getChildrenList() + ] + switch (nodeType) { + case expandData.NodeType.NODE_TYPE_LEAF: + return { type: 'leaf', subject } + case expandData.NodeType.NODE_TYPE_UNION: + return { type: 'union', subject, children: children.map(prettyTree) } + } +} + +expandClient.expand(expandRequest, (error, resp) => { + if (error) { + console.log('Encountered error:', error) + } else { + console.log(JSON.stringify(prettyTree(resp.getTree()), null, 2)) + } +}) diff --git a/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/main.go b/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/main.go new file mode 100644 index 000000000..772211745 --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/01-expand-beach/main.go @@ -0,0 +1,47 @@ +package main + +import ( + "context" + "encoding/json" + "os" + + "github.com/ory/keto/internal/expand" + + "google.golang.org/grpc" + + acl "github.com/ory/keto/proto/ory/keto/acl/v1alpha1" +) + +func main() { + conn, err := grpc.Dial("127.0.0.1:4466", grpc.WithInsecure()) + if err != nil { + panic(err) + } + + client := acl.NewExpandServiceClient(conn) + + res, err := client.Expand(context.Background(), &acl.ExpandRequest{ + Subject: &acl.Subject{ + Ref: &acl.Subject_Set{Set: &acl.SubjectSet{ + Namespace: "files", + Object: "/photos/beach.jpg", + Relation: "access", + }}, + }, + MaxDepth: 3, + }) + if err != nil { + panic(err) + } + + tree, err := expand.TreeFromProto(res.Tree) + if err != nil { + panic(err) + } + + enc := json.NewEncoder(os.Stdout) + enc.SetIndent("", " ") + if err := enc.Encode(tree); err != nil { + panic(err.Error()) + } +} diff --git a/contrib/docs-code-samples/expand-api-display-access/99-cleanup/cli.sh b/contrib/docs-code-samples/expand-api-display-access/99-cleanup/cli.sh new file mode 100755 index 000000000..9b2d81730 --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/99-cleanup/cli.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -euo pipefail + +export KETO_READ_REMOTE="127.0.0.1:4466" +export KETO_WRITE_REMOTE="127.0.0.1:4467" + +keto relation-tuple get files --format json | \ + jq ".relation_tuples" | \ + keto relation-tuple delete - -q > /dev/null + +keto relation-tuple get directories --format json | \ + jq ".relation_tuples" | \ + keto relation-tuple delete - -q > /dev/null diff --git a/contrib/docs-code-samples/expand-api-display-access/99-cleanup/curl.sh b/contrib/docs-code-samples/expand-api-display-access/99-cleanup/curl.sh new file mode 100755 index 000000000..4c995d5fa --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/99-cleanup/curl.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -euo pipefail + +export KETO_READ_REMOTE="127.0.0.1:4466" +export KETO_WRITE_REMOTE="127.0.0.1:4467" + +curl -G --silent \ + --data-urlencode "namespace=files" \ + http://127.0.0.1:4466/relationtuple | \ + jq "[ .relation_tuples[] | { relation_tuple: . , action: \"delete\" } ]" -c | \ + curl -X PATCH --silent --fail \ + --data @- \ + http://127.0.0.1:4467/relationtuple + +curl -G --silent \ + --data-urlencode "namespace=directories" \ + http://127.0.0.1:4466/relationtuple | \ + jq "[ .relation_tuples[] | { relation_tuple: . , action: \"delete\" } ]" -c | \ + curl -X PATCH --silent --fail \ + --data @- \ + http://127.0.0.1:4467/relationtuple diff --git a/contrib/docs-code-samples/expand-api-display-access/99-cleanup/expected_output.txt b/contrib/docs-code-samples/expand-api-display-access/99-cleanup/expected_output.txt new file mode 100644 index 000000000..e69de29bb diff --git a/contrib/docs-code-samples/expand-api-display-access/99-cleanup/index.js b/contrib/docs-code-samples/expand-api-display-access/99-cleanup/index.js new file mode 100644 index 000000000..b4d04340c --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/99-cleanup/index.js @@ -0,0 +1,44 @@ +import grpc from '@ory/keto-acl/node_modules/@grpc/grpc-js/build/src/index.js' +import writeService from '@ory/keto-acl/write_service_grpc_pb.js' +import writeData from '@ory/keto-acl/write_service_pb.js' +import readService from '@ory/keto-acl/read_service_grpc_pb.js' +import readData from '@ory/keto-acl/read_service_pb.js' + +const readClient = new readService.ReadServiceClient( + '127.0.0.1:4466', + grpc.credentials.createInsecure() +) + +const purgeNamespace = (namespace) => { + const query = new readData.ListRelationTuplesRequest.Query() + query.setNamespace(namespace) + + const readRequest = new readData.ListRelationTuplesRequest() + readRequest.setQuery(query) + + readClient.listRelationTuples(readRequest, (err, resp) => { + const writeClient = new writeService.WriteServiceClient( + '127.0.0.1:4467', + grpc.credentials.createInsecure() + ) + + const writeRequest = new writeData.TransactRelationTuplesRequest() + + resp.getRelationTuplesList().forEach((tuple) => { + const tupleDelta = new writeData.RelationTupleDelta() + tupleDelta.setAction(writeData.RelationTupleDelta.Action.DELETE) + tupleDelta.setRelationTuple(tuple) + writeRequest.addRelationTupleDeltas(tupleDelta) + }) + + writeClient.transactRelationTuples(writeRequest, (err) => { + if (err) { + console.log('Unexpected err', err) + return 1 + } + }) + }) +} + +purgeNamespace('files') +purgeNamespace('directories') diff --git a/contrib/docs-code-samples/expand-api-display-access/99-cleanup/main.go b/contrib/docs-code-samples/expand-api-display-access/99-cleanup/main.go new file mode 100644 index 000000000..4c8253fec --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/99-cleanup/main.go @@ -0,0 +1,57 @@ +// +build docscodesamples + +package main + +import ( + "context" + + "google.golang.org/grpc" + "google.golang.org/protobuf/proto" + + acl "github.com/ory/keto/proto/ory/keto/acl/v1alpha1" +) + +func purgeNamespace(nspace string) { + rc, err := grpc.Dial("127.0.0.1:4466", grpc.WithInsecure()) + if err != nil { + panic(err) + } + defer rc.Close() + + rClient := acl.NewReadServiceClient(rc) + resp, err := rClient.ListRelationTuples(context.Background(), &acl.ListRelationTuplesRequest{ + Query: &acl.ListRelationTuplesRequest_Query{ + Namespace: nspace, + }, + }) + if err != nil { + panic(err) + } + + wc, err := grpc.Dial("127.0.0.1:4467", grpc.WithInsecure()) + if err != nil { + panic(err) + } + defer wc.Close() + + deltas := make([]*acl.RelationTupleDelta, len(resp.RelationTuples)) + for i, rt := range resp.RelationTuples { + deltas[i] = &acl.RelationTupleDelta{ + Action: acl.RelationTupleDelta_DELETE, + RelationTuple: proto.Clone(rt).(*acl.RelationTuple), + } + } + + wClient := acl.NewWriteServiceClient(wc) + _, err = wClient.TransactRelationTuples(context.Background(), &acl.TransactRelationTuplesRequest{ + RelationTupleDeltas: deltas, + }) + if err != nil { + panic(err) + } +} + +func main() { + purgeNamespace("directories") + purgeNamespace("files") +} diff --git a/contrib/docs-code-samples/expand-api-display-access/keto.yml b/contrib/docs-code-samples/expand-api-display-access/keto.yml new file mode 100644 index 000000000..5b8f5866a --- /dev/null +++ b/contrib/docs-code-samples/expand-api-display-access/keto.yml @@ -0,0 +1,9 @@ +dsn: memory +log: + level: trace + +namespaces: + - name: files + id: 1 + - name: directories + id: 2 diff --git a/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/cli.sh b/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/cli.sh new file mode 100755 index 000000000..5010e73e9 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/cli.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -euo pipefail + +export KETO_WRITE_REMOTE="127.0.0.1:4467" + +echo 'chats:memes#member@PM +chats:memes#member@Vincent +chats:memes#member@Julia + +chats:cars#member@PM +chats:cars#member@Julia + +chats:coffee-break#member@PM +chats:coffee-break#member@Vincent +chats:coffee-break#member@Julia +chats:coffee-break#member@Patrik' | \ + keto relation-tuple parse - --format json | \ + keto relation-tuple create - >/dev/null \ + && echo "Successfully created tuples" \ + || echo "Encountered error" diff --git a/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/curl.sh b/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/curl.sh new file mode 100755 index 000000000..2a2a8c579 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/curl.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -euo pipefail + +echo 'chats:memes#member@PM +chats:memes#member@Vincent +chats:memes#member@Julia + +chats:cars#member@PM +chats:cars#member@Julia + +chats:coffee-break#member@PM +chats:coffee-break#member@Vincent +chats:coffee-break#member@Julia +chats:coffee-break#member@Patrik' | \ + keto relation-tuple parse - --format json | \ + jq "[ .[] | { relation_tuple: . , action: \"insert\" } ]" -c | \ + curl -X PATCH --silent --fail \ + --data @- \ + http://127.0.0.1:4467/relationtuple + +echo "Successfully created tuples" diff --git a/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/expected_output.txt b/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/expected_output.txt new file mode 100644 index 000000000..6306203bb --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/expected_output.txt @@ -0,0 +1 @@ +Successfully created tuples diff --git a/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/index.js b/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/index.js new file mode 100644 index 000000000..6c9dc9bb4 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/index.js @@ -0,0 +1,40 @@ +import grpc from '@ory/keto-acl/node_modules/@grpc/grpc-js/build/src/index.js' +import acl from '@ory/keto-acl/acl_pb.js' +import writeService from '@ory/keto-acl/write_service_grpc_pb.js' +import writeData from '@ory/keto-acl/write_service_pb.js' + +const writeClient = new writeService.WriteServiceClient( + '127.0.0.1:4467', + grpc.credentials.createInsecure() +) + +const writeRequest = new writeData.TransactRelationTuplesRequest() + +const addToChat = (chatName) => (user) => { + const relationTuple = new acl.RelationTuple() + relationTuple.setNamespace('chats') + relationTuple.setObject(chatName) + relationTuple.setRelation('member') + + const sub = new acl.Subject() + sub.setId(user) + relationTuple.setSubject(sub) + + const tupleDelta = new writeData.RelationTupleDelta() + tupleDelta.setAction(writeData.RelationTupleDelta.Action.INSERT) + tupleDelta.setRelationTuple(relationTuple) + + writeRequest.addRelationTupleDeltas(tupleDelta) +} + +;['PM', 'Vincent', 'Julia'].forEach(addToChat('memes')) +;['PM', 'Julia'].forEach(addToChat('cars')) +;['PM', 'Vincent', 'Julia', 'Patrik'].forEach(addToChat('coffee-break')) + +writeClient.transactRelationTuples(writeRequest, (error) => { + if (error) { + console.log('Encountered error', error) + } else { + console.log('Successfully created tuples') + } +}) diff --git a/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/main.go b/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/main.go new file mode 100644 index 000000000..68befdd0d --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/00-create-tuples/main.go @@ -0,0 +1,72 @@ +package main + +import ( + "context" + "fmt" + + "google.golang.org/grpc" + + acl "github.com/ory/keto/proto/ory/keto/acl/v1alpha1" +) + +func main() { + conn, err := grpc.Dial("127.0.0.1:4467", grpc.WithInsecure()) + if err != nil { + panic("Encountered error: " + err.Error()) + } + + client := acl.NewWriteServiceClient(conn) + + var tupleDeltas []*acl.RelationTupleDelta + // memes + for _, user := range []string{"PM", "Vincent", "Julia"} { + tupleDeltas = append(tupleDeltas, &acl.RelationTupleDelta{ + Action: acl.RelationTupleDelta_INSERT, + RelationTuple: &acl.RelationTuple{ + Namespace: "chats", + Object: "memes", + Relation: "member", + Subject: &acl.Subject{Ref: &acl.Subject_Id{ + Id: user, + }}, + }, + }) + } + // cars + for _, user := range []string{"PM", "Julia"} { + tupleDeltas = append(tupleDeltas, &acl.RelationTupleDelta{ + Action: acl.RelationTupleDelta_INSERT, + RelationTuple: &acl.RelationTuple{ + Namespace: "chats", + Object: "cars", + Relation: "member", + Subject: &acl.Subject{Ref: &acl.Subject_Id{ + Id: user, + }}, + }, + }) + } + // coffee-break + for _, user := range []string{"PM", "Vincent", "Julia", "Patrik"} { + tupleDeltas = append(tupleDeltas, &acl.RelationTupleDelta{ + Action: acl.RelationTupleDelta_INSERT, + RelationTuple: &acl.RelationTuple{ + Namespace: "chats", + Object: "coffee-break", + Relation: "member", + Subject: &acl.Subject{Ref: &acl.Subject_Id{ + Id: user, + }}, + }, + }) + } + + _, err = client.TransactRelationTuples(context.Background(), &acl.TransactRelationTuplesRequest{ + RelationTupleDeltas: tupleDeltas, + }) + if err != nil { + panic("Encountered error: " + err.Error()) + } + + fmt.Println("Successfully created tuples") +} diff --git a/contrib/docs-code-samples/list-api-display-objects/01-list-PM/cli.sh b/contrib/docs-code-samples/list-api-display-objects/01-list-PM/cli.sh new file mode 100755 index 000000000..a0763cc68 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/01-list-PM/cli.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -euo pipefail + +export KETO_READ_REMOTE="127.0.0.1:4466" + +keto relation-tuple get chats --relation member --subject PM --format json | \ + jq ".relation_tuples[] | .object" -r diff --git a/contrib/docs-code-samples/list-api-display-objects/01-list-PM/curl.sh b/contrib/docs-code-samples/list-api-display-objects/01-list-PM/curl.sh new file mode 100755 index 000000000..9e67346bf --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/01-list-PM/curl.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -euo pipefail + +curl -G --silent \ + --data-urlencode "namespace=chats" \ + --data-urlencode "relation=member" \ + --data-urlencode "subject=PM" \ + http://127.0.0.1:4466/relationtuple | \ + jq ".relation_tuples[] | .object" -r diff --git a/contrib/docs-code-samples/list-api-display-objects/01-list-PM/expected_output.txt b/contrib/docs-code-samples/list-api-display-objects/01-list-PM/expected_output.txt new file mode 100644 index 000000000..7f7652242 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/01-list-PM/expected_output.txt @@ -0,0 +1,3 @@ +cars +coffee-break +memes diff --git a/contrib/docs-code-samples/list-api-display-objects/01-list-PM/index.js b/contrib/docs-code-samples/list-api-display-objects/01-list-PM/index.js new file mode 100644 index 000000000..fa0349cd6 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/01-list-PM/index.js @@ -0,0 +1,33 @@ +import grpc from '@ory/keto-acl/node_modules/@grpc/grpc-js/build/src/index.js' +import acl from '@ory/keto-acl/acl_pb.js' +import readService from '@ory/keto-acl/read_service_grpc_pb.js' +import readData from '@ory/keto-acl/read_service_pb.js' + +const readClient = new readService.ReadServiceClient( + '127.0.0.1:4466', + grpc.credentials.createInsecure() +) + +const readRequest = new readData.ListRelationTuplesRequest() +const query = new readData.ListRelationTuplesRequest.Query() +query.setNamespace('chats') +query.setRelation('member') + +const sub = new acl.Subject() +sub.setId('PM') +query.setSubject(sub) + +readRequest.setQuery(query) + +readClient.listRelationTuples(readRequest, (error, resp) => { + if (error) { + console.log('Encountered error:', error) + } else { + console.log( + resp + .getRelationTuplesList() + .map((tuple) => tuple.getObject()) + .join('\n') + ) + } +}) diff --git a/contrib/docs-code-samples/list-api-display-objects/01-list-PM/main.go b/contrib/docs-code-samples/list-api-display-objects/01-list-PM/main.go new file mode 100644 index 000000000..e83d0fa8b --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/01-list-PM/main.go @@ -0,0 +1,36 @@ +package main + +import ( + "context" + "fmt" + + "google.golang.org/grpc" + + acl "github.com/ory/keto/proto/ory/keto/acl/v1alpha1" +) + +func main() { + conn, err := grpc.Dial("127.0.0.1:4466", grpc.WithInsecure()) + if err != nil { + panic(err.Error()) + } + + client := acl.NewReadServiceClient(conn) + + res, err := client.ListRelationTuples(context.Background(), &acl.ListRelationTuplesRequest{ + Query: &acl.ListRelationTuplesRequest_Query{ + Namespace: "chats", + Relation: "member", + Subject: &acl.Subject{Ref: &acl.Subject_Id{ + Id: "PM", + }}, + }, + }) + if err != nil { + panic(err.Error()) + } + + for _, rt := range res.RelationTuples { + fmt.Println(rt.Object) + } +} diff --git a/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/cli.sh b/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/cli.sh new file mode 100755 index 000000000..d189f8414 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/cli.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -euo pipefail + +export KETO_READ_REMOTE="127.0.0.1:4466" + +keto relation-tuple get chats --object coffee-break --relation member --format json | \ + jq ".relation_tuples[] | .subject" -r diff --git a/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/curl.sh b/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/curl.sh new file mode 100755 index 000000000..6b7bd2152 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/curl.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -euo pipefail + +curl -G --silent \ + --data-urlencode "namespace=chats" \ + --data-urlencode "object=coffee-break" \ + --data-urlencode "relation=member" \ + http://127.0.0.1:4466/relationtuple | \ + jq ".relation_tuples[] | .subject" -r diff --git a/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/expected_output.txt b/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/expected_output.txt new file mode 100644 index 000000000..e196c528b --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/expected_output.txt @@ -0,0 +1,4 @@ +Julia +PM +Patrik +Vincent diff --git a/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/index.js b/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/index.js new file mode 100644 index 000000000..bdd72a8a3 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/index.js @@ -0,0 +1,30 @@ +import grpc from '@ory/keto-acl/node_modules/@grpc/grpc-js/build/src/index.js' +import acl from '@ory/keto-acl/acl_pb.js' +import readService from '@ory/keto-acl/read_service_grpc_pb.js' +import readData from '@ory/keto-acl/read_service_pb.js' + +const readClient = new readService.ReadServiceClient( + '127.0.0.1:4466', + grpc.credentials.createInsecure() +) + +const readRequest = new readData.ListRelationTuplesRequest() +const query = new readData.ListRelationTuplesRequest.Query() +query.setNamespace('chats') +query.setObject('coffee-break') +query.setRelation('member') + +readRequest.setQuery(query) + +readClient.listRelationTuples(readRequest, (error, resp) => { + if (error) { + console.log('Encountered error:', error) + } else { + console.log( + resp + .getRelationTuplesList() + .map((tuple) => tuple.getSubject().getId()) + .join('\n') + ) + } +}) diff --git a/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/main.go b/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/main.go new file mode 100644 index 000000000..f45309e73 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/02-list-coffee-break/main.go @@ -0,0 +1,34 @@ +package main + +import ( + "context" + "fmt" + + "google.golang.org/grpc" + + acl "github.com/ory/keto/proto/ory/keto/acl/v1alpha1" +) + +func main() { + conn, err := grpc.Dial("127.0.0.1:4466", grpc.WithInsecure()) + if err != nil { + panic(err.Error()) + } + + client := acl.NewReadServiceClient(conn) + + res, err := client.ListRelationTuples(context.Background(), &acl.ListRelationTuplesRequest{ + Query: &acl.ListRelationTuplesRequest_Query{ + Namespace: "chats", + Object: "coffee-break", + Relation: "member", + }, + }) + if err != nil { + panic(err.Error()) + } + + for _, rt := range res.RelationTuples { + fmt.Println(rt.Subject.Ref.(*acl.Subject_Id).Id) + } +} diff --git a/contrib/docs-code-samples/list-api-display-objects/99-cleanup/cli.sh b/contrib/docs-code-samples/list-api-display-objects/99-cleanup/cli.sh new file mode 100755 index 000000000..818601ea7 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/99-cleanup/cli.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -euo pipefail + +export KETO_READ_REMOTE="127.0.0.1:4466" +export KETO_WRITE_REMOTE="127.0.0.1:4467" + +keto relation-tuple get chats --format json | \ + jq ".relation_tuples" | \ + keto relation-tuple delete - -q > /dev/null diff --git a/contrib/docs-code-samples/list-api-display-objects/99-cleanup/curl.sh b/contrib/docs-code-samples/list-api-display-objects/99-cleanup/curl.sh new file mode 100755 index 000000000..e88829b88 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/99-cleanup/curl.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -euo pipefail + +export KETO_READ_REMOTE="127.0.0.1:4466" +export KETO_WRITE_REMOTE="127.0.0.1:4467" + +curl -G --silent \ + --data-urlencode "namespace=chats" \ + http://127.0.0.1:4466/relationtuple | \ + jq "[ .relation_tuples[] | { relation_tuple: . , action: \"delete\" } ]" -c | \ + curl -X PATCH --silent --fail \ + --data @- \ + http://127.0.0.1:4467/relationtuple diff --git a/contrib/docs-code-samples/list-api-display-objects/99-cleanup/expected_output.txt b/contrib/docs-code-samples/list-api-display-objects/99-cleanup/expected_output.txt new file mode 100644 index 000000000..e69de29bb diff --git a/contrib/docs-code-samples/list-api-display-objects/99-cleanup/index.js b/contrib/docs-code-samples/list-api-display-objects/99-cleanup/index.js new file mode 100644 index 000000000..b5a5907b5 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/99-cleanup/index.js @@ -0,0 +1,39 @@ +import grpc from '@ory/keto-acl/node_modules/@grpc/grpc-js/build/src/index.js' +import writeService from '@ory/keto-acl/write_service_grpc_pb.js' +import writeData from '@ory/keto-acl/write_service_pb.js' +import readService from '@ory/keto-acl/read_service_grpc_pb.js' +import readData from '@ory/keto-acl/read_service_pb.js' + +const readClient = new readService.ReadServiceClient( + '127.0.0.1:4466', + grpc.credentials.createInsecure() +) + +const query = new readData.ListRelationTuplesRequest.Query() +query.setNamespace('chats') + +const readRequest = new readData.ListRelationTuplesRequest() +readRequest.setQuery(query) + +readClient.listRelationTuples(readRequest, (err, resp) => { + const writeClient = new writeService.WriteServiceClient( + '127.0.0.1:4467', + grpc.credentials.createInsecure() + ) + + const writeRequest = new writeData.TransactRelationTuplesRequest() + + resp.getRelationTuplesList().forEach((tuple) => { + const tupleDelta = new writeData.RelationTupleDelta() + tupleDelta.setAction(writeData.RelationTupleDelta.Action.DELETE) + tupleDelta.setRelationTuple(tuple) + writeRequest.addRelationTupleDeltas(tupleDelta) + }) + + writeClient.transactRelationTuples(writeRequest, (err) => { + if (err) { + console.log('Unexpected err', err) + return 1 + } + }) +}) diff --git a/contrib/docs-code-samples/list-api-display-objects/99-cleanup/main.go b/contrib/docs-code-samples/list-api-display-objects/99-cleanup/main.go new file mode 100644 index 000000000..f2423d5fb --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/99-cleanup/main.go @@ -0,0 +1,52 @@ +// +build docscodesamples + +package main + +import ( + "context" + + "google.golang.org/grpc" + "google.golang.org/protobuf/proto" + + acl "github.com/ory/keto/proto/ory/keto/acl/v1alpha1" +) + +func main() { + rc, err := grpc.Dial("127.0.0.1:4466", grpc.WithInsecure()) + if err != nil { + panic(err) + } + defer rc.Close() + + rClient := acl.NewReadServiceClient(rc) + resp, err := rClient.ListRelationTuples(context.Background(), &acl.ListRelationTuplesRequest{ + Query: &acl.ListRelationTuplesRequest_Query{ + Namespace: "chats", + }, + }) + if err != nil { + panic(err) + } + + wc, err := grpc.Dial("127.0.0.1:4467", grpc.WithInsecure()) + if err != nil { + panic(err) + } + defer wc.Close() + + deltas := make([]*acl.RelationTupleDelta, len(resp.RelationTuples)) + for i, rt := range resp.RelationTuples { + deltas[i] = &acl.RelationTupleDelta{ + Action: acl.RelationTupleDelta_DELETE, + RelationTuple: proto.Clone(rt).(*acl.RelationTuple), + } + } + + wClient := acl.NewWriteServiceClient(wc) + _, err = wClient.TransactRelationTuples(context.Background(), &acl.TransactRelationTuplesRequest{ + RelationTupleDeltas: deltas, + }) + if err != nil { + panic(err) + } +} diff --git a/contrib/docs-code-samples/list-api-display-objects/keto.yml b/contrib/docs-code-samples/list-api-display-objects/keto.yml new file mode 100644 index 000000000..9f0a233f2 --- /dev/null +++ b/contrib/docs-code-samples/list-api-display-objects/keto.yml @@ -0,0 +1,7 @@ +dsn: memory +log: + level: trace + +namespaces: + - name: chats + id: 1 diff --git a/contrib/docs-code-samples/simple-access-check-guide/00-write-direct-access/cli.sh b/contrib/docs-code-samples/simple-access-check-guide/00-write-direct-access/cli.sh index 517318b04..6d99aff73 100755 --- a/contrib/docs-code-samples/simple-access-check-guide/00-write-direct-access/cli.sh +++ b/contrib/docs-code-samples/simple-access-check-guide/00-write-direct-access/cli.sh @@ -1,6 +1,8 @@ #!/bin/bash set -euo pipefail +export KETO_WRITE_REMOTE="127.0.0.1:4467" + echo "messages:02y_15_4w350m3#decypher@john" | \ keto relation-tuple parse - --format json | \ keto relation-tuple create - >/dev/null \ diff --git a/contrib/docs-code-samples/simple-access-check-guide/00-write-direct-access/index.js b/contrib/docs-code-samples/simple-access-check-guide/00-write-direct-access/index.js index da7856122..4f66ca800 100644 --- a/contrib/docs-code-samples/simple-access-check-guide/00-write-direct-access/index.js +++ b/contrib/docs-code-samples/simple-access-check-guide/00-write-direct-access/index.js @@ -4,7 +4,7 @@ import writeService from '@ory/keto-acl/write_service_grpc_pb.js' import writeData from '@ory/keto-acl/write_service_pb.js' const writeClient = new writeService.WriteServiceClient( - 'localhost:4467', + '127.0.0.1:4467', grpc.credentials.createInsecure() ) diff --git a/contrib/docs-code-samples/simple-access-check-guide/01-check-direct-access/cli.sh b/contrib/docs-code-samples/simple-access-check-guide/01-check-direct-access/cli.sh index 134841938..4882aafd0 100755 --- a/contrib/docs-code-samples/simple-access-check-guide/01-check-direct-access/cli.sh +++ b/contrib/docs-code-samples/simple-access-check-guide/01-check-direct-access/cli.sh @@ -1,4 +1,6 @@ #!/bin/bash set -euo pipefail +export KETO_READ_REMOTE="127.0.0.1:4466" + keto check john decypher messages 02y_15_4w350m3 diff --git a/contrib/docs-code-samples/simple-access-check-guide/01-check-direct-access/index.js b/contrib/docs-code-samples/simple-access-check-guide/01-check-direct-access/index.js index 88f8f72ac..ad0c6c489 100644 --- a/contrib/docs-code-samples/simple-access-check-guide/01-check-direct-access/index.js +++ b/contrib/docs-code-samples/simple-access-check-guide/01-check-direct-access/index.js @@ -4,7 +4,7 @@ import checkService from '@ory/keto-acl/check_service_grpc_pb.js' import checkData from '@ory/keto-acl/check_service_pb.js' const checkClient = new checkService.CheckServiceClient( - 'localhost:4466', + '127.0.0.1:4466', grpc.credentials.createInsecure() ) diff --git a/contrib/docs-code-samples/simple-access-check-guide/99-cleanup/cli.sh b/contrib/docs-code-samples/simple-access-check-guide/99-cleanup/cli.sh index c365c3605..ba2856af2 100755 --- a/contrib/docs-code-samples/simple-access-check-guide/99-cleanup/cli.sh +++ b/contrib/docs-code-samples/simple-access-check-guide/99-cleanup/cli.sh @@ -1,6 +1,8 @@ #!/bin/bash set -euo pipefail +export KETO_WRITE_REMOTE="127.0.0.1:4467" + relationtuple=' { "namespace": "messages", diff --git a/contrib/docs-code-samples/test.sh b/contrib/docs-code-samples/test.sh index c1efd9f0b..4ce40cf24 100755 --- a/contrib/docs-code-samples/test.sh +++ b/contrib/docs-code-samples/test.sh @@ -25,23 +25,25 @@ for suite in */ ; do for main in "$suite"/*/main.go; do echo "Running $main" - diff <(go run -tags docscodesamples "./$main") "$(dirname "$main")/expected_output.txt" + diff <(go run -tags docscodesamples "./$main" 2>&1) "$(dirname "$main")/expected_output.txt" done for index in "$suite"/*/index.js; do echo "Running $index" - diff <(node "$index") "$(dirname "$index")/expected_output.txt" + diff <(node "$index" 2>&1) "$(dirname "$index")/expected_output.txt" done for tc in "$suite"/*/curl.sh; do echo "Running $tc" - diff <("$tc") "$(dirname "$tc")/expected_output.txt" + diff <("$tc" 2>&1) "$(dirname "$tc")/expected_output.txt" done for tc in "$suite"/*/cli.sh; do echo "Running $tc" - diff <("$tc") "$(dirname "$tc")/expected_output.txt" + diff <("$tc" 2>&1) "$(dirname "$tc")/expected_output.txt" done + + kill "$keto_server_pid" done echo diff --git a/docs/docs/guides/expand-api-display-who-has-access.mdx b/docs/docs/guides/expand-api-display-who-has-access.mdx new file mode 100644 index 000000000..3d574085f --- /dev/null +++ b/docs/docs/guides/expand-api-display-who-has-access.mdx @@ -0,0 +1,102 @@ +--- +title: 'Expand API: Display who has Access to an Object' +--- + +import CodeTabs from '@theme/CodeTabs' +import RelationTuplePrism from '@theme/RelationTuplePrism' +RelationTuplePrism() + +This guide will explain how to use Ory Keto's expand API to display who has +access to an object, and why. Please refer to the +[gRPC](../reference/proto-api.mdx) and [REST](../reference/api.mdx) API +reference documentation for all details. In general, the expand API allows to +expand a given subject set into all its effective subjects. + +## Example + +As an example, we want to look at a file sharing application. Files are +hierarchically organized in a directory structure. Every user owns files and +directories, and can grant any other user access to them on a per-file or +per-directory basis. Users can only see and access files they own or were +granted access by the owner. + +Directories and files are stored in Ory Keto within the `directories` and +`files` namespaces respectively. They are identified by a UUID that the +application maps to the actual object metadata. Users are also identified by and +mapped to a UUID. + +:::info + +For the sake of readability, the code samples use the object path and user name +instead. Please refer to the [objects](../concepts/objects.mdx) and +[subjects](../concepts/subjects.mdx) pages for why the mapping is necessary. + +::: + +### Displaying who has Access + +To assist users with managing permissions for their files, the application has +to display exactly who has access to a file and why. In this example, we assume +that the application knows the following files and directories: + +``` +├─ photos (owner: maureen; shared with laura) + ├─ beach.jpg (owner: maureen) + ├─ mountains.jpg (owner: laura) +``` + +This is represented in Ory Keto by the following +[relation tuples](../concepts/relation-tuples.mdx): + +```keto-relation-tuples +// ownership +directories:/photos#owner@maureen +files:/photos/beach.jpg#owner@maureen +files:/photos/mountains.jpg#owner@laura + +// maureen granted access to /photos to laura +directories:/photos#access@laura + +// the following tuples are defined implicitly through subject set rewrites (not supported yet) +directories:/photos#access@(directories:/photos#owner) +files:/photos/beach.jpg#access@(files:/photos/beach.jpg#owner) +files:/photos/beach.jpg#access@(directories:/photos#access) +files:/photos/mountains.jpg#access@(files:/photos/mountains.jpg#owner) +files:/photos/mountains.jpg#access@(directories:/photos#access) + +// the follwoing tuples are required to allow the subject set rewrites (not supported yet) +directories:/photos#parent@(files:/photos/beach.jpg#_) +directories:/photos#parent@(files:/photos/mountains.jpg#_) +``` + +The user `maureen` now wants to manage `access` for the file +`/photos/beach.jpg`. Therefore, the application uses the expand API to get a +tree of everyone who has access to that file: + + + +### Maximum Tree Depth + +The `max-depth` parameter is important to keep the request latency within an +acceptable bound, but also abstract away the most basic subject sets. In many +cases the application does not want to resolve all subject sets, but rather +wants to display that e.g. `Everyone in the company` or `Admins` have a specific +relation. + +In this example the application knows the rough structure of the relation tuples +it uses and can therefore determine that `max-depth=3` is sufficient to display +all relevant relations: + +1. directly granted access (depth 1) +2. indirectly granted access through ownership (depth 2) +3. indirectly granted access through ownership of the parent (depth 3) + +### Analyzing the Tree + +The tree does not only include the subject IDs (in this case usernames), but +also for what reason they were included. This can be useful for users to audits +permissions. Also, in many cases the application would not want to list all +subject IDs but rather abstract away some subject sets. diff --git a/docs/docs/guides/list-api-display-objects.mdx b/docs/docs/guides/list-api-display-objects.mdx new file mode 100644 index 000000000..6f898822e --- /dev/null +++ b/docs/docs/guides/list-api-display-objects.mdx @@ -0,0 +1,128 @@ +--- +title: 'List API: Display all Objects a User has Access to' +--- + +import CodeTabs from '@theme/CodeTabs' +import RelationTuplePrism from '@theme/RelationTuplePrism' +RelationTuplePrism() + +In this guide you will learn how to use Ory Keto's list API to display a list of +all objects (e.g. files, ...) a user has access to. Please refer to the +[gRPC](../reference/proto-api.mdx) and [REST](../reference/api.mdx) API +reference documentation for all details. In general, the list API allows you to +query relation tuples based on partial relation tuples. + +## Example + +As an example, we want to look at a chat application. Every user is part of one +or more chats, and each chat has one or more members. + +Chats are stored in Ory Keto within the `chats` namespace. They are identified +by a UUID that the application maps to the actual object metadata. Users are +also identified by and mapped to a UUID. + +:::info + +For the sake of readability, the code samples use the name of the chat and +username instead of the UUIDs. Please refer to the +[objects](../concepts/objects.mdx) and [subjects](../concepts/subjects.mdx) +pages for why the mapping is necessary. + +::: + +### Listing Objects + +Our example application allows users to browse the chats they belong to. To +achieve that, it uses Ory Keto's list API. + +We assume that the application currently has the following chats: + +```yml +memes: + members: + - PM + - Vincent + - Julia +cars: + members: + - PM + - Julia +coffee-break: + members: + - PM + - Vincent + - Julia + - Patrik +``` + +This is represented in Ory Keto by the following +[relation tuples](../concepts/relation-tuples.mdx): + +```keto-relation-tuples +chats:memes#member@PM +chats:memes#member@Vincent +chats:memes#member@Julia + +chats:cars#member@PM +chats:cars#member@Julia + +chats:coffee-break#member@PM +chats:coffee-break#member@Vincent +chats:coffee-break#member@Julia +chats:coffee-break#member@Patrik +``` + +The user `PM` now opens the chat application. To display a list of all of `PM`'s +chats, the application uses Keto's list API: + + + +As a response, the application gets the list of all chats the user `PM` is a +member of. It can then use the information to build the UI. + +### Listing Subjects + +Another view of the chat application has to display all members of a specific +group to the user. This can also be achieved using the list API. In cases where +such a membership would be modeled through +[subject sets](../concepts/subjects.mdx#subject-sets), you have to use the +[expand API](./expand-api-display-who-has-access.mdx). + +:::caution + +In this case the application should probably first use the +[check API](./simple-access-check-guide.mdx) to check whether the user is +allowed to list the members of a group. This step is not part of this example. + +::: + +In our example, a user wants to see who is a member of the `coffee-break` group: + + + +## Application Context + +It is important to note that the list API does **not** expand +[subject sets](../concepts/subjects.mdx#subject-sets). Usually the application +has some context to determine what tuples to query anyway. That could be e.g. +knowledge of the structure of subject sets like depth or hierarchy, or the UI +context, like a "My Items" view which should probably contain other objects than +a "My Organizations" or "Shared with Me" views. If there really is no way to +narrow down a query, you will have to use the +[expand API](./expand-api-display-who-has-access) instead, or repeatedly call +the list API. Try to avoid such cases because they require a lot of resources +and can quickly degrade the service quality for all users. Please refer to the +[performance considerations](../performance.mdx). + +## Pagination + +The list API only returns paginated results. Currently, it is not possible to +customize the order of results. The response returns an opaque token that has to +be used to retrieve the following page. The first page can be retrieved by +passing no, or an empty token. + +The page size can be adjusted at any point, not only when requesting the first +page. It defaults to 100 items. diff --git a/docs/docs/index.md b/docs/docs/index.md index 0c427e21e..2f78685a3 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -15,17 +15,14 @@ mechanisms. If you came looking for the answer to the question: between 4pm and 5pm on a Monday? - ... -Ory Keto provides various access control engines: +Ory Keto is build based on +[Google's Zanzibar research paper](https://research.google/pubs/pub48190/) and +provides an extensible ACL language. -- Available today: - - Ory-flavored Access Control Policies with exact, glob, and regexp matching - strategies -- Available soon: - - [Access Control Lists](https://en.wikipedia.org/wiki/Access_control_list) - - [Role-based Access Control](https://en.wikipedia.org/wiki/Role-based_access_control) - - Role Based Access Control with Context (Google/Kubernetes-flavored) - - Amazon Web Services Identity & Access Management Policies (AWS IAM Policies) +Soon, there will be native support for: -Each mechanism is powered by a decision engine implemented on top of the -[Open Policy Agent](https://www.openpolicyagent.org/) and provides well-defined -management and authorization REST API endpoints. +- [Role-based Access Control](https://en.wikipedia.org/wiki/Role-based_access_control) +- Role Based Access Control with Context (Google/Kubernetes-flavored) +- [Attribute-based Access Control](https://en.wikipedia.org/wiki/Attribute-based_access_control) +- decision engines based on + [Open Policy Agent](https://www.openpolicyagent.org/) diff --git a/docs/package-lock.json b/docs/package-lock.json index 8c444f269..01d684b97 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -22,6 +22,7 @@ "prismjs": "^1.22.0", "react": "16.13.1", "react-dom": "16.13.1", + "remarkable": "2.0.1", "url-loader": "^4.1.0" }, "devDependencies": { @@ -32,7 +33,6 @@ "ramda": "0.27.1", "raw-loader": "4.0.2", "remark-admonitions": "1.2.1", - "remarkable": "2.0.1", "widdershins": "4.0.1", "yaml": "1.8.3" } @@ -3170,7 +3170,6 @@ "version": "3.14.2", "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-3.14.2.tgz", "integrity": "sha512-VO66nXUCZFxTq7fVHAaiAkZNXRQ1l3IFi6D5P7DLoyIEAn2E8g7TWbyEgLlz1uW74LfWmu1A17IPWuPQyGuNVg==", - "dev": true, "dependencies": { "tslib": "^1.9.3" } @@ -3178,8 +3177,7 @@ "node_modules/autolinker/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/autoprefixer": { "version": "9.8.6", @@ -14795,7 +14793,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-2.0.1.tgz", "integrity": "sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA==", - "dev": true, "dependencies": { "argparse": "^1.0.10", "autolinker": "^3.11.0" @@ -22163,7 +22160,6 @@ "version": "3.14.2", "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-3.14.2.tgz", "integrity": "sha512-VO66nXUCZFxTq7fVHAaiAkZNXRQ1l3IFi6D5P7DLoyIEAn2E8g7TWbyEgLlz1uW74LfWmu1A17IPWuPQyGuNVg==", - "dev": true, "requires": { "tslib": "^1.9.3" }, @@ -22171,8 +22167,7 @@ "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" } } }, @@ -31502,7 +31497,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-2.0.1.tgz", "integrity": "sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA==", - "dev": true, "requires": { "argparse": "^1.0.10", "autolinker": "^3.11.0" diff --git a/docs/package.json b/docs/package.json index 15e56df91..8076ba39f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -33,6 +33,7 @@ "prismjs": "^1.22.0", "react": "16.13.1", "react-dom": "16.13.1", + "remarkable": "2.0.1", "url-loader": "^4.1.0" }, "browserslist": { @@ -55,7 +56,6 @@ "ramda": "0.27.1", "raw-loader": "4.0.2", "remark-admonitions": "1.2.1", - "remarkable": "2.0.1", "widdershins": "4.0.1", "yaml": "1.8.3" } diff --git a/docs/sidebar.json b/docs/sidebar.json index 27de68b49..de67db13e 100644 --- a/docs/sidebar.json +++ b/docs/sidebar.json @@ -14,7 +14,9 @@ ], "Guides": [ "secure", - "guides/simple-access-check-guide" + "guides/simple-access-check-guide", + "guides/list-api-display-objects", + "guides/expand-api-display-who-has-access" ], "Examples": [ "examples/olymp-file-sharing" diff --git a/docs/src/theme/CodeFromRemote.js b/docs/src/theme/CodeFromRemote.js index e24b3e127..a3609647f 100644 --- a/docs/src/theme/CodeFromRemote.js +++ b/docs/src/theme/CodeFromRemote.js @@ -70,7 +70,7 @@ const transform = ({ startAt, endAt }) => (content) => { } const CodeFromRemote = (props) => { - const { src } = props + const { src, title } = props const [content, setContent] = useState('') useEffect(() => { @@ -86,11 +86,11 @@ const CodeFromRemote = (props) => { }, []) const lang = `language-${detectLanguage(src)}` - const title = `title="${findPath(src)}"` + const metaString = `title="${title || findPath(src)}"` return (
- +
) } diff --git a/docs/src/theme/CodeTabs/index.js b/docs/src/theme/CodeTabs/index.js index efc927875..d3588ae1f 100644 --- a/docs/src/theme/CodeTabs/index.js +++ b/docs/src/theme/CodeTabs/index.js @@ -4,36 +4,42 @@ import TabItem from '@theme/TabItem' import CodeFromRemote from '../CodeFromRemote' const CodeTabs = ({ sampleId, version }) => ( - - - - - - - - - - - - - - + <> + + + + + + + + + + + + + + + + ) export default CodeTabs diff --git a/internal/e2e/http_client_test.go b/internal/e2e/http_client_test.go index a201b1a6a..4103251b1 100644 --- a/internal/e2e/http_client_test.go +++ b/internal/e2e/http_client_test.go @@ -169,7 +169,7 @@ func (c *sdkClient) expand(t require.TestingT, r *relationtuple.SubjectSet, dept WithNamespace(r.Namespace). WithObject(r.Object). WithRelation(r.Relation). - WithDepth(pointerx.Int64(int64(depth))), + WithMaxDepth(pointerx.Int64(int64(depth))), ) require.NoError(t, err) return buildTree(t, resp.Payload) diff --git a/internal/e2e/rest_client_test.go b/internal/e2e/rest_client_test.go index 46314b1c7..77da466d3 100644 --- a/internal/e2e/rest_client_test.go +++ b/internal/e2e/rest_client_test.go @@ -134,7 +134,7 @@ func (rc *restClient) check(t require.TestingT, r *relationtuple.InternalRelatio func (rc *restClient) expand(t require.TestingT, r *relationtuple.SubjectSet, depth int) *expand.Tree { query := r.ToURLQuery() - query.Set("depth", fmt.Sprintf("%d", depth)) + query.Set("max-depth", fmt.Sprintf("%d", depth)) body, code := rc.makeRequest(t, http.MethodGet, fmt.Sprintf("%s?%s", expand.RouteBase, query.Encode()), "", false) require.Equal(t, http.StatusOK, code, body) diff --git a/internal/expand/handler.go b/internal/expand/handler.go index 5bce87a0f..2ed25c2ca 100644 --- a/internal/expand/handler.go +++ b/internal/expand/handler.go @@ -52,7 +52,7 @@ func (h *handler) RegisterWriteGRPC(s *grpc.Server) {} // swagger:parameters getExpand // nolint:deadcode,unused type getExpandRequest struct { - Depth int `json:"depth"` + Depth int `json:"max-depth"` } // swagger:route GET /expand read getExpand @@ -73,7 +73,7 @@ type getExpandRequest struct { // 404: genericError // 500: genericError func (h *handler) getExpand(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - depth, err := strconv.ParseInt(r.URL.Query().Get("depth"), 0, 0) + depth, err := strconv.ParseInt(r.URL.Query().Get("max-depth"), 0, 0) if err != nil { h.d.Writer().WriteError(w, r, herodot.ErrBadRequest.WithError(err.Error())) return diff --git a/internal/expand/handler_test.go b/internal/expand/handler_test.go index 5e714bf76..a35c1a9bd 100644 --- a/internal/expand/handler_test.go +++ b/internal/expand/handler_test.go @@ -33,7 +33,7 @@ func TestRESTHandler(t *testing.T) { defer ts.Close() t.Run("case=returns bad request on malformed int", func(t *testing.T) { - resp, err := ts.Client().Get(ts.URL + expand.RouteBase + "?depth=foo") + resp, err := ts.Client().Get(ts.URL + expand.RouteBase + "?max-depth=foo") require.NoError(t, err) assert.Equal(t, http.StatusBadRequest, resp.StatusCode) @@ -44,7 +44,7 @@ func TestRESTHandler(t *testing.T) { t.Run("case=returns not found on unknown namespace", func(t *testing.T) { resp, err := ts.Client().Get(ts.URL + expand.RouteBase + "?" + url.Values{ - "depth": {"10"}, + "max-depth": {"10"}, "namespace": {"not " + nspace.Name}, }.Encode()) require.NoError(t, err) @@ -92,7 +92,7 @@ func TestRESTHandler(t *testing.T) { }...)) qs := rootSub.ToURLQuery() - qs.Set("depth", "2") + qs.Set("max-depth", "2") resp, err := ts.Client().Get(ts.URL + expand.RouteBase + "?" + qs.Encode()) require.NoError(t, err) diff --git a/internal/httpclient/client/read/get_expand_parameters.go b/internal/httpclient/client/read/get_expand_parameters.go index ee817e4ef..6227ee035 100644 --- a/internal/httpclient/client/read/get_expand_parameters.go +++ b/internal/httpclient/client/read/get_expand_parameters.go @@ -60,10 +60,10 @@ func NewGetExpandParamsWithHTTPClient(client *http.Client) *GetExpandParams { */ type GetExpandParams struct { - // Depth. + // MaxDepth. // // Format: int64 - Depth *int64 + MaxDepth *int64 // Namespace. Namespace string @@ -127,15 +127,15 @@ func (o *GetExpandParams) SetHTTPClient(client *http.Client) { o.HTTPClient = client } -// WithDepth adds the depth to the get expand params -func (o *GetExpandParams) WithDepth(depth *int64) *GetExpandParams { - o.SetDepth(depth) +// WithMaxDepth adds the maxDepth to the get expand params +func (o *GetExpandParams) WithMaxDepth(maxDepth *int64) *GetExpandParams { + o.SetMaxDepth(maxDepth) return o } -// SetDepth adds the depth to the get expand params -func (o *GetExpandParams) SetDepth(depth *int64) { - o.Depth = depth +// SetMaxDepth adds the maxDepth to the get expand params +func (o *GetExpandParams) SetMaxDepth(maxDepth *int64) { + o.MaxDepth = maxDepth } // WithNamespace adds the namespace to the get expand params @@ -179,18 +179,18 @@ func (o *GetExpandParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Reg } var res []error - if o.Depth != nil { + if o.MaxDepth != nil { - // query param depth - var qrDepth int64 + // query param max-depth + var qrMaxDepth int64 - if o.Depth != nil { - qrDepth = *o.Depth + if o.MaxDepth != nil { + qrMaxDepth = *o.MaxDepth } - qDepth := swag.FormatInt64(qrDepth) - if qDepth != "" { + qMaxDepth := swag.FormatInt64(qrMaxDepth) + if qMaxDepth != "" { - if err := r.SetQueryParam("depth", qDepth); err != nil { + if err := r.SetQueryParam("max-depth", qMaxDepth); err != nil { return err } }