Skip to content

Commit 152b49e

Browse files
author
Martin Taillefer (from Dev Box)
committed
Revamp data classification model.
- Introduce the DataClassificationSet type that represents a set of combined classifications. This replaces the previous ability to OR together multiple classifications, which was too constraining.
1 parent 0265fb8 commit 152b49e

File tree

36 files changed

+296
-197
lines changed

36 files changed

+296
-197
lines changed

src/Generators/Microsoft.Gen.Logging/Emission/Emitter.Method.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -559,23 +559,25 @@ bool GenVariableAssignments(LoggingMethod lm, string lambdaStateName, int numRes
559559

560560
private string MakeClassificationValue(HashSet<string> classificationTypes)
561561
{
562-
if (classificationTypes.Count == 1)
563-
{
564-
return _classificationMap[classificationTypes.First()];
565-
}
566-
567562
var sb = _sbPool.GetStringBuilder();
568563

564+
_ = sb.Append("new global::Microsoft.Extensions.Compliance.Classification.DataClassificationSet(");
565+
566+
int i = 0;
567+
569568
foreach (var ct in classificationTypes)
570569
{
571-
if (sb.Length > 0)
570+
if (i > 0)
572571
{
573-
_ = sb.Append(" | ");
572+
_ = sb.Append(" , ");
574573
}
575574

576575
_ = sb.Append(_classificationMap[ct]);
576+
i++;
577577
}
578578

579+
_ = sb.Append(')');
580+
579581
return sb.ToString();
580582
}
581583

src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Classification/DataClassification.cs

Lines changed: 8 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,24 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5-
using System.Diagnostics.CodeAnalysis;
65
using Microsoft.Shared.Diagnostics;
76

87
namespace Microsoft.Extensions.Compliance.Classification;
98

109
/// <summary>
11-
/// Represents a set of data classes as a part of a data taxonomy.
10+
/// Represents a single data classes which is part of a data taxonomy.
1211
/// </summary>
1312
public readonly struct DataClassification : IEquatable<DataClassification>
1413
{
1514
/// <summary>
1615
/// Represents unclassified data.
1716
/// </summary>
18-
public const ulong NoneTaxonomyValue = 0UL;
17+
public const long NoneTaxonomyValue = 0;
1918

2019
/// <summary>
2120
/// Represents the unknown classification.
2221
/// </summary>
23-
public const ulong UnknownTaxonomyValue = 1UL << 63;
22+
public const long UnknownTaxonomyValue = -1;
2423

2524
/// <summary>
2625
/// Gets the value to represent data with no defined classification.
@@ -38,28 +37,28 @@ namespace Microsoft.Extensions.Compliance.Classification;
3837
public string TaxonomyName { get; }
3938

4039
/// <summary>
41-
/// Gets the bit mask representing the data classes.
40+
/// Gets the value representing the data classes within the taxonomy.
4241
/// </summary>
43-
public ulong Value { get; }
42+
public long Value { get; }
4443

4544
/// <summary>
4645
/// Initializes a new instance of the <see cref="DataClassification"/> struct.
4746
/// </summary>
4847
/// <param name="taxonomyName">The name of the taxonomy this classification belongs to.</param>
4948
/// <param name="value">The taxonomy-specific bit vector representing the data classes.</param>
5049
/// <exception cref="ArgumentException">Bit 63, which corresponds to <see cref="UnknownTaxonomyValue"/>, is set in the <paramref name="value"/> value.</exception>
51-
public DataClassification(string taxonomyName, ulong value)
50+
public DataClassification(string taxonomyName, long value)
5251
{
5352
TaxonomyName = Throw.IfNullOrEmpty(taxonomyName);
5453
Value = value;
5554

56-
if (((value & UnknownTaxonomyValue) != 0) || (value == NoneTaxonomyValue))
55+
if ((value == UnknownTaxonomyValue) || (value == NoneTaxonomyValue))
5756
{
5857
Throw.ArgumentException(nameof(value), $"Cannot create a classification with a value of 0x{value:x}.");
5958
}
6059
}
6160

62-
private DataClassification(ulong taxonomyValue)
61+
private DataClassification(long taxonomyValue)
6362
{
6463
TaxonomyName = string.Empty;
6564
Value = taxonomyValue;
@@ -110,45 +109,6 @@ public override int GetHashCode()
110109
return !left.Equals(right);
111110
}
112111

113-
/// <summary>
114-
/// Combines together two data classifications.
115-
/// </summary>
116-
/// <param name="left">The first classification to combine.</param>
117-
/// <param name="right">The second classification to combine.</param>
118-
/// <returns>A new classification object representing the combination of the two input classifications.</returns>
119-
/// <exception cref="ArgumentException">The two classifications aren't part of the same taxonomy.</exception>
120-
public static DataClassification Or(DataClassification left, DataClassification right)
121-
{
122-
if (string.IsNullOrEmpty(left.TaxonomyName))
123-
{
124-
return (left.Value == NoneTaxonomyValue) ? right : Unknown;
125-
}
126-
else if (string.IsNullOrEmpty(right.TaxonomyName))
127-
{
128-
return (right.Value == NoneTaxonomyValue) ? left : Unknown;
129-
}
130-
131-
if (left.TaxonomyName != right.TaxonomyName)
132-
{
133-
Throw.ArgumentException(nameof(right), $"Mismatched data taxonomies: {left.TaxonomyName} and {right.TaxonomyName} cannot be combined");
134-
}
135-
136-
return new(left.TaxonomyName, left.Value | right.Value);
137-
}
138-
139-
/// <summary>
140-
/// Combines together two data classifications.
141-
/// </summary>
142-
/// <param name="left">The first classification to combine.</param>
143-
/// <param name="right">The second classification to combine.</param>
144-
/// <returns>A new classification object representing the combination of the two input classifications.</returns>
145-
/// <exception cref="ArgumentException">The two classifications aren't part of the same taxonomy.</exception>
146-
[SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "It's called Combine")]
147-
public static DataClassification operator |(DataClassification left, DataClassification right)
148-
{
149-
return Or(left, right);
150-
}
151-
152112
/// <summary>
153113
/// Gets a string representation of this object.
154114
/// </summary>
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using Microsoft.Shared.Diagnostics;
7+
8+
namespace Microsoft.Extensions.Compliance.Classification;
9+
10+
/// <summary>
11+
/// Represents a set of data classes.
12+
/// </summary>
13+
public sealed class DataClassificationSet : IEquatable<DataClassificationSet>
14+
{
15+
private readonly HashSet<DataClassification> _classifications = [];
16+
17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="DataClassificationSet"/> class.
19+
/// </summary>
20+
/// <param name="classification">The class to include in the set.</param>
21+
public DataClassificationSet(DataClassification classification)
22+
{
23+
_ = _classifications.Add(classification);
24+
}
25+
26+
/// <summary>
27+
/// Initializes a new instance of the <see cref="DataClassificationSet"/> class.
28+
/// </summary>
29+
/// <param name="classifications">The classes to include in the set.</param>
30+
public DataClassificationSet(IEnumerable<DataClassification> classifications)
31+
{
32+
_ = Throw.IfNull(classifications);
33+
_classifications.UnionWith(classifications);
34+
}
35+
36+
/// <summary>
37+
/// Initializes a new instance of the <see cref="DataClassificationSet"/> class.
38+
/// </summary>
39+
/// <param name="classifications">The classes to include in the set.</param>
40+
public DataClassificationSet(params DataClassification[] classifications)
41+
{
42+
_ = Throw.IfNull(classifications);
43+
_classifications.UnionWith(classifications);
44+
}
45+
46+
/// <summary>
47+
/// Converts a data classification to a data classification set.
48+
/// </summary>
49+
/// <param name="classification">The classification to include in the set.</param>
50+
public static implicit operator DataClassificationSet(DataClassification classification)
51+
{
52+
return FromDataClassification(classification);
53+
}
54+
55+
/// <summary>
56+
/// Converts a data classification to a data classification set.
57+
/// </summary>
58+
/// <param name="classification">The classification to include in the set.</param>
59+
/// <returns>The resulting data classification set.</returns>
60+
public static DataClassificationSet FromDataClassification(DataClassification classification) => new(classification);
61+
62+
/// <summary>
63+
/// Creates a new data classification that combines the current classifications with another set.
64+
/// </summary>
65+
/// <param name="other">The other set.</param>
66+
/// <returns>The resulting set which combines the current instance's classifications and the other ones.</returns>
67+
public DataClassificationSet Union(DataClassificationSet other)
68+
{
69+
_ = Throw.IfNull(other);
70+
71+
var result = new DataClassificationSet(other._classifications);
72+
result._classifications.UnionWith(_classifications);
73+
74+
return result;
75+
}
76+
77+
/// <summary>
78+
/// Gets a hash code for the current object instance.
79+
/// </summary>
80+
/// <returns>The hash code value.</returns>
81+
public override int GetHashCode() => _classifications.GetHashCode();
82+
83+
/// <summary>
84+
/// Compares an object with the current instance to see if they contain the same data classes.
85+
/// </summary>
86+
/// <param name="obj">The other data classification to compare to.</param>
87+
/// <returns><see langword="true"/> if the two sets contain the same classifications.</returns>
88+
public override bool Equals(object? obj)
89+
{
90+
var dc = obj as DataClassificationSet;
91+
if (dc == null)
92+
{
93+
return false;
94+
}
95+
96+
return Equals(dc);
97+
}
98+
99+
/// <summary>
100+
/// Compares an object with the current instance to see if they contain the same data classes.
101+
/// </summary>
102+
/// <param name="other">The other data classification to compare to.</param>
103+
/// <returns><see langword="true"/> if the two sets contain the same classifications.</returns>
104+
public bool Equals(DataClassificationSet? other)
105+
{
106+
if (other == null)
107+
{
108+
return false;
109+
}
110+
111+
return _classifications.SetEquals(other._classifications);
112+
}
113+
}

src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Microsoft.Extensions.Compliance.Abstractions.json

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"Stage": "Stable",
77
"Methods": [
88
{
9-
"Member": "Microsoft.Extensions.Compliance.Classification.DataClassification.DataClassification(string taxonomyName, ulong value);",
9+
"Member": "Microsoft.Extensions.Compliance.Classification.DataClassification.DataClassification(string taxonomyName, long value);",
1010
"Stage": "Stable"
1111
},
1212
{
@@ -25,10 +25,6 @@
2525
"Member": "override int Microsoft.Extensions.Compliance.Classification.DataClassification.GetHashCode();",
2626
"Stage": "Stable"
2727
},
28-
{
29-
"Member": "static Microsoft.Extensions.Compliance.Classification.DataClassification Microsoft.Extensions.Compliance.Classification.DataClassification.operator |(Microsoft.Extensions.Compliance.Classification.DataClassification left, Microsoft.Extensions.Compliance.Classification.DataClassification right);",
30-
"Stage": "Stable"
31-
},
3228
{
3329
"Member": "static bool Microsoft.Extensions.Compliance.Classification.DataClassification.operator ==(Microsoft.Extensions.Compliance.Classification.DataClassification left, Microsoft.Extensions.Compliance.Classification.DataClassification right);",
3430
"Stage": "Stable"
@@ -37,25 +33,21 @@
3733
"Member": "static bool Microsoft.Extensions.Compliance.Classification.DataClassification.operator !=(Microsoft.Extensions.Compliance.Classification.DataClassification left, Microsoft.Extensions.Compliance.Classification.DataClassification right);",
3834
"Stage": "Stable"
3935
},
40-
{
41-
"Member": "static Microsoft.Extensions.Compliance.Classification.DataClassification Microsoft.Extensions.Compliance.Classification.DataClassification.Or(Microsoft.Extensions.Compliance.Classification.DataClassification left, Microsoft.Extensions.Compliance.Classification.DataClassification right);",
42-
"Stage": "Stable"
43-
},
4436
{
4537
"Member": "override string Microsoft.Extensions.Compliance.Classification.DataClassification.ToString();",
4638
"Stage": "Stable"
4739
}
4840
],
4941
"Fields": [
5042
{
51-
"Member": "const ulong Microsoft.Extensions.Compliance.Classification.DataClassification.NoneTaxonomyValue",
43+
"Member": "const long Microsoft.Extensions.Compliance.Classification.DataClassification.NoneTaxonomyValue",
5244
"Stage": "Stable",
5345
"Value": "0"
5446
},
5547
{
56-
"Member": "const ulong Microsoft.Extensions.Compliance.Classification.DataClassification.UnknownTaxonomyValue",
48+
"Member": "const long Microsoft.Extensions.Compliance.Classification.DataClassification.UnknownTaxonomyValue",
5749
"Stage": "Stable",
58-
"Value": "9223372036854775808"
50+
"Value": "-1"
5951
}
6052
],
6153
"Properties": [
@@ -72,7 +64,7 @@
7264
"Stage": "Stable"
7365
},
7466
{
75-
"Member": "ulong Microsoft.Extensions.Compliance.Classification.DataClassification.Value { get; }",
67+
"Member": "long Microsoft.Extensions.Compliance.Classification.DataClassification.Value { get; }",
7668
"Stage": "Stable"
7769
}
7870
]
@@ -97,6 +89,48 @@
9789
}
9890
]
9991
},
92+
{
93+
"Type": "sealed class Microsoft.Extensions.Compliance.Classification.DataClassificationSet : System.IEquatable<Microsoft.Extensions.Compliance.Classification.DataClassificationSet>",
94+
"Stage": "Stable",
95+
"Methods": [
96+
{
97+
"Member": "Microsoft.Extensions.Compliance.Classification.DataClassificationSet.DataClassificationSet(Microsoft.Extensions.Compliance.Classification.DataClassification classification);",
98+
"Stage": "Stable"
99+
},
100+
{
101+
"Member": "Microsoft.Extensions.Compliance.Classification.DataClassificationSet.DataClassificationSet(System.Collections.Generic.IEnumerable<Microsoft.Extensions.Compliance.Classification.DataClassification> classifications);",
102+
"Stage": "Stable"
103+
},
104+
{
105+
"Member": "Microsoft.Extensions.Compliance.Classification.DataClassificationSet.DataClassificationSet(params Microsoft.Extensions.Compliance.Classification.DataClassification[] classifications);",
106+
"Stage": "Stable"
107+
},
108+
{
109+
"Member": "override bool Microsoft.Extensions.Compliance.Classification.DataClassificationSet.Equals(object? obj);",
110+
"Stage": "Stable"
111+
},
112+
{
113+
"Member": "bool Microsoft.Extensions.Compliance.Classification.DataClassificationSet.Equals(Microsoft.Extensions.Compliance.Classification.DataClassificationSet? other);",
114+
"Stage": "Stable"
115+
},
116+
{
117+
"Member": "static Microsoft.Extensions.Compliance.Classification.DataClassificationSet Microsoft.Extensions.Compliance.Classification.DataClassificationSet.FromDataClassification(Microsoft.Extensions.Compliance.Classification.DataClassification classification);",
118+
"Stage": "Stable"
119+
},
120+
{
121+
"Member": "override int Microsoft.Extensions.Compliance.Classification.DataClassificationSet.GetHashCode();",
122+
"Stage": "Stable"
123+
},
124+
{
125+
"Member": "static Microsoft.Extensions.Compliance.Classification.DataClassificationSet.implicit operator Microsoft.Extensions.Compliance.Classification.DataClassificationSet(Microsoft.Extensions.Compliance.Classification.DataClassification classification);",
126+
"Stage": "Stable"
127+
},
128+
{
129+
"Member": "Microsoft.Extensions.Compliance.Classification.DataClassificationSet Microsoft.Extensions.Compliance.Classification.DataClassificationSet.Union(Microsoft.Extensions.Compliance.Classification.DataClassificationSet other);",
130+
"Stage": "Stable"
131+
}
132+
]
133+
},
100134
{
101135
"Type": "interface Microsoft.Extensions.Compliance.Redaction.IRedactionBuilder",
102136
"Stage": "Stable",
@@ -106,7 +140,7 @@
106140
"Stage": "Stable"
107141
},
108142
{
109-
"Member": "Microsoft.Extensions.Compliance.Redaction.IRedactionBuilder Microsoft.Extensions.Compliance.Redaction.IRedactionBuilder.SetRedactor<T>(params Microsoft.Extensions.Compliance.Classification.DataClassification[] classifications);",
143+
"Member": "Microsoft.Extensions.Compliance.Redaction.IRedactionBuilder Microsoft.Extensions.Compliance.Redaction.IRedactionBuilder.SetRedactor<T>(params Microsoft.Extensions.Compliance.Classification.DataClassificationSet[] classifications);",
110144
"Stage": "Stable"
111145
}
112146
],
@@ -122,7 +156,7 @@
122156
"Stage": "Stable",
123157
"Methods": [
124158
{
125-
"Member": "Microsoft.Extensions.Compliance.Redaction.Redactor Microsoft.Extensions.Compliance.Redaction.IRedactorProvider.GetRedactor(Microsoft.Extensions.Compliance.Classification.DataClassification classification);",
159+
"Member": "Microsoft.Extensions.Compliance.Redaction.Redactor Microsoft.Extensions.Compliance.Redaction.IRedactorProvider.GetRedactor(Microsoft.Extensions.Compliance.Classification.DataClassificationSet classifications);",
126160
"Stage": "Stable"
127161
}
128162
]
@@ -174,7 +208,7 @@
174208
"Stage": "Stable"
175209
},
176210
{
177-
"Member": "Microsoft.Extensions.Compliance.Redaction.Redactor Microsoft.Extensions.Compliance.Redaction.NullRedactorProvider.GetRedactor(Microsoft.Extensions.Compliance.Classification.DataClassification classification);",
211+
"Member": "Microsoft.Extensions.Compliance.Redaction.Redactor Microsoft.Extensions.Compliance.Redaction.NullRedactorProvider.GetRedactor(Microsoft.Extensions.Compliance.Classification.DataClassificationSet classifications);",
178212
"Stage": "Stable"
179213
}
180214
],

src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Redaction/IRedactionBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public interface IRedactionBuilder
2424
/// <param name="classifications">The data classes for which the redactor type should be used.</param>
2525
/// <returns>The value of this instance.</returns>
2626
/// <exception cref="ArgumentNullException"><paramref name="classifications" /> is <see langword="null" />.</exception>
27-
IRedactionBuilder SetRedactor<T>(params DataClassification[] classifications)
27+
IRedactionBuilder SetRedactor<T>(params DataClassificationSet[] classifications)
2828
where T : Redactor;
2929

3030
/// <summary>

0 commit comments

Comments
 (0)