Skip to content

Commit f23f6a9

Browse files
authored
Fix Infinite Loop (#272)
* wip wip wip * fixed infinite loop
1 parent 7854360 commit f23f6a9

File tree

3 files changed

+64
-12
lines changed

3 files changed

+64
-12
lines changed

pkg/sync/expand/graph.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,17 @@ type Node struct {
3939
// This is because the graph can have cycles, and we address them by reducing
4040
// _all_ nodes in a cycle into a single node.
4141
type EntitlementGraph struct {
42-
NextNodeID int `json:"next_node_id"` // Automatically incremented so that each node has a unique ID.
43-
NextEdgeID int `json:"next_edge_id"` // Automatically incremented so that each edge has a unique ID.
44-
Nodes map[int]Node `json:"nodes"` // The mapping of all node IDs to nodes.
45-
EntitlementsToNodes map[string]int `json:"entitlements_to_nodes"` // Internal mapping of entitlements to nodes for quicker lookup.
46-
SourcesToDestinations map[int]map[int]int `json:"sources_to_destinations"` // Internal mapping of outgoing edges by node ID.
47-
DestinationsToSources map[int]map[int]int `json:"destinations_to_sources"` // Internal mapping of incoming edges by node ID.
48-
Edges map[int]Edge `json:"edges"` // Adjacency list. Source node -> descendant node
49-
Loaded bool `json:"loaded"`
50-
Depth int `json:"depth"`
51-
Actions []EntitlementGraphAction `json:"actions"`
52-
HasNoCycles bool `json:"has_no_cycles"`
42+
NextNodeID int `json:"next_node_id"` // Automatically incremented so that each node has a unique ID.
43+
NextEdgeID int `json:"next_edge_id"` // Automatically incremented so that each edge has a unique ID.
44+
Nodes map[int]Node `json:"nodes"` // The mapping of all node IDs to nodes.
45+
EntitlementsToNodes map[string]int `json:"entitlements_to_nodes"` // Internal mapping of entitlements to nodes for quicker lookup.
46+
SourcesToDestinations map[int]map[int]int `json:"sources_to_destinations"` // Internal mapping of outgoing edges by node ID.
47+
DestinationsToSources map[int]map[int]int `json:"destinations_to_sources"` // Internal mapping of incoming edges by node ID.
48+
Edges map[int]Edge `json:"edges"` // Adjacency list. Source node -> descendant node
49+
Loaded bool `json:"loaded"`
50+
Depth int `json:"depth"`
51+
Actions []*EntitlementGraphAction `json:"actions"`
52+
HasNoCycles bool `json:"has_no_cycles"`
5353
}
5454

5555
func NewEntitlementGraph(_ context.Context) *EntitlementGraph {

pkg/sync/syncer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1469,7 +1469,7 @@ func (s *syncer) expandGrantsForEntitlements(ctx context.Context) error {
14691469
if grantInfo.IsExpanded {
14701470
continue
14711471
}
1472-
graph.Actions = append(graph.Actions, expand.EntitlementGraphAction{
1472+
graph.Actions = append(graph.Actions, &expand.EntitlementGraphAction{
14731473
SourceEntitlementID: sourceEntitlementID,
14741474
DescendantEntitlementID: descendantEntitlementID,
14751475
PageToken: "",

pkg/sync/syncer_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,58 @@ var userResourceType = &v2.ResourceType{
2929
Annotations: annotations.New(&v2.SkipEntitlementsAndGrants{}),
3030
}
3131

32+
func TestExpandGrants(t *testing.T) {
33+
ctx, cancel := context.WithCancel(context.Background())
34+
defer cancel()
35+
36+
// 2500 * 4 = 10K - used to cause an infinite loop on pagition
37+
usersPerLayer := 2500
38+
groupCount := 5
39+
40+
mc := newMockConnector()
41+
42+
mc.rtDB = append(mc.rtDB, groupResourceType, userResourceType)
43+
type asdf struct {
44+
r *v2.Resource
45+
e *v2.Entitlement
46+
}
47+
groups := make([]*asdf, 0)
48+
for i := 0; i < groupCount; i++ {
49+
groupId := "group_" + strconv.Itoa(i)
50+
group, groupEnt, err := mc.AddGroup(ctx, groupId)
51+
for _, g := range groups {
52+
_ = mc.AddGroupMember(ctx, g.r, group, groupEnt)
53+
}
54+
groups = append(groups, &asdf{
55+
r: group,
56+
e: groupEnt,
57+
})
58+
require.NoError(t, err)
59+
60+
for j := 0; j < usersPerLayer; j++ {
61+
pid := fmt.Sprintf("user_%d_%d_%d", i, usersPerLayer, j)
62+
principal, err := mc.AddUser(ctx, pid)
63+
require.NoError(t, err)
64+
65+
// This isn't needed because grant expansion will create this grant
66+
// _ = mc.AddGroupMember(ctx, group, principal)
67+
_ = mc.AddGroupMember(ctx, group, principal)
68+
}
69+
}
70+
71+
tempDir, err := os.MkdirTemp("", "baton-benchmark-expand-grants")
72+
require.NoError(t, err)
73+
defer os.RemoveAll(tempDir)
74+
c1zpath := filepath.Join(tempDir, "expand-grants.c1z")
75+
syncer, err := NewSyncer(ctx, mc, WithC1ZPath(c1zpath), WithTmpDir(tempDir))
76+
require.NoError(t, err)
77+
err = syncer.Sync(ctx)
78+
require.NoError(t, err)
79+
err = syncer.Close(ctx)
80+
require.NoError(t, err)
81+
_ = os.Remove(c1zpath)
82+
}
83+
3284
func BenchmarkExpandCircle(b *testing.B) {
3385
ctx, cancel := context.WithCancel(context.Background())
3486
defer cancel()

0 commit comments

Comments
 (0)