Skip to content

Commit

Permalink
feat: expose function to generate OPL (#1057)
Browse files Browse the repository at this point in the history
Co-authored-by: Patrik <[email protected]>
  • Loading branch information
hperl and zepatrik authored Oct 10, 2022
1 parent b80c42b commit b80a230
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"import { Namespace, SubjectSet, Context } from '@ory/keto-namespace-types'\n\n// Declare new namespaces as classes that implement `Namespace`"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"import { Namespace, SubjectSet, Context } from '@ory/keto-namespace-types'\n\n// Declare new namespaces as classes that implement `Namespace`\nclass one implements Namespace {\n related: {\n // Define relations to other objects here.\n // Examples:\n //\n // parents: (File | Folder)[]\n // viewers: SubjectSet\u003cGroup, \"members\"\u003e[]\n }\n\n permits = {\n // Define permissions here. These can be derived from the relations above.\n // Examples:\n //\n // view: (ctx: Context): boolean =\u003e\n // this.related.viewers.includes(ctx.subject) ||\n // this.related.parents.traverse((p) =\u003e p.permits.view(ctx)),\n }\n}\n\nclass two implements Namespace {\n related: {\n // Define relations to other objects here.\n // Examples:\n //\n // parents: (File | Folder)[]\n // viewers: SubjectSet\u003cGroup, \"members\"\u003e[]\n }\n\n permits = {\n // Define permissions here. These can be derived from the relations above.\n // Examples:\n //\n // view: (ctx: Context): boolean =\u003e\n // this.related.viewers.includes(ctx.subject) ||\n // this.related.parents.traverse((p) =\u003e p.permits.view(ctx)),\n }\n}\n\nclass three implements Namespace {\n related: {\n // Define relations to other objects here.\n // Examples:\n //\n // parents: (File | Folder)[]\n // viewers: SubjectSet\u003cGroup, \"members\"\u003e[]\n }\n\n permits = {\n // Define permissions here. These can be derived from the relations above.\n // Examples:\n //\n // view: (ctx: Context): boolean =\u003e\n // this.related.viewers.includes(ctx.subject) ||\n // this.related.parents.traverse((p) =\u003e p.permits.view(ctx)),\n }\n}\n"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"import { Namespace, SubjectSet, Context } from '@ory/keto-namespace-types'\n\n// Declare new namespaces as classes that implement `Namespace`\nclass one implements Namespace {\n related: {\n // Define relations to other objects here.\n // Examples:\n //\n // parents: (File | Folder)[]\n // viewers: SubjectSet\u003cGroup, \"members\"\u003e[]\n }\n\n permits = {\n // Define permissions here. These can be derived from the relations above.\n // Examples:\n //\n // view: (ctx: Context): boolean =\u003e\n // this.related.viewers.includes(ctx.subject) ||\n // this.related.parents.traverse((p) =\u003e p.permits.view(ctx)),\n }\n}\n"
22 changes: 22 additions & 0 deletions cmd/namespace/config_template/namespaces.ts.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Namespace, SubjectSet, Context } from '@ory/keto-namespace-types'

// Declare new namespaces as classes that implement `Namespace`{{ range .Namespaces }}
class {{ . }} implements Namespace {
related: {
// Define relations to other objects here.
// Examples:
//
// parents: (File | Folder)[]
// viewers: SubjectSet<Group, "members">[]
}

permits = {
// Define permissions here. These can be derived from the relations above.
// Examples:
//
// view: (ctx: Context): boolean =>
// this.related.viewers.includes(ctx.subject) ||
// this.related.parents.traverse((p) => p.permits.view(ctx)),
}
}
{{ end }}
25 changes: 25 additions & 0 deletions cmd/namespace/opl_generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package namespace

import (
"embed"
"io"
"text/template"

"github.com/pkg/errors"
)

//go:embed config_template/*
var configTemplate embed.FS

// GenerateOPLConfig derives an Ory Permission Language config from the
// namespaces and writes it to out. The OPL config is functionally equivalent to
// the list of namespaces.
func GenerateOPLConfig(namespaces []string, out io.Writer) error {
t, err := template.New("config_template").ParseFS(configTemplate, "config_template/*")
if err != nil {
return errors.WithStack(err)
}
return errors.WithStack(t.ExecuteTemplate(out,
"namespaces.ts.tmpl",
struct{ Namespaces []string }{Namespaces: namespaces}))
}
35 changes: 35 additions & 0 deletions cmd/namespace/opl_generate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package namespace_test

import (
"bytes"
"testing"

"github.com/ory/x/snapshotx"
"github.com/stretchr/testify/require"

"github.com/ory/keto/cmd/namespace"
)

func TestGenerateOPLConfig(t *testing.T) {
cases := []struct {
name string
namespaces []string
}{{
name: "empty",
namespaces: []string{},
}, {
name: "one",
namespaces: []string{"one"},
}, {
name: "many",
namespaces: []string{"one", "two", "three"},
}}

for _, tc := range cases {
t.Run("case="+tc.name, func(t *testing.T) {
var out bytes.Buffer
require.NoError(t, namespace.GenerateOPLConfig(tc.namespaces, &out))
snapshotx.SnapshotT(t, out.String())
})
}
}

0 comments on commit b80a230

Please sign in to comment.