Skip to content

Commit

Permalink
better represent structure in mermaid graph (#263)
Browse files Browse the repository at this point in the history
This better represents the action and action relationship lookups in mermaid graphs.

Before:

```mermaid
erDiagram
	rolebinding }o--o{ rolev2 : role
	rolebinding }o--o{ user : subject
	rolebinding }o--o{ client : subject
	rolebinding }o--o{ group : subject
	user {
		id_prefix idntusr
	}
	client {
		id_prefix idntclt
	}
	role {
		id_prefix permrol
	}
	role }o--o{ subject: subject
	tenant {
		id_prefix tnntten
	}
	tenant }o--o{ tenant: parent
	tenant }o--o{ rolebinding: grant
	group {
		id_prefix idntgrp
		subgroup_action member
	}
	group }o--o{ rolebinding: grant
	group }o--o{ group: parent
	group }o--o{ tenant: parent
	group }o--o{ user: direct_member
	group }o--o{ client: direct_member
	group }o--o{ group: subgroup
	loadbalancer {
		id_prefix loadbal
		action loadbalancer_get
		action loadbalancer_update
		action loadbalancer_delete
	}
	loadbalancer }o--o{ resourceowner: owner
	loadbalancer }o--o{ rolebinding: grant
	resourceowner {
	}
	resourceowner ||--|| tenant: alias
	resourcemanager {
		action role_create
		action role_get
		action role_list
		action role_update
		action role_delete
		action loadbalancer_create
		action loadbalancer_get
		action loadbalancer_list
		action loadbalancer_update
		action loadbalancer_delete
	}
	resourcemanager ||--|| tenant: alias
	resourcemanager ||--|| group: alias
	subject {
	}
	subject ||--|| user: alias
	subject ||--|| client: alias

```

After:

```mermaid
erDiagram
	rolebinding }o--o{ rolev2 : role
	rolebinding }o--o{ user : subject
	rolebinding }o--o{ client : subject
	rolebinding }o--o{ group : subject
	user {
		id_prefix idntusr
	}
	client {
		id_prefix idntclt
	}
	role {
		id_prefix permrol
	}
	role }o--o{ subject: subject
	tenant {
		id_prefix tnntten
	}
	tenant }o--o{ tenant: parent
	tenant }o--o{ rolebinding: grant
	group {
		id_prefix idntgrp
		action member "direct_member> | subgroup>member"
	}
	group }o--o{ rolebinding: grant
	group }o--o{ group: parent
	group }o--o{ tenant: parent
	group }o--o{ user: direct_member
	group }o--o{ client: direct_member
	group }o--o{ group: subgroup
	loadbalancer {
		id_prefix loadbal
		action loadbalancer_delete "self"
		action loadbalancer_get "self"
		action loadbalancer_update "self"
	}
	loadbalancer }o--o{ resourceowner: owner
	loadbalancer }o--o{ rolebinding: grant
	resourceowner {
	}
	resourceowner ||--|| tenant: alias
	resourcemanager {
		action loadbalancer_create "self"
		action loadbalancer_delete "self"
		action loadbalancer_get "self"
		action loadbalancer_list "self"
		action loadbalancer_update "self"
		action role_create "self"
		action role_delete "self"
		action role_get "self"
		action role_list "self"
		action role_update "self"
	}
	resourcemanager ||--|| tenant: alias
	resourcemanager ||--|| group: alias
	subject {
	}
	subject ||--|| user: alias
	subject ||--|| client: alias

```

Signed-off-by: Mike Mason <[email protected]>
  • Loading branch information
mikemrm authored Aug 7, 2024
1 parent 1ab6bf1 commit 72685ad
Showing 1 changed file with 83 additions and 30 deletions.
113 changes: 83 additions & 30 deletions cmd/schema_mermaid.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"bytes"
"fmt"
"slices"
"text/template"

"go.infratographer.com/permissions-api/internal/iapl"
Expand All @@ -11,22 +12,39 @@ import (
var (
mermaidTemplate = `erDiagram
{{- if ne .RBAC nil}}
{{ .RBAC.RoleBindingResource }} }o--o{ {{ .RBAC.RoleResource }} : role
{{ .RBAC.RoleBindingResource.Name }} }o--o{ {{ .RBAC.RoleResource.Name }} : role
{{- range $subj := .RBAC.RoleBindingSubjects }}
{{ $.RBAC.RoleBindingResource }} }o--o{ {{ $subj.Name }} : subject
{{ $.RBAC.RoleBindingResource.Name }} }o--o{ {{ $subj.Name }} : subject
{{- end }}
{{- end }}
{{- range $resource := .ResourceTypes }}
{{ $resource.Name }} {
id_prefix {{ $resource.IDPrefix }}
{{- range $action := index $.Actions $resource.Name }}
{{- range $action, $relations := index $.Actions $resource.Name }}
action {{ $action }}
{{- end }}
{{- range $relation, $actions := index $.RelatedActions $resource.Name }}
{{- range $action := $actions }}
{{ $relation }}_action {{ $action }}
{{- end }}
{{- $quoted := false }}
{{- with index $relations "!!SELF!!" }}
{{- " \"self" }}
{{- $quoted = true }}
{{- end }}
{{- range $relation := $.RelationOrder }}
{{- with index $relations $relation }}
{{- range $i, $rel_action := . }}
{{- if not $quoted }}
{{- " \"" }}
{{- $quoted = true }}
{{- else }}
{{- " | " }}
{{- end }}
{{- $relation }}>{{- $rel_action }}
{{- end }}
{{- end }}
{{- end }}
{{- if $quoted }}
{{- "\"" }}
{{- end }}
{{- end }}
}
{{- range $rel := $resource.Relationships }}
Expand All @@ -39,13 +57,30 @@ var (
{{- end }}
{{- range $union := .Unions }}
{{ $union.Name }} {
{{- range $action := index $.Actions $union.Name }}
{{- range $action, $relations := index $.Actions $union.Name }}
action {{ $action }}
{{- end }}
{{- range $relation, $actions := index $.RelatedActions $union.Name }}
{{- range $action := $actions }}
{{ $relation }}_action {{ $action }}
{{- end }}
{{- $quoted := false }}
{{- with index $relations "!!SELF!!" }}
{{- " \"self" }}
{{- $quoted = true }}
{{- end }}
{{- range $relation := $.RelationOrder }}
{{- with index $relations $relation }}
{{- range $i, $rel_action := . }}
{{- if not $quoted }}
{{- " \"" }}
{{- $quoted = true }}
{{- else }}
{{- " | " }}
{{- end }}
{{- $relation }}>{{- $rel_action }}
{{- end }}
{{- end }}
{{- end }}
{{- if $quoted }}
{{- "\"" }}
{{- end }}
{{- end }}
}
{{- range $typ := $union.ResourceTypes }}
Expand All @@ -59,11 +94,11 @@ var (
)

type mermaidContext struct {
ResourceTypes []iapl.ResourceType
Unions []iapl.Union
Actions map[string][]string
RelatedActions map[string]map[string][]string
RBAC *iapl.RBAC
ResourceTypes []iapl.ResourceType
Unions []iapl.Union
Actions map[string]map[string]map[string][]string
RelationOrder []string
RBAC *iapl.RBAC
}

func outputPolicyMermaid(dirPath string, markdown bool) {
Expand All @@ -81,31 +116,49 @@ func outputPolicyMermaid(dirPath string, markdown bool) {
policy = iapl.DefaultPolicyDocument()
}

actions := map[string][]string{}
relatedActions := map[string]map[string][]string{}
actions := map[string]map[string]map[string][]string{}
relations := []string{}

for _, binding := range policy.ActionBindings {
for _, cond := range binding.Conditions {
if cond.RoleBinding != nil {
actions[binding.TypeName] = append(actions[binding.TypeName], binding.ActionName)
if _, ok := actions[binding.TypeName]; !ok {
actions[binding.TypeName] = make(map[string]map[string][]string)
}

if _, ok := actions[binding.TypeName][binding.ActionName]; !ok {
actions[binding.TypeName][binding.ActionName] = make(map[string][]string)
}

actions[binding.TypeName][binding.ActionName]["!!SELF!!"] = append(actions[binding.TypeName][binding.ActionName]["!!SELF!!"], binding.ActionName)
}

if cond.RelationshipAction != nil {
if _, ok := relatedActions[binding.TypeName]; !ok {
relatedActions[binding.TypeName] = make(map[string][]string)
if _, ok := actions[binding.TypeName]; !ok {
actions[binding.TypeName] = make(map[string]map[string][]string)
}

if _, ok := actions[binding.TypeName][binding.ActionName]; !ok {
actions[binding.TypeName][binding.ActionName] = make(map[string][]string)
}

relatedActions[binding.TypeName][cond.RelationshipAction.Relation] = append(relatedActions[binding.TypeName][cond.RelationshipAction.Relation], cond.RelationshipAction.ActionName)
actions[binding.TypeName][binding.ActionName][cond.RelationshipAction.Relation] = append(actions[binding.TypeName][binding.ActionName][cond.RelationshipAction.Relation], cond.RelationshipAction.ActionName)

if !slices.Contains(relations, cond.RelationshipAction.Relation) {
relations = append(relations, cond.RelationshipAction.Relation)
}
}
}
}

slices.Sort(relations)

ctx := mermaidContext{
ResourceTypes: policy.ResourceTypes,
Unions: policy.Unions,
Actions: actions,
RelatedActions: relatedActions,
RBAC: nil,
ResourceTypes: policy.ResourceTypes,
Unions: policy.Unions,
Actions: actions,
RelationOrder: relations,
RBAC: nil,
}

if policy.RBAC != nil {
Expand Down

0 comments on commit 72685ad

Please sign in to comment.