Skip to content

Commit d6871e1

Browse files
authored
feat: support computed relations in graph (#309)
2 parents b27a3bc + 946f556 commit d6871e1

File tree

3 files changed

+74
-2
lines changed

3 files changed

+74
-2
lines changed

pkg/go/graph/graph_builder.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ func parseModel(model *openfgav1.AuthorizationModel) (*multi.DirectedGraph, erro
6363
if _, ok := rewrite.GetUserset().(*openfgav1.Userset_This); ok {
6464
parseThis(typeDef, relation, graphBuilder, relationNode)
6565
}
66+
67+
if _, ok := rewrite.GetUserset().(*openfgav1.Userset_ComputedUserset); ok {
68+
parseComputed(rewrite, typeDef.GetType(), graphBuilder, relationNode)
69+
}
6670
}
6771
}
6872

@@ -104,6 +108,15 @@ func parseThis(typeDef *openfgav1.TypeDefinition, relation string, graphBuilder
104108
}
105109
}
106110

111+
func parseComputed(rewrite *openfgav1.Userset, typeName string, graphBuilder *AuthorizationModelGraphBuilder, relationNode *AuthorizationModelNode) {
112+
// e.g. define x: y. Here y is the rewritten relation
113+
rewrittenRelation := rewrite.GetComputedUserset().GetRelation()
114+
rewrittenNodeName := fmt.Sprintf("%s#%s", typeName, rewrittenRelation)
115+
newNode := graphBuilder.GetOrAddNode(rewrittenNodeName, rewrittenNodeName, SpecificTypeAndRelation)
116+
// new edge from y to x
117+
graphBuilder.AddEdge(newNode, relationNode, ComputedEdge)
118+
}
119+
107120
func (g *AuthorizationModelGraphBuilder) GetOrAddNode(uniqueLabel, label string, nodeType NodeType) *AuthorizationModelNode {
108121
if existingNode := g.GetNodeFor(uniqueLabel); existingNode != nil {
109122
return existingNode

pkg/go/graph/graph_builder_test.go

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,57 @@ rankdir=BT
139139
140140
// Edge definitions.
141141
2 -> 1 [label=direct];
142+
}`,
143+
},
144+
`computed_relation`: {
145+
model: `
146+
model
147+
schema 1.1
148+
type folder
149+
relations
150+
define x: y
151+
define y: [user]
152+
type user`,
153+
expectedOutput: `digraph {
154+
graph [
155+
rankdir=BT
156+
];
157+
158+
// Node definitions.
159+
0 [label=folder];
160+
1 [label="folder#x"];
161+
2 [label="folder#y"];
162+
3 [label=user];
163+
164+
// Edge definitions.
165+
2 -> 1 [style=dashed];
166+
3 -> 2 [label=direct];
167+
}`,
168+
},
169+
`computed_relation_with_cycle`: {
170+
model: `
171+
model
172+
schema 1.1
173+
type folder
174+
relations
175+
define x: y
176+
define y: z
177+
define z: x`,
178+
expectedOutput: `digraph {
179+
graph [
180+
rankdir=BT
181+
];
182+
183+
// Node definitions.
184+
0 [label=folder];
185+
1 [label="folder#x"];
186+
2 [label="folder#y"];
187+
3 [label="folder#z"];
188+
189+
// Edge definitions.
190+
1 -> 3 [style=dashed];
191+
2 -> 1 [style=dashed];
192+
3 -> 2 [style=dashed];
142193
}`,
143194
},
144195
}
@@ -159,7 +210,7 @@ rankdir=BT
159210

160211
diff := cmp.Diff(expectedSorted, actualSorted)
161212

162-
require.Empty(t, diff, "expected %s\ngot %s", test.expectedOutput, actualDOT)
213+
require.Empty(t, diff, "expected %s\ngot\n%s", test.expectedOutput, actualDOT)
163214
})
164215
}
165216
}

pkg/go/graph/graph_edge.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import (
88
type EdgeType int64
99

1010
const (
11-
DirectEdge EdgeType = 0 // e.g. `group`
11+
DirectEdge EdgeType = 0
12+
ComputedEdge EdgeType = 1
1213
)
1314

1415
type AuthorizationModelEdge struct {
@@ -30,5 +31,12 @@ func (n *AuthorizationModelEdge) Attributes() []encoding.Attribute {
3031
})
3132
}
3233

34+
if n.edgeType == ComputedEdge {
35+
attrs = append(attrs, encoding.Attribute{
36+
Key: "style",
37+
Value: "dashed",
38+
})
39+
}
40+
3341
return attrs
3442
}

0 commit comments

Comments
 (0)