Skip to content

Commit 949b80b

Browse files
Merge branch 'dev' into dev-pkgdeprecation
2 parents 7fefe5e + 71896c6 commit 949b80b

8 files changed

Lines changed: 302 additions & 5 deletions

File tree

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Linq;
5+
using NuGet.Services.FeatureFlags;
6+
7+
namespace NuGetGallery.Auditing.AuditedEntities
8+
{
9+
public class AuditedFeatureFlagFeature
10+
{
11+
public string Name { get; private set; }
12+
public FeatureStatus Status { get; private set; }
13+
14+
public static AuditedFeatureFlagFeature[] CreateFrom(FeatureFlags flags)
15+
{
16+
return flags.Features?
17+
.Select(f => CreateFrom(f.Key, f.Value))
18+
.ToArray() ?? new AuditedFeatureFlagFeature[0];
19+
}
20+
21+
public static AuditedFeatureFlagFeature CreateFrom(string name, FeatureStatus status)
22+
{
23+
return new AuditedFeatureFlagFeature
24+
{
25+
Name = name,
26+
Status = status
27+
};
28+
}
29+
}
30+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Linq;
5+
using NuGet.Services.FeatureFlags;
6+
7+
namespace NuGetGallery.Auditing.AuditedEntities
8+
{
9+
public class AuditedFeatureFlagFlight
10+
{
11+
public string Name { get; private set; }
12+
public bool All { get; private set; }
13+
public bool SiteAdmins { get; private set; }
14+
public string[] Accounts { get; private set; }
15+
public string[] Domains { get; private set; }
16+
17+
public static AuditedFeatureFlagFlight[] CreateFrom(FeatureFlags flags)
18+
{
19+
return flags.Flights?
20+
.Select(f => CreateFrom(f.Key, f.Value))
21+
.ToArray() ?? new AuditedFeatureFlagFlight[0];
22+
}
23+
24+
public static AuditedFeatureFlagFlight CreateFrom(string name, Flight flight)
25+
{
26+
return new AuditedFeatureFlagFlight
27+
{
28+
Name = name,
29+
All = flight.All,
30+
SiteAdmins = flight.SiteAdmins,
31+
Accounts = flight.Accounts?.ToArray() ?? new string[0],
32+
Domains = flight.Domains?.ToArray() ?? new string[0]
33+
};
34+
}
35+
}
36+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace NuGetGallery.Auditing
5+
{
6+
public enum AuditedFeatureFlagsAction
7+
{
8+
Update
9+
}
10+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using NuGet.Services.FeatureFlags;
6+
using NuGetGallery.Auditing.AuditedEntities;
7+
using NuGetGallery.Features;
8+
9+
namespace NuGetGallery.Auditing
10+
{
11+
public sealed class FeatureFlagsAuditRecord : AuditRecord<AuditedFeatureFlagsAction>
12+
{
13+
public AuditedFeatureFlagFeature[] Features { get; }
14+
public AuditedFeatureFlagFlight[] Flights { get; }
15+
public string ContentId { get; }
16+
public FeatureFlagSaveResult Result { get; }
17+
18+
public FeatureFlagsAuditRecord(
19+
AuditedFeatureFlagsAction action,
20+
FeatureFlags flags,
21+
string contentId,
22+
FeatureFlagSaveResult result)
23+
: base(action)
24+
{
25+
if (flags == null)
26+
{
27+
throw new ArgumentNullException(nameof(flags));
28+
}
29+
30+
ContentId = contentId ?? throw new ArgumentNullException(nameof(contentId));
31+
32+
Features = AuditedFeatureFlagFeature.CreateFrom(flags);
33+
Flights = AuditedFeatureFlagFlight.CreateFrom(flags);
34+
35+
Result = result;
36+
37+
// Group feature flags changes by the month they occurred in.
38+
var currentTime = DateTime.UtcNow;
39+
_path = $"{currentTime.Year}-{currentTime.Month}";
40+
}
41+
42+
private readonly string _path;
43+
public override string GetPath()
44+
{
45+
return _path;
46+
}
47+
}
48+
}

src/NuGetGallery.Core/Features/FeatureFlagFileStorageService.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
using Microsoft.WindowsAzure.Storage;
1111
using Newtonsoft.Json;
1212
using Newtonsoft.Json.Converters;
13-
using Newtonsoft.Json.Linq;
1413
using NuGet.Services.Entities;
1514
using NuGet.Services.FeatureFlags;
15+
using NuGetGallery.Auditing;
1616

1717
namespace NuGetGallery.Features
1818
{
@@ -23,6 +23,7 @@ public class FeatureFlagFileStorageService : IEditableFeatureFlagStorageService
2323
private static readonly JsonSerializer Serializer;
2424

2525
private readonly ICoreFileStorageService _storage;
26+
private readonly IAuditingService _auditing;
2627
private readonly ILogger<FeatureFlagFileStorageService> _logger;
2728

2829
static FeatureFlagFileStorageService()
@@ -40,9 +41,11 @@ static FeatureFlagFileStorageService()
4041

4142
public FeatureFlagFileStorageService(
4243
ICoreFileStorageService storage,
44+
IAuditingService auditing,
4345
ILogger<FeatureFlagFileStorageService> logger)
4446
{
4547
_storage = storage ?? throw new ArgumentNullException(nameof(storage));
48+
_auditing = auditing ?? throw new ArgumentNullException(nameof(auditing));
4649
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
4750
}
4851

@@ -118,6 +121,19 @@ public async Task RemoveUserAsync(User user)
118121
}
119122

120123
public async Task<FeatureFlagSaveResult> TrySaveAsync(FeatureFlags flags, string contentId)
124+
{
125+
var result = await TrySaveInternalAsync(flags, contentId);
126+
await _auditing.SaveAuditRecordAsync(
127+
new FeatureFlagsAuditRecord(
128+
AuditedFeatureFlagsAction.Update,
129+
flags,
130+
contentId,
131+
result));
132+
133+
return result;
134+
}
135+
136+
private async Task<FeatureFlagSaveResult> TrySaveInternalAsync(FeatureFlags flags, string contentId)
121137
{
122138
var accessCondition = AccessConditionWrapper.GenerateIfMatchCondition(contentId);
123139

src/NuGetGallery.Core/NuGetGallery.Core.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,13 @@
6262
</ItemGroup>
6363
<ItemGroup>
6464
<Compile Include="Auditing\AggregateAuditingService.cs" />
65+
<Compile Include="Auditing\AuditedEntities\AuditedFeatureFlagFlight.cs" />
66+
<Compile Include="Auditing\AuditedEntities\AuditedFeatureFlagFeature.cs" />
67+
<Compile Include="Auditing\AuditedFeatureFlagsAction.cs" />
6568
<Compile Include="Auditing\AuditedCertificateAction.cs" />
6669
<Compile Include="Auditing\AuditedDeleteAccountAction.cs" />
6770
<Compile Include="Auditing\AuditedEntities\AuditedPackageDeprecation.cs" />
71+
<Compile Include="Auditing\FeatureFlagsAuditRecord.cs" />
6872
<Compile Include="Auditing\CertificateAuditRecord.cs" />
6973
<Compile Include="Auditing\Obfuscation\ObfuscateAttribute.cs" />
7074
<Compile Include="Auditing\Obfuscation\ObfuscationType.cs" />

tests/NuGetGallery.Core.Facts/Auditing/AuditRecordTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public void SubclassingTypeSet_HasNotChanged()
1818
"NuGetGallery.Auditing.CertificateAuditRecord",
1919
"NuGetGallery.Auditing.DeleteAccountAuditRecord",
2020
"NuGetGallery.Auditing.FailedAuthenticatedOperationAuditRecord",
21+
"NuGetGallery.Auditing.FeatureFlagsAuditRecord",
2122
"NuGetGallery.Auditing.PackageAuditRecord",
2223
"NuGetGallery.Auditing.PackageRegistrationAuditRecord",
2324
"NuGetGallery.Auditing.ReservedNamespaceAuditRecord",

0 commit comments

Comments
 (0)