Skip to content

Commit

Permalink
feat: configure subject-set rewrites
Browse files Browse the repository at this point in the history
The subject-set rewrites can now be configured through the Ory Permission
Language (OPL), which is a subset of TypeScript. The OPL config is
referenced in the central configuration under namespaces as such:

  [...]
  namespaces:
    location: <location>
  [...]

The <location> can be any valid file, directory or URI.
  • Loading branch information
hperl authored and zepatrik committed Aug 24, 2022
1 parent b17417a commit 0ce1519
Show file tree
Hide file tree
Showing 7 changed files with 450 additions and 149 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Expand Up @@ -5,4 +5,5 @@ dist/
**/*.sqlite
**/*.sqlite-journal
.vscode/
.fuzzer/
.fuzzer/
keto
25 changes: 22 additions & 3 deletions embedx/config.schema.json
Expand Up @@ -29,7 +29,7 @@
}
},
"additionalProperties": false,
"required": ["name", "id"]
"required": ["name"]
},
"tlsxSource": {
"type": "object",
Expand Down Expand Up @@ -287,16 +287,35 @@
"default": "file://./keto_namespaces",
"oneOf": [
{
"title": "Namespace Repo URI",
"description": "URI that points to a directory of namespace files, a single file with all namespaces, or a websocket connection that provides former via `github.com/ory/x/watcherx.WatchAndServeWS`",
"title": "Legacy namespace Repo URI",
"description": "A URI that points to a directory of namespace files, a single file with all namespaces, or a websocket connection that provides former via `github.com/ory/x/watcherx.WatchAndServeWS`",
"type": "string",
"format": "uri"
},
{
"type": "array",
"title": "Legacy namespace configuration",
"items": {
"$ref": "#/definitions/namespace"
}
},
{
"type": "object",
"title": "Namespace configuration",
"properties": {
"location": {
"type": "string",
"title": "Ory Permission Language config file URI",
"description": "A URI that points to a directory of namespace files, a single file with all namespaces, or a websocket connection that provides former via `github.com/ory/x/watcherx.WatchAndServeWS`",
"format": "uri",
"examples": [
"file://./keto_namespaces.ts",
"file:///etc/configs/keto_namespaces.ts",
"ws://my.websocket.server/keto_namespaces.ts"
]
}
},
"required": ["location"]
}
]
},
Expand Down
59 changes: 39 additions & 20 deletions internal/driver/config/namespace_memory.go
Expand Up @@ -3,6 +3,7 @@ package config
import (
"context"
"reflect"
"sync"

"github.com/ory/herodot"
"github.com/pkg/errors"
Expand All @@ -11,35 +12,37 @@ import (
)

type (
memoryNamespaceManager []*namespace.Namespace
memoryNamespaceManager struct {
byName map[string]*namespace.Namespace
sync.RWMutex
}
)

var _ namespace.Manager = &memoryNamespaceManager{}

func NewMemoryNamespaceManager(nn ...*namespace.Namespace) *memoryNamespaceManager {
nm := make(memoryNamespaceManager, len(nn))

for i, np := range nn {
n := *np
nm[i] = &n
}

return &nm
s := &memoryNamespaceManager{}
s.set(nn)
return s
}

func (s *memoryNamespaceManager) GetNamespaceByName(_ context.Context, name string) (*namespace.Namespace, error) {
for _, n := range *s {
if n.Name == name {
return n, nil
}
s.RLock()
defer s.RUnlock()

if n, ok := s.byName[name]; ok {
return n, nil
}

return nil, errors.WithStack(herodot.ErrNotFound.WithReasonf("Unknown namespace with name %q.", name))
}

func (s *memoryNamespaceManager) GetNamespaceByConfigID(_ context.Context, id int32) (*namespace.Namespace, error) {
for _, n := range *s {
if n.ID == id {
s.RLock()
defer s.RUnlock()

for _, n := range s.byName {
if n.ID == id { // nolint ignore deprecated method
return n, nil
}
}
Expand All @@ -48,16 +51,32 @@ func (s *memoryNamespaceManager) GetNamespaceByConfigID(_ context.Context, id in
}

func (s *memoryNamespaceManager) Namespaces(_ context.Context) ([]*namespace.Namespace, error) {
nn := make([]*namespace.Namespace, 0, len(*s))
s.RLock()
defer s.RUnlock()

for _, n := range *s {
nc := *n
nn = append(nn, &nc)
nn := make([]*namespace.Namespace, 0, len(s.byName))
for _, n := range s.byName {
nn = append(nn, n)
}

return nn, nil
}

func (s *memoryNamespaceManager) ShouldReload(newValue interface{}) bool {
return !reflect.DeepEqual(newValue, []*namespace.Namespace(*s))
s.RLock()
defer s.RUnlock()

nn, _ := s.Namespaces(context.Background())

return !reflect.DeepEqual(newValue, nn)
}

func (s *memoryNamespaceManager) set(nn []*namespace.Namespace) {
s.Lock()
defer s.Unlock()

s.byName = make(map[string]*namespace.Namespace, len(nn))
for _, n := range nn {
s.byName[n.Name] = n
}
}

0 comments on commit 0ce1519

Please sign in to comment.