Skip to content

Commit 20d94c3

Browse files
authored
Add density profiles to Seeder CLI (#7205)
1 parent 7677107 commit 20d94c3

8 files changed

Lines changed: 778 additions & 64 deletions

File tree

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
using Bit.Seeder.Data.Enums;
2+
using Bit.Seeder.Options;
3+
4+
namespace Bit.Seeder.Data.Distributions;
5+
6+
/// <summary>
7+
/// Named density profiles for CLI usage. Size-independent — user controls entity counts
8+
/// via <c>-u</c>, <c>-g</c>, <c>-c</c>, <c>-l</c> flags separately.
9+
/// </summary>
10+
public static class DensityProfiles
11+
{
12+
/// <summary>
13+
/// Balanced mid-market org. Even split between direct and group-mediated access.
14+
/// Archetype: Sterling Cooper / Wayne Enterprises.
15+
/// </summary>
16+
public static DensityProfile Balanced { get; } = new()
17+
{
18+
MembershipShape = MembershipDistributionShape.PowerLaw,
19+
MembershipSkew = 0.6,
20+
CollectionFanOutMin = 1,
21+
CollectionFanOutMax = 5,
22+
FanOutShape = CollectionFanOutShape.PowerLaw,
23+
EmptyGroupRate = 0.1,
24+
DirectAccessRatio = 0.5,
25+
PermissionDistribution = PermissionDistributions.MidMarket,
26+
UserCollectionMin = 1,
27+
UserCollectionMax = 10,
28+
UserCollectionShape = CollectionFanOutShape.PowerLaw,
29+
UserCollectionSkew = 0.5,
30+
CipherSkew = CipherCollectionSkew.HeavyRight,
31+
OrphanCipherRate = 0.08,
32+
MultiCollectionRate = 0.20,
33+
MaxCollectionsPerCipher = 3,
34+
PersonalCipherDistribution = PersonalCipherDistributions.Realistic,
35+
FolderDistribution = FolderCountDistributions.Realistic,
36+
};
37+
38+
/// <summary>
39+
/// High permission density with steep power-law membership and enterprise read-heavy permissions.
40+
/// Archetype: Tyrell Corp / Bluth Company.
41+
/// </summary>
42+
public static DensityProfile HighPerm { get; } = new()
43+
{
44+
MembershipShape = MembershipDistributionShape.PowerLaw,
45+
MembershipSkew = 0.8,
46+
CollectionFanOutMin = 2,
47+
CollectionFanOutMax = 8,
48+
FanOutShape = CollectionFanOutShape.PowerLaw,
49+
EmptyGroupRate = 0.2,
50+
DirectAccessRatio = 0.6,
51+
PermissionDistribution = PermissionDistributions.Enterprise,
52+
UserCollectionMin = 1,
53+
UserCollectionMax = 30,
54+
UserCollectionShape = CollectionFanOutShape.PowerLaw,
55+
UserCollectionSkew = 0.7,
56+
CipherSkew = CipherCollectionSkew.HeavyRight,
57+
OrphanCipherRate = 0.15,
58+
MultiCollectionRate = 0.30,
59+
MaxCollectionsPerCipher = 4,
60+
PersonalCipherDistribution = PersonalCipherDistributions.Realistic,
61+
FolderDistribution = FolderCountDistributions.Enterprise,
62+
};
63+
64+
/// <summary>
65+
/// Mega-group with high collection count and write-heavy permissions.
66+
/// Archetype: Umbrella Corp.
67+
/// </summary>
68+
public static DensityProfile HighCollection { get; } = new()
69+
{
70+
MembershipShape = MembershipDistributionShape.MegaGroup,
71+
MembershipSkew = 0.5,
72+
CollectionFanOutMin = 1,
73+
CollectionFanOutMax = 3,
74+
FanOutShape = CollectionFanOutShape.FrontLoaded,
75+
EmptyGroupRate = 0.0,
76+
DirectAccessRatio = 0.9,
77+
PermissionDistribution = PermissionDistributions.MidMarketWriteHeavy,
78+
UserCollectionMin = 1,
79+
UserCollectionMax = 15,
80+
UserCollectionShape = CollectionFanOutShape.PowerLaw,
81+
UserCollectionSkew = 0.6,
82+
CipherSkew = CipherCollectionSkew.HeavyRight,
83+
OrphanCipherRate = 0.20,
84+
MultiCollectionRate = 0.25,
85+
MaxCollectionsPerCipher = 3,
86+
PersonalCipherDistribution = PersonalCipherDistributions.Realistic,
87+
FolderDistribution = FolderCountDistributions.Realistic,
88+
};
89+
90+
/// <summary>
91+
/// Extreme mega-group with all-direct access and very high orphan rate.
92+
/// Archetype: Initech (Baker McKenzie production pattern).
93+
/// </summary>
94+
public static DensityProfile Broad { get; } = new()
95+
{
96+
MembershipShape = MembershipDistributionShape.MegaGroup,
97+
MembershipSkew = 0.95,
98+
CollectionFanOutMin = 1,
99+
CollectionFanOutMax = 2,
100+
FanOutShape = CollectionFanOutShape.Uniform,
101+
EmptyGroupRate = 0.0,
102+
DirectAccessRatio = 1.0,
103+
PermissionDistribution = PermissionDistributions.EnterpriseManageHeavy,
104+
UserCollectionMin = 1,
105+
UserCollectionMax = 20,
106+
UserCollectionShape = CollectionFanOutShape.PowerLaw,
107+
UserCollectionSkew = 0.5,
108+
CipherSkew = CipherCollectionSkew.HeavyRight,
109+
OrphanCipherRate = 0.85,
110+
MultiCollectionRate = 0.15,
111+
MaxCollectionsPerCipher = 3,
112+
PersonalCipherDistribution = PersonalCipherDistributions.LightUsage,
113+
FolderDistribution = FolderCountDistributions.Minimal,
114+
};
115+
116+
/// <summary>
117+
/// Low-complexity family/starter org with uniform distributions and no orphans.
118+
/// Archetype: Central Perk.
119+
/// </summary>
120+
public static DensityProfile Minimal { get; } = new()
121+
{
122+
MembershipShape = MembershipDistributionShape.Uniform,
123+
MembershipSkew = 0.0,
124+
CollectionFanOutMin = 1,
125+
CollectionFanOutMax = 2,
126+
FanOutShape = CollectionFanOutShape.Uniform,
127+
EmptyGroupRate = 0.0,
128+
DirectAccessRatio = 0.8,
129+
PermissionDistribution = PermissionDistributions.Family,
130+
UserCollectionMin = 1,
131+
UserCollectionMax = 3,
132+
UserCollectionShape = CollectionFanOutShape.Uniform,
133+
UserCollectionSkew = 0.0,
134+
CipherSkew = CipherCollectionSkew.Uniform,
135+
OrphanCipherRate = 0.0,
136+
MultiCollectionRate = 0.20,
137+
MaxCollectionsPerCipher = 2,
138+
PersonalCipherDistribution = PersonalCipherDistributions.Realistic,
139+
FolderDistribution = FolderCountDistributions.Realistic,
140+
};
141+
142+
/// <summary>
143+
/// Almost all access via groups, very low direct access. Tests CollectionGroup-heavy code paths.
144+
/// </summary>
145+
public static DensityProfile GroupHeavy { get; } = new()
146+
{
147+
MembershipShape = MembershipDistributionShape.PowerLaw,
148+
MembershipSkew = 0.7,
149+
CollectionFanOutMin = 2,
150+
CollectionFanOutMax = 6,
151+
FanOutShape = CollectionFanOutShape.PowerLaw,
152+
EmptyGroupRate = 0.1,
153+
DirectAccessRatio = 0.1,
154+
PermissionDistribution = PermissionDistributions.MidMarketWriteHeavy,
155+
UserCollectionMin = 1,
156+
UserCollectionMax = 8,
157+
UserCollectionShape = CollectionFanOutShape.PowerLaw,
158+
UserCollectionSkew = 0.5,
159+
CipherSkew = CipherCollectionSkew.HeavyRight,
160+
OrphanCipherRate = 0.10,
161+
MultiCollectionRate = 0.20,
162+
MaxCollectionsPerCipher = 3,
163+
PersonalCipherDistribution = PersonalCipherDistributions.Realistic,
164+
FolderDistribution = FolderCountDistributions.Realistic,
165+
};
166+
167+
/// <summary>
168+
/// Low access density — few groups per collection, few collections per user, high orphan rate.
169+
/// Models orgs where most users have minimal access and most ciphers are unassigned.
170+
/// </summary>
171+
public static DensityProfile Sparse { get; } = new()
172+
{
173+
MembershipShape = MembershipDistributionShape.PowerLaw,
174+
MembershipSkew = 0.5,
175+
CollectionFanOutMin = 1,
176+
CollectionFanOutMax = 2,
177+
FanOutShape = CollectionFanOutShape.Uniform,
178+
EmptyGroupRate = 0.3,
179+
DirectAccessRatio = 0.3,
180+
PermissionDistribution = PermissionDistributions.Enterprise,
181+
UserCollectionMin = 1,
182+
UserCollectionMax = 3,
183+
UserCollectionShape = CollectionFanOutShape.Uniform,
184+
UserCollectionSkew = 0.0,
185+
CipherSkew = CipherCollectionSkew.HeavyRight,
186+
OrphanCipherRate = 0.30,
187+
MultiCollectionRate = 0.10,
188+
MaxCollectionsPerCipher = 2,
189+
PersonalCipherDistribution = PersonalCipherDistributions.LightUsage,
190+
FolderDistribution = FolderCountDistributions.Minimal,
191+
};
192+
193+
/// <summary>
194+
/// Parses a profile name to a <see cref="DensityProfile"/>. Returns null for null/empty input.
195+
/// </summary>
196+
public static DensityProfile? Parse(string? name)
197+
{
198+
if (string.IsNullOrEmpty(name))
199+
{
200+
return null;
201+
}
202+
203+
return name.ToLowerInvariant() switch
204+
{
205+
"balanced" => Balanced,
206+
"highperm" => HighPerm,
207+
"highcollection" => HighCollection,
208+
"broad" => Broad,
209+
"minimal" => Minimal,
210+
"groupheavy" => GroupHeavy,
211+
"sparse" => Sparse,
212+
_ => throw new ArgumentException(
213+
$"Unknown density profile '{name}'. Use: balanced, highPerm, highCollection, broad, minimal, groupHeavy, or sparse")
214+
};
215+
}
216+
}

util/Seeder/Data/Enums/CompanyCategory.cs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,42 @@
55
/// </summary>
66
public enum CompanyCategory
77
{
8-
SocialMedia, Streaming, ECommerce, CRM, Security, CloudInfrastructure,
9-
DevOps, Collaboration, HRTalent, FinanceERP, Analytics, ProjectManagement,
10-
Marketing, ITServiceManagement, Productivity, Developer, Financial
8+
SocialMedia,
9+
Streaming,
10+
ECommerce,
11+
CRM,
12+
Security,
13+
CloudInfrastructure,
14+
DevOps,
15+
Collaboration,
16+
HRTalent,
17+
FinanceERP,
18+
Analytics,
19+
ProjectManagement,
20+
Marketing,
21+
ITServiceManagement,
22+
Productivity,
23+
Developer,
24+
Financial,
25+
Travel,
26+
Airlines,
27+
Hotels,
28+
CarRental,
29+
Rail,
30+
RideShare,
31+
Banking,
32+
Insurance,
33+
Healthcare,
34+
Telecom,
35+
Education,
36+
Retail,
37+
FoodBeverage,
38+
Automotive,
39+
Gaming,
40+
News,
41+
Energy,
42+
RealEstate,
43+
Logistics,
44+
Fitness,
45+
Government
1146
}

util/Seeder/Data/Enums/OrgStructureModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
/// <summary>
44
/// Organizational structure model types.
55
/// </summary>
6-
public enum OrgStructureModel { Traditional, Spotify, Modern }
6+
public enum OrgStructureModel { Traditional, Spotify, Modern, Government, SchoolDistrict, Healthcare, Startup }

0 commit comments

Comments
 (0)