diff --git a/src/ApiService/ApiService/ApiService.csproj b/src/ApiService/ApiService/ApiService.csproj
index c6f25abd3..a1d9018e1 100644
--- a/src/ApiService/ApiService/ApiService.csproj
+++ b/src/ApiService/ApiService/ApiService.csproj
@@ -11,6 +11,9 @@
+
+
+
diff --git a/src/ApiService/ApiService/FeatureFlags.cs b/src/ApiService/ApiService/FeatureFlags.cs
new file mode 100644
index 000000000..a55a3dad1
--- /dev/null
+++ b/src/ApiService/ApiService/FeatureFlags.cs
@@ -0,0 +1,5 @@
+namespace Microsoft.OneFuzz.Service;
+
+public static class FeatureFlagConstants {
+ public const string EnableScribanOnly = "EnableScribanOnly";
+}
diff --git a/src/ApiService/ApiService/Functions/AgentCanSchedule.cs b/src/ApiService/ApiService/Functions/AgentCanSchedule.cs
index af41c3efe..8d74f2dec 100644
--- a/src/ApiService/ApiService/Functions/AgentCanSchedule.cs
+++ b/src/ApiService/ApiService/Functions/AgentCanSchedule.cs
@@ -8,6 +8,7 @@ public class AgentCanSchedule {
private readonly IEndpointAuthorization _auth;
private readonly IOnefuzzContext _context;
+
public AgentCanSchedule(ILogTracer log, IEndpointAuthorization auth, IOnefuzzContext context) {
_log = log;
_auth = auth;
diff --git a/src/ApiService/ApiService/Program.cs b/src/ApiService/ApiService/Program.cs
index 7db6db60f..00b3d686a 100644
--- a/src/ApiService/ApiService/Program.cs
+++ b/src/ApiService/ApiService/Program.cs
@@ -13,8 +13,10 @@ using Azure.Identity;
using Microsoft.ApplicationInsights.DependencyCollector;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Middleware;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
+using Microsoft.FeatureManagement;
using Microsoft.Graph;
using Microsoft.OneFuzz.Service.OneFuzzLib.Orm;
@@ -47,6 +49,13 @@ public class Program {
using var host =
new HostBuilder()
+ .ConfigureAppConfiguration(builder => {
+ var _ = builder.AddAzureAppConfiguration(options => {
+ var _ = options
+ .Connect(new Uri(configuration.AppConfigurationEndpoint!), new DefaultAzureCredential())
+ .UseFeatureFlags(ffOptions => ffOptions.CacheExpirationInterval = TimeSpan.FromMinutes(1));
+ });
+ })
.ConfigureFunctionsWorkerDefaults(builder => {
builder.UseMiddleware();
builder.AddApplicationInsights(options => {
@@ -54,6 +63,8 @@ public class Program {
});
})
.ConfigureServices((context, services) => {
+ services.AddAzureAppConfiguration();
+ _ = services.AddFeatureManagement();
services.Configure(options => {
options = EntityConverter.GetJsonSerializerOptions();
});
diff --git a/src/ApiService/ApiService/ServiceConfiguration.cs b/src/ApiService/ApiService/ServiceConfiguration.cs
index d535cc7a7..7dca0b427 100644
--- a/src/ApiService/ApiService/ServiceConfiguration.cs
+++ b/src/ApiService/ApiService/ServiceConfiguration.cs
@@ -16,6 +16,7 @@ public interface IServiceConfig {
public string? ApplicationInsightsAppId { get; }
public string? ApplicationInsightsInstrumentationKey { get; }
+ public string? AppConfigurationEndpoint { get; }
public string? AzureSignalRConnectionString { get; }
public string? AzureSignalRServiceTransportType { get; }
@@ -82,6 +83,8 @@ public class ServiceConfiguration : IServiceConfig {
public string? ApplicationInsightsAppId => GetEnv("APPINSIGHTS_APPID");
public string? ApplicationInsightsInstrumentationKey => GetEnv("APPINSIGHTS_INSTRUMENTATIONKEY");
+ public string? AppConfigurationEndpoint => GetEnv("APPCONFIGURATION_ENDPOINT");
+
public string? AzureSignalRConnectionString => GetEnv("AzureSignalRConnectionString");
public string? AzureSignalRServiceTransportType => GetEnv("AzureSignalRServiceTransportType");
diff --git a/src/ApiService/ApiService/onefuzzlib/OnefuzzContext.cs b/src/ApiService/ApiService/onefuzzlib/OnefuzzContext.cs
index 01c9e6dc7..ffda56aaa 100644
--- a/src/ApiService/ApiService/onefuzzlib/OnefuzzContext.cs
+++ b/src/ApiService/ApiService/onefuzzlib/OnefuzzContext.cs
@@ -1,8 +1,11 @@
using Microsoft.OneFuzz.Service.OneFuzzLib.Orm;
+
namespace Microsoft.OneFuzz.Service;
+using Microsoft.Extensions.Configuration.AzureAppConfiguration;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.FeatureManagement;
public interface IOnefuzzContext {
IAutoScaleOperations AutoScaleOperations { get; }
@@ -46,6 +49,9 @@ public interface IOnefuzzContext {
ITeams Teams { get; }
IGithubIssues GithubIssues { get; }
IAdo Ado { get; }
+
+ IFeatureManagerSnapshot FeatureManagerSnapshot { get; }
+ IConfigurationRefresher ConfigurationRefresher { get; }
}
public class OnefuzzContext : IOnefuzzContext {
@@ -95,4 +101,8 @@ public class OnefuzzContext : IOnefuzzContext {
public ITeams Teams => _serviceProvider.GetRequiredService();
public IGithubIssues GithubIssues => _serviceProvider.GetRequiredService();
public IAdo Ado => _serviceProvider.GetRequiredService();
+
+ public IFeatureManagerSnapshot FeatureManagerSnapshot => _serviceProvider.GetRequiredService();
+
+ public IConfigurationRefresher ConfigurationRefresher => _serviceProvider.GetRequiredService().Refreshers.First();
}
diff --git a/src/ApiService/ApiService/onefuzzlib/notifications/NotificationsBase.cs b/src/ApiService/ApiService/onefuzzlib/notifications/NotificationsBase.cs
index c727617ba..8ae8d7287 100644
--- a/src/ApiService/ApiService/onefuzzlib/notifications/NotificationsBase.cs
+++ b/src/ApiService/ApiService/onefuzzlib/notifications/NotificationsBase.cs
@@ -34,6 +34,7 @@ public abstract class NotificationsBase {
private readonly Uri _targetUrl;
private readonly Uri _inputUrl;
private readonly Uri _reportUrl;
+ private readonly bool _scribanOnly;
public static async Async.Task ConstructRenderer(
IOnefuzzContext context,
@@ -66,6 +67,9 @@ public abstract class NotificationsBase {
inputUrl = new Uri(context.Containers.AuthDownloadUrl(report.InputBlob.Container, report.InputBlob.Name));
}
+ await context.ConfigurationRefresher.TryRefreshAsync().IgnoreResult();
+ var scribanOnly = await context.FeatureManagerSnapshot.IsEnabledAsync(FeatureFlagConstants.EnableScribanOnly);
+
return new Renderer(
container,
filename,
@@ -74,7 +78,8 @@ public abstract class NotificationsBase {
checkedJob,
targetUrl,
inputUrl!, // TODO: incorrect
- reportUrl);
+ reportUrl,
+ scribanOnly);
}
public Renderer(
Container container,
@@ -84,7 +89,8 @@ public abstract class NotificationsBase {
Job job,
Uri targetUrl,
Uri inputUrl,
- Uri reportUrl) {
+ Uri reportUrl,
+ bool scribanOnly) {
_report = report;
_container = container;
_filename = filename;
@@ -93,13 +99,17 @@ public abstract class NotificationsBase {
_reportUrl = reportUrl;
_targetUrl = targetUrl;
_inputUrl = inputUrl;
+ _scribanOnly = scribanOnly;
}
// TODO: This function is fallible but the python
// implementation doesn't have that so I'm trying to match it.
// We should probably propagate any errors up
public async Async.Task Render(string templateString, Uri instanceUrl) {
- templateString = JinjaTemplateAdapter.IsJinjaTemplate(templateString) ? JinjaTemplateAdapter.AdaptForScriban(templateString) : templateString;
+ if (!_scribanOnly && JinjaTemplateAdapter.IsJinjaTemplate(templateString)) {
+ templateString = JinjaTemplateAdapter.AdaptForScriban(templateString);
+ }
+
var template = Template.Parse(templateString);
if (template != null) {
return await template.RenderAsync(new {
diff --git a/src/ApiService/ApiService/packages.lock.json b/src/ApiService/ApiService/packages.lock.json
index b033ab012..82f60a9de 100644
--- a/src/ApiService/ApiService/packages.lock.json
+++ b/src/ApiService/ApiService/packages.lock.json
@@ -157,6 +157,16 @@
"resolved": "0.12.2",
"contentHash": "JgMAGj8ekeAzKkagubXqf1UqgfHq89GyA1UQYWbkAe441uRr2Rh2rktkx5Z0LPwmD/aOqu9cxjekD2GZjP8rbw=="
},
+ "Microsoft.Azure.Functions.Extensions": {
+ "type": "Direct",
+ "requested": "[1.1.0, )",
+ "resolved": "1.1.0",
+ "contentHash": "zYKtQQoS1fdzufxFApuMFiFtoi9QAGH6McXxntpylwLKgKjmCMWdgUd1dcekzTKNR9DPSDPRLiulvukqXnpWrQ==",
+ "dependencies": {
+ "Microsoft.Azure.WebJobs": "3.0.18",
+ "Microsoft.Extensions.DependencyInjection": "2.1.0"
+ }
+ },
"Microsoft.Azure.Functions.Worker": {
"type": "Direct",
"requested": "[1.10.0, )",
@@ -262,6 +272,31 @@
"System.Net.Http": "4.3.0"
}
},
+ "Microsoft.Extensions.Configuration.AzureAppConfiguration": {
+ "type": "Direct",
+ "requested": "[5.1.0, )",
+ "resolved": "5.1.0",
+ "contentHash": "FoAfgvT/rjL/+c7BP7q0LrJIdc4Hu6SH56BTIUbwCwVjHoUw4dpgGtLQULi5GmMjdbdAxyLQSnbwpOEWuBy+RA==",
+ "dependencies": {
+ "Azure.Data.AppConfiguration": "1.2.0",
+ "Azure.Messaging.EventGrid": "4.7.0",
+ "Azure.Security.KeyVault.Secrets": "4.0.1",
+ "Microsoft.Extensions.Configuration": "3.1.18",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.18",
+ "Microsoft.Extensions.Logging": "3.1.18",
+ "System.Text.Json": "4.6.0"
+ }
+ },
+ "Microsoft.FeatureManagement": {
+ "type": "Direct",
+ "requested": "[2.5.1, )",
+ "resolved": "2.5.1",
+ "contentHash": "ERbRjk0etZs4d5Pv17unfogO4iBwV2c/HoBt4jqIJmfbKbmTLV+GbjBPYzidIg2RgYIFi8yA+EoEapSAIOp19g==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Binder": "2.1.10",
+ "Microsoft.Extensions.Logging": "2.1.1"
+ }
+ },
"Microsoft.Graph": {
"type": "Direct",
"requested": "[4.37.0, )",
@@ -355,6 +390,16 @@
"resolved": "2.0.0",
"contentHash": "rXkSI9t4vP2EaPhuchsWiD3elcLNth3UOZAlGohGmuckpkiOr57oMHuzM5WDzz7MJd+ZewE27/WfrZhhhFDHzA=="
},
+ "Azure.Data.AppConfiguration": {
+ "type": "Transitive",
+ "resolved": "1.2.0",
+ "contentHash": "KA1dAM9TuDsq0CRFd+3cJTYUAzA2z9N8t9/xKdDbP9URuReq/NDFcKYr7GW2W9xzVGDtCHlD5j5am/+zLLBdSg==",
+ "dependencies": {
+ "Azure.Core": "1.20.0",
+ "Microsoft.Bcl.AsyncInterfaces": "1.0.0",
+ "System.Text.Json": "4.6.0"
+ }
+ },
"Azure.Storage.Common": {
"type": "Transitive",
"resolved": "12.12.0",
@@ -567,6 +612,33 @@
"Microsoft.CodeAnalysis.CSharp": "3.11.0"
}
},
+ "Microsoft.Azure.WebJobs": {
+ "type": "Transitive",
+ "resolved": "3.0.18",
+ "contentHash": "aYJ76yjPkIpsafqFp1Xz1sA06RvhUwqJnk4AqX4I0teuRjPyig9Sv7LTzxUMAppKXc4JyR/Asos2At/LMiblqg==",
+ "dependencies": {
+ "Microsoft.Azure.WebJobs.Core": "3.0.18",
+ "Microsoft.Extensions.Configuration": "2.1.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "2.1.0",
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": "2.1.0",
+ "Microsoft.Extensions.Configuration.Json": "2.1.0",
+ "Microsoft.Extensions.Hosting": "2.1.0",
+ "Microsoft.Extensions.Logging": "2.1.0",
+ "Microsoft.Extensions.Logging.Abstractions": "2.1.0",
+ "Microsoft.Extensions.Logging.Configuration": "2.1.0",
+ "Newtonsoft.Json": "11.0.2",
+ "System.Threading.Tasks.Dataflow": "4.8.0"
+ }
+ },
+ "Microsoft.Azure.WebJobs.Core": {
+ "type": "Transitive",
+ "resolved": "3.0.18",
+ "contentHash": "ajYI8pPzPn4qq7FL8C2tz9WmFEG5PorUlkw8W9CF5M+5egnFJaF7yH48WYC+zBoQIzv2vHmFq0zhQpnv+O8v5Q==",
+ "dependencies": {
+ "System.ComponentModel.Annotations": "4.4.0",
+ "System.Diagnostics.TraceSource": "4.3.0"
+ }
+ },
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "6.0.0",
@@ -1381,6 +1453,22 @@
"System.Runtime": "4.3.0"
}
},
+ "System.Diagnostics.TraceSource": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "VnYp1NxGx8Ww731y2LJ1vpfb/DKVNKEZ8Jsh5SgQTZREL/YpWRArgh9pI8CDLmgHspZmLL697CaLvH85qQpRiw==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0",
+ "System.Collections": "4.3.0",
+ "System.Diagnostics.Debug": "4.3.0",
+ "System.Globalization": "4.3.0",
+ "System.Resources.ResourceManager": "4.3.0",
+ "System.Runtime": "4.3.0",
+ "System.Runtime.Extensions": "4.3.0",
+ "System.Threading": "4.3.0",
+ "runtime.native.System": "4.3.0"
+ }
+ },
"System.Diagnostics.Tracing": {
"type": "Transitive",
"resolved": "4.3.0",
@@ -2077,6 +2165,11 @@
"System.Runtime": "4.3.0"
}
},
+ "System.Threading.Tasks.Dataflow": {
+ "type": "Transitive",
+ "resolved": "4.8.0",
+ "contentHash": "PSIdcgbyNv7FZvZ1I9Mqy6XZOwstYYMdZiXuHvIyc0gDyPjEhrrP9OvTGDHp+LAHp1RNSLjPYssyqox9+Kt9Ug=="
+ },
"System.Threading.Tasks.Extensions": {
"type": "Transitive",
"resolved": "4.5.4",
diff --git a/src/ApiService/IntegrationTests/Fakes/TestContext.cs b/src/ApiService/IntegrationTests/Fakes/TestContext.cs
index 60d2af0ca..9106dfc0d 100644
--- a/src/ApiService/IntegrationTests/Fakes/TestContext.cs
+++ b/src/ApiService/IntegrationTests/Fakes/TestContext.cs
@@ -1,7 +1,9 @@
using System;
using System.Linq;
using Microsoft.Extensions.Caching.Memory;
+using Microsoft.Extensions.Configuration.AzureAppConfiguration;
using Microsoft.Extensions.Options;
+using Microsoft.FeatureManagement;
using Microsoft.OneFuzz.Service;
using Microsoft.OneFuzz.Service.OneFuzzLib.Orm;
using Async = System.Threading.Tasks;
@@ -120,6 +122,7 @@ public sealed class TestContext : IOnefuzzContext {
public ITeams Teams => throw new NotImplementedException();
public IGithubIssues GithubIssues => throw new NotImplementedException();
public IAdo Ado => throw new NotImplementedException();
+ public IFeatureManagerSnapshot FeatureManagerSnapshot => throw new NotImplementedException();
-
+ public IConfigurationRefresher ConfigurationRefresher => throw new NotImplementedException();
}
diff --git a/src/ApiService/IntegrationTests/Fakes/TestServiceConfiguration.cs b/src/ApiService/IntegrationTests/Fakes/TestServiceConfiguration.cs
index 9ab9250f4..20f91bbe9 100644
--- a/src/ApiService/IntegrationTests/Fakes/TestServiceConfiguration.cs
+++ b/src/ApiService/IntegrationTests/Fakes/TestServiceConfiguration.cs
@@ -63,4 +63,5 @@ public sealed class TestServiceConfiguration : IServiceConfig {
public string? OneFuzzResourceGroup => throw new NotImplementedException();
public string? OneFuzzAllowOutdatedAgent => throw new NotImplementedException();
+ public string? AppConfigurationEndpoint => throw new NotImplementedException();
}
diff --git a/src/ApiService/IntegrationTests/packages.lock.json b/src/ApiService/IntegrationTests/packages.lock.json
index 2a98dad36..83c59842a 100644
--- a/src/ApiService/IntegrationTests/packages.lock.json
+++ b/src/ApiService/IntegrationTests/packages.lock.json
@@ -68,6 +68,16 @@
"System.Threading.Tasks.Extensions": "4.5.4"
}
},
+ "Azure.Data.AppConfiguration": {
+ "type": "Transitive",
+ "resolved": "1.2.0",
+ "contentHash": "KA1dAM9TuDsq0CRFd+3cJTYUAzA2z9N8t9/xKdDbP9URuReq/NDFcKYr7GW2W9xzVGDtCHlD5j5am/+zLLBdSg==",
+ "dependencies": {
+ "Azure.Core": "1.20.0",
+ "Microsoft.Bcl.AsyncInterfaces": "1.0.0",
+ "System.Text.Json": "4.6.0"
+ }
+ },
"Azure.Data.Tables": {
"type": "Transitive",
"resolved": "12.5.0",
@@ -365,6 +375,15 @@
"resolved": "5.0.8",
"contentHash": "ZI9S2NGjuOKXN3PxJcF8EKVwd1cqpWyUSqiVoH8gqq5tlHaXULwPmoR0DBOFON4sEFETRWI69f5RQ3tJWw205A=="
},
+ "Microsoft.Azure.Functions.Extensions": {
+ "type": "Transitive",
+ "resolved": "1.1.0",
+ "contentHash": "zYKtQQoS1fdzufxFApuMFiFtoi9QAGH6McXxntpylwLKgKjmCMWdgUd1dcekzTKNR9DPSDPRLiulvukqXnpWrQ==",
+ "dependencies": {
+ "Microsoft.Azure.WebJobs": "3.0.18",
+ "Microsoft.Extensions.DependencyInjection": "2.1.0"
+ }
+ },
"Microsoft.Azure.Functions.Worker": {
"type": "Transitive",
"resolved": "1.10.0",
@@ -519,6 +538,33 @@
"System.Net.Http": "4.3.0"
}
},
+ "Microsoft.Azure.WebJobs": {
+ "type": "Transitive",
+ "resolved": "3.0.18",
+ "contentHash": "aYJ76yjPkIpsafqFp1Xz1sA06RvhUwqJnk4AqX4I0teuRjPyig9Sv7LTzxUMAppKXc4JyR/Asos2At/LMiblqg==",
+ "dependencies": {
+ "Microsoft.Azure.WebJobs.Core": "3.0.18",
+ "Microsoft.Extensions.Configuration": "2.1.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "2.1.0",
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": "2.1.0",
+ "Microsoft.Extensions.Configuration.Json": "2.1.0",
+ "Microsoft.Extensions.Hosting": "2.1.0",
+ "Microsoft.Extensions.Logging": "2.1.0",
+ "Microsoft.Extensions.Logging.Abstractions": "2.1.0",
+ "Microsoft.Extensions.Logging.Configuration": "2.1.0",
+ "Newtonsoft.Json": "11.0.2",
+ "System.Threading.Tasks.Dataflow": "4.8.0"
+ }
+ },
+ "Microsoft.Azure.WebJobs.Core": {
+ "type": "Transitive",
+ "resolved": "3.0.18",
+ "contentHash": "ajYI8pPzPn4qq7FL8C2tz9WmFEG5PorUlkw8W9CF5M+5egnFJaF7yH48WYC+zBoQIzv2vHmFq0zhQpnv+O8v5Q==",
+ "dependencies": {
+ "System.ComponentModel.Annotations": "4.4.0",
+ "System.Diagnostics.TraceSource": "4.3.0"
+ }
+ },
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "6.0.0",
@@ -598,6 +644,20 @@
"Microsoft.Extensions.Primitives": "5.0.0"
}
},
+ "Microsoft.Extensions.Configuration.AzureAppConfiguration": {
+ "type": "Transitive",
+ "resolved": "5.1.0",
+ "contentHash": "FoAfgvT/rjL/+c7BP7q0LrJIdc4Hu6SH56BTIUbwCwVjHoUw4dpgGtLQULi5GmMjdbdAxyLQSnbwpOEWuBy+RA==",
+ "dependencies": {
+ "Azure.Data.AppConfiguration": "1.2.0",
+ "Azure.Messaging.EventGrid": "4.7.0",
+ "Azure.Security.KeyVault.Secrets": "4.0.1",
+ "Microsoft.Extensions.Configuration": "3.1.18",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.18",
+ "Microsoft.Extensions.Logging": "3.1.18",
+ "System.Text.Json": "4.6.0"
+ }
+ },
"Microsoft.Extensions.Configuration.Binder": {
"type": "Transitive",
"resolved": "5.0.0",
@@ -856,6 +916,15 @@
"resolved": "5.0.1",
"contentHash": "5WPSmL4YeP7eW+Vc8XZ4DwjYWBAiSwDV9Hm63JJWcz1Ie3Xjv4KuJXzgCstj48LkLfVCYa7mLcx7y+q6yqVvtw=="
},
+ "Microsoft.FeatureManagement": {
+ "type": "Transitive",
+ "resolved": "2.5.1",
+ "contentHash": "ERbRjk0etZs4d5Pv17unfogO4iBwV2c/HoBt4jqIJmfbKbmTLV+GbjBPYzidIg2RgYIFi8yA+EoEapSAIOp19g==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Binder": "2.1.10",
+ "Microsoft.Extensions.Logging": "2.1.1"
+ }
+ },
"Microsoft.Graph": {
"type": "Transitive",
"resolved": "4.37.0",
@@ -2238,6 +2307,11 @@
"System.Runtime": "4.3.0"
}
},
+ "System.Threading.Tasks.Dataflow": {
+ "type": "Transitive",
+ "resolved": "4.8.0",
+ "contentHash": "PSIdcgbyNv7FZvZ1I9Mqy6XZOwstYYMdZiXuHvIyc0gDyPjEhrrP9OvTGDHp+LAHp1RNSLjPYssyqox9+Kt9Ug=="
+ },
"System.Threading.Tasks.Extensions": {
"type": "Transitive",
"resolved": "4.5.4",
@@ -2419,6 +2493,7 @@
"Azure.Storage.Blobs": "[12.13.0, )",
"Azure.Storage.Queues": "[12.11.0, )",
"Faithlife.Utility": "[0.12.2, )",
+ "Microsoft.Azure.Functions.Extensions": "[1.1.0, )",
"Microsoft.Azure.Functions.Worker": "[1.10.0, )",
"Microsoft.Azure.Functions.Worker.ApplicationInsights": "[1.0.0-preview3, )",
"Microsoft.Azure.Functions.Worker.Extensions.EventGrid": "[2.1.0, )",
@@ -2429,6 +2504,8 @@
"Microsoft.Azure.Functions.Worker.Sdk": "[1.7.0, )",
"Microsoft.Azure.Management.Monitor": "[0.28.0-preview, )",
"Microsoft.Azure.Management.OperationalInsights": "[0.24.0-preview, )",
+ "Microsoft.Extensions.Configuration.AzureAppConfiguration": "[5.1.0, )",
+ "Microsoft.FeatureManagement": "[2.5.1, )",
"Microsoft.Graph": "[4.37.0, )",
"Microsoft.Identity.Client": "[4.46.2, )",
"Microsoft.Identity.Web.TokenCache": "[1.23.1, )",
diff --git a/src/ApiService/Tests/packages.lock.json b/src/ApiService/Tests/packages.lock.json
index edddf0818..715810521 100644
--- a/src/ApiService/Tests/packages.lock.json
+++ b/src/ApiService/Tests/packages.lock.json
@@ -87,6 +87,16 @@
"System.Threading.Tasks.Extensions": "4.5.4"
}
},
+ "Azure.Data.AppConfiguration": {
+ "type": "Transitive",
+ "resolved": "1.2.0",
+ "contentHash": "KA1dAM9TuDsq0CRFd+3cJTYUAzA2z9N8t9/xKdDbP9URuReq/NDFcKYr7GW2W9xzVGDtCHlD5j5am/+zLLBdSg==",
+ "dependencies": {
+ "Azure.Core": "1.20.0",
+ "Microsoft.Bcl.AsyncInterfaces": "1.0.0",
+ "System.Text.Json": "4.6.0"
+ }
+ },
"Azure.Data.Tables": {
"type": "Transitive",
"resolved": "12.5.0",
@@ -414,6 +424,15 @@
"resolved": "5.0.8",
"contentHash": "ZI9S2NGjuOKXN3PxJcF8EKVwd1cqpWyUSqiVoH8gqq5tlHaXULwPmoR0DBOFON4sEFETRWI69f5RQ3tJWw205A=="
},
+ "Microsoft.Azure.Functions.Extensions": {
+ "type": "Transitive",
+ "resolved": "1.1.0",
+ "contentHash": "zYKtQQoS1fdzufxFApuMFiFtoi9QAGH6McXxntpylwLKgKjmCMWdgUd1dcekzTKNR9DPSDPRLiulvukqXnpWrQ==",
+ "dependencies": {
+ "Microsoft.Azure.WebJobs": "3.0.18",
+ "Microsoft.Extensions.DependencyInjection": "2.1.0"
+ }
+ },
"Microsoft.Azure.Functions.Worker": {
"type": "Transitive",
"resolved": "1.10.0",
@@ -568,6 +587,33 @@
"System.Net.Http": "4.3.0"
}
},
+ "Microsoft.Azure.WebJobs": {
+ "type": "Transitive",
+ "resolved": "3.0.18",
+ "contentHash": "aYJ76yjPkIpsafqFp1Xz1sA06RvhUwqJnk4AqX4I0teuRjPyig9Sv7LTzxUMAppKXc4JyR/Asos2At/LMiblqg==",
+ "dependencies": {
+ "Microsoft.Azure.WebJobs.Core": "3.0.18",
+ "Microsoft.Extensions.Configuration": "2.1.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "2.1.0",
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": "2.1.0",
+ "Microsoft.Extensions.Configuration.Json": "2.1.0",
+ "Microsoft.Extensions.Hosting": "2.1.0",
+ "Microsoft.Extensions.Logging": "2.1.0",
+ "Microsoft.Extensions.Logging.Abstractions": "2.1.0",
+ "Microsoft.Extensions.Logging.Configuration": "2.1.0",
+ "Newtonsoft.Json": "11.0.2",
+ "System.Threading.Tasks.Dataflow": "4.8.0"
+ }
+ },
+ "Microsoft.Azure.WebJobs.Core": {
+ "type": "Transitive",
+ "resolved": "3.0.18",
+ "contentHash": "ajYI8pPzPn4qq7FL8C2tz9WmFEG5PorUlkw8W9CF5M+5egnFJaF7yH48WYC+zBoQIzv2vHmFq0zhQpnv+O8v5Q==",
+ "dependencies": {
+ "System.ComponentModel.Annotations": "4.4.0",
+ "System.Diagnostics.TraceSource": "4.3.0"
+ }
+ },
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "6.0.0",
@@ -647,6 +693,20 @@
"Microsoft.Extensions.Primitives": "5.0.0"
}
},
+ "Microsoft.Extensions.Configuration.AzureAppConfiguration": {
+ "type": "Transitive",
+ "resolved": "5.1.0",
+ "contentHash": "FoAfgvT/rjL/+c7BP7q0LrJIdc4Hu6SH56BTIUbwCwVjHoUw4dpgGtLQULi5GmMjdbdAxyLQSnbwpOEWuBy+RA==",
+ "dependencies": {
+ "Azure.Data.AppConfiguration": "1.2.0",
+ "Azure.Messaging.EventGrid": "4.7.0",
+ "Azure.Security.KeyVault.Secrets": "4.0.1",
+ "Microsoft.Extensions.Configuration": "3.1.18",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.18",
+ "Microsoft.Extensions.Logging": "3.1.18",
+ "System.Text.Json": "4.6.0"
+ }
+ },
"Microsoft.Extensions.Configuration.Binder": {
"type": "Transitive",
"resolved": "5.0.0",
@@ -905,6 +965,15 @@
"resolved": "5.0.1",
"contentHash": "5WPSmL4YeP7eW+Vc8XZ4DwjYWBAiSwDV9Hm63JJWcz1Ie3Xjv4KuJXzgCstj48LkLfVCYa7mLcx7y+q6yqVvtw=="
},
+ "Microsoft.FeatureManagement": {
+ "type": "Transitive",
+ "resolved": "2.5.1",
+ "contentHash": "ERbRjk0etZs4d5Pv17unfogO4iBwV2c/HoBt4jqIJmfbKbmTLV+GbjBPYzidIg2RgYIFi8yA+EoEapSAIOp19g==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Binder": "2.1.10",
+ "Microsoft.Extensions.Logging": "2.1.1"
+ }
+ },
"Microsoft.Graph": {
"type": "Transitive",
"resolved": "4.37.0",
@@ -2333,6 +2402,11 @@
"System.Runtime": "4.3.0"
}
},
+ "System.Threading.Tasks.Dataflow": {
+ "type": "Transitive",
+ "resolved": "4.8.0",
+ "contentHash": "PSIdcgbyNv7FZvZ1I9Mqy6XZOwstYYMdZiXuHvIyc0gDyPjEhrrP9OvTGDHp+LAHp1RNSLjPYssyqox9+Kt9Ug=="
+ },
"System.Threading.Tasks.Extensions": {
"type": "Transitive",
"resolved": "4.5.4",
@@ -2546,6 +2620,7 @@
"Azure.Storage.Blobs": "[12.13.0, )",
"Azure.Storage.Queues": "[12.11.0, )",
"Faithlife.Utility": "[0.12.2, )",
+ "Microsoft.Azure.Functions.Extensions": "[1.1.0, )",
"Microsoft.Azure.Functions.Worker": "[1.10.0, )",
"Microsoft.Azure.Functions.Worker.ApplicationInsights": "[1.0.0-preview3, )",
"Microsoft.Azure.Functions.Worker.Extensions.EventGrid": "[2.1.0, )",
@@ -2556,6 +2631,8 @@
"Microsoft.Azure.Functions.Worker.Sdk": "[1.7.0, )",
"Microsoft.Azure.Management.Monitor": "[0.28.0-preview, )",
"Microsoft.Azure.Management.OperationalInsights": "[0.24.0-preview, )",
+ "Microsoft.Extensions.Configuration.AzureAppConfiguration": "[5.1.0, )",
+ "Microsoft.FeatureManagement": "[2.5.1, )",
"Microsoft.Graph": "[4.37.0, )",
"Microsoft.Identity.Client": "[4.46.2, )",
"Microsoft.Identity.Web.TokenCache": "[1.23.1, )",
diff --git a/src/deployment/azuredeploy.bicep b/src/deployment/azuredeploy.bicep
index e8ac1acc0..20568e5eb 100644
--- a/src/deployment/azuredeploy.bicep
+++ b/src/deployment/azuredeploy.bicep
@@ -40,23 +40,27 @@ var roleAssignmentsParams = [
}
{
suffix: '-storage'
- role:'17d1049b-9a84-46fb-8f53-869881c3d3ab' //StorageAccountContributor
+ role: '17d1049b-9a84-46fb-8f53-869881c3d3ab' //StorageAccountContributor
}
{
suffix: '-network'
- role: '4d97b98b-1d4f-4787-a291-c67834d212e7'//NetworkContributor
+ role: '4d97b98b-1d4f-4787-a291-c67834d212e7' //NetworkContributor
}
{
suffix: '-logs'
- role: '92aaf0da-9dab-42b6-94a3-d43ce8d16293'//LogAnalyticsContributor
+ role: '92aaf0da-9dab-42b6-94a3-d43ce8d16293' //LogAnalyticsContributor
}
{
suffix: '-user_managed_identity'
- role: 'f1a07417-d97a-45cb-824c-7a7467783830'//ManagedIdentityOperator
+ role: 'f1a07417-d97a-45cb-824c-7a7467783830' //ManagedIdentityOperator
}
{
suffix: '-contributor'
- role: 'b24988ac-6180-42a0-ab88-20f7382dd24c'//Contributor
+ role: 'b24988ac-6180-42a0-ab88-20f7382dd24c' //Contributor
+ }
+ {
+ suffix: '-app_config_reader'
+ role: '516239f1-63e1-4d78-a4de-a74fb236a071' //App Configuration Data Reader
}
]
resource scalesetIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
@@ -162,7 +166,7 @@ module autoscaleSettings 'bicep-templates/autoscale-settings.bicep' = {
module eventGrid 'bicep-templates/event-grid.bicep' = {
name: 'event-grid'
- params:{
+ params: {
location: location
storageFuzzId: storage.outputs.FuzzId
storageFuncId: storage.outputs.FuncId
@@ -184,6 +188,7 @@ resource roleAssignments 'Microsoft.Authorization/roleAssignments@2020-10-01-pre
eventGrid
keyVault
serverFarm
+ featureFlags
]
}]
@@ -198,10 +203,10 @@ resource roleAssignmentsNet 'Microsoft.Authorization/roleAssignments@2020-10-01-
eventGrid
keyVault
serverFarm
+ featureFlags
]
}]
-
// try to make role assignments to deploy as late as possible in order to have principalId ready
resource readBlobUserAssignment 'Microsoft.Authorization/roleAssignments@2020-10-01-preview' = {
name: guid('${resourceGroup().id}-user_managed_idenity_read_blob')
@@ -213,9 +218,16 @@ resource readBlobUserAssignment 'Microsoft.Authorization/roleAssignments@2020-10
eventGrid
keyVault
serverFarm
- ]
+ featureFlags
+ ]
}
+module featureFlags 'bicep-templates/feature-flags.bicep' = {
+ name: 'featureFlags'
+ params: {
+ location: location
+ }
+}
module function 'bicep-templates/function.bicep' = {
name: 'function'
@@ -278,45 +290,46 @@ module functionSettings 'bicep-templates/function-settings.bicep' = {
monitor_account_name: operationalInsights.outputs.monitorAccountName
multi_tenant_domain: multi_tenant_domain
enable_profiler: enable_profiler
+ app_config_endpoint: featureFlags.outputs.AppConfigEndpoint
functions_disabled: '0'
agent_function_names: [
- 'AgentCanSchedule' //0
- 'AgentCommands' //1
- 'AgentEvents' //2
- 'AgentRegistration' //3
- 'Containers' //4
- 'Download' //5
- 'Info' //6
- 'InstanceConfig' //7
- 'Jobs' //8
- 'JobTemplates' //9
- 'JobTemplatesManage' //10
- 'Negotiate' //11
- 'Node' //12
- 'NodeAddSshKey' //13
- 'Notifications' //14
- 'Pool' //15
- 'Proxy' //16
- 'QueueFileChanges' //17
- 'QueueNodeHeartbeat' //18
- 'QueueProxyUpdate' //19
- 'QueueSignalrEvents' //20
- 'QueueTaskHeartbeat' //21
- 'QueueUpdates' //22
- 'QueueWebhooks' //23
- 'ReproVms' //24
- 'Scaleset' //25
- 'Tasks' //26
- 'TimerDaily' //27
- 'TimerProxy' //28
- 'TimerRepro' //29
- 'TimerRetention' //30
- 'TimerTasks' //31
- 'TimerWorkers' //32
- 'Tools' //33
- 'Webhooks' //34
- 'WebhooksLogs' //35
- 'WebhooksPing' //36
+ 'AgentCanSchedule' //0
+ 'AgentCommands' //1
+ 'AgentEvents' //2
+ 'AgentRegistration' //3
+ 'Containers' //4
+ 'Download' //5
+ 'Info' //6
+ 'InstanceConfig' //7
+ 'Jobs' //8
+ 'JobTemplates' //9
+ 'JobTemplatesManage' //10
+ 'Negotiate' //11
+ 'Node' //12
+ 'NodeAddSshKey' //13
+ 'Notifications' //14
+ 'Pool' //15
+ 'Proxy' //16
+ 'QueueFileChanges' //17
+ 'QueueNodeHeartbeat' //18
+ 'QueueProxyUpdate' //19
+ 'QueueSignalrEvents' //20
+ 'QueueTaskHeartbeat' //21
+ 'QueueUpdates' //22
+ 'QueueWebhooks' //23
+ 'ReproVms' //24
+ 'Scaleset' //25
+ 'Tasks' //26
+ 'TimerDaily' //27
+ 'TimerProxy' //28
+ 'TimerRepro' //29
+ 'TimerRetention' //30
+ 'TimerTasks' //31
+ 'TimerWorkers' //32
+ 'Tools' //33
+ 'Webhooks' //34
+ 'WebhooksLogs' //35
+ 'WebhooksPing' //36
]
}
dependsOn: [
@@ -324,7 +337,6 @@ module functionSettings 'bicep-templates/function-settings.bicep' = {
]
}
-
module netFunctionSettings 'bicep-templates/function-settings.bicep' = {
name: 'netFunctionSettings'
params: {
@@ -344,45 +356,46 @@ module netFunctionSettings 'bicep-templates/function-settings.bicep' = {
monitor_account_name: operationalInsights.outputs.monitorAccountName
multi_tenant_domain: multi_tenant_domain
enable_profiler: enable_profiler
+ app_config_endpoint: featureFlags.outputs.AppConfigEndpoint
functions_disabled: '1'
agent_function_names: [
- 'AgentCanSchedule' //0
- 'AgentCommands' //1
- 'AgentEvents' //2
- 'AgentRegistration' //3
- 'Containers' //4
- 'Download' //5
- 'Info' //6
- 'InstanceConfig' //7
- 'Jobs' //8
- 'JobTemplates' //9
- 'JobTemplatesManage' //10
- 'Negotiate' //11
- 'Node' //12
- 'NodeAddSshKey' //13
- 'Notifications' //14
- 'Pool' //15
- 'Proxy' //16
- 'QueueFileChanges' //17
- 'QueueNodeHeartbeat' //18
- 'QueueProxyUpdate' //19
- 'QueueSignalrEvents' //20
- 'QueueTaskHeartbeat' //21
- 'QueueUpdates' //22
- 'QueueWebhooks' //23
- 'ReproVms' //24
- 'Scaleset' //25
- 'Tasks' //26
- 'TimerDaily' //27
- 'TimerProxy' //28
- 'TimerRepro' //29
- 'TimerRetention' //30
- 'TimerTasks' //31
- 'TimerWorkers' //32
- 'Tools' //33
- 'Webhooks' //34
- 'WebhookLogs' //35
- 'WebhookPing' //36
+ 'AgentCanSchedule' //0
+ 'AgentCommands' //1
+ 'AgentEvents' //2
+ 'AgentRegistration' //3
+ 'Containers' //4
+ 'Download' //5
+ 'Info' //6
+ 'InstanceConfig' //7
+ 'Jobs' //8
+ 'JobTemplates' //9
+ 'JobTemplatesManage' //10
+ 'Negotiate' //11
+ 'Node' //12
+ 'NodeAddSshKey' //13
+ 'Notifications' //14
+ 'Pool' //15
+ 'Proxy' //16
+ 'QueueFileChanges' //17
+ 'QueueNodeHeartbeat' //18
+ 'QueueProxyUpdate' //19
+ 'QueueSignalrEvents' //20
+ 'QueueTaskHeartbeat' //21
+ 'QueueUpdates' //22
+ 'QueueWebhooks' //23
+ 'ReproVms' //24
+ 'Scaleset' //25
+ 'Tasks' //26
+ 'TimerDaily' //27
+ 'TimerProxy' //28
+ 'TimerRepro' //29
+ 'TimerRetention' //30
+ 'TimerTasks' //31
+ 'TimerWorkers' //32
+ 'Tools' //33
+ 'Webhooks' //34
+ 'WebhookLogs' //35
+ 'WebhookPing' //36
]
}
dependsOn: [
diff --git a/src/deployment/bicep-templates/feature-flags.bicep b/src/deployment/bicep-templates/feature-flags.bicep
new file mode 100644
index 000000000..49742cd72
--- /dev/null
+++ b/src/deployment/bicep-templates/feature-flags.bicep
@@ -0,0 +1,14 @@
+param location string
+
+var suffix = uniqueString(resourceGroup().id)
+var appConfigName = 'app-config-${suffix}'
+
+resource featureFlags 'Microsoft.AppConfiguration/configurationStores@2022-05-01' = {
+ name: appConfigName
+ location: location
+ sku:{
+ name: 'standard'
+ }
+}
+
+output AppConfigEndpoint string = 'https://${appConfigName}.azconfig.io'
diff --git a/src/deployment/bicep-templates/function-settings.bicep b/src/deployment/bicep-templates/function-settings.bicep
index af42bb629..739681f26 100644
--- a/src/deployment/bicep-templates/function-settings.bicep
+++ b/src/deployment/bicep-templates/function-settings.bicep
@@ -13,6 +13,8 @@ param multi_tenant_domain string
@secure()
param signal_r_connection_string string
+param app_config_endpoint string
+
param func_storage_resource_id string
param fuzz_storage_resource_id string
@@ -67,6 +69,7 @@ resource functionSettings 'Microsoft.Web/sites/config@2021-03-01' = {
AzureWebJobsDisableHomepage: 'true'
AzureSignalRConnectionString: signal_r_connection_string
AzureSignalRServiceTransportType: 'Transient'
+ APPCONFIGURATION_ENDPOINT: app_config_endpoint
ONEFUZZ_INSTANCE_NAME: instance_name
ONEFUZZ_INSTANCE: 'https://${instance_name}.azurewebsites.net'
ONEFUZZ_RESOURCE_GROUP: resourceGroup().id