Hello! I’m trying to make a proof of concept using...
# talk-keto
t
Hello! I’m trying to make a proof of concept using Keto for my company, using one of the example OPL schemas:
Copy code
import { Namespace, Context } from "@ory/keto-namespace-types"

class User implements Namespace {}

class Document implements Namespace {
  related: {
    owners: User[]
    editors: User[]
    viewers: User[]
    parents: Folder[]
  }

  permits = {
    view: (ctx: Context): boolean =>
        this.related.viewers.includes(ctx.subject) ||
        this.permits.edit(ctx),
    edit: (ctx: Context): boolean =>
        this.related.editors.includes(ctx.subject) ||
        this.permits.share(ctx),
    delete: (ctx: Context): boolean =>
        this.permits.share(ctx),
    share: (ctx: Context): boolean =>
        this.related.owners.includes(ctx.subject) || this.related.parents.traverse((parent) => parent.permits.share(ctx)),
  }
}

class Folder implements Namespace {
  related: {
    owners: User[]
    editors: User[]
    viewers: User[]
    parents: Folder[]
  }

  permits = {
    delete: (ctx: Context): boolean =>
        this.permits.share(ctx),
    share: (ctx: Context): boolean =>
        this.related.owners.includes(ctx.subject) || this.related.parents.traverse((parent) => parent.permits.share(ctx)),
  }
}
I then use the go SDK to set a document as having a parent folder, and then make a user an owner of the folder. However when I go to check if the user has view permission on the document, the permissions api returns that they do not. Perhaps I’m misunderstanding something? For reference here’s the go code I have:
Copy code
package main

import (
	"context"
	"fmt"
	"os"

	ory "<http://github.com/ory/keto-client-go|github.com/ory/keto-client-go>"
)

func Ptr[T any](v T) *T {
	return &v
}

func main() {
	configuration := ory.NewConfiguration()
	configuration.Servers = []ory.ServerConfiguration{
		{
			URL: "<http://127.0.0.1:4467>", // Write API
		},
	}
	writeClient := ory.NewAPIClient(configuration)
	ctx := context.Background()

	_, r, err := writeClient.RelationshipApi.CreateRelationship(ctx).CreateRelationshipBody(ory.CreateRelationshipBody{
		Namespace: Ptr("Document"),
		Object:    Ptr("doc_1"),
		Relation:  Ptr("parents"),
		SubjectId: Ptr("folder_1"),
	}).Execute()

	if err != nil {
		fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
		panic("Encountered error: " + err.Error())
	}

	_, r, err = writeClient.RelationshipApi.CreateRelationship(ctx).CreateRelationshipBody(ory.CreateRelationshipBody{
		Namespace: Ptr("Folder"),
		Object:    Ptr("folder_1"),
		Relation:  Ptr("owners"),
		SubjectId: Ptr("user_1"),
	}).Execute()

	if err != nil {
		fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
		panic("Encountered error: " + err.Error())
	}

	configuration.Servers = []ory.ServerConfiguration{
		{
			URL: "<http://127.0.0.1:4466>", // Read API
		},
	}
	readClient := ory.NewAPIClient(configuration)
	checkRelation(ctx, readClient, "Folder", "folder_1", "share", "user_1")
	checkRelation(ctx, readClient, "Document", "doc_1", "view", "user_1")
}

func checkRelation(ctx context.Context, readClient *ory.APIClient, namespace, object, relation, subjectId string) {
	check, r, err := readClient.PermissionApi.CheckPermission(ctx).
		Namespace(namespace).
		Object(object).
		Relation(relation).
		SubjectId(subjectId).Execute()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
		panic("Encountered error: " + err.Error())
	}
	if check.Allowed {
		fmt.Println(subjectId + " CAN " + relation + " the " + object)
	} else {
		fmt.Println(subjectId + " CANNOT " + relation + " the " + object)
	}
}
and here’s the output:
Copy code
user_1 CAN share the folder_1
user_1 CANNOT view the doc_1
Any help would be greatly appreciated!
s
Sorry to have overlooked this. I think it does not work, because you are using subject IDs. What you want to use instead are subject sets without a relation, because then the subject has a namespace as well. This is currently unfortunately not very clear from the docs and SDK, but we are working on a v1 API that only allows subjects with a namespace.
t
Thanks for clearing that up Patrik!