From 1784b30daa53c4d9833710077b08edefcd02ea79 Mon Sep 17 00:00:00 2001 From: Cheick Keita Date: Tue, 26 Apr 2022 09:11:25 -0700 Subject: [PATCH] adding formatting rule --- src/ApiService/.editorconfig | 129 +++++++ src/ApiService/ApiService/HttpClient.cs | 40 +-- src/ApiService/ApiService/Log.cs | 201 ++++------- .../ApiService/OneFuzzTypes/Enums.cs | 102 ++---- .../ApiService/OneFuzzTypes/Events.cs | 37 +- .../ApiService/OneFuzzTypes/Model.cs | 89 ++--- .../ApiService/OneFuzzTypes/ReturnTypes.cs | 12 +- .../ApiService/OneFuzzTypes/Webhooks.cs | 7 +- src/ApiService/ApiService/Program.cs | 37 +- src/ApiService/ApiService/QueueFileChanges.cs | 20 +- .../ApiService/QueueNodeHearbeat.cs | 17 +- .../ApiService/QueueProxyHeartbeat.cs | 17 +- .../ApiService/QueueSignalREvents.cs | 11 +- .../ApiService/QueueTaskHearbeat.cs | 14 +- .../ApiService/ServiceConfiguration.cs | 14 +- src/ApiService/ApiService/TestHooks.cs | 19 +- src/ApiService/ApiService/TimerDaily.cs | 17 +- src/ApiService/ApiService/TimerProxy.cs | 58 +-- src/ApiService/ApiService/TimerRepro.cs | 14 +- src/ApiService/ApiService/TimerRetention.cs | 51 +-- src/ApiService/ApiService/UserCredentials.cs | 66 ++-- src/ApiService/ApiService/onefuzzlib/Auth.cs | 6 +- .../ApiService/onefuzzlib/Containers.cs | 58 ++- src/ApiService/ApiService/onefuzzlib/Creds.cs | 29 +- .../ApiService/onefuzzlib/DiskOperations.cs | 17 +- .../ApiService/onefuzzlib/Events.cs | 43 +-- .../ApiService/onefuzzlib/InstanceConfig.cs | 39 +-- .../ApiService/onefuzzlib/IpOperations.cs | 23 +- .../ApiService/onefuzzlib/JobOperations.cs | 9 +- .../ApiService/onefuzzlib/Network.cs | 25 +- .../ApiService/onefuzzlib/NodeOperations.cs | 16 +- .../onefuzzlib/NotificationOperations.cs | 76 ++-- src/ApiService/ApiService/onefuzzlib/Nsg.cs | 42 +-- .../ApiService/onefuzzlib/PoolOperations.cs | 20 +- .../onefuzzlib/ProxyForwardOperations.cs | 12 +- .../ApiService/onefuzzlib/ProxyOperations.cs | 74 ++-- src/ApiService/ApiService/onefuzzlib/Queue.cs | 54 +-- .../ApiService/onefuzzlib/Reports.cs | 68 ++-- .../ApiService/onefuzzlib/ReproOperations.cs | 42 +-- .../onefuzzlib/ScalesetOperations.cs | 15 +- .../ApiService/onefuzzlib/Secrets.cs | 67 ++-- .../ApiService/onefuzzlib/Storage.cs | 58 ++- .../ApiService/onefuzzlib/Subnet.cs | 21 +- .../ApiService/onefuzzlib/TaskOperations.cs | 45 +-- src/ApiService/ApiService/onefuzzlib/Utils.cs | 13 +- .../ApiService/onefuzzlib/VmOperations.cs | 59 ++-- .../onefuzzlib/WebhookOperations.cs | 55 +-- .../onefuzzlib/orm/CaseConverter.cs | 34 +- .../onefuzzlib/orm/CustomConverterFactory.cs | 134 +++---- .../onefuzzlib/orm/EntityConverter.cs | 199 ++++------- .../ApiService/onefuzzlib/orm/Orm.cs | 115 ++---- src/ApiService/Tests/OrmModelsTest.cs | 330 ++++++------------ src/ApiService/Tests/OrmTest.cs | 68 ++-- 53 files changed, 1040 insertions(+), 1798 deletions(-) diff --git a/src/ApiService/.editorconfig b/src/ApiService/.editorconfig index f1bbe0eebe6..3ba00364b2b 100644 --- a/src/ApiService/.editorconfig +++ b/src/ApiService/.editorconfig @@ -1,4 +1,133 @@ root = true +############################### +# Core EditorConfig Options # +############################### +root = true +# All files +[*] +indent_style = space + + +# XML project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# XML config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + +# Code files +[*.{cs,csx,vb,vbx}] +indent_size = 4 +insert_final_newline = true +charset = utf-8-bom +############################### +# .NET Coding Conventions # +############################### +[*.{cs,vb}] +# Organize usings +dotnet_sort_system_directives_first = true +# this. preferences +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_readonly_field = true:suggestion +# Expression-level preferences +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +############################### +# Naming Conventions # +############################### +# Style Definitions +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +# Use PascalCase for constant fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_accessibilities = * +dotnet_naming_symbols.constant_fields.required_modifiers = const +############################### +# C# Coding Conventions # +############################### +[*.cs] +# var preferences +csharp_style_var_for_built_in_types = true:silent +csharp_style_var_when_type_is_apparent = true:silent +csharp_style_var_elsewhere = true:silent +# Expression-bodied members +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +# Pattern matching preferences +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +# Null-checking preferences +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +# Modifier preferences +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion +# Expression-level preferences +csharp_prefer_braces = true:silent +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +############################### +# C# Formatting Rules # +############################### +# New line preferences +csharp_new_line_before_open_brace = none +csharp_new_line_before_else = false +csharp_new_line_before_catch = false +csharp_new_line_before_finally = false +csharp_new_line_before_members_in_object_initializers = false +csharp_new_line_before_members_in_anonymous_types = false +csharp_new_line_between_query_expression_clauses = false +# Indentation preferences +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left +# Space preferences +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +# Wrapping preferences +csharp_preserve_single_line_statements = true +csharp_preserve_single_line_blocks = true + + [*.{cs}] dotnet_diagnostic.IDE0005.severity = warning \ No newline at end of file diff --git a/src/ApiService/ApiService/HttpClient.cs b/src/ApiService/ApiService/HttpClient.cs index 6b244ff6784..a51ca6bfee4 100644 --- a/src/ApiService/ApiService/HttpClient.cs +++ b/src/ApiService/ApiService/HttpClient.cs @@ -1,42 +1,35 @@ using System.Net.Http; -using System.Threading.Tasks; using System.Net.Http.Headers; +using System.Threading.Tasks; namespace Microsoft.OneFuzz.Service; -using TokenType = String; using AccessToken = String; +using TokenType = String; -public class Request -{ +public class Request { private readonly HttpClient _httpClient; Func>? _auth; - public Request(HttpClient httpClient, Func>? auth = null) - { + public Request(HttpClient httpClient, Func>? auth = null) { _auth = auth; _httpClient = httpClient; } - private async Task Send(HttpMethod method, Uri url, HttpContent? content = null, IDictionary? headers = null) - { + private async Task Send(HttpMethod method, Uri url, HttpContent? content = null, IDictionary? headers = null) { var request = new HttpRequestMessage(method: method, requestUri: url); - if (_auth is not null) - { + if (_auth is not null) { var (tokenType, accessToken) = await _auth(); request.Headers.Authorization = new AuthenticationHeaderValue(tokenType, accessToken); } - if (content is not null) - { + if (content is not null) { request.Content = content; } - if (headers is not null) - { - foreach (var v in headers) - { + if (headers is not null) { + foreach (var v in headers) { request.Headers.Add(v.Key, v.Value); } } @@ -44,31 +37,26 @@ private async Task Send(HttpMethod method, Uri url, HttpCon return await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); } - public async Task Get(Uri url) - { + public async Task Get(Uri url) { return await Send(method: HttpMethod.Get, url: url); } - public async Task Delete(Uri url) - { + public async Task Delete(Uri url) { return await Send(method: HttpMethod.Delete, url: url); } - public async Task Post(Uri url, String json, IDictionary? headers = null) - { + public async Task Post(Uri url, String json, IDictionary? headers = null) { using var b = new StringContent(json); b.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); return await Send(method: HttpMethod.Post, url: url, headers: headers); } - public async Task Put(Uri url, String json, IDictionary? headers = null) - { + public async Task Put(Uri url, String json, IDictionary? headers = null) { using var b = new StringContent(json); b.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); return await Send(method: HttpMethod.Put, url: url, headers: headers); } - public async Task Patch(Uri url, String json, IDictionary? headers = null) - { + public async Task Patch(Uri url, String json, IDictionary? headers = null) { using var b = new StringContent(json); b.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); return await Send(method: HttpMethod.Patch, url: url, headers: headers); diff --git a/src/ApiService/ApiService/Log.cs b/src/ApiService/ApiService/Log.cs index 12d07d0c359..31bce2b09d7 100644 --- a/src/ApiService/ApiService/Log.cs +++ b/src/ApiService/ApiService/Log.cs @@ -1,129 +1,105 @@ -using Microsoft.ApplicationInsights; -using Microsoft.ApplicationInsights.Extensibility; +using System.Diagnostics; +using Microsoft.ApplicationInsights; using Microsoft.ApplicationInsights.DataContracts; - -using System.Diagnostics; +using Microsoft.ApplicationInsights.Extensibility; namespace Microsoft.OneFuzz.Service; -public interface ILog -{ +public interface ILog { void Log(Guid correlationId, String message, SeverityLevel level, IReadOnlyDictionary tags, string? caller); void LogEvent(Guid correlationId, String evt, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller); void LogException(Guid correlationId, Exception ex, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller); void Flush(); } -class AppInsights : ILog -{ +class AppInsights : ILog { private TelemetryClient _telemetryClient; - public AppInsights(string instrumentationKey) - { + public AppInsights(string instrumentationKey) { _telemetryClient = new TelemetryClient(new TelemetryConfiguration(instrumentationKey)); } - public void Log(Guid correlationId, String message, SeverityLevel level, IReadOnlyDictionary tags, string? caller) - { + public void Log(Guid correlationId, String message, SeverityLevel level, IReadOnlyDictionary tags, string? caller) { Dictionary copyTags = new(tags); copyTags["Correlation ID"] = correlationId.ToString(); if (caller is not null) copyTags["CalledBy"] = caller; _telemetryClient.TrackTrace(message, level, copyTags); } - public void LogEvent(Guid correlationId, String evt, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller) - { + public void LogEvent(Guid correlationId, String evt, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller) { Dictionary copyTags = new(tags); copyTags["Correlation ID"] = correlationId.ToString(); if (caller is not null) copyTags["CalledBy"] = caller; Dictionary? copyMetrics = null; - if (metrics is not null) - { + if (metrics is not null) { copyMetrics = new(metrics); } _telemetryClient.TrackEvent(evt, properties: copyTags, metrics: copyMetrics); } - public void LogException(Guid correlationId, Exception ex, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller) - { + public void LogException(Guid correlationId, Exception ex, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller) { Dictionary copyTags = new(tags); copyTags["Correlation ID"] = correlationId.ToString(); if (caller is not null) copyTags["CalledBy"] = caller; Dictionary? copyMetrics = null; - if (metrics is not null) - { + if (metrics is not null) { copyMetrics = new(metrics); } _telemetryClient.TrackException(ex, copyTags, copyMetrics); } - public void Flush() - { + public void Flush() { _telemetryClient.Flush(); } } //TODO: Should we write errors and Exception to std err ? -class Console : ILog -{ +class Console : ILog { - private string DictToString(IReadOnlyDictionary? d) - { - if (d is null) - { + private string DictToString(IReadOnlyDictionary? d) { + if (d is null) { return string.Empty; - } - else - { + } else { return string.Join("", d); } } - private void LogTags(Guid correlationId, IReadOnlyDictionary tags) - { + private void LogTags(Guid correlationId, IReadOnlyDictionary tags) { var ts = DictToString(tags); - if (!string.IsNullOrEmpty(ts)) - { + if (!string.IsNullOrEmpty(ts)) { System.Console.WriteLine($"[{correlationId}] Tags:{ts}"); } } - private void LogMetrics(Guid correlationId, IReadOnlyDictionary? metrics) - { + private void LogMetrics(Guid correlationId, IReadOnlyDictionary? metrics) { var ms = DictToString(metrics); - if (!string.IsNullOrEmpty(ms)) - { + if (!string.IsNullOrEmpty(ms)) { System.Console.Out.WriteLine($"[{correlationId}] Metrics:{DictToString(metrics)}"); } } - public void Log(Guid correlationId, String message, SeverityLevel level, IReadOnlyDictionary tags, string? caller) - { + public void Log(Guid correlationId, String message, SeverityLevel level, IReadOnlyDictionary tags, string? caller) { System.Console.Out.WriteLine($"[{correlationId}][{level}] {message}"); LogTags(correlationId, tags); } - public void LogEvent(Guid correlationId, String evt, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller) - { + public void LogEvent(Guid correlationId, String evt, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller) { System.Console.Out.WriteLine($"[{correlationId}][Event] {evt}"); LogTags(correlationId, tags); LogMetrics(correlationId, metrics); } - public void LogException(Guid correlationId, Exception ex, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller) - { + public void LogException(Guid correlationId, Exception ex, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller) { System.Console.Out.WriteLine($"[{correlationId}][Exception] {ex}"); LogTags(correlationId, tags); LogMetrics(correlationId, metrics); } - public void Flush() - { + public void Flush() { System.Console.Out.Flush(); } } -public interface ILogTracer -{ +public interface ILogTracer { IReadOnlyDictionary Tags { get; } void Critical(string message); @@ -139,18 +115,15 @@ public interface ILogTracer ILogTracer WithTags((string, string)[]? tags); } -internal interface ILogTracerInternal : ILogTracer -{ +internal interface ILogTracerInternal : ILogTracer { void ReplaceCorrelationId(Guid newCorrelationId); void AddTags((string, string)[] tags); } -public class LogTracer : ILogTracerInternal -{ - private string? GetCaller() - { +public class LogTracer : ILogTracerInternal { + private string? GetCaller() { return new StackTrace()?.GetFrame(2)?.GetMethod()?.DeclaringType?.FullName; } @@ -162,17 +135,12 @@ public class LogTracer : ILogTracerInternal public Guid CorrelationId => _correlationId; public IReadOnlyDictionary Tags => _tags; - private static List> ConvertTags((string, string)[]? tags) - { + private static List> ConvertTags((string, string)[]? tags) { List> converted = new List>(); - if (tags is null) - { + if (tags is null) { return converted; - } - else - { - foreach (var (k, v) in tags) - { + } else { + foreach (var (k, v) in tags) { converted.Add(new KeyValuePair(k, v)); } return converted; @@ -180,12 +148,10 @@ private static List> ConvertTags((string, string)[] } public LogTracer(Guid correlationId, (string, string)[]? tags, List loggers, SeverityLevel logSeverityLevel) : - this(correlationId, new Dictionary(ConvertTags(tags)), loggers, logSeverityLevel) - { } + this(correlationId, new Dictionary(ConvertTags(tags)), loggers, logSeverityLevel) { } - public LogTracer(Guid correlationId, IReadOnlyDictionary tags, List loggers, SeverityLevel logSeverityLevel) - { + public LogTracer(Guid correlationId, IReadOnlyDictionary tags, List loggers, SeverityLevel logSeverityLevel) { _correlationId = correlationId; _tags = new(tags); _loggers = loggers; @@ -193,144 +159,111 @@ public LogTracer(Guid correlationId, IReadOnlyDictionary tags, L } //Single threaded only - public void ReplaceCorrelationId(Guid newCorrelationId) - { + public void ReplaceCorrelationId(Guid newCorrelationId) { _correlationId = newCorrelationId; } //single threaded only - public void AddTags((string, string)[] tags) - { - if (tags is not null) - { - foreach (var (k, v) in tags) - { + public void AddTags((string, string)[] tags) { + if (tags is not null) { + foreach (var (k, v) in tags) { _tags[k] = v; } } } - public ILogTracer WithTag(string k, string v) - { + public ILogTracer WithTag(string k, string v) { return WithTags(new[] { (k, v) }); } - public ILogTracer WithTags((string, string)[]? tags) - { + public ILogTracer WithTags((string, string)[]? tags) { var newTags = new Dictionary(Tags); - if (tags is not null) - { - foreach (var (k, v) in tags) - { + if (tags is not null) { + foreach (var (k, v) in tags) { newTags[k] = v; } } return new LogTracer(CorrelationId, newTags, _loggers, _logSeverityLevel); } - public void Verbose(string message) - { - if (_logSeverityLevel <= SeverityLevel.Verbose) - { + public void Verbose(string message) { + if (_logSeverityLevel <= SeverityLevel.Verbose) { var caller = GetCaller(); - foreach (var logger in _loggers) - { + foreach (var logger in _loggers) { logger.Log(CorrelationId, message, SeverityLevel.Verbose, Tags, caller); } } } - public void Info(string message) - { - if (_logSeverityLevel <= SeverityLevel.Information) - { + public void Info(string message) { + if (_logSeverityLevel <= SeverityLevel.Information) { var caller = GetCaller(); - foreach (var logger in _loggers) - { + foreach (var logger in _loggers) { logger.Log(CorrelationId, message, SeverityLevel.Information, Tags, caller); } } } - public void Warning(string message) - { - if (_logSeverityLevel <= SeverityLevel.Warning) - { + public void Warning(string message) { + if (_logSeverityLevel <= SeverityLevel.Warning) { var caller = GetCaller(); - foreach (var logger in _loggers) - { + foreach (var logger in _loggers) { logger.Log(CorrelationId, message, SeverityLevel.Warning, Tags, caller); } } } - public void Error(string message) - { - if (_logSeverityLevel <= SeverityLevel.Error) - { + public void Error(string message) { + if (_logSeverityLevel <= SeverityLevel.Error) { var caller = GetCaller(); - foreach (var logger in _loggers) - { + foreach (var logger in _loggers) { logger.Log(CorrelationId, message, SeverityLevel.Error, Tags, caller); } } } - public void Critical(string message) - { - if (_logSeverityLevel <= SeverityLevel.Critical) - { + public void Critical(string message) { + if (_logSeverityLevel <= SeverityLevel.Critical) { var caller = GetCaller(); - foreach (var logger in _loggers) - { + foreach (var logger in _loggers) { logger.Log(CorrelationId, message, SeverityLevel.Critical, Tags, caller); } } } - public void Event(string evt, IReadOnlyDictionary? metrics) - { + public void Event(string evt, IReadOnlyDictionary? metrics) { var caller = GetCaller(); - foreach (var logger in _loggers) - { + foreach (var logger in _loggers) { logger.LogEvent(CorrelationId, evt, Tags, metrics, caller); } } - public void Exception(Exception ex, IReadOnlyDictionary? metrics) - { + public void Exception(Exception ex, IReadOnlyDictionary? metrics) { var caller = GetCaller(); - foreach (var logger in _loggers) - { + foreach (var logger in _loggers) { logger.LogException(CorrelationId, ex, Tags, metrics, caller); } } - public void ForceFlush() - { - foreach (var logger in _loggers) - { + public void ForceFlush() { + foreach (var logger in _loggers) { logger.Flush(); } } } -public interface ILogTracerFactory -{ +public interface ILogTracerFactory { LogTracer CreateLogTracer(Guid correlationId, (string, string)[]? tags = null, SeverityLevel severityLevel = SeverityLevel.Verbose); } -public class LogTracerFactory : ILogTracerFactory -{ +public class LogTracerFactory : ILogTracerFactory { private List _loggers; - public LogTracerFactory(List loggers) - { + public LogTracerFactory(List loggers) { _loggers = loggers; } - public LogTracer CreateLogTracer(Guid correlationId, (string, string)[]? tags = null, SeverityLevel severityLevel = SeverityLevel.Verbose) - { + public LogTracer CreateLogTracer(Guid correlationId, (string, string)[]? tags = null, SeverityLevel severityLevel = SeverityLevel.Verbose) { return new(correlationId, tags, _loggers, severityLevel); } diff --git a/src/ApiService/ApiService/OneFuzzTypes/Enums.cs b/src/ApiService/ApiService/OneFuzzTypes/Enums.cs index 248b93e3d72..01d3aeb4c75 100644 --- a/src/ApiService/ApiService/OneFuzzTypes/Enums.cs +++ b/src/ApiService/ApiService/OneFuzzTypes/Enums.cs @@ -1,8 +1,7 @@ using System.Collections.Concurrent; namespace Microsoft.OneFuzz.Service; -public enum ErrorCode -{ +public enum ErrorCode { INVALID_REQUEST = 450, INVALID_PERMISSION = 451, MISSING_EULA_AGREEMENT = 452, @@ -29,8 +28,7 @@ public enum ErrorCode INVALID_CONFIGURATION = 473, } -public enum VmState -{ +public enum VmState { Init, ExtensionsLaunched, ExtensionsFailed, @@ -40,16 +38,14 @@ public enum VmState Stopped } -public enum WebhookMessageState -{ +public enum WebhookMessageState { Queued, Retrying, Succeeded, Failed } -public enum TaskState -{ +public enum TaskState { Init, Waiting, Scheduled, @@ -60,8 +56,7 @@ public enum TaskState WaitJob } -public enum TaskType -{ +public enum TaskType { Coverage, LibfuzzerFuzz, LibfuzzerCoverage, @@ -76,14 +71,12 @@ public enum TaskType GenericRegression } -public enum Os -{ +public enum Os { Windows, Linux } -public enum ContainerType -{ +public enum ContainerType { Analysis, Coverage, Crashes, @@ -100,19 +93,16 @@ public enum ContainerType } -public enum StatsFormat -{ +public enum StatsFormat { AFL } -public enum TaskDebugFlag -{ +public enum TaskDebugFlag { KeepNodeOnFailure, KeepNodeOnCompletion, } -public enum ScalesetState -{ +public enum ScalesetState { Init, Setup, Resize, @@ -123,16 +113,14 @@ public enum ScalesetState } -public enum JobState -{ +public enum JobState { Init, Enabled, Stopping, Stopped } -public static class JobStateHelper -{ +public static class JobStateHelper { private static readonly HashSet _shuttingDown = new HashSet(new[] { JobState.Stopping, JobState.Stopped }); private static readonly HashSet _avaiable = new HashSet(new[] { JobState.Init, JobState.Enabled }); private static readonly HashSet _needsWork = new HashSet(new[] { JobState.Init, JobState.Stopping }); @@ -144,13 +132,11 @@ public static class JobStateHelper -public static class ScalesetStateHelper -{ +public static class ScalesetStateHelper { static ConcurrentDictionary _states = new ConcurrentDictionary(); /// set of states that indicate the scaleset can be updated - public static ScalesetState[] CanUpdate() - { + public static ScalesetState[] CanUpdate() { return _states.GetOrAdd(nameof(CanUpdate), k => new[]{ ScalesetState.Running, @@ -159,8 +145,7 @@ public static ScalesetState[] CanUpdate() } /// set of states that indicate work is needed during eventing - public static ScalesetState[] NeedsWork() - { + public static ScalesetState[] NeedsWork() { return _states.GetOrAdd(nameof(NeedsWork), k => new[]{ ScalesetState.Init, @@ -172,11 +157,9 @@ public static ScalesetState[] NeedsWork() } /// set of states that indicate if it's available for work - public static ScalesetState[] Available() - { + public static ScalesetState[] Available() { return - _states.GetOrAdd(nameof(Available), k => - { + _states.GetOrAdd(nameof(Available), k => { return new[]{ ScalesetState.Resize, @@ -186,11 +169,9 @@ public static ScalesetState[] Available() } /// set of states that indicate scaleset is resizing - public static ScalesetState[] Resizing() - { + public static ScalesetState[] Resizing() { return - _states.GetOrAdd(nameof(Resizing), k => - { + _states.GetOrAdd(nameof(Resizing), k => { return new[]{ ScalesetState.Halt, @@ -202,15 +183,12 @@ public static ScalesetState[] Resizing() } -public static class VmStateHelper -{ +public static class VmStateHelper { static ConcurrentDictionary _states = new ConcurrentDictionary(); - public static VmState[] NeedsWork() - { + public static VmState[] NeedsWork() { return - _states.GetOrAdd(nameof(VmStateHelper.NeedsWork), k => - { + _states.GetOrAdd(nameof(VmStateHelper.NeedsWork), k => { return new[]{ VmState.Init, @@ -220,11 +198,9 @@ public static VmState[] NeedsWork() }); } - public static VmState[] Available() - { + public static VmState[] Available() { return - _states.GetOrAdd(nameof(VmStateHelper.Available), k => - { + _states.GetOrAdd(nameof(VmStateHelper.Available), k => { return new[]{ VmState.Init, @@ -237,14 +213,11 @@ public static VmState[] Available() } } -public static class TaskStateHelper -{ +public static class TaskStateHelper { static ConcurrentDictionary _states = new ConcurrentDictionary(); - public static TaskState[] Available() - { + public static TaskState[] Available() { return - _states.GetOrAdd(nameof(Available), k => - { + _states.GetOrAdd(nameof(Available), k => { return new[]{ TaskState.Waiting, @@ -257,22 +230,18 @@ public static TaskState[] Available() } } -public enum PoolState -{ +public enum PoolState { Init, Running, Shutdown, Halt } -public static class PoolStateHelper -{ +public static class PoolStateHelper { static ConcurrentDictionary _states = new ConcurrentDictionary(); - public static PoolState[] NeedsWork() - { + public static PoolState[] NeedsWork() { return - _states.GetOrAdd("NeedsWork", k => - { + _states.GetOrAdd("NeedsWork", k => { return new[]{ PoolState.Init, @@ -282,11 +251,9 @@ public static PoolState[] NeedsWork() }); } - public static PoolState[] Available() - { + public static PoolState[] Available() { return - _states.GetOrAdd("Available", k => - { + _states.GetOrAdd("Available", k => { return new[]{ PoolState.Running @@ -295,7 +262,6 @@ public static PoolState[] Available() } } -public enum Architecture -{ +public enum Architecture { x86_64 } diff --git a/src/ApiService/ApiService/OneFuzzTypes/Events.cs b/src/ApiService/ApiService/OneFuzzTypes/Events.cs index 205b8758260..e8cbc4d6490 100644 --- a/src/ApiService/ApiService/OneFuzzTypes/Events.cs +++ b/src/ApiService/ApiService/OneFuzzTypes/Events.cs @@ -1,6 +1,6 @@ -using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; -using System.Text.Json; +using System.Text.Json; using System.Text.Json.Serialization; +using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; using PoolName = System.String; using Region = System.String; @@ -9,8 +9,7 @@ namespace Microsoft.OneFuzz.Service; -public enum EventType -{ +public enum EventType { JobCreated, JobStopped, NodeCreated, @@ -40,13 +39,10 @@ public enum EventType InstanceConfigUpdated, } -public abstract record BaseEvent() -{ - public EventType GetEventType() - { +public abstract record BaseEvent() { + public EventType GetEventType() { return - this switch - { + this switch { EventNodeHeartbeat _ => EventType.NodeHeartbeat, EventTaskHeartbeat _ => EventType.TaskHeartbeat, EventInstanceConfigUpdated _ => EventType.InstanceConfigUpdated, @@ -62,10 +58,8 @@ public EventType GetEventType() } - public static Type GetTypeInfo(EventType eventType) - { - return (eventType) switch - { + public static Type GetTypeInfo(EventType eventType) { + return (eventType) switch { EventType.NodeHeartbeat => typeof(EventNodeHeartbeat), EventType.InstanceConfigUpdated => typeof(EventInstanceConfigUpdated), EventType.TaskHeartbeat => typeof(EventTaskHeartbeat), @@ -82,10 +76,8 @@ public static Type GetTypeInfo(EventType eventType) } }; -public class EventTypeProvider : ITypeProvider -{ - public Type GetTypeInfo(object input) - { +public class EventTypeProvider : ITypeProvider { + public Type GetTypeInfo(object input) { return BaseEvent.GetTypeInfo((input as EventType?) ?? throw new ArgumentException($"input is expected to be an EventType {input}")); } } @@ -297,15 +289,12 @@ public record EventMessage( String InstanceName ) : EntityBase(); -public class BaseEventConverter : JsonConverter -{ - public override BaseEvent? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { +public class BaseEventConverter : JsonConverter { + public override BaseEvent? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return null; } - public override void Write(Utf8JsonWriter writer, BaseEvent value, JsonSerializerOptions options) - { + public override void Write(Utf8JsonWriter writer, BaseEvent value, JsonSerializerOptions options) { var eventType = value.GetType(); JsonSerializer.Serialize(writer, value, eventType, options); } diff --git a/src/ApiService/ApiService/OneFuzzTypes/Model.cs b/src/ApiService/ApiService/OneFuzzTypes/Model.cs index 516b1227620..ce1b88fc9a9 100644 --- a/src/ApiService/ApiService/OneFuzzTypes/Model.cs +++ b/src/ApiService/ApiService/OneFuzzTypes/Model.cs @@ -1,11 +1,11 @@ -using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; +using System.Text.Json; using System.Text.Json.Serialization; -using Region = System.String; -using PoolName = System.String; +using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; using Endpoint = System.String; using GroupId = System.Guid; +using PoolName = System.String; using PrincipalId = System.Guid; -using System.Text.Json; +using Region = System.String; namespace Microsoft.OneFuzz.Service; @@ -27,8 +27,7 @@ string PrivateKey ); [SkipRename] -public enum HeartbeatType -{ +public enum HeartbeatType { MachineAlive, TaskAlive, } @@ -60,8 +59,7 @@ public record NodeCommand NodeCommandStopIfFree? StopIfFree ); -public enum NodeTaskState -{ +public enum NodeTaskState { Init, SettingUp, Running, @@ -74,8 +72,7 @@ public record NodeTasks NodeTaskState State = NodeTaskState.Init ); -public enum NodeState -{ +public enum NodeState { Init, Free, SettingUp, @@ -258,8 +255,7 @@ public record Task( Authentication? Auth, DateTimeOffset? Heartbeat, DateTimeOffset? EndTime, - UserInfo? UserInfo) : StatefulEntityBase(State) -{ + UserInfo? UserInfo) : StatefulEntityBase(State) { List Events { get; set; } = new List(); List Nodes { get; set; } = new List(); } @@ -292,8 +288,7 @@ AzureMonitorExtensionConfig AzureMonitor public record NetworkConfig( string AddressSpace, string Subnet -) -{ +) { public static NetworkConfig Default { get; } = new NetworkConfig("10.0.0.0/8", "10.0.0.0/16"); @@ -303,8 +298,7 @@ public NetworkConfig() : this("10.0.0.0/8", "10.0.0.0/16") { } public record NetworkSecurityGroupConfig( string[] AllowedServiceTags, string[] AllowedIps -) -{ +) { public NetworkSecurityGroupConfig() : this(Array.Empty(), Array.Empty()) { } } @@ -331,8 +325,7 @@ public record InstanceConfig IDictionary? VmTags, IDictionary? VmssTags -) : EntityBase() -{ +) : EntityBase() { public InstanceConfig(string instanceName) : this( instanceName, null, @@ -345,19 +338,14 @@ public InstanceConfig(string instanceName) : this( null, null, null, - null) - { } + null) { } public InstanceConfig() : this(String.Empty) { } - public List? CheckAdmins(List? value) - { - if (value is not null && value.Count == 0) - { + public List? CheckAdmins(List? value) { + if (value is not null && value.Count == 0) { throw new ArgumentException("admins must be null or contain at least one UUID"); - } - else - { + } else { return value; } } @@ -365,19 +353,14 @@ public InstanceConfig() : this(String.Empty) { } //# At the moment, this only checks allowed_aad_tenants, however adding //# support for 3rd party JWT validation is anticipated in a future release. - public ResultVoid> CheckInstanceConfig() - { + public ResultVoid> CheckInstanceConfig() { List errors = new(); - if (AllowedAadTenants.Length == 0) - { + if (AllowedAadTenants.Length == 0) { errors.Add("allowed_aad_tenants must not be empty"); } - if (errors.Count == 0) - { + if (errors.Count == 0) { return ResultVoid>.Ok(); - } - else - { + } else { return ResultVoid>.Error(errors); } } @@ -412,21 +395,17 @@ Dictionary Tags ) : StatefulEntityBase(State); [JsonConverter(typeof(ContainerConverter))] -public record Container(string ContainerName) -{ +public record Container(string ContainerName) { public string ContainerName { get; } = ContainerName.All(c => char.IsLetterOrDigit(c) || c == '-') ? ContainerName : throw new ArgumentException("Container name must have only numbers, letters or dashes"); } -public class ContainerConverter : JsonConverter -{ - public override Container? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { +public class ContainerConverter : JsonConverter { + public override Container? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var containerName = reader.GetString(); return containerName == null ? null : new Container(containerName); } - public override void Write(Utf8JsonWriter writer, Container value, JsonSerializerOptions options) - { + public override void Write(Utf8JsonWriter writer, Container value, JsonSerializerOptions options) { writer.WriteStringValue(value.ContainerName); } } @@ -548,8 +527,7 @@ public record Vm( Authentication Auth, Nsg? Nsg, IDictionary? Tags -) -{ +) { public string Name { get; } = Name.Length > 40 ? throw new ArgumentOutOfRangeException("VM name too long") : Name; }; @@ -561,22 +539,15 @@ public record SecretAddress(Uri Url); /// The secret field stores either the raw data or the address of that data /// This class allows us to maintain backward compatibility with existing /// NotificationTemplate classes -public record SecretData(T Secret) -{ - public override string ToString() - { - if (Secret is SecretAddress) - { - if (Secret is null) - { +public record SecretData(T Secret) { + public override string ToString() { + if (Secret is SecretAddress) { + if (Secret is null) { return string.Empty; - } - else - { + } else { return Secret.ToString()!; } - } - else + } else return "[REDACTED]"; } } diff --git a/src/ApiService/ApiService/OneFuzzTypes/ReturnTypes.cs b/src/ApiService/ApiService/OneFuzzTypes/ReturnTypes.cs index f92ef5cbbd2..89f543fe8f2 100644 --- a/src/ApiService/ApiService/OneFuzzTypes/ReturnTypes.cs +++ b/src/ApiService/ApiService/OneFuzzTypes/ReturnTypes.cs @@ -1,8 +1,6 @@ -namespace Microsoft.OneFuzz.Service -{ +namespace Microsoft.OneFuzz.Service { - public struct ResultVoid - { + public struct ResultVoid { public static ResultVoid Ok() => new(); public static ResultVoid Error(T_Error err) => new(err); @@ -19,8 +17,7 @@ public struct ResultVoid } - public struct Result - { + public struct Result { public static Result Ok(T_Ok ok) => new(ok); public static Result Error(T_Error err) => new(err); @@ -39,8 +36,7 @@ public struct Result } - public struct OneFuzzResult - { + public struct OneFuzzResult { static Error NoError = new(0); readonly T_Ok? ok; diff --git a/src/ApiService/ApiService/OneFuzzTypes/Webhooks.cs b/src/ApiService/ApiService/OneFuzzTypes/Webhooks.cs index ab2a333ec09..1e62054262f 100644 --- a/src/ApiService/ApiService/OneFuzzTypes/Webhooks.cs +++ b/src/ApiService/ApiService/OneFuzzTypes/Webhooks.cs @@ -1,11 +1,10 @@ -using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; -using System.Text.Json.Serialization; +using System.Text.Json.Serialization; +using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; namespace Microsoft.OneFuzz.Service; -public enum WebhookMessageFormat -{ +public enum WebhookMessageFormat { Onefuzz, EventGrid } diff --git a/src/ApiService/ApiService/Program.cs b/src/ApiService/ApiService/Program.cs index 751cf0737b3..f1b79d02e60 100644 --- a/src/ApiService/ApiService/Program.cs +++ b/src/ApiService/ApiService/Program.cs @@ -1,26 +1,20 @@ // to avoid collision with Task in model.cs -global using Async = System.Threading.Tasks; - global using System; global using System.Collections.Generic; global using System.Linq; - -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Azure.Functions.Worker.Middleware; +global using Async = System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Middleware; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; namespace Microsoft.OneFuzz.Service; -public class Program -{ - public class LoggingMiddleware : IFunctionsWorkerMiddleware - { - public async Async.Task Invoke(FunctionContext context, FunctionExecutionDelegate next) - { +public class Program { + public class LoggingMiddleware : IFunctionsWorkerMiddleware { + public async Async.Task Invoke(FunctionContext context, FunctionExecutionDelegate next) { var log = (ILogTracerInternal?)context.InstanceServices.GetService(); - if (log is not null) - { + if (log is not null) { //TODO //if correlation ID is available in HTTP request //if correlation ID is available in Queue message @@ -37,14 +31,11 @@ public async Async.Task Invoke(FunctionContext context, FunctionExecutionDelegat } - public static List GetLoggers(IServiceConfig config) - { + public static List GetLoggers(IServiceConfig config) { List loggers = new List(); - foreach (var dest in config.LogDestinations) - { + foreach (var dest in config.LogDestinations) { loggers.Add( - dest switch - { + dest switch { LogDestination.AppInsights => new AppInsights(config.ApplicationInsightsInstrumentationKey!), LogDestination.Console => new Console(), _ => throw new Exception($"Unhandled Log Destination type: {dest}"), @@ -55,12 +46,10 @@ public static List GetLoggers(IServiceConfig config) } - public static void Main() - { + public static void Main() { var host = new HostBuilder() .ConfigureFunctionsWorkerDefaults( - builder => - { + builder => { builder.UseMiddleware(); } ) diff --git a/src/ApiService/ApiService/QueueFileChanges.cs b/src/ApiService/ApiService/QueueFileChanges.cs index d70b9096fe5..1083d411993 100644 --- a/src/ApiService/ApiService/QueueFileChanges.cs +++ b/src/ApiService/ApiService/QueueFileChanges.cs @@ -1,11 +1,10 @@ +using System.Text.Json; using Microsoft.Azure.Functions.Worker; -using System.Text.Json; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; namespace Microsoft.OneFuzz.Service; -public class QueueFileChanges -{ +public class QueueFileChanges { // The number of time the function will be retried if an error occurs // https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-queue-trigger?tabs=csharp#poison-messages const int MAX_DEQUEUE_COUNT = 5; @@ -16,8 +15,7 @@ public class QueueFileChanges private readonly INotificationOperations _notificationOperations; - public QueueFileChanges(ILogTracer log, IStorage storage, INotificationOperations notificationOperations) - { + public QueueFileChanges(ILogTracer log, IStorage storage, INotificationOperations notificationOperations) { _log = log; _storage = storage; _notificationOperations = notificationOperations; @@ -26,8 +24,7 @@ public QueueFileChanges(ILogTracer log, IStorage storage, INotificationOperation [Function("QueueFileChanges")] public async Async.Task Run( [QueueTrigger("file-changes-refactored", Connection = "AzureWebJobsStorage")] string msg, - int dequeueCount) - { + int dequeueCount) { var fileChangeEvent = JsonSerializer.Deserialize(msg, EntityConverter.GetJsonSerializerOptions()); var lastTry = dequeueCount == MAX_DEQUEUE_COUNT; @@ -36,23 +33,20 @@ public async Async.Task Run( // check type first before calling Azure APIs const string eventType = "eventType"; if (!fileChangeEvent.RootElement.TryGetProperty(eventType, out var eventTypeElement) - || eventTypeElement.GetString() != "Microsoft.Storage.BlobCreated") - { + || eventTypeElement.GetString() != "Microsoft.Storage.BlobCreated") { return; } const string topic = "topic"; if (!fileChangeEvent.RootElement.TryGetProperty(topic, out var topicElement) - || !_storage.CorpusAccounts().Contains(topicElement.GetString())) - { + || !_storage.CorpusAccounts().Contains(topicElement.GetString())) { return; } await file_added(_log, fileChangeEvent, lastTry); } - private async Async.Task file_added(ILogTracer log, JsonDocument fileChangeEvent, bool failTaskOnTransientError) - { + private async Async.Task file_added(ILogTracer log, JsonDocument fileChangeEvent, bool failTaskOnTransientError) { var data = fileChangeEvent.RootElement.GetProperty("data"); var url = data.GetProperty("url").GetString()!; var parts = url.Split("/").Skip(3).ToList(); diff --git a/src/ApiService/ApiService/QueueNodeHearbeat.cs b/src/ApiService/ApiService/QueueNodeHearbeat.cs index 247bd1aa4b7..c724137ed56 100644 --- a/src/ApiService/ApiService/QueueNodeHearbeat.cs +++ b/src/ApiService/ApiService/QueueNodeHearbeat.cs @@ -1,27 +1,24 @@ +using System.Text.Json; using Microsoft.Azure.Functions.Worker; -using System.Text.Json; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; namespace Microsoft.OneFuzz.Service; -public class QueueNodeHearbeat -{ +public class QueueNodeHearbeat { private readonly ILogTracer _log; private readonly IEvents _events; private readonly INodeOperations _nodes; - public QueueNodeHearbeat(ILogTracer log, INodeOperations nodes, IEvents events) - { + public QueueNodeHearbeat(ILogTracer log, INodeOperations nodes, IEvents events) { _log = log; _nodes = nodes; _events = events; } [Function("QueueNodeHearbeat")] - public async Async.Task Run([QueueTrigger("myqueue-items", Connection = "AzureWebJobsStorage")] string msg) - { + public async Async.Task Run([QueueTrigger("myqueue-items", Connection = "AzureWebJobsStorage")] string msg) { _log.Info($"heartbeat: {msg}"); var hb = JsonSerializer.Deserialize(msg, EntityConverter.GetJsonSerializerOptions()).EnsureNotNull($"wrong data {msg}"); @@ -30,8 +27,7 @@ public async Async.Task Run([QueueTrigger("myqueue-items", Connection = "AzureWe var log = _log.WithTag("NodeId", hb.NodeId.ToString()); - if (node == null) - { + if (node == null) { log.Warning($"invalid node id: {hb.NodeId}"); return; } @@ -40,8 +36,7 @@ public async Async.Task Run([QueueTrigger("myqueue-items", Connection = "AzureWe var r = await _nodes.Replace(newNode); - if (!r.IsOk) - { + if (!r.IsOk) { var (status, reason) = r.ErrorV; log.Error($"Failed to replace heartbeat info due to [{status}] {reason}"); } diff --git a/src/ApiService/ApiService/QueueProxyHeartbeat.cs b/src/ApiService/ApiService/QueueProxyHeartbeat.cs index 6b963f58475..cc3d61dad68 100644 --- a/src/ApiService/ApiService/QueueProxyHeartbeat.cs +++ b/src/ApiService/ApiService/QueueProxyHeartbeat.cs @@ -1,24 +1,21 @@ +using System.Text.Json; using Microsoft.Azure.Functions.Worker; -using System.Text.Json; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; namespace Microsoft.OneFuzz.Service; -public class QueueProxyHearbeat -{ +public class QueueProxyHearbeat { private readonly ILogTracer _log; private readonly IProxyOperations _proxy; - public QueueProxyHearbeat(ILogTracer log, IProxyOperations proxy) - { + public QueueProxyHearbeat(ILogTracer log, IProxyOperations proxy) { _log = log; _proxy = proxy; } [Function("QueueProxyHearbeat")] - public async Async.Task Run([QueueTrigger("myqueue-items", Connection = "AzureWebJobsStorage")] string msg) - { + public async Async.Task Run([QueueTrigger("myqueue-items", Connection = "AzureWebJobsStorage")] string msg) { _log.Info($"heartbeat: {msg}"); var hb = JsonSerializer.Deserialize(msg, EntityConverter.GetJsonSerializerOptions()).EnsureNotNull($"wrong data {msg}"); ; @@ -28,16 +25,14 @@ public async Async.Task Run([QueueTrigger("myqueue-items", Connection = "AzureWe var log = _log.WithTag("ProxyId", newHb.ProxyId.ToString()); - if (proxy == null) - { + if (proxy == null) { log.Warning($"invalid proxy id: {newHb.ProxyId}"); return; } var newProxy = proxy with { Heartbeat = newHb }; var r = await _proxy.Replace(newProxy); - if (!r.IsOk) - { + if (!r.IsOk) { var (status, reason) = r.ErrorV; log.Error($"Failed to replace proxy heartbeat record due to [{status}] {reason}"); } diff --git a/src/ApiService/ApiService/QueueSignalREvents.cs b/src/ApiService/ApiService/QueueSignalREvents.cs index 21a5a05b4e8..4aaea09f38e 100644 --- a/src/ApiService/ApiService/QueueSignalREvents.cs +++ b/src/ApiService/ApiService/QueueSignalREvents.cs @@ -1,21 +1,18 @@ -using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker; namespace Microsoft.OneFuzz.Service; -public class QueueSignalREvents -{ +public class QueueSignalREvents { private readonly ILogTracerFactory _loggerFactory; - public QueueSignalREvents(ILogTracerFactory loggerFactory) - { + public QueueSignalREvents(ILogTracerFactory loggerFactory) { _loggerFactory = loggerFactory; } [Function("QueueSignalREvents")] [SignalROutput(HubName = "dashboard")] public static string Run( - [QueueTrigger("signalr-events-refactored", Connection = "AzureWebJobsStorage")] string msg) - { + [QueueTrigger("signalr-events-refactored", Connection = "AzureWebJobsStorage")] string msg) { return msg; } } diff --git a/src/ApiService/ApiService/QueueTaskHearbeat.cs b/src/ApiService/ApiService/QueueTaskHearbeat.cs index f6af56e05bc..58a36d8e3ae 100644 --- a/src/ApiService/ApiService/QueueTaskHearbeat.cs +++ b/src/ApiService/ApiService/QueueTaskHearbeat.cs @@ -1,36 +1,32 @@ +using System.Text.Json; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; -using System.Text.Json; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; namespace Microsoft.OneFuzz.Service; -public class QueueTaskHearbeat -{ +public class QueueTaskHearbeat { private readonly ILogger _logger; private readonly IEvents _events; private readonly ITaskOperations _tasks; - public QueueTaskHearbeat(ILoggerFactory loggerFactory, ITaskOperations tasks, IEvents events) - { + public QueueTaskHearbeat(ILoggerFactory loggerFactory, ITaskOperations tasks, IEvents events) { _logger = loggerFactory.CreateLogger(); _tasks = tasks; _events = events; } [Function("QueueTaskHearbeat")] - public async Async.Task Run([QueueTrigger("myqueue-items2", Connection = "AzureWebJobsStorage")] string msg) - { + public async Async.Task Run([QueueTrigger("myqueue-items2", Connection = "AzureWebJobsStorage")] string msg) { _logger.LogInformation($"heartbeat: {msg}"); var hb = JsonSerializer.Deserialize(msg, EntityConverter.GetJsonSerializerOptions()).EnsureNotNull($"wrong data {msg}"); var task = await _tasks.GetByTaskId(hb.TaskId); - if (task == null) - { + if (task == null) { _logger.LogWarning($"invalid task id: {hb.TaskId}"); return; } diff --git a/src/ApiService/ApiService/ServiceConfiguration.cs b/src/ApiService/ApiService/ServiceConfiguration.cs index f82a8e7606d..416c324f631 100644 --- a/src/ApiService/ApiService/ServiceConfiguration.cs +++ b/src/ApiService/ApiService/ServiceConfiguration.cs @@ -1,14 +1,12 @@ namespace Microsoft.OneFuzz.Service; -public enum LogDestination -{ +public enum LogDestination { Console, AppInsights, } -public interface IServiceConfig -{ +public interface IServiceConfig { public LogDestination[] LogDestinations { get; set; } public ApplicationInsights.DataContracts.SeverityLevel LogSeverityLevel { get; } @@ -40,11 +38,9 @@ public interface IServiceConfig public string OnefuzzVersion { get; } } -public class ServiceConfiguration : IServiceConfig -{ +public class ServiceConfiguration : IServiceConfig { - public ServiceConfiguration() - { + public ServiceConfiguration() { #if DEBUG LogDestinations = new LogDestination[] { LogDestination.AppInsights, LogDestination.Console }; #else @@ -82,4 +78,4 @@ public ServiceConfiguration() public string? OneFuzzResourceGroup { get => Environment.GetEnvironmentVariable("ONEFUZZ_RESOURCE_GROUP"); } public string? OneFuzzTelemetry { get => Environment.GetEnvironmentVariable("ONEFUZZ_TELEMETRY"); } public string OnefuzzVersion { get => Environment.GetEnvironmentVariable("ONEFUZZ_VERSION") ?? "0.0.0"; } -} \ No newline at end of file +} diff --git a/src/ApiService/ApiService/TestHooks.cs b/src/ApiService/ApiService/TestHooks.cs index 9949cf9bfda..a06522233bd 100644 --- a/src/ApiService/ApiService/TestHooks.cs +++ b/src/ApiService/ApiService/TestHooks.cs @@ -7,16 +7,14 @@ namespace Microsoft.OneFuzz.Service; public record FunctionInfo(string Name, string ResourceGroup, string? SlotName); -public class TestHooks -{ +public class TestHooks { private readonly ILogTracer _log; private readonly IConfigOperations _configOps; private readonly IEvents _events; private readonly IServiceConfig _config; - public TestHooks(ILogTracer log, IConfigOperations configOps, IEvents events, IServiceConfig config) - { + public TestHooks(ILogTracer log, IConfigOperations configOps, IEvents events, IServiceConfig config) { _log = log; _configOps = configOps; _events = events; @@ -24,8 +22,7 @@ public TestHooks(ILogTracer log, IConfigOperations configOps, IEvents events, IS } [Function("Info")] - public async Task Info([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/info")] HttpRequestData req) - { + public async Task Info([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/info")] HttpRequestData req) { _log.Info("Creating function info response"); var response = req.CreateResponse(); FunctionInfo info = new( @@ -40,21 +37,17 @@ public async Task Info([HttpTrigger(AuthorizationLevel.Anonymo } [Function("InstanceConfig")] - public async Task InstanceConfig([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/instance-config")] HttpRequestData req) - { + public async Task InstanceConfig([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/instance-config")] HttpRequestData req) { _log.Info("Fetching instance config"); var config = await _configOps.Fetch(); - if (config is null) - { + if (config is null) { _log.Error("Instance config is null"); Error err = new(ErrorCode.INVALID_REQUEST, new[] { "Instance config is null" }); var resp = req.CreateResponse(HttpStatusCode.InternalServerError); await resp.WriteAsJsonAsync(err); return resp; - } - else - { + } else { await _events.SendEvent(new EventInstanceConfigUpdated(config)); var str = (new EntityConverter()).ToJsonString(config); diff --git a/src/ApiService/ApiService/TimerDaily.cs b/src/ApiService/ApiService/TimerDaily.cs index 84b933af510..a7426f64094 100644 --- a/src/ApiService/ApiService/TimerDaily.cs +++ b/src/ApiService/ApiService/TimerDaily.cs @@ -1,30 +1,26 @@ -using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; -public class TimerDaily -{ +public class TimerDaily { private readonly ILogger _logger; private readonly IScalesetOperations _scalesets; private readonly IWebhookMessageLogOperations _webhookMessageLogs; - public TimerDaily(ILoggerFactory loggerFactory, IScalesetOperations scalesets, IWebhookMessageLogOperations webhookMessageLogs) - { + public TimerDaily(ILoggerFactory loggerFactory, IScalesetOperations scalesets, IWebhookMessageLogOperations webhookMessageLogs) { _logger = loggerFactory.CreateLogger(); _scalesets = scalesets; _webhookMessageLogs = webhookMessageLogs; } //[Function("TimerDaily")] - public async Async.Task Run([TimerTrigger("1.00:00:00")] TimerInfo myTimer) - { + public async Async.Task Run([TimerTrigger("1.00:00:00")] TimerInfo myTimer) { var scalesets = _scalesets.Search(); - await foreach (var scaleset in scalesets) - { + await foreach (var scaleset in scalesets) { _logger.LogInformation($"updating scaleset configs: {scaleset.ScalesetId}"); // todo: do it in batches await _scalesets.Replace(scaleset with { NeedsConfigUpdate = true }); @@ -32,8 +28,7 @@ public async Async.Task Run([TimerTrigger("1.00:00:00")] TimerInfo myTimer) var expiredWebhookLogs = _webhookMessageLogs.SearchExpired(); - await foreach (var logEntry in expiredWebhookLogs) - { + await foreach (var logEntry in expiredWebhookLogs) { _logger.LogInformation($"stopping expired webhook message log: {logEntry.WebhookId}:{logEntry.EventId}"); await _webhookMessageLogs.Delete(logEntry); } diff --git a/src/ApiService/ApiService/TimerProxy.cs b/src/ApiService/ApiService/TimerProxy.cs index edb3e3bf860..14c08934408 100644 --- a/src/ApiService/ApiService/TimerProxy.cs +++ b/src/ApiService/ApiService/TimerProxy.cs @@ -1,10 +1,9 @@ -using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker; namespace Microsoft.OneFuzz.Service; -public partial class TimerProxy -{ +public partial class TimerProxy { private readonly ILogTracer _logger; private readonly IProxyOperations _proxYOperations; @@ -19,8 +18,7 @@ public partial class TimerProxy private readonly ISubnet _subnet; - public TimerProxy(ILogTracer logTracer, IProxyOperations proxies, IScalesetOperations scalesets, INsg nsg, ICreds creds, IConfigOperations configOperations, ISubnet subnet) - { + public TimerProxy(ILogTracer logTracer, IProxyOperations proxies, IScalesetOperations scalesets, INsg nsg, ICreds creds, IConfigOperations configOperations, ISubnet subnet) { _logger = logTracer; _proxYOperations = proxies; _scalesetOperations = scalesets; @@ -31,42 +29,32 @@ public TimerProxy(ILogTracer logTracer, IProxyOperations proxies, IScalesetOpera } //[Function("TimerDaily")] - public async Async.Task Run([TimerTrigger("1.00:00:00")] TimerInfo myTimer) - { + public async Async.Task Run([TimerTrigger("1.00:00:00")] TimerInfo myTimer) { var proxies = await _proxYOperations.QueryAsync().ToListAsync(); - foreach (var proxy in proxies) - { - if (VmStateHelper.Available().Contains(proxy.State)) - { + foreach (var proxy in proxies) { + if (VmStateHelper.Available().Contains(proxy.State)) { // Note, outdated checked at the start, but set at the end of this loop. // As this function is called via a timer, this works around a user // requesting to use the proxy while this function is checking if it's // out of date - if (proxy.Outdated) - { + if (proxy.Outdated) { await _proxYOperations.SetState(proxy, VmState.Stopping); // If something is "wrong" with a proxy, delete & recreate it - } - else if (!_proxYOperations.IsAlive(proxy)) - { + } else if (!_proxYOperations.IsAlive(proxy)) { _logger.Error($"scaleset-proxy: alive check failed, stopping: {proxy.Region}"); await _proxYOperations.SetState(proxy, VmState.Stopping); - } - else - { + } else { await _proxYOperations.SaveProxyConfig(proxy); } } - if (VmStateHelper.NeedsWork().Contains(proxy.State)) - { + if (VmStateHelper.NeedsWork().Contains(proxy.State)) { _logger.Error($"scaleset-proxy: update state. proxy:{proxy.Region} state:{proxy.State}"); await _proxYOperations.ProcessStateUpdate(proxy); } - if (proxy.State != VmState.Stopped && _proxYOperations.IsOutdated(proxy)) - { + if (proxy.State != VmState.Stopped && _proxYOperations.IsOutdated(proxy)) { await _proxYOperations.Replace(proxy with { Outdated = true }); } } @@ -74,11 +62,9 @@ public async Async.Task Run([TimerTrigger("1.00:00:00")] TimerInfo myTimer) // make sure there is a proxy for every currently active region var regions = await _scalesetOperations.QueryAsync().Select(x => x.Region).ToHashSetAsync(); - foreach (var region in regions) - { + foreach (var region in regions) { var allOutdated = proxies.Where(x => x.Region == region).All(p => p.Outdated); - if (allOutdated) - { + if (allOutdated) { await _proxYOperations.GetOrCreate(region); _logger.Info($"Creating new proxy in region {region}"); } @@ -88,17 +74,14 @@ public async Async.Task Run([TimerTrigger("1.00:00:00")] TimerInfo myTimer) // assignment though. This behavior is acceptable at this point // since we do not support bring your own NSG - if (await _nsg.GetNsg(region) != null) - { + if (await _nsg.GetNsg(region) != null) { var network = await Network.Create(region, _creds, _configOperations, _subnet); var subnet = await network.GetSubnet(); var vnet = await network.GetVnet(); - if (subnet != null && vnet != null) - { + if (subnet != null && vnet != null) { var error = _nsg.AssociateSubnet(region, vnet, subnet); - if (error != null) - { + if (error != null) { _logger.Error($"Failed to associate NSG and subnet due to {error} in region {region}"); } } @@ -106,12 +89,9 @@ public async Async.Task Run([TimerTrigger("1.00:00:00")] TimerInfo myTimer) // if there are NSGs with name same as the region that they are allocated // and have no NIC associated with it then delete the NSG - await foreach (var nsg in _nsg.ListNsgs()) - { - if (_nsg.OkToDelete(regions, nsg.Data.Location, nsg.Data.Name)) - { - if (nsg.Data.NetworkInterfaces.Count == 0 && nsg.Data.Subnets.Count == 0) - { + await foreach (var nsg in _nsg.ListNsgs()) { + if (_nsg.OkToDelete(regions, nsg.Data.Location, nsg.Data.Name)) { + if (nsg.Data.NetworkInterfaces.Count == 0 && nsg.Data.Subnets.Count == 0) { await _nsg.StartDeleteNsg(nsg.Data.Name); } } diff --git a/src/ApiService/ApiService/TimerRepro.cs b/src/ApiService/ApiService/TimerRepro.cs index 48126e2f72f..648e85d7dfd 100644 --- a/src/ApiService/ApiService/TimerRepro.cs +++ b/src/ApiService/ApiService/TimerRepro.cs @@ -1,27 +1,23 @@ -using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker; namespace Microsoft.OneFuzz.Service; -public class TimerRepro -{ +public class TimerRepro { private readonly ILogTracer _log; private readonly IStorage _storage; private readonly IReproOperations _reproOperations; - public TimerRepro(ILogTracer log, IStorage storage, IReproOperations reproOperations) - { + public TimerRepro(ILogTracer log, IStorage storage, IReproOperations reproOperations) { _log = log; _storage = storage; _reproOperations = reproOperations; } - public async Async.Task Run([TimerTrigger("00:00:30")] TimerInfo myTimer) - { + public async Async.Task Run([TimerTrigger("00:00:30")] TimerInfo myTimer) { var expired = _reproOperations.SearchExpired(); - await foreach (var repro in expired) - { + await foreach (var repro in expired) { _log.Info($"stopping repro: {repro?.VmId}"); } } diff --git a/src/ApiService/ApiService/TimerRetention.cs b/src/ApiService/ApiService/TimerRetention.cs index 377c495f63c..a93b1bc1160 100644 --- a/src/ApiService/ApiService/TimerRetention.cs +++ b/src/ApiService/ApiService/TimerRetention.cs @@ -2,8 +2,7 @@ namespace Microsoft.OneFuzz.Service; -public class TimerRetention -{ +public class TimerRetention { private readonly TimeSpan RETENTION_POLICY = TimeSpan.FromDays(18 * 30); private readonly TimeSpan SEARCH_EXTENT = TimeSpan.FromDays(20 * 30); @@ -18,8 +17,7 @@ public TimerRetention( ITaskOperations taskOps, INotificationOperations notificaitonOps, IJobOperations jobOps, - IReproOperations reproOps) - { + IReproOperations reproOps) { _log = log; _taskOps = taskOps; _notificaitonOps = notificaitonOps; @@ -28,8 +26,7 @@ public TimerRetention( } - public async Async.Task Run([TimerTrigger("20:00:00")] TimerInfo t) - { + public async Async.Task Run([TimerTrigger("20:00:00")] TimerInfo t) { var now = DateTimeOffset.UtcNow; var timeRetainedOlder = now - RETENTION_POLICY; @@ -44,75 +41,61 @@ public async Async.Task Run([TimerTrigger("20:00:00")] TimerInfo t) var usedContainers = new HashSet(); - await foreach (var task in _taskOps.QueryAsync(timeFilter)) - { + await foreach (var task in _taskOps.QueryAsync(timeFilter)) { var containerNames = from container in task.Config.Containers select container.Name; - foreach (var c in containerNames) - { + foreach (var c in containerNames) { usedContainers.Add(c); } } - await foreach (var notification in _notificaitonOps.QueryAsync(timeFilter)) - { + await foreach (var notification in _notificaitonOps.QueryAsync(timeFilter)) { _log.Verbose($"checking expired notification for removal: {notification.NotificationId}"); var container = notification.Container; - if (!usedContainers.Contains(container)) - { + if (!usedContainers.Contains(container)) { _log.Info($"deleting expired notification: {notification.NotificationId}"); var r = await _notificaitonOps.Delete(notification); - if (!r.IsOk) - { + if (!r.IsOk) { _log.Error($"failed to delete notification with id {notification.NotificationId} due to [{r.ErrorV.Item1}] {r.ErrorV.Item2}"); } } } - await foreach (var job in _jobOps.QueryAsync($"{timeFilter} and state eq '{JobState.Enabled}'")) - { - if (job.UserInfo is not null && job.UserInfo.Upn is not null) - { + await foreach (var job in _jobOps.QueryAsync($"{timeFilter} and state eq '{JobState.Enabled}'")) { + if (job.UserInfo is not null && job.UserInfo.Upn is not null) { _log.Info($"removing PII from job {job.JobId}"); var userInfo = job.UserInfo with { Upn = null }; var updatedJob = job with { UserInfo = userInfo }; var r = await _jobOps.Replace(updatedJob); - if (!r.IsOk) - { + if (!r.IsOk) { _log.Error($"Failed to save job {updatedJob.JobId} due to [{r.ErrorV.Item1}] {r.ErrorV.Item2}"); } } } - await foreach (var task in _taskOps.QueryAsync($"{timeFilter} and state eq '{TaskState.Stopped}'")) - { - if (task.UserInfo is not null && task.UserInfo.Upn is not null) - { + await foreach (var task in _taskOps.QueryAsync($"{timeFilter} and state eq '{TaskState.Stopped}'")) { + if (task.UserInfo is not null && task.UserInfo.Upn is not null) { _log.Info($"removing PII from task {task.TaskId}"); var userInfo = task.UserInfo with { Upn = null }; var updatedTask = task with { UserInfo = userInfo }; var r = await _taskOps.Replace(updatedTask); - if (!r.IsOk) - { + if (!r.IsOk) { _log.Error($"Failed to save task {updatedTask.TaskId} due to [{r.ErrorV.Item1}] {r.ErrorV.Item2}"); } } } - await foreach (var repro in _reproOps.QueryAsync(timeFilter)) - { - if (repro.UserInfo is not null && repro.UserInfo.Upn is not null) - { + await foreach (var repro in _reproOps.QueryAsync(timeFilter)) { + if (repro.UserInfo is not null && repro.UserInfo.Upn is not null) { _log.Info($"removing PII from repro: {repro.VmId}"); var userInfo = repro.UserInfo with { Upn = null }; var updatedRepro = repro with { UserInfo = userInfo }; var r = await _reproOps.Replace(updatedRepro); - if (!r.IsOk) - { + if (!r.IsOk) { _log.Error($"Failed to save repro {updatedRepro.VmId} due to [{r.ErrorV.Item1}] {r.ErrorV.Item2}"); } } diff --git a/src/ApiService/ApiService/UserCredentials.cs b/src/ApiService/ApiService/UserCredentials.cs index 6ecc3d13e3d..ec79e205fb3 100644 --- a/src/ApiService/ApiService/UserCredentials.cs +++ b/src/ApiService/ApiService/UserCredentials.cs @@ -6,66 +6,50 @@ namespace Microsoft.OneFuzz.Service; -public interface IUserCredentials -{ +public interface IUserCredentials { public string? GetBearerToken(HttpRequestData req); public string? GetAuthToken(HttpRequestData req); public Task> ParseJwtToken(LogTracer log, HttpRequestData req); } -public class UserCredentials : IUserCredentials -{ +public class UserCredentials : IUserCredentials { ILogTracer _log; IConfigOperations _instanceConfig; - public UserCredentials(ILogTracer log, IConfigOperations instanceConfig) - { + public UserCredentials(ILogTracer log, IConfigOperations instanceConfig) { _log = log; _instanceConfig = instanceConfig; } - public string? GetBearerToken(HttpRequestData req) - { + public string? GetBearerToken(HttpRequestData req) { var authHeader = req.Headers.GetValues("Authorization"); - if (authHeader.IsNullOrEmpty()) - { + if (authHeader.IsNullOrEmpty()) { return null; - } - else - { + } else { var auth = AuthenticationHeaderValue.Parse(authHeader.First()); - return auth.Scheme.ToLower() switch - { + return auth.Scheme.ToLower() switch { "bearer" => auth.Parameter, _ => null, }; } } - public string? GetAuthToken(HttpRequestData req) - { + public string? GetAuthToken(HttpRequestData req) { var token = GetBearerToken(req); - if (token is not null) - { + if (token is not null) { return token; - } - else - { + } else { var tokenHeader = req.Headers.GetValues("x-ms-token-aad-id-token"); - if (tokenHeader.IsNullOrEmpty()) - { + if (tokenHeader.IsNullOrEmpty()) { return null; - } - else - { + } else { return tokenHeader.First(); } } } - async Task> GetAllowedTenants() - { + async Task> GetAllowedTenants() { var r = await _instanceConfig.Fetch(); var allowedAddTenantsQuery = from t in r.AllowedAadTenants @@ -74,21 +58,15 @@ from t in r.AllowedAadTenants return OneFuzzResult.Ok(allowedAddTenantsQuery.ToArray()); } - public async Task> ParseJwtToken(LogTracer log, HttpRequestData req) - { + public async Task> ParseJwtToken(LogTracer log, HttpRequestData req) { var authToken = GetAuthToken(req); - if (authToken is null) - { + if (authToken is null) { return OneFuzzResult.Error(ErrorCode.INVALID_REQUEST, new[] { "unable to find authorization token" }); - } - else - { + } else { var token = new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(authToken); var allowedTenants = await GetAllowedTenants(); - if (allowedTenants.IsOk) - { - if (allowedTenants.OkV is not null && allowedTenants.OkV.Contains(token.Issuer)) - { + if (allowedTenants.IsOk) { + if (allowedTenants.OkV is not null && allowedTenants.OkV.Contains(token.Issuer)) { Guid? applicationId = ( from t in token.Claims where t.Type == "appId" @@ -105,15 +83,11 @@ from t in token.Claims select t.Value).FirstOrDefault(); return OneFuzzResult.Ok(new(applicationId, objectId, upn)); - } - else - { + } else { log.Error($"issuer not from allowed tenant: {token.Issuer} - {allowedTenants}"); return OneFuzzResult.Error(ErrorCode.INVALID_REQUEST, new[] { "unauthorized AAD issuer" }); } - } - else - { + } else { log.Error("Failed to get allowed tenants"); return OneFuzzResult.Error(allowedTenants.ErrorV); } diff --git a/src/ApiService/ApiService/onefuzzlib/Auth.cs b/src/ApiService/ApiService/onefuzzlib/Auth.cs index 67b8473c14b..c6779854bf4 100644 --- a/src/ApiService/ApiService/onefuzzlib/Auth.cs +++ b/src/ApiService/ApiService/onefuzzlib/Auth.cs @@ -2,10 +2,8 @@ using System.Security.Cryptography; -public class Auth -{ - public static Authentication BuildAuth() - { +public class Auth { + public static Authentication BuildAuth() { var rsa = RSA.Create(2048); string header = "-----BEGIN RSA PRIVATE KEY-----"; string footer = "-----END RSA PRIVATE KEY-----"; diff --git a/src/ApiService/ApiService/onefuzzlib/Containers.cs b/src/ApiService/ApiService/onefuzzlib/Containers.cs index 80dbc34ab23..3a469428557 100644 --- a/src/ApiService/ApiService/onefuzzlib/Containers.cs +++ b/src/ApiService/ApiService/onefuzzlib/Containers.cs @@ -1,15 +1,14 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; +using Azure; using Azure.ResourceManager; -using Azure.Storage.Blobs; using Azure.Storage; -using Azure; +using Azure.Storage.Blobs; using Azure.Storage.Sas; namespace Microsoft.OneFuzz.Service; -public interface IContainers -{ +public interface IContainers { public Task GetBlob(Container container, string name, StorageType storageType); public Async.Task FindContainer(Container container, StorageType storageType); @@ -19,41 +18,33 @@ public interface IContainers Task GetInstanceId(); } -public class Containers : IContainers -{ +public class Containers : IContainers { private ILogTracer _log; private IStorage _storage; private ICreds _creds; private ArmClient _armClient; - public Containers(ILogTracer log, IStorage storage, ICreds creds) - { + public Containers(ILogTracer log, IStorage storage, ICreds creds) { _log = log; _storage = storage; _creds = creds; _armClient = creds.ArmClient; } - public async Task GetBlob(Container container, string name, StorageType storageType) - { + public async Task GetBlob(Container container, string name, StorageType storageType) { var client = await FindContainer(container, storageType); - if (client == null) - { + if (client == null) { return null; } - try - { + try { return (await client.GetBlobClient(name).DownloadContentAsync()) .Value.Content; - } - catch (RequestFailedException) - { + } catch (RequestFailedException) { return null; } } - public async Async.Task FindContainer(Container container, StorageType storageType) - { + public async Async.Task FindContainer(Container container, StorageType storageType) { // # check secondary accounts first by searching in reverse. // # // # By implementation, the primary account is specified first, followed by @@ -69,12 +60,10 @@ public Containers(ILogTracer log, IStorage storage, ICreds creds) .FirstOrDefaultAsync(); } - private BlobServiceClient? GetBlobService(string accountId) - { + private BlobServiceClient? GetBlobService(string accountId) { _log.Info($"getting blob container (account_id: {accountId}"); var (accountName, accountKey) = _storage.GetStorageAccountNameAndKey(accountId); - if (accountName == null) - { + if (accountName == null) { _log.Error("Failed to get storage account name"); return null; } @@ -83,20 +72,17 @@ public Containers(ILogTracer log, IStorage storage, ICreds creds) return new BlobServiceClient(accountUrl, storageKeyCredential); } - private static Uri GetUrl(string accountName) - { + private static Uri GetUrl(string accountName) { return new Uri($"https://{accountName}.blob.core.windows.net/"); } - public async Async.Task GetFileSasUrl(Container container, string name, StorageType storageType, BlobSasPermissions permissions, TimeSpan? duration = null) - { + public async Async.Task GetFileSasUrl(Container container, string name, StorageType storageType, BlobSasPermissions permissions, TimeSpan? duration = null) { var client = await FindContainer(container, storageType) ?? throw new Exception($"unable to find container: {container.ContainerName} - {storageType}"); var (accountName, accountKey) = _storage.GetStorageAccountNameAndKey(client.AccountName); var (startTime, endTime) = SasTimeWindow(duration ?? TimeSpan.FromDays(30)); - var sasBuilder = new BlobSasBuilder(permissions, endTime) - { + var sasBuilder = new BlobSasBuilder(permissions, endTime) { StartsOn = startTime, BlobContainerName = container.ContainerName, BlobName = name @@ -106,8 +92,7 @@ private static Uri GetUrl(string accountName) return sasUrl; } - public (DateTimeOffset, DateTimeOffset) SasTimeWindow(TimeSpan timeSpan) - { + public (DateTimeOffset, DateTimeOffset) SasTimeWindow(TimeSpan timeSpan) { // SAS URLs are valid 6 hours earlier, primarily to work around dev // workstations having out-of-sync time. Additionally, SAS URLs are stopped // 15 minutes later than requested based on "Be careful with SAS start time" @@ -123,18 +108,15 @@ private static Uri GetUrl(string accountName) return (start, expiry); } - public async System.Threading.Tasks.Task saveBlob(Container container, string name, string data, StorageType storageType) - { + public async System.Threading.Tasks.Task saveBlob(Container container, string name, string data, StorageType storageType) { var client = await FindContainer(container, storageType) ?? throw new Exception($"unable to find container: {container.ContainerName} - {storageType}"); await client.UploadBlobAsync(name, new BinaryData(data)); } - public async Async.Task GetInstanceId() - { + public async Async.Task GetInstanceId() { var blob = await GetBlob(new Container("base-config"), "instance_id", StorageType.Config); - if (blob == null) - { + if (blob == null) { throw new System.Exception("Blob Not Found"); } return System.Guid.Parse(blob.ToString()); diff --git a/src/ApiService/ApiService/onefuzzlib/Creds.cs b/src/ApiService/ApiService/onefuzzlib/Creds.cs index ccc47b2e5b0..97b7d221cc5 100644 --- a/src/ApiService/ApiService/onefuzzlib/Creds.cs +++ b/src/ApiService/ApiService/onefuzzlib/Creds.cs @@ -1,12 +1,11 @@ +using Azure.Core; using Azure.Identity; -using Azure.Core; using Azure.ResourceManager; using Azure.ResourceManager.Resources; namespace Microsoft.OneFuzz.Service; -public interface ICreds -{ +public interface ICreds { public DefaultAzureCredential GetIdentity(); public string GetSubcription(); @@ -23,57 +22,49 @@ public interface ICreds public string GetBaseRegion(); } -public class Creds : ICreds -{ +public class Creds : ICreds { private readonly ArmClient _armClient; private readonly DefaultAzureCredential _azureCredential; private readonly IServiceConfig _config; public ArmClient ArmClient => _armClient; - public Creds(IServiceConfig config) - { + public Creds(IServiceConfig config) { _config = config; _azureCredential = new DefaultAzureCredential(); _armClient = new ArmClient(this.GetIdentity(), this.GetSubcription()); } - public DefaultAzureCredential GetIdentity() - { + public DefaultAzureCredential GetIdentity() { return _azureCredential; } - public string GetSubcription() - { + public string GetSubcription() { var storageResourceId = _config.OneFuzzDataStorage ?? throw new System.Exception("Data storage env var is not present"); var storageResource = new ResourceIdentifier(storageResourceId); return storageResource.SubscriptionId!; } - public string GetBaseResourceGroup() - { + public string GetBaseResourceGroup() { var storageResourceId = _config.OneFuzzDataStorage ?? throw new System.Exception("Data storage env var is not present"); var storageResource = new ResourceIdentifier(storageResourceId); return storageResource.ResourceGroupName!; } - public ResourceIdentifier GetResourceGroupResourceIdentifier() - { + public ResourceIdentifier GetResourceGroupResourceIdentifier() { var resourceId = _config.OneFuzzResourceGroup ?? throw new System.Exception("Resource group env var is not present"); return new ResourceIdentifier(resourceId); } - public ResourceGroupResource GetResourceGroupResource() - { + public ResourceGroupResource GetResourceGroupResource() { var resourceId = GetResourceGroupResourceIdentifier(); return ArmClient.GetResourceGroupResource(resourceId); } - public string GetBaseRegion() - { + public string GetBaseRegion() { return ArmClient.GetResourceGroupResource(GetResourceGroupResourceIdentifier()).Data.Location.Name; } } diff --git a/src/ApiService/ApiService/onefuzzlib/DiskOperations.cs b/src/ApiService/ApiService/onefuzzlib/DiskOperations.cs index e1c9cafca64..3e14f4ad16e 100644 --- a/src/ApiService/ApiService/onefuzzlib/DiskOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/DiskOperations.cs @@ -1,34 +1,29 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Azure.ResourceManager.Compute; namespace Microsoft.OneFuzz.Service; -public interface IDiskOperations -{ +public interface IDiskOperations { DiskCollection ListDisks(string resourceGroup); Async.Task DeleteDisk(string resourceGroup, string name); } -public class DiskOperations : IDiskOperations -{ +public class DiskOperations : IDiskOperations { private ILogTracer _logTracer; private ICreds _creds; - public DiskOperations(ILogTracer log, ICreds creds) - { + public DiskOperations(ILogTracer log, ICreds creds) { _logTracer = log; _creds = creds; } - public Task DeleteDisk(string resourceGroup, string name) - { + public Task DeleteDisk(string resourceGroup, string name) { throw new NotImplementedException(); } - public DiskCollection ListDisks(string resourceGroup) - { + public DiskCollection ListDisks(string resourceGroup) { _logTracer.Info($"listing disks {resourceGroup}"); return _creds.GetResourceGroupResource().GetDisks(); } diff --git a/src/ApiService/ApiService/onefuzzlib/Events.cs b/src/ApiService/ApiService/onefuzzlib/Events.cs index b15e7dca240..c5b377bfee6 100644 --- a/src/ApiService/ApiService/onefuzzlib/Events.cs +++ b/src/ApiService/ApiService/onefuzzlib/Events.cs @@ -1,10 +1,9 @@ -using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; -using System.Text; +using System.Text; using System.Text.Json; using System.Text.Json.Serialization; +using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; -namespace Microsoft.OneFuzz.Service -{ +namespace Microsoft.OneFuzz.Service { public record SignalREvent @@ -14,35 +13,30 @@ List arguments ); - public interface IEvents - { + public interface IEvents { public Async.Task SendEvent(BaseEvent anEvent); public Async.Task QueueSignalrEvent(EventMessage message); } - public class Events : IEvents - { + public class Events : IEvents { private readonly IQueue _queue; private readonly IWebhookOperations _webhook; private ILogTracer _log; - public Events(IQueue queue, IWebhookOperations webhook, ILogTracer log) - { + public Events(IQueue queue, IWebhookOperations webhook, ILogTracer log) { _queue = queue; _webhook = webhook; _log = log; } - public async Async.Task QueueSignalrEvent(EventMessage eventMessage) - { + public async Async.Task QueueSignalrEvent(EventMessage eventMessage) { var message = new SignalREvent("events", new List() { eventMessage }); var encodedMessage = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(message)); await _queue.SendMessage("signalr-events", encodedMessage, StorageType.Config); } - public async Async.Task SendEvent(BaseEvent anEvent) - { + public async Async.Task SendEvent(BaseEvent anEvent) { var eventType = anEvent.GetEventType(); var eventMessage = new EventMessage( @@ -57,8 +51,7 @@ public async Async.Task SendEvent(BaseEvent anEvent) LogEvent(anEvent, eventType); } - public void LogEvent(BaseEvent anEvent, EventType eventType) - { + public void LogEvent(BaseEvent anEvent, EventType eventType) { var options = EntityConverter.GetJsonSerializerOptions(); options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; options.Converters.Add(new RemoveUserInfo()); @@ -68,33 +61,27 @@ public void LogEvent(BaseEvent anEvent, EventType eventType) } - internal class RemoveUserInfo : JsonConverter - { - public override UserInfo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { + internal class RemoveUserInfo : JsonConverter { + public override UserInfo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { //TODO: I might be wrong but seems like better way of doing this is to have a separate type, //that if object of the type - then ignore user info... var newOptions = new JsonSerializerOptions(options); RemoveUserInfo? self = null; - foreach (var converter in newOptions.Converters) - { - if (converter is RemoveUserInfo) - { + foreach (var converter in newOptions.Converters) { + if (converter is RemoveUserInfo) { self = (RemoveUserInfo)converter; break; } } - if (self != null) - { + if (self != null) { newOptions.Converters.Remove(self); } return JsonSerializer.Deserialize(ref reader, newOptions); } - public override void Write(Utf8JsonWriter writer, UserInfo value, JsonSerializerOptions options) - { + public override void Write(Utf8JsonWriter writer, UserInfo value, JsonSerializerOptions options) { writer.WriteStringValue("{}"); } } diff --git a/src/ApiService/ApiService/onefuzzlib/InstanceConfig.cs b/src/ApiService/ApiService/onefuzzlib/InstanceConfig.cs index cabdf93447a..f964ee2cb54 100644 --- a/src/ApiService/ApiService/onefuzzlib/InstanceConfig.cs +++ b/src/ApiService/ApiService/onefuzzlib/InstanceConfig.cs @@ -1,60 +1,47 @@ -using ApiService.OneFuzzLib.Orm; -using System.Threading.Tasks; +using System.Threading.Tasks; +using ApiService.OneFuzzLib.Orm; namespace Microsoft.OneFuzz.Service; -public interface IConfigOperations : IOrm -{ +public interface IConfigOperations : IOrm { Task Fetch(); Async.Task Save(InstanceConfig config, bool isNew, bool requireEtag); } -public class ConfigOperations : Orm, IConfigOperations -{ +public class ConfigOperations : Orm, IConfigOperations { private readonly IEvents _events; private readonly ILogTracer _log; - public ConfigOperations(IStorage storage, IEvents events, ILogTracer log, IServiceConfig config) : base(storage, log, config) - { + public ConfigOperations(IStorage storage, IEvents events, ILogTracer log, IServiceConfig config) : base(storage, log, config) { _events = events; _log = log; } - public async Task Fetch() - { + public async Task Fetch() { var key = _config.OneFuzzInstanceName ?? throw new Exception("Environment variable ONEFUZZ_INSTANCE_NAME is not set"); var config = await GetEntityAsync(key, key); return config; } - public async Async.Task Save(InstanceConfig config, bool isNew = false, bool requireEtag = false) - { + public async Async.Task Save(InstanceConfig config, bool isNew = false, bool requireEtag = false) { ResultVoid<(int, string)> r; - if (isNew) - { + if (isNew) { r = await Insert(config); - if (!r.IsOk) - { + if (!r.IsOk) { var (status, reason) = r.ErrorV; _log.Error($"Failed to save new instance config record with result [{status}] {reason}"); } - } - else if (requireEtag && config.ETag.HasValue) - { + } else if (requireEtag && config.ETag.HasValue) { r = await Update(config); - if (!r.IsOk) - { + if (!r.IsOk) { var (status, reason) = r.ErrorV; _log.Error($"Failed to update instance config record with result: [{status}] {reason}"); } - } - else - { + } else { r = await Replace(config); - if (!r.IsOk) - { + if (!r.IsOk) { var (status, reason) = r.ErrorV; _log.Error($"Failed to replace instance config record with result [{status}] {reason}"); } diff --git a/src/ApiService/ApiService/onefuzzlib/IpOperations.cs b/src/ApiService/ApiService/onefuzzlib/IpOperations.cs index 86e9cbc67de..15e647ad7a9 100644 --- a/src/ApiService/ApiService/onefuzzlib/IpOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/IpOperations.cs @@ -1,9 +1,8 @@ -using Azure.ResourceManager.Network; +using Azure.ResourceManager.Network; namespace Microsoft.OneFuzz.Service; -public interface IIpOperations -{ +public interface IIpOperations { public Async.Task GetPublicNic(string resourceGroup, string name); public Async.Task GetIp(string resourceGroup, string name); @@ -13,37 +12,31 @@ public interface IIpOperations public Async.Task DeleteIp(string resourceGroup, string name); } -public class IpOperations : IIpOperations -{ +public class IpOperations : IIpOperations { private ILogTracer _logTracer; private ICreds _creds; - public IpOperations(ILogTracer log, ICreds creds) - { + public IpOperations(ILogTracer log, ICreds creds) { _logTracer = log; _creds = creds; } - public async Async.Task GetPublicNic(string resourceGroup, string name) - { + public async Async.Task GetPublicNic(string resourceGroup, string name) { _logTracer.Info($"getting nic: {resourceGroup} {name}"); return await _creds.GetResourceGroupResource().GetNetworkInterfaceAsync(name); } - public async Async.Task GetIp(string resourceGroup, string name) - { + public async Async.Task GetIp(string resourceGroup, string name) { _logTracer.Info($"getting ip {resourceGroup}:{name}"); return await _creds.GetResourceGroupResource().GetPublicIPAddressAsync(name); } - public System.Threading.Tasks.Task DeleteNic(string resourceGroup, string name) - { + public System.Threading.Tasks.Task DeleteNic(string resourceGroup, string name) { throw new NotImplementedException(); } - public System.Threading.Tasks.Task DeleteIp(string resourceGroup, string name) - { + public System.Threading.Tasks.Task DeleteIp(string resourceGroup, string name) { throw new NotImplementedException(); } } diff --git a/src/ApiService/ApiService/onefuzzlib/JobOperations.cs b/src/ApiService/ApiService/onefuzzlib/JobOperations.cs index fad7a59a21e..f19e3731c27 100644 --- a/src/ApiService/ApiService/onefuzzlib/JobOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/JobOperations.cs @@ -2,18 +2,15 @@ namespace Microsoft.OneFuzz.Service; -public interface IJobOperations : IStatefulOrm -{ +public interface IJobOperations : IStatefulOrm { } -public class JobOperations : StatefulOrm, IJobOperations -{ +public class JobOperations : StatefulOrm, IJobOperations { public JobOperations(IStorage storage, ILogTracer log, IServiceConfig config) - : base(storage, log, config) - { + : base(storage, log, config) { } } diff --git a/src/ApiService/ApiService/onefuzzlib/Network.cs b/src/ApiService/ApiService/onefuzzlib/Network.cs index 77e9a21e801..dd63f765be7 100644 --- a/src/ApiService/ApiService/onefuzzlib/Network.cs +++ b/src/ApiService/ApiService/onefuzzlib/Network.cs @@ -3,10 +3,8 @@ namespace Microsoft.OneFuzz.Service; -public partial class TimerProxy -{ - public class Network - { +public partial class TimerProxy { + public class Network { private readonly string _name; private readonly string _group; private readonly string _region; @@ -16,8 +14,7 @@ public class Network // This was generated randomly and should be preserved moving forwards static Guid NETWORK_GUID_NAMESPACE = Guid.Parse("372977ad-b533-416a-b1b4-f770898e0b11"); - public Network(string region, string group, string name, NetworkConfig networkConfig, ISubnet subnet) - { + public Network(string region, string group, string name, NetworkConfig networkConfig, ISubnet subnet) { _networkConfig = networkConfig; _region = region; _group = group; @@ -25,8 +22,7 @@ public Network(string region, string group, string name, NetworkConfig networkCo _subnet = subnet; } - public static async Async.Task Create(string region, ICreds creds, IConfigOperations configOperations, ISubnet subnet) - { + public static async Async.Task Create(string region, ICreds creds, IConfigOperations configOperations, ISubnet subnet) { var group = creds.GetBaseResourceGroup(); var instanceConfig = await configOperations.Fetch(); var networkConfig = instanceConfig.NetworkConfig; @@ -38,12 +34,9 @@ public static async Async.Task Create(string region, ICreds creds, ICon string name; - if (networkConfig.AddressSpace == NetworkConfig.Default.AddressSpace && networkConfig.Subnet == NetworkConfig.Default.Subnet) - { + if (networkConfig.AddressSpace == NetworkConfig.Default.AddressSpace && networkConfig.Subnet == NetworkConfig.Default.Subnet) { name = region; - } - else - { + } else { var networkId = Faithlife.Utility.GuidUtility.Create(NETWORK_GUID_NAMESPACE, string.Join("|", networkConfig.AddressSpace, networkConfig.Subnet), 5); name = $"{region}-{networkId}"; } @@ -52,13 +45,11 @@ public static async Async.Task Create(string region, ICreds creds, ICon return new Network(region, group, name, networkConfig, subnet); } - public Async.Task GetSubnet() - { + public Async.Task GetSubnet() { return _subnet.GetSubnet(_name, _name); } - internal System.Threading.Tasks.Task GetVnet() - { + internal System.Threading.Tasks.Task GetVnet() { return _subnet.GetVnet(_name); } } diff --git a/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs b/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs index 0f8338c9e82..87e76611203 100644 --- a/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs @@ -1,24 +1,20 @@ -using ApiService.OneFuzzLib.Orm; -using System.Threading.Tasks; +using System.Threading.Tasks; +using ApiService.OneFuzzLib.Orm; namespace Microsoft.OneFuzz.Service; -public interface INodeOperations : IStatefulOrm -{ +public interface INodeOperations : IStatefulOrm { Task GetByMachineId(Guid machineId); } -public class NodeOperations : StatefulOrm, INodeOperations -{ +public class NodeOperations : StatefulOrm, INodeOperations { public NodeOperations(IStorage storage, ILogTracer log, IServiceConfig config) - : base(storage, log, config) - { + : base(storage, log, config) { } - public async Task GetByMachineId(Guid machineId) - { + public async Task GetByMachineId(Guid machineId) { var data = QueryAsync(filter: $"RowKey eq '{machineId}'"); return await data.FirstOrDefaultAsync(); diff --git a/src/ApiService/ApiService/onefuzzlib/NotificationOperations.cs b/src/ApiService/ApiService/onefuzzlib/NotificationOperations.cs index bb9d62baca5..6063f4d5cf1 100644 --- a/src/ApiService/ApiService/onefuzzlib/NotificationOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/NotificationOperations.cs @@ -1,16 +1,14 @@ -using System.Text.Json; +using System.Text.Json; using ApiService.OneFuzzLib.Orm; using Azure.Storage.Sas; namespace Microsoft.OneFuzz.Service; -public interface INotificationOperations : IOrm -{ +public interface INotificationOperations : IOrm { Async.Task NewFiles(Container container, string filename, bool failTaskOnTransientError); } -public class NotificationOperations : Orm, INotificationOperations -{ +public class NotificationOperations : Orm, INotificationOperations { private IReports _reports; private ITaskOperations _taskOperations; @@ -21,8 +19,7 @@ public class NotificationOperations : Orm, INotificationOperations private IEvents _events; public NotificationOperations(ILogTracer log, IStorage storage, IReports reports, ITaskOperations taskOperations, IContainers containers, IQueue queue, IEvents events, IServiceConfig config) - : base(storage, log, config) - { + : base(storage, log, config) { _reports = reports; _taskOperations = taskOperations; @@ -30,98 +27,78 @@ public NotificationOperations(ILogTracer log, IStorage storage, IReports reports _queue = queue; _events = events; } - public async Async.Task NewFiles(Container container, string filename, bool failTaskOnTransientError) - { + public async Async.Task NewFiles(Container container, string filename, bool failTaskOnTransientError) { var notifications = GetNotifications(container); var hasNotifications = await notifications.AnyAsync(); var report = await _reports.GetReportOrRegression(container, filename, expectReports: hasNotifications); - if (!hasNotifications) - { + if (!hasNotifications) { return; } var done = new List(); - await foreach (var notification in notifications) - { - if (done.Contains(notification.Config)) - { + await foreach (var notification in notifications) { + if (done.Contains(notification.Config)) { continue; } done.Add(notification.Config); - if (notification.Config.TeamsTemplate != null) - { + if (notification.Config.TeamsTemplate != null) { NotifyTeams(notification.Config.TeamsTemplate, container, filename, report); } - if (report == null) - { + if (report == null) { continue; } - if (notification.Config.AdoTemplate != null) - { + if (notification.Config.AdoTemplate != null) { NotifyAdo(notification.Config.AdoTemplate, container, filename, report, failTaskOnTransientError); } - if (notification.Config.GithubIssuesTemplate != null) - { + if (notification.Config.GithubIssuesTemplate != null) { GithubIssue(notification.Config.GithubIssuesTemplate, container, filename, report); } } - await foreach (var (task, containers) in GetQueueTasks()) - { - if (containers.Contains(container.ContainerName)) - { + await foreach (var (task, containers) in GetQueueTasks()) { + if (containers.Contains(container.ContainerName)) { _logTracer.Info($"queuing input {container.ContainerName} {filename} {task.TaskId}"); var url = _containers.GetFileSasUrl(container, filename, StorageType.Corpus, BlobSasPermissions.Read | BlobSasPermissions.Delete); await _queue.SendMessage(task.TaskId.ToString(), System.Text.Encoding.UTF8.GetBytes(url?.ToString() ?? ""), StorageType.Corpus); } } - if (report == null) - { + if (report == null) { await _events.SendEvent(new EventFileAdded(container, filename)); - } - else if (report.Report != null) - { + } else if (report.Report != null) { var reportTask = await _taskOperations.GetByJobIdAndTaskId(report.Report.JobId, report.Report.TaskId); var crashReportedEvent = new EventCrashReported(report.Report, container, filename, reportTask?.Config); await _events.SendEvent(crashReportedEvent); - } - else if (report.RegressionReport != null) - { + } else if (report.RegressionReport != null) { var reportTask = await GetRegressionReportTask(report.RegressionReport); var regressionEvent = new EventRegressionReported(report.RegressionReport, container, filename, reportTask?.Config); } } - public IAsyncEnumerable GetNotifications(Container container) - { + public IAsyncEnumerable GetNotifications(Container container) { return QueryAsync(filter: $"container eq '{container.ContainerName}'"); } - public IAsyncEnumerable<(Task, IEnumerable)> GetQueueTasks() - { + public IAsyncEnumerable<(Task, IEnumerable)> GetQueueTasks() { // Nullability mismatch: We filter tuples where the containers are null return _taskOperations.SearchStates(states: TaskStateHelper.Available()) .Select(task => (task, _taskOperations.GetInputContainerQueues(task.Config))) .Where(taskTuple => taskTuple.Item2 != null)!; } - private async Async.Task GetRegressionReportTask(RegressionReport report) - { - if (report.CrashTestResult.CrashReport != null) - { + private async Async.Task GetRegressionReportTask(RegressionReport report) { + if (report.CrashTestResult.CrashReport != null) { return await _taskOperations.GetByJobIdAndTaskId(report.CrashTestResult.CrashReport.JobId, report.CrashTestResult.CrashReport.TaskId); } - if (report.CrashTestResult.NoReproReport != null) - { + if (report.CrashTestResult.NoReproReport != null) { return await _taskOperations.GetByJobIdAndTaskId(report.CrashTestResult.NoReproReport.JobId, report.CrashTestResult.NoReproReport.TaskId); } @@ -129,18 +106,15 @@ public IAsyncEnumerable GetNotifications(Container container) return null; } - private void GithubIssue(GithubIssuesTemplate config, Container container, string filename, RegressionReportOrReport? report) - { + private void GithubIssue(GithubIssuesTemplate config, Container container, string filename, RegressionReportOrReport? report) { throw new NotImplementedException(); } - private void NotifyAdo(AdoTemplate config, Container container, string filename, RegressionReportOrReport report, bool failTaskOnTransientError) - { + private void NotifyAdo(AdoTemplate config, Container container, string filename, RegressionReportOrReport report, bool failTaskOnTransientError) { throw new NotImplementedException(); } - private void NotifyTeams(TeamsTemplate config, Container container, string filename, RegressionReportOrReport? report) - { + private void NotifyTeams(TeamsTemplate config, Container container, string filename, RegressionReportOrReport? report) { throw new NotImplementedException(); } } diff --git a/src/ApiService/ApiService/onefuzzlib/Nsg.cs b/src/ApiService/ApiService/onefuzzlib/Nsg.cs index 419e69fe865..71d9e56442e 100644 --- a/src/ApiService/ApiService/onefuzzlib/Nsg.cs +++ b/src/ApiService/ApiService/onefuzzlib/Nsg.cs @@ -2,10 +2,8 @@ using Azure.ResourceManager.Network; -namespace Microsoft.OneFuzz.Service -{ - public interface INsg - { +namespace Microsoft.OneFuzz.Service { + public interface INsg { Async.Task GetNsg(string name); public Async.Task AssociateSubnet(string name, VirtualNetworkResource vnet, SubnetResource subnet); IAsyncEnumerable ListNsgs(); @@ -16,34 +14,28 @@ public interface INsg } - public class Nsg : INsg - { + public class Nsg : INsg { private readonly ICreds _creds; private readonly ILogTracer _logTracer; - public Nsg(ICreds creds, ILogTracer logTracer) - { + public Nsg(ICreds creds, ILogTracer logTracer) { _creds = creds; _logTracer = logTracer; } - public async Async.Task AssociateSubnet(string name, VirtualNetworkResource vnet, SubnetResource subnet) - { + public async Async.Task AssociateSubnet(string name, VirtualNetworkResource vnet, SubnetResource subnet) { var nsg = await GetNsg(name); - if (nsg == null) - { + if (nsg == null) { return new Error(ErrorCode.UNABLE_TO_FIND, new[] { $"cannot associate subnet. nsg {name} not found" }); } - if (nsg.Data.Location != vnet.Data.Location) - { + if (nsg.Data.Location != vnet.Data.Location) { return new Error(ErrorCode.UNABLE_TO_UPDATE, new[] { $"subnet and nsg have to be in the same region. nsg {nsg.Data.Name} {nsg.Data.Location}, subnet: {subnet.Data.Name} {subnet.Data}" }); } - if (subnet.Data.NetworkSecurityGroup != null && subnet.Data.NetworkSecurityGroup.Id == nsg.Id) - { + if (subnet.Data.NetworkSecurityGroup != null && subnet.Data.NetworkSecurityGroup.Id == nsg.Id) { _logTracer.Info($"Subnet {subnet.Data.Name} and NSG {name} already associated, not updating"); return null; } @@ -54,28 +46,23 @@ public Nsg(ICreds creds, ILogTracer logTracer) return null; } - public System.Threading.Tasks.Task DissociateNic(NetworkInterfaceResource nic) - { + public System.Threading.Tasks.Task DissociateNic(NetworkInterfaceResource nic) { throw new NotImplementedException(); } - public async Async.Task GetNsg(string name) - { + public async Async.Task GetNsg(string name) { var response = await _creds.GetResourceGroupResource().GetNetworkSecurityGroupAsync(name); - if (response == null) - { + if (response == null) { //_logTracer.Debug($"nsg %s does not exist: {name}"); } return response?.Value; } - public IAsyncEnumerable ListNsgs() - { + public IAsyncEnumerable ListNsgs() { return _creds.GetResourceGroupResource().GetNetworkSecurityGroups().GetAllAsync(); } - public bool OkToDelete(HashSet active_regions, string nsg_region, string nsg_name) - { + public bool OkToDelete(HashSet active_regions, string nsg_region, string nsg_name) { return !active_regions.Contains(nsg_region) && nsg_region == nsg_name; } @@ -83,8 +70,7 @@ public bool OkToDelete(HashSet active_regions, string nsg_region, string /// Returns True if deletion completed (thus resource not found) or successfully started. /// Returns False if failed to start deletion. /// - public async Async.Task StartDeleteNsg(string name) - { + public async Async.Task StartDeleteNsg(string name) { _logTracer.Info($"deleting nsg: {name}"); var nsg = await _creds.GetResourceGroupResource().GetNetworkSecurityGroupAsync(name); await nsg.Value.DeleteAsync(WaitUntil.Completed); diff --git a/src/ApiService/ApiService/onefuzzlib/PoolOperations.cs b/src/ApiService/ApiService/onefuzzlib/PoolOperations.cs index 23444362367..fea248cc666 100644 --- a/src/ApiService/ApiService/onefuzzlib/PoolOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/PoolOperations.cs @@ -1,36 +1,30 @@ -using ApiService.OneFuzzLib.Orm; +using ApiService.OneFuzzLib.Orm; namespace Microsoft.OneFuzz.Service; -public interface IPoolOperations -{ +public interface IPoolOperations { public Async.Task> GetByName(string poolName); } -public class PoolOperations : StatefulOrm, IPoolOperations -{ +public class PoolOperations : StatefulOrm, IPoolOperations { private IConfigOperations _configOperations; private ITaskOperations _taskOperations; public PoolOperations(IStorage storage, ILogTracer log, IServiceConfig config, IConfigOperations configOperations, ITaskOperations taskOperations) - : base(storage, log, config) - { + : base(storage, log, config) { _configOperations = configOperations; _taskOperations = taskOperations; } - public async Async.Task> GetByName(string poolName) - { + public async Async.Task> GetByName(string poolName) { var pools = QueryAsync(filter: $"name eq '{poolName}'"); - if (pools == null) - { + if (pools == null) { return new Result(new Error(ErrorCode.INVALID_REQUEST, new[] { "unable to find pool" })); } - if (await pools.CountAsync() != 1) - { + if (await pools.CountAsync() != 1) { return new Result(new Error(ErrorCode.INVALID_REQUEST, new[] { "error identifying pool" })); } diff --git a/src/ApiService/ApiService/onefuzzlib/ProxyForwardOperations.cs b/src/ApiService/ApiService/onefuzzlib/ProxyForwardOperations.cs index f5ee7679754..805b5485d38 100644 --- a/src/ApiService/ApiService/onefuzzlib/ProxyForwardOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/ProxyForwardOperations.cs @@ -3,20 +3,16 @@ namespace Microsoft.OneFuzz.Service; -public interface IProxyForwardOperations : IOrm -{ +public interface IProxyForwardOperations : IOrm { IAsyncEnumerable SearchForward(Guid? scalesetId = null, string? region = null, Guid? machineId = null, Guid? proxyId = null, int? dstPort = null); } -public class ProxyForwardOperations : Orm, IProxyForwardOperations -{ - public ProxyForwardOperations(IStorage storage, ILogTracer logTracer, IServiceConfig config) : base(storage, logTracer, config) - { +public class ProxyForwardOperations : Orm, IProxyForwardOperations { + public ProxyForwardOperations(IStorage storage, ILogTracer logTracer, IServiceConfig config) : base(storage, logTracer, config) { } - public IAsyncEnumerable SearchForward(Guid? scalesetId = null, string? region = null, Guid? machineId = null, Guid? proxyId = null, int? dstPort = null) - { + public IAsyncEnumerable SearchForward(Guid? scalesetId = null, string? region = null, Guid? machineId = null, Guid? proxyId = null, int? dstPort = null) { var conditions = new[] { diff --git a/src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs b/src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs index 4f36e7f24e2..847bfa13677 100644 --- a/src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs @@ -1,11 +1,10 @@ -using ApiService.OneFuzzLib.Orm; +using System.Threading.Tasks; +using ApiService.OneFuzzLib.Orm; using Azure.Storage.Sas; -using System.Threading.Tasks; namespace Microsoft.OneFuzz.Service; -public interface IProxyOperations : IStatefulOrm -{ +public interface IProxyOperations : IStatefulOrm { Task GetByProxyId(Guid proxyId); Async.Task SetState(Proxy proxy, VmState state); @@ -14,8 +13,7 @@ public interface IProxyOperations : IStatefulOrm bool IsOutdated(Proxy proxy); System.Threading.Tasks.Task GetOrCreate(string region); } -public class ProxyOperations : StatefulOrm, IProxyOperations -{ +public class ProxyOperations : StatefulOrm, IProxyOperations { private readonly IEvents _events; private readonly IProxyForwardOperations _proxyForwardOperations; @@ -26,8 +24,7 @@ public class ProxyOperations : StatefulOrm, IProxyOperations static TimeSpan PROXY_LIFESPAN = TimeSpan.FromDays(7); public ProxyOperations(ILogTracer log, IStorage storage, IEvents events, IProxyForwardOperations proxyForwardOperations, IContainers containers, IQueue queue, ICreds creds, IServiceConfig config) - : base(storage, log.WithTag("Component", "scaleset-proxy"), config) - { + : base(storage, log.WithTag("Component", "scaleset-proxy"), config) { _events = events; _proxyForwardOperations = proxyForwardOperations; _containers = containers; @@ -35,28 +32,23 @@ public ProxyOperations(ILogTracer log, IStorage storage, IEvents events, IProxyF _creds = creds; } - public async Task GetByProxyId(Guid proxyId) - { + public async Task GetByProxyId(Guid proxyId) { var data = QueryAsync(filter: $"RowKey eq '{proxyId}'"); return await data.FirstOrDefaultAsync(); } - public async System.Threading.Tasks.Task GetOrCreate(string region) - { + public async System.Threading.Tasks.Task GetOrCreate(string region) { var proxyList = QueryAsync(filter: $"region eq '{region}' and outdated eq false"); - await foreach (var proxy in proxyList) - { - if (IsOutdated(proxy)) - { + await foreach (var proxy in proxyList) { + if (IsOutdated(proxy)) { await Replace(proxy with { Outdated = true }); continue; } - if (!VmStateHelper.Available().Contains(proxy.State)) - { + if (!VmStateHelper.Available().Contains(proxy.State)) { continue; } return proxy; @@ -70,18 +62,15 @@ public ProxyOperations(ILogTracer log, IStorage storage, IEvents events, IProxyF return newProxy; } - public bool IsAlive(Proxy proxy) - { + public bool IsAlive(Proxy proxy) { var tenMinutesAgo = DateTimeOffset.UtcNow - TimeSpan.FromMinutes(10); - if (proxy.Heartbeat != null && proxy.Heartbeat.TimeStamp < tenMinutesAgo) - { + if (proxy.Heartbeat != null && proxy.Heartbeat.TimeStamp < tenMinutesAgo) { _logTracer.Info($"last heartbeat is more than an 10 minutes old: {proxy.Region} - last heartbeat:{proxy.Heartbeat} compared_to:{tenMinutesAgo}"); return false; } - if (proxy.Heartbeat != null && proxy.TimeStamp != null && proxy.TimeStamp < tenMinutesAgo) - { + if (proxy.Heartbeat != null && proxy.TimeStamp != null && proxy.TimeStamp < tenMinutesAgo) { _logTracer.Error($"no heartbeat in the last 10 minutes: {proxy.Region} timestamp: {proxy.TimeStamp} compared_to:{tenMinutesAgo}"); return false; } @@ -89,23 +78,18 @@ public bool IsAlive(Proxy proxy) return true; } - public bool IsOutdated(Proxy proxy) - { - if (!VmStateHelper.Available().Contains(proxy.State)) - { + public bool IsOutdated(Proxy proxy) { + if (!VmStateHelper.Available().Contains(proxy.State)) { return false; } - if (proxy.Version != _config.OnefuzzVersion) - { + if (proxy.Version != _config.OnefuzzVersion) { _logTracer.Info($"mismatch version: proxy:{proxy.Version} service:{_config.OnefuzzVersion} state:{proxy.State}"); return true; } - if (proxy.CreatedTimestamp != null) - { - if (proxy.CreatedTimestamp < (DateTimeOffset.UtcNow - PROXY_LIFESPAN)) - { + if (proxy.CreatedTimestamp != null) { + if (proxy.CreatedTimestamp < (DateTimeOffset.UtcNow - PROXY_LIFESPAN)) { _logTracer.Info($"proxy older than 7 days:proxy-created:{proxy.CreatedTimestamp} state:{proxy.State}"); return true; } @@ -113,8 +97,7 @@ public bool IsOutdated(Proxy proxy) return false; } - public async System.Threading.Tasks.Task SaveProxyConfig(Proxy proxy) - { + public async System.Threading.Tasks.Task SaveProxyConfig(Proxy proxy) { var forwards = await GetForwards(proxy); var url = (await _containers.GetFileSasUrl(new Container("proxy-configs"), $"{proxy.Region}/{proxy.ProxyId}/config.json", StorageType.Config, BlobSasPermissions.Read)).EnsureNotNull("Can't generate file sas"); @@ -134,10 +117,8 @@ public async System.Threading.Tasks.Task SaveProxyConfig(Proxy proxy) - public async Async.Task SetState(Proxy proxy, VmState state) - { - if (proxy.State == state) - { + public async Async.Task SetState(Proxy proxy, VmState state) { + if (proxy.State == state) { return; } @@ -147,18 +128,13 @@ public async Async.Task SetState(Proxy proxy, VmState state) } - public async Async.Task> GetForwards(Proxy proxy) - { + public async Async.Task> GetForwards(Proxy proxy) { var forwards = new List(); - await foreach (var entry in _proxyForwardOperations.SearchForward(region: proxy.Region, proxyId: proxy.ProxyId)) - { - if (entry.EndTime < DateTimeOffset.UtcNow) - { + await foreach (var entry in _proxyForwardOperations.SearchForward(region: proxy.Region, proxyId: proxy.ProxyId)) { + if (entry.EndTime < DateTimeOffset.UtcNow) { await _proxyForwardOperations.Delete(entry); - } - else - { + } else { forwards.Add(new Forward(entry.Port, entry.DstPort, entry.DstIp)); } } diff --git a/src/ApiService/ApiService/onefuzzlib/Queue.cs b/src/ApiService/ApiService/onefuzzlib/Queue.cs index 648825528a8..c9f7aa359ae 100644 --- a/src/ApiService/ApiService/onefuzzlib/Queue.cs +++ b/src/ApiService/ApiService/onefuzzlib/Queue.cs @@ -1,64 +1,51 @@ -using Azure.Storage; +using System.Text.Json; +using System.Threading.Tasks; +using Azure.Storage; using Azure.Storage.Queues; using Azure.Storage.Sas; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; -using System.Text.Json; -using System.Threading.Tasks; namespace Microsoft.OneFuzz.Service; -public interface IQueue -{ +public interface IQueue { Async.Task SendMessage(string name, byte[] message, StorageType storageType, TimeSpan? visibilityTimeout = null, TimeSpan? timeToLive = null); Async.Task QueueObject(string name, T obj, StorageType storageType, TimeSpan? visibilityTimeout); Uri? GetQueueSas(string name, StorageType storageType, QueueSasPermissions permissions, TimeSpan? duration = null); } -public class Queue : IQueue -{ +public class Queue : IQueue { IStorage _storage; ILogTracer _log; static TimeSpan DEFAULT_DURATION = TimeSpan.FromDays(30); - public Queue(IStorage storage, ILogTracer log) - { + public Queue(IStorage storage, ILogTracer log) { _storage = storage; _log = log; } - public async Async.Task SendMessage(string name, byte[] message, StorageType storageType, TimeSpan? visibilityTimeout = null, TimeSpan? timeToLive = null) - { + public async Async.Task SendMessage(string name, byte[] message, StorageType storageType, TimeSpan? visibilityTimeout = null, TimeSpan? timeToLive = null) { var queue = GetQueue(name, storageType); - if (queue != null) - { - try - { + if (queue != null) { + try { await queue.SendMessageAsync(Convert.ToBase64String(message), visibilityTimeout: visibilityTimeout, timeToLive: timeToLive); - } - catch (Exception) - { + } catch (Exception) { } } } - public QueueClient? GetQueue(string name, StorageType storageType) - { + public QueueClient? GetQueue(string name, StorageType storageType) { var client = GetQueueClient(storageType); - try - { + try { return client.GetQueueClient(name); - } - catch (Exception) - { + } catch (Exception) { return null; } } - public QueueServiceClient GetQueueClient(StorageType storageType) - { + public QueueServiceClient GetQueueClient(StorageType storageType) { var accountId = _storage.GetPrimaryAccount(storageType); //_logger.LogDEbug("getting blob container (account_id: %s)", account_id) (var name, var key) = _storage.GetStorageAccountNameAndKey(accountId); @@ -67,26 +54,21 @@ public QueueServiceClient GetQueueClient(StorageType storageType) return client; } - public async Task QueueObject(string name, T obj, StorageType storageType, TimeSpan? visibilityTimeout) - { + public async Task QueueObject(string name, T obj, StorageType storageType, TimeSpan? visibilityTimeout) { var queue = GetQueue(name, storageType) ?? throw new Exception($"unable to queue object, no such queue: {name}"); var serialized = JsonSerializer.Serialize(obj, EntityConverter.GetJsonSerializerOptions()); //var encoded = Encoding.UTF8.GetBytes(serialized); - try - { + try { await queue.SendMessageAsync(serialized, visibilityTimeout: visibilityTimeout); return true; - } - catch (Exception) - { + } catch (Exception) { return false; } } - public Uri? GetQueueSas(string name, StorageType storageType, QueueSasPermissions permissions, TimeSpan? duration) - { + public Uri? GetQueueSas(string name, StorageType storageType, QueueSasPermissions permissions, TimeSpan? duration) { var queue = GetQueue(name, storageType) ?? throw new Exception($"unable to queue object, no such queue: {name}"); var sasaBuilder = new QueueSasBuilder(permissions, DateTimeOffset.UtcNow + (duration ?? DEFAULT_DURATION)); var url = queue.GenerateSasUri(sasaBuilder); diff --git a/src/ApiService/ApiService/onefuzzlib/Reports.cs b/src/ApiService/ApiService/onefuzzlib/Reports.cs index 19622abba9f..fa5fa7d40be 100644 --- a/src/ApiService/ApiService/onefuzzlib/Reports.cs +++ b/src/ApiService/ApiService/onefuzzlib/Reports.cs @@ -1,30 +1,24 @@ -using System.Text.Json; +using System.Text.Json; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; namespace Microsoft.OneFuzz.Service; -public interface IReports -{ +public interface IReports { public Async.Task GetReportOrRegression(Container container, string fileName, bool expectReports = false, params string[] args); } -public class Reports : IReports -{ +public class Reports : IReports { private ILogTracer _log; private IContainers _containers; - public Reports(ILogTracer log, IContainers containers) - { + public Reports(ILogTracer log, IContainers containers) { _log = log; _containers = containers; } - public async Async.Task GetReportOrRegression(Container container, string fileName, bool expectReports = false, params string[] args) - { + public async Async.Task GetReportOrRegression(Container container, string fileName, bool expectReports = false, params string[] args) { var filePath = String.Join("/", new[] { container.ContainerName, fileName }); - if (!fileName.EndsWith(".json")) - { - if (expectReports) - { + if (!fileName.EndsWith(".json")) { + if (expectReports) { _log.Error($"get_report invalid extension: {filePath}"); } return null; @@ -32,10 +26,8 @@ public Reports(ILogTracer log, IContainers containers) var blob = await _containers.GetBlob(container, fileName, StorageType.Corpus); - if (blob == null) - { - if (expectReports) - { + if (blob == null) { + if (expectReports) { _log.Error($"get_report invalid blob: {filePath}"); } return null; @@ -44,28 +36,18 @@ public Reports(ILogTracer log, IContainers containers) return ParseReportOrRegression(blob.ToString(), filePath, expectReports); } - private RegressionReportOrReport? ParseReportOrRegression(string content, string? filePath, bool expectReports = false) - { - try - { - return new RegressionReportOrReport - { + private RegressionReportOrReport? ParseReportOrRegression(string content, string? filePath, bool expectReports = false) { + try { + return new RegressionReportOrReport { RegressionReport = JsonSerializer.Deserialize(content, EntityConverter.GetJsonSerializerOptions()) }; - } - catch (JsonException e) - { - try - { - return new RegressionReportOrReport - { + } catch (JsonException e) { + try { + return new RegressionReportOrReport { Report = JsonSerializer.Deserialize(content, EntityConverter.GetJsonSerializerOptions()) }; - } - catch (JsonException e2) - { - if (expectReports) - { + } catch (JsonException e2) { + if (expectReports) { _log.Error($"unable to parse report ({filePath}) as a report or regression. regression error: {e.Message} report error: {e2.Message}"); } return null; @@ -73,17 +55,12 @@ public Reports(ILogTracer log, IContainers containers) } } - private RegressionReportOrReport? ParseReportOrRegression(IEnumerable content, string? filePath, bool expectReports = false) - { - try - { + private RegressionReportOrReport? ParseReportOrRegression(IEnumerable content, string? filePath, bool expectReports = false) { + try { var str = System.Text.Encoding.UTF8.GetString(content.ToArray()); return ParseReportOrRegression(str, filePath, expectReports); - } - catch (Exception e) - { - if (expectReports) - { + } catch (Exception e) { + if (expectReports) { _log.Error($"unable to parse report ({filePath}): unicode decode of report failed - {e.Message} {e.StackTrace}"); } return null; @@ -91,8 +68,7 @@ public Reports(ILogTracer log, IContainers containers) } } -public class RegressionReportOrReport -{ +public class RegressionReportOrReport { public RegressionReport? RegressionReport { get; set; } public Report? Report { get; set; } } diff --git a/src/ApiService/ApiService/onefuzzlib/ReproOperations.cs b/src/ApiService/ApiService/onefuzzlib/ReproOperations.cs index d1aa0b3cad4..06a563a4558 100644 --- a/src/ApiService/ApiService/onefuzzlib/ReproOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/ReproOperations.cs @@ -1,14 +1,12 @@ -using ApiService.OneFuzzLib.Orm; +using ApiService.OneFuzzLib.Orm; namespace Microsoft.OneFuzz.Service; -public interface IReproOperations : IStatefulOrm -{ +public interface IReproOperations : IStatefulOrm { public IAsyncEnumerable SearchExpired(); } -public class ReproOperations : StatefulOrm, IReproOperations -{ +public class ReproOperations : StatefulOrm, IReproOperations { private static readonly Dictionary DEFAULT_OS = new Dictionary { {Os.Linux, "Canonical:UbuntuServer:18.04-LTS:latest"}, @@ -25,33 +23,27 @@ public class ReproOperations : StatefulOrm, IReproOperations private ICreds _creds; public ReproOperations(IStorage storage, ILogTracer log, IServiceConfig config, IConfigOperations configOperations, ITaskOperations taskOperations, ICreds creds, IVmOperations vmOperations) - : base(storage, log, config) - { + : base(storage, log, config) { _configOperations = configOperations; _taskOperations = taskOperations; _creds = creds; _vmOperations = vmOperations; } - public IAsyncEnumerable SearchExpired() - { + public IAsyncEnumerable SearchExpired() { return QueryAsync(filter: $"end_time lt datetime'{DateTime.UtcNow.ToString("o")}'"); } - public async Async.Task GetVm(Repro repro, InstanceConfig config) - { + public async Async.Task GetVm(Repro repro, InstanceConfig config) { var tags = config.VmTags; var task = await _taskOperations.GetByTaskId(repro.TaskId); - if (task == null) - { + if (task == null) { throw new Exception($"previous existing task missing: {repro.TaskId}"); } var vmConfig = await _taskOperations.GetReproVmConfig(task); - if (vmConfig == null) - { - if (!DEFAULT_OS.ContainsKey(task.Os)) - { + if (vmConfig == null) { + if (!DEFAULT_OS.ContainsKey(task.Os)) { throw new NotImplementedException($"unsupport OS for repro {task.Os}"); } @@ -63,8 +55,7 @@ public async Async.Task GetVm(Repro repro, InstanceConfig config) ); } - if (repro.Auth == null) - { + if (repro.Auth == null) { throw new Exception("missing auth"); } @@ -79,24 +70,19 @@ public async Async.Task GetVm(Repro repro, InstanceConfig config) ); } - public async System.Threading.Tasks.Task Stopping(Repro repro) - { + public async System.Threading.Tasks.Task Stopping(Repro repro) { var config = await _configOperations.Fetch(); var vm = await GetVm(repro, config); - if (!await _vmOperations.IsDeleted(vm)) - { + if (!await _vmOperations.IsDeleted(vm)) { _logTracer.Info($"vm stopping: {repro.VmId}"); await _vmOperations.Delete(vm); await Replace(repro); - } - else - { + } else { await Stopped(repro); } } - public async Async.Task Stopped(Repro repro) - { + public async Async.Task Stopped(Repro repro) { _logTracer.Info($"vm stopped: {repro.VmId}"); await Delete(repro); } diff --git a/src/ApiService/ApiService/onefuzzlib/ScalesetOperations.cs b/src/ApiService/ApiService/onefuzzlib/ScalesetOperations.cs index d3da95202a1..a3e89e1a329 100644 --- a/src/ApiService/ApiService/onefuzzlib/ScalesetOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/ScalesetOperations.cs @@ -2,30 +2,25 @@ namespace Microsoft.OneFuzz.Service; -public interface IScalesetOperations : IOrm -{ +public interface IScalesetOperations : IOrm { IAsyncEnumerable Search(); public IAsyncEnumerable SearchByPool(string poolName); } -public class ScalesetOperations : StatefulOrm, IScalesetOperations -{ +public class ScalesetOperations : StatefulOrm, IScalesetOperations { public ScalesetOperations(IStorage storage, ILogTracer log, IServiceConfig config) - : base(storage, log, config) - { + : base(storage, log, config) { } - public IAsyncEnumerable Search() - { + public IAsyncEnumerable Search() { return QueryAsync(); } - public IAsyncEnumerable SearchByPool(string poolName) - { + public IAsyncEnumerable SearchByPool(string poolName) { return QueryAsync(filter: $"pool_name eq '{poolName}'"); } diff --git a/src/ApiService/ApiService/onefuzzlib/Secrets.cs b/src/ApiService/ApiService/onefuzzlib/Secrets.cs index eeb4d40b221..6a91f6ad6f7 100644 --- a/src/ApiService/ApiService/onefuzzlib/Secrets.cs +++ b/src/ApiService/ApiService/onefuzzlib/Secrets.cs @@ -5,8 +5,7 @@ namespace Microsoft.OneFuzz.Service; -public interface ISecretsOperations -{ +public interface ISecretsOperations { public (Uri, string) ParseSecretUrl(Uri secretsUrl); public Task?> SaveToKeyvault(SecretData secretData); public Task GetSecretStringValue(SecretData data); @@ -20,43 +19,33 @@ public interface ISecretsOperations } -public class SecretsOperations : ISecretsOperations -{ +public class SecretsOperations : ISecretsOperations { private readonly ICreds _creds; private readonly IServiceConfig _config; - public SecretsOperations(ICreds creds, IServiceConfig config) - { + public SecretsOperations(ICreds creds, IServiceConfig config) { _creds = creds; _config = config; } - public (Uri, string) ParseSecretUrl(Uri secretsUrl) - { + public (Uri, string) ParseSecretUrl(Uri secretsUrl) { // format: https://{vault-name}.vault.azure.net/secrets/{secret-name}/{version} var vaultUrl = $"{secretsUrl.Scheme}://{secretsUrl.Host}"; var secretName = secretsUrl.Segments[secretsUrl.Segments.Length - 2].Trim('/'); return (new Uri(vaultUrl), secretName); } - public async Task?> SaveToKeyvault(SecretData secretData) - { + public async Task?> SaveToKeyvault(SecretData secretData) { if (secretData == null || secretData.Secret is null) return null; - if (secretData.Secret is SecretAddress) - { + if (secretData.Secret is SecretAddress) { return secretData as SecretData; - } - else - { + } else { var secretName = Guid.NewGuid(); string secretValue; - if (secretData.Secret is string) - { + if (secretData.Secret is string) { secretValue = (secretData.Secret as string)!.Trim(); - } - else - { + } else { secretValue = JsonSerializer.Serialize(secretData.Secret, EntityConverter.GetJsonSerializerOptions()); } @@ -65,48 +54,39 @@ public SecretsOperations(ICreds creds, IServiceConfig config) } } - public async Task GetSecretStringValue(SecretData data) - { - if (data.Secret is null) - { + public async Task GetSecretStringValue(SecretData data) { + if (data.Secret is null) { return null; } - if (data.Secret is SecretAddress) - { + if (data.Secret is SecretAddress) { var secret = await GetSecret((data.Secret as SecretAddress)!.Url); return secret.Value; - } - else - { + } else { return data.Secret.ToString(); } } - public Uri GetKeyvaultAddress() - { + public Uri GetKeyvaultAddress() { // https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates#vault-name-and-object-name var keyvaultName = _config!.OneFuzzKeyvault; return new Uri($"https://{keyvaultName}.vault.azure.net"); } - public async Task StoreInKeyvault(Uri keyvaultUrl, string secretName, string secretValue) - { + public async Task StoreInKeyvault(Uri keyvaultUrl, string secretName, string secretValue) { var keyvaultClient = new SecretClient(keyvaultUrl, _creds.GetIdentity()); var r = await keyvaultClient.SetSecretAsync(secretName, secretValue); return r.Value; } - public async Task GetSecret(Uri secretUrl) - { + public async Task GetSecret(Uri secretUrl) { var (vaultUrl, secretName) = ParseSecretUrl(secretUrl); var keyvaultClient = new SecretClient(vaultUrl, _creds.GetIdentity()); return await keyvaultClient.GetSecretAsync(secretName); } - public async Task GetSecretObj(Uri secretUrl) - { + public async Task GetSecretObj(Uri secretUrl) { var secret = await GetSecret(secretUrl); if (secret is null) return default(T); @@ -114,24 +94,19 @@ public async Task GetSecret(Uri secretUrl) return JsonSerializer.Deserialize(secret.Value, EntityConverter.GetJsonSerializerOptions()); } - public async Task DeleteSecret(Uri secretUrl) - { + public async Task DeleteSecret(Uri secretUrl) { var (vaultUrl, secretName) = ParseSecretUrl(secretUrl); var keyvaultClient = new SecretClient(vaultUrl, _creds.GetIdentity()); return await keyvaultClient.StartDeleteSecretAsync(secretName); } - public async Task DeleteRemoteSecretData(SecretData data) - { - if (data.Secret is SecretAddress) - { + public async Task DeleteRemoteSecretData(SecretData data) { + if (data.Secret is SecretAddress) { if (data.Secret is not null) return await DeleteSecret((data.Secret as SecretAddress)!.Url); else return null; - } - else - { + } else { return null; } } diff --git a/src/ApiService/ApiService/onefuzzlib/Storage.cs b/src/ApiService/ApiService/onefuzzlib/Storage.cs index 3225f5cd428..92775df8c30 100644 --- a/src/ApiService/ApiService/onefuzzlib/Storage.cs +++ b/src/ApiService/ApiService/onefuzzlib/Storage.cs @@ -1,18 +1,16 @@ +using System.Text.Json; +using Azure.Core; using Azure.ResourceManager; using Azure.ResourceManager.Storage; -using Azure.Core; -using System.Text.Json; namespace Microsoft.OneFuzz.Service; -public enum StorageType -{ +public enum StorageType { Corpus, Config } -public interface IStorage -{ +public interface IStorage { public IEnumerable CorpusAccounts(); string GetPrimaryAccount(StorageType storageType); public (string?, string?) GetStorageAccountNameAndKey(string accountId); @@ -20,41 +18,35 @@ public interface IStorage public IEnumerable GetAccounts(StorageType storageType); } -public class Storage : IStorage -{ +public class Storage : IStorage { private ICreds _creds; private ArmClient _armClient; private ILogTracer _log; private IServiceConfig _config; - public Storage(ICreds creds, ILogTracer log, IServiceConfig config) - { + public Storage(ICreds creds, ILogTracer log, IServiceConfig config) { _creds = creds; _armClient = creds.ArmClient; _log = log; _config = config; } - public string GetFuncStorage() - { + public string GetFuncStorage() { return _config.OneFuzzFuncStorage ?? throw new Exception("Func storage env var is missing"); } - public string GetFuzzStorage() - { + public string GetFuzzStorage() { return _config.OneFuzzDataStorage ?? throw new Exception("Fuzz storage env var is missing"); } - public ArmClient GetMgmtClient() - { + public ArmClient GetMgmtClient() { return _armClient; } // TODO: @cached - public IEnumerable CorpusAccounts() - { + public IEnumerable CorpusAccounts() { var skip = GetFuncStorage(); var results = new List { GetFuzzStorage() }; @@ -64,26 +56,21 @@ public IEnumerable CorpusAccounts() const string storageTypeTagKey = "storage_type"; var resourceGroup = client.GetResourceGroupResource(group); - foreach (var account in resourceGroup.GetStorageAccounts()) - { - if (account.Id == skip) - { + foreach (var account in resourceGroup.GetStorageAccounts()) { + if (account.Id == skip) { continue; } - if (results.Contains(account.Id!)) - { + if (results.Contains(account.Id!)) { continue; } - if (string.IsNullOrEmpty(account.Data.PrimaryEndpoints.Blob)) - { + if (string.IsNullOrEmpty(account.Data.PrimaryEndpoints.Blob)) { continue; } if (!account.Data.Tags.ContainsKey(storageTypeTagKey) - || account.Data.Tags[storageTypeTagKey] != "corpus") - { + || account.Data.Tags[storageTypeTagKey] != "corpus") { continue; } @@ -94,19 +81,16 @@ public IEnumerable CorpusAccounts() return results; } - public string GetPrimaryAccount(StorageType storageType) - { + public string GetPrimaryAccount(StorageType storageType) { return - storageType switch - { + storageType switch { StorageType.Corpus => GetFuzzStorage(), StorageType.Config => GetFuncStorage(), _ => throw new NotImplementedException(), }; } - public (string?, string?) GetStorageAccountNameAndKey(string accountId) - { + public (string?, string?) GetStorageAccountNameAndKey(string accountId) { var resourceId = new ResourceIdentifier(accountId); var armClient = GetMgmtClient(); var storageAccount = armClient.GetStorageAccountResource(resourceId); @@ -114,10 +98,8 @@ public string GetPrimaryAccount(StorageType storageType) return (resourceId.Name, key?.Value); } - public IEnumerable GetAccounts(StorageType storageType) - { - switch (storageType) - { + public IEnumerable GetAccounts(StorageType storageType) { + switch (storageType) { case StorageType.Corpus: return CorpusAccounts(); case StorageType.Config: diff --git a/src/ApiService/ApiService/onefuzzlib/Subnet.cs b/src/ApiService/ApiService/onefuzzlib/Subnet.cs index 6796b5a7690..9a5d599baf1 100644 --- a/src/ApiService/ApiService/onefuzzlib/Subnet.cs +++ b/src/ApiService/ApiService/onefuzzlib/Subnet.cs @@ -3,37 +3,30 @@ namespace Microsoft.OneFuzz.Service; -public interface ISubnet -{ +public interface ISubnet { System.Threading.Tasks.Task GetVnet(string vnetName); System.Threading.Tasks.Task GetSubnet(string vnetName, string subnetName); } -public partial class TimerProxy -{ - public class Subnet : ISubnet - { +public partial class TimerProxy { + public class Subnet : ISubnet { private readonly ICreds _creds; - public Subnet(ICreds creds) - { + public Subnet(ICreds creds) { _creds = creds; } - public async System.Threading.Tasks.Task GetSubnet(string vnetName, string subnetName) - { + public async System.Threading.Tasks.Task GetSubnet(string vnetName, string subnetName) { var vnet = await this.GetVnet(vnetName); - if (vnet != null) - { + if (vnet != null) { return await vnet.GetSubnetAsync(subnetName); } return null; } - public async System.Threading.Tasks.Task GetVnet(string vnetName) - { + public async System.Threading.Tasks.Task GetVnet(string vnetName) { var resourceGroupId = _creds.GetResourceGroupResourceIdentifier(); var response = await _creds.ArmClient.GetResourceGroupResource(resourceGroupId).GetVirtualNetworkAsync(vnetName); return response.Value; diff --git a/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs b/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs index 992051af5b9..8534d952d1a 100644 --- a/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs @@ -2,8 +2,7 @@ namespace Microsoft.OneFuzz.Service; -public interface ITaskOperations : IStatefulOrm -{ +public interface ITaskOperations : IStatefulOrm { Async.Task GetByTaskId(Guid taskId); Async.Task GetByJobIdAndTaskId(Guid jobId, Guid taskId); @@ -16,44 +15,36 @@ public interface ITaskOperations : IStatefulOrm Async.Task GetReproVmConfig(Task task); } -public class TaskOperations : StatefulOrm, ITaskOperations -{ +public class TaskOperations : StatefulOrm, ITaskOperations { private IPoolOperations _poolOperations; private IScalesetOperations _scalesetOperations; public TaskOperations(IStorage storage, ILogTracer log, IServiceConfig config, IPoolOperations poolOperations, IScalesetOperations scalesetOperations) - : base(storage, log, config) - { + : base(storage, log, config) { _poolOperations = poolOperations; _scalesetOperations = scalesetOperations; } - public async Async.Task GetByTaskId(Guid taskId) - { + public async Async.Task GetByTaskId(Guid taskId) { var data = QueryAsync(filter: $"RowKey eq '{taskId}'"); return await data.FirstOrDefaultAsync(); } - public async Async.Task GetByJobIdAndTaskId(Guid jobId, Guid taskId) - { + public async Async.Task GetByJobIdAndTaskId(Guid jobId, Guid taskId) { var data = QueryAsync(filter: $"PartitionKey eq '{jobId}' and RowKey eq '{taskId}'"); return await data.FirstOrDefaultAsync(); } - public IAsyncEnumerable SearchStates(Guid? jobId = null, IEnumerable? states = null) - { + public IAsyncEnumerable SearchStates(Guid? jobId = null, IEnumerable? states = null) { var queryString = String.Empty; - if (jobId != null) - { + if (jobId != null) { queryString += $"PartitionKey eq '{jobId}'"; } - if (states != null) - { - if (jobId != null) - { + if (states != null) { + if (jobId != null) { queryString += " and "; } @@ -64,35 +55,29 @@ public IAsyncEnumerable SearchStates(Guid? jobId = null, IEnumerable? GetInputContainerQueues(TaskConfig config) - { + public IEnumerable? GetInputContainerQueues(TaskConfig config) { throw new NotImplementedException(); } - public async Async.Task GetReproVmConfig(Task task) - { - if (task.Config.Vm != null) - { + public async Async.Task GetReproVmConfig(Task task) { + if (task.Config.Vm != null) { return task.Config.Vm; } - if (task.Config.Pool == null) - { + if (task.Config.Pool == null) { throw new Exception($"either pool or vm must be specified: {task.TaskId}"); } var pool = await _poolOperations.GetByName(task.Config.Pool.PoolName); - if (!pool.IsOk) - { + if (!pool.IsOk) { _logTracer.Info($"unable to find pool from task: {task.TaskId}"); return null; } var scaleset = await _scalesetOperations.SearchByPool(task.Config.Pool.PoolName).FirstOrDefaultAsync(); - if (scaleset == null) - { + if (scaleset == null) { _logTracer.Warning($"no scalesets are defined for task: {task.JobId}:{task.TaskId}"); return null; } diff --git a/src/ApiService/ApiService/onefuzzlib/Utils.cs b/src/ApiService/ApiService/onefuzzlib/Utils.cs index 0be4062275a..817ba63cf43 100644 --- a/src/ApiService/ApiService/onefuzzlib/Utils.cs +++ b/src/ApiService/ApiService/onefuzzlib/Utils.cs @@ -1,13 +1,10 @@ -namespace Microsoft.OneFuzz.Service; +namespace Microsoft.OneFuzz.Service; -public static class ObjectExtention -{ - public static T EnsureNotNull(this T? thisObject, string message) - { - if (thisObject == null) - { +public static class ObjectExtention { + public static T EnsureNotNull(this T? thisObject, string message) { + if (thisObject == null) { throw new ArgumentNullException(message); } return thisObject; } -} \ No newline at end of file +} diff --git a/src/ApiService/ApiService/onefuzzlib/VmOperations.cs b/src/ApiService/ApiService/onefuzzlib/VmOperations.cs index 56407795714..44101b62032 100644 --- a/src/ApiService/ApiService/onefuzzlib/VmOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/VmOperations.cs @@ -1,10 +1,9 @@ -using Azure.ResourceManager.Compute; +using Azure.ResourceManager.Compute; namespace Microsoft.OneFuzz.Service; -public interface IVmOperations -{ +public interface IVmOperations { Async.Task IsDeleted(Vm vm); Async.Task HasComponents(string name); @@ -15,8 +14,7 @@ public interface IVmOperations } -public class VmOperations : IVmOperations -{ +public class VmOperations : IVmOperations { private ILogTracer _logTracer; private ICreds _creds; @@ -25,33 +23,27 @@ public class VmOperations : IVmOperations private IDiskOperations _diskOperations; - public VmOperations(ILogTracer log, ICreds creds, IIpOperations ipOperations, IDiskOperations diskOperations) - { + public VmOperations(ILogTracer log, ICreds creds, IIpOperations ipOperations, IDiskOperations diskOperations) { _logTracer = log; _creds = creds; _ipOperations = ipOperations; _diskOperations = diskOperations; } - public async Async.Task IsDeleted(Vm vm) - { + public async Async.Task IsDeleted(Vm vm) { return !(await HasComponents(vm.Name)); } - public async Async.Task HasComponents(string name) - { + public async Async.Task HasComponents(string name) { var resourceGroup = _creds.GetBaseResourceGroup(); - if (await GetVm(name) != null) - { + if (await GetVm(name) != null) { return true; } - if (await _ipOperations.GetPublicNic(resourceGroup, name) != null) - { + if (await _ipOperations.GetPublicNic(resourceGroup, name) != null) { return true; } - if (await _ipOperations.GetIp(resourceGroup, name) != null) - { + if (await _ipOperations.GetIp(resourceGroup, name) != null) { return true; } @@ -60,41 +52,34 @@ public async Async.Task HasComponents(string name) .Where(disk => disk.Data.Name.StartsWith(name)) .AnyAsync(); - if (disks) - { + if (disks) { return true; } return false; } - public async Async.Task GetVm(string name) - { + public async Async.Task GetVm(string name) { return await _creds.GetResourceGroupResource().GetVirtualMachineAsync(name); } - public async Async.Task Delete(Vm vm) - { + public async Async.Task Delete(Vm vm) { return await DeleteVmComponents(vm.Name, vm.Nsg); } - public async Async.Task DeleteVmComponents(string name, Nsg? nsg) - { + public async Async.Task DeleteVmComponents(string name, Nsg? nsg) { var resourceGroup = _creds.GetBaseResourceGroup(); _logTracer.Info($"deleting vm components {resourceGroup}:{name}"); - if (GetVm(name) != null) - { + if (GetVm(name) != null) { _logTracer.Info($"deleting vm {resourceGroup}:{name}"); DeleteVm(name); return false; } var nic = await _ipOperations.GetPublicNic(resourceGroup, name); - if (nic != null) - { + if (nic != null) { _logTracer.Info($"deleting nic {resourceGroup}:{name}"); - if (nic.Data.NetworkSecurityGroup != null && nsg != null) - { + if (nic.Data.NetworkSecurityGroup != null && nsg != null) { await nsg.DissociateNic(nic); return false; } @@ -102,8 +87,7 @@ public async Async.Task DeleteVmComponents(string name, Nsg? nsg) return false; } - if (await _ipOperations.GetIp(resourceGroup, name) != null) - { + if (await _ipOperations.GetIp(resourceGroup, name) != null) { _logTracer.Info($"deleting ip {resourceGroup}:{name}"); await _ipOperations.DeleteIp(resourceGroup, name); return false; @@ -113,10 +97,8 @@ public async Async.Task DeleteVmComponents(string name, Nsg? nsg) .ToAsyncEnumerable() .Where(disk => disk.Data.Name.StartsWith(name)); - if (await disks.AnyAsync()) - { - await foreach (var disk in disks) - { + if (await disks.AnyAsync()) { + await foreach (var disk in disks) { _logTracer.Info($"deleting disk {resourceGroup}:{disk?.Data.Name}"); await _diskOperations.DeleteDisk(resourceGroup, disk?.Data.Name!); } @@ -126,8 +108,7 @@ public async Async.Task DeleteVmComponents(string name, Nsg? nsg) return true; } - public void DeleteVm(string name) - { + public void DeleteVm(string name) { throw new NotImplementedException(); } } diff --git a/src/ApiService/ApiService/onefuzzlib/WebhookOperations.cs b/src/ApiService/ApiService/onefuzzlib/WebhookOperations.cs index 8b1abd05f43..9651cd9dca9 100644 --- a/src/ApiService/ApiService/onefuzzlib/WebhookOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/WebhookOperations.cs @@ -3,14 +3,12 @@ namespace Microsoft.OneFuzz.Service; -public interface IWebhookMessageLogOperations : IOrm -{ +public interface IWebhookMessageLogOperations : IOrm { IAsyncEnumerable SearchExpired(); } -public class WebhookMessageLogOperations : Orm, IWebhookMessageLogOperations -{ +public class WebhookMessageLogOperations : Orm, IWebhookMessageLogOperations { const int EXPIRE_DAYS = 7; record WebhookMessageQueueObj( @@ -20,46 +18,38 @@ Guid EventId private readonly IQueue _queue; private readonly ILogTracer _log; - public WebhookMessageLogOperations(IStorage storage, IQueue queue, ILogTracer log, IServiceConfig config) : base(storage, log, config) - { + public WebhookMessageLogOperations(IStorage storage, IQueue queue, ILogTracer log, IServiceConfig config) : base(storage, log, config) { _queue = queue; _log = log; } - public async Async.Task QueueWebhook(WebhookMessageLog webhookLog) - { + public async Async.Task QueueWebhook(WebhookMessageLog webhookLog) { var obj = new WebhookMessageQueueObj(webhookLog.WebhookId, webhookLog.EventId); - TimeSpan? visibilityTimeout = webhookLog.State switch - { + TimeSpan? visibilityTimeout = webhookLog.State switch { WebhookMessageState.Queued => TimeSpan.Zero, WebhookMessageState.Retrying => TimeSpan.FromSeconds(30), _ => null }; - if (visibilityTimeout == null) - { + if (visibilityTimeout == null) { _log.WithTags( new[] { ("WebhookId", webhookLog.WebhookId.ToString()), ("EventId", webhookLog.EventId.ToString()) } ). Error($"invalid WebhookMessage queue state, not queuing. {webhookLog.WebhookId}:{webhookLog.EventId} - {webhookLog.State}"); - } - else - { + } else { await _queue.QueueObject("webhooks", obj, StorageType.Config, visibilityTimeout: visibilityTimeout); } } - private void QueueObject(string v, WebhookMessageQueueObj obj, StorageType config, int? visibility_timeout) - { + private void QueueObject(string v, WebhookMessageQueueObj obj, StorageType config, int? visibility_timeout) { throw new NotImplementedException(); } - public IAsyncEnumerable SearchExpired() - { + public IAsyncEnumerable SearchExpired() { var expireTime = (DateTimeOffset.UtcNow - TimeSpan.FromDays(EXPIRE_DAYS)).ToString("o"); var timeFilter = $"Timestamp lt datetime'{expireTime}'"; @@ -68,36 +58,29 @@ public IAsyncEnumerable SearchExpired() } -public interface IWebhookOperations -{ +public interface IWebhookOperations { Async.Task SendEvent(EventMessage eventMessage); } -public class WebhookOperations : Orm, IWebhookOperations -{ +public class WebhookOperations : Orm, IWebhookOperations { private readonly IWebhookMessageLogOperations _webhookMessageLogOperations; private readonly ILogTracer _log; public WebhookOperations(IStorage storage, IWebhookMessageLogOperations webhookMessageLogOperations, ILogTracer log, IServiceConfig config) - : base(storage, log, config) - { + : base(storage, log, config) { _webhookMessageLogOperations = webhookMessageLogOperations; _log = log; } - async public Async.Task SendEvent(EventMessage eventMessage) - { - await foreach (var webhook in GetWebhooksCached()) - { - if (!webhook.EventTypes.Contains(eventMessage.EventType)) - { + async public Async.Task SendEvent(EventMessage eventMessage) { + await foreach (var webhook in GetWebhooksCached()) { + if (!webhook.EventTypes.Contains(eventMessage.EventType)) { continue; } await AddEvent(webhook, eventMessage); } } - async private Async.Task AddEvent(Webhook webhook, EventMessage eventMessage) - { + async private Async.Task AddEvent(Webhook webhook, EventMessage eventMessage) { var message = new WebhookMessageLog( EventId: eventMessage.EventId, EventType: eventMessage.EventType, @@ -108,8 +91,7 @@ async private Async.Task AddEvent(Webhook webhook, EventMessage eventMessage) ); var r = await _webhookMessageLogOperations.Replace(message); - if (!r.IsOk) - { + if (!r.IsOk) { var (status, reason) = r.ErrorV; _log.Error($"Failed to replace webhook message log due to [{status}] {reason}"); } @@ -117,8 +99,7 @@ async private Async.Task AddEvent(Webhook webhook, EventMessage eventMessage) //todo: caching - public IAsyncEnumerable GetWebhooksCached() - { + public IAsyncEnumerable GetWebhooksCached() { return QueryAsync(); } diff --git a/src/ApiService/ApiService/onefuzzlib/orm/CaseConverter.cs b/src/ApiService/ApiService/onefuzzlib/orm/CaseConverter.cs index 2cd734e254f..bba360c5868 100644 --- a/src/ApiService/ApiService/onefuzzlib/orm/CaseConverter.cs +++ b/src/ApiService/ApiService/onefuzzlib/orm/CaseConverter.cs @@ -1,39 +1,29 @@ namespace Microsoft.OneFuzz.Service.OneFuzzLib.Orm; -public class CaseConverter -{ +public class CaseConverter { /// get the start indices of each word and the lat indice - static IEnumerable getIndices(string input) - { + static IEnumerable getIndices(string input) { yield return 0; - for (var i = 1; i < input.Length; i++) - { + for (var i = 1; i < input.Length; i++) { - if (Char.IsDigit(input[i])) - { + if (Char.IsDigit(input[i])) { continue; } - if (i < input.Length - 1 && Char.IsDigit(input[i + 1])) - { + if (i < input.Length - 1 && Char.IsDigit(input[i + 1])) { continue; } // is the current letter uppercase - if (Char.IsUpper(input[i])) - { - if (input[i - 1] == '_') - { + if (Char.IsUpper(input[i])) { + if (input[i - 1] == '_') { continue; } - if (i < input.Length - 1 && !Char.IsUpper(input[i + 1])) - { + if (i < input.Length - 1 && !Char.IsUpper(input[i + 1])) { yield return i; - } - else if (!Char.IsUpper(input[i - 1])) - { + } else if (!Char.IsUpper(input[i - 1])) { yield return i; } } @@ -41,14 +31,12 @@ static IEnumerable getIndices(string input) yield return input.Length; } - public static string PascalToSnake(string input) - { + public static string PascalToSnake(string input) { var indices = getIndices(input).ToArray(); return string.Join("_", Enumerable.Zip(indices, indices.Skip(1)).Select(x => input.Substring(x.First, x.Second - x.First).ToLowerInvariant())); } - public static string SnakeToPascal(string input) - { + public static string SnakeToPascal(string input) { return string.Join("", input.Split('_', StringSplitOptions.RemoveEmptyEntries).Select(x => $"{Char.ToUpper(x[0])}{x.Substring(1)}")); } } diff --git a/src/ApiService/ApiService/onefuzzlib/orm/CustomConverterFactory.cs b/src/ApiService/ApiService/onefuzzlib/orm/CustomConverterFactory.cs index 97fb4f30a50..90505d4c656 100644 --- a/src/ApiService/ApiService/onefuzzlib/orm/CustomConverterFactory.cs +++ b/src/ApiService/ApiService/onefuzzlib/orm/CustomConverterFactory.cs @@ -7,16 +7,13 @@ namespace Microsoft.OneFuzz.Service.OneFuzzLib.Orm; -public sealed class CustomEnumConverterFactory : JsonConverterFactory -{ +public sealed class CustomEnumConverterFactory : JsonConverterFactory { public override bool CanConvert(Type typeToConvert) => typeToConvert.IsEnum; - public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) - { + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { object[]? knownValues = null; - if (typeToConvert == typeof(BindingFlags)) - { + if (typeToConvert == typeof(BindingFlags)) { knownValues = new object[] { BindingFlags.CreateInstance | BindingFlags.DeclaredOnly }; } @@ -29,8 +26,7 @@ public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializer } } -public sealed class CustomEnumConverter : JsonConverter where T : Enum -{ +public sealed class CustomEnumConverter : JsonConverter where T : Enum { private readonly JsonNamingPolicy _namingPolicy; private readonly Dictionary _readCache = new(); @@ -41,15 +37,12 @@ public sealed class CustomEnumConverter : JsonConverter where T : Enum private const string ValueSeparator = ","; - public CustomEnumConverter(JsonNamingPolicy namingPolicy, JsonSerializerOptions options, object[]? knownValues) - { + public CustomEnumConverter(JsonNamingPolicy namingPolicy, JsonSerializerOptions options, object[]? knownValues) { _namingPolicy = namingPolicy; bool continueProcessing = true; - for (int i = 0; i < knownValues?.Length; i++) - { - if (!TryProcessValue((T)knownValues[i])) - { + for (int i = 0; i < knownValues?.Length; i++) { + if (!TryProcessValue((T)knownValues[i])) { continueProcessing = false; break; } @@ -57,25 +50,20 @@ public CustomEnumConverter(JsonNamingPolicy namingPolicy, JsonSerializerOptions var type = typeof(T); var skipFormat = type.GetCustomAttribute() != null; - if (continueProcessing) - { + if (continueProcessing) { Array values = Enum.GetValues(type); - for (int i = 0; i < values.Length; i++) - { + for (int i = 0; i < values.Length; i++) { T value = (T)values.GetValue(i)!; - if (!TryProcessValue(value, skipFormat)) - { + if (!TryProcessValue(value, skipFormat)) { break; } } } - bool TryProcessValue(T value, bool skipFormat = false) - { - if (_readCache.Count == NameCacheLimit) - { + bool TryProcessValue(T value, bool skipFormat = false) { + if (_readCache.Count == NameCacheLimit) { Debug.Assert(_writeCache.Count == NameCacheLimit); return false; } @@ -85,40 +73,32 @@ bool TryProcessValue(T value, bool skipFormat = false) } } - public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { string? json; - if (reader.TokenType != JsonTokenType.String || (json = reader.GetString()) == null) - { + if (reader.TokenType != JsonTokenType.String || (json = reader.GetString()) == null) { throw new JsonException(); } var value = json.Split(ValueSeparator, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) - .Select(x => - { - if (!_readCache.TryGetValue(x, out T? value)) - { + .Select(x => { + if (!_readCache.TryGetValue(x, out T? value)) { throw new JsonException(); } return value; }).ToArray(); - if (value.Length == 1) - { + if (value.Length == 1) { return value[0]; } return (T)(object)value.Aggregate(0, (state, value) => (int)(object)state | (int)(object)value); } - public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) - { - if (!_writeCache.TryGetValue(value, out JsonEncodedText formatted)) - { - if (_writeCache.Count == NameCacheLimit) - { + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { + if (!_writeCache.TryGetValue(value, out JsonEncodedText formatted)) { + if (_writeCache.Count == NameCacheLimit) { Debug.Assert(_readCache.Count == NameCacheLimit); throw new ArgumentOutOfRangeException(); } @@ -129,29 +109,23 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions writer.WriteStringValue(formatted); } - private JsonEncodedText FormatAndAddToCaches(T value, JavaScriptEncoder? encoder, bool skipFormat = false) - { + private JsonEncodedText FormatAndAddToCaches(T value, JavaScriptEncoder? encoder, bool skipFormat = false) { (string valueFormattedToStr, JsonEncodedText valueEncoded) = FormatEnumValue(value.ToString(), _namingPolicy, encoder, skipFormat); _readCache[valueFormattedToStr] = value; _writeCache[value] = valueEncoded; return valueEncoded; } - private ValueTuple FormatEnumValue(string value, JsonNamingPolicy namingPolicy, JavaScriptEncoder? encoder, bool skipFormat = false) - { + private ValueTuple FormatEnumValue(string value, JsonNamingPolicy namingPolicy, JavaScriptEncoder? encoder, bool skipFormat = false) { string converted; - if (!value.Contains(ValueSeparator)) - { + if (!value.Contains(ValueSeparator)) { converted = skipFormat ? value : namingPolicy.ConvertName(value); - } - else - { + } else { // todo: optimize implementation here by leveraging https://github.com/dotnet/runtime/issues/934. string[] enumValues = value.Split(ValueSeparator); - for (int i = 0; i < enumValues.Length; i++) - { + for (int i = 0; i < enumValues.Length; i++) { var trimmed = enumValues[i].Trim(); enumValues[i] = skipFormat ? trimmed : namingPolicy.ConvertName(trimmed); } @@ -164,13 +138,10 @@ private ValueTuple FormatEnumValue(string value, JsonNa } -public sealed class PolymorphicConverterFactory : JsonConverterFactory -{ - public override bool CanConvert(Type typeToConvert) - { +public sealed class PolymorphicConverterFactory : JsonConverterFactory { + public override bool CanConvert(Type typeToConvert) { var converter = typeToConvert.GetCustomAttribute(); - if (converter != null) - { + if (converter != null) { return false; } @@ -180,24 +151,18 @@ public override bool CanConvert(Type typeToConvert) .Where(p => p.attribute != null) .ToList(); - if (propertyAndAttributes.Count == 0) - { + if (propertyAndAttributes.Count == 0) { return false; } - if (propertyAndAttributes.Count == 1) - { + if (propertyAndAttributes.Count == 1) { return true; - } - - else - { + } else { throw new InvalidOperationException("the attribute TypeDiscrimnatorAttribute can only be aplied once"); } } - public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) - { + public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) { var (field, attribute) = typeToConvert.GetProperties() .Select(p => (p.Name, p.GetCustomAttribute())) .Where(p => p.Item2 != null) @@ -213,8 +178,7 @@ public override bool CanConvert(Type typeToConvert) } } -public sealed class PolymorphicConverter : JsonConverter -{ +public sealed class PolymorphicConverter : JsonConverter { private readonly ITypeProvider _typeProvider; private readonly string _discriminatorField; private readonly string _discriminatedField; @@ -227,8 +191,7 @@ public sealed class PolymorphicConverter : JsonConverter - public PolymorphicConverter(TypeDiscrimnatorAttribute typeDiscriminator, string discriminatedField) : base() - { + public PolymorphicConverter(TypeDiscrimnatorAttribute typeDiscriminator, string discriminatedField) : base() { _discriminatorField = typeDiscriminator.FieldName; _typeProvider = (ITypeProvider)(typeDiscriminator.ConverterType.GetConstructor(new Type[] { })?.Invoke(null) ?? throw new JsonException()); _discriminatedField = discriminatedField; @@ -245,33 +208,27 @@ public PolymorphicConverter(TypeDiscrimnatorAttribute typeDiscriminator, string .ToDictionary(x => x.Item1, x => x.Item2!) ?? new Dictionary(); } - private string ConvertName(string name, JsonSerializerOptions options) - { + private string ConvertName(string name, JsonSerializerOptions options) { - if (_renamedViaJsonPropery.TryGetValue(name, out var renamed)) - { + if (_renamedViaJsonPropery.TryGetValue(name, out var renamed)) { return renamed; } return options.PropertyNamingPolicy?.ConvertName(name) ?? name; } - public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType != JsonTokenType.StartObject) - { + public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { + if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(); } - using (var jsonDocument = JsonDocument.ParseValue(ref reader)) - { + using (var jsonDocument = JsonDocument.ParseValue(ref reader)) { var discriminatorName = ConvertName(_discriminatorField, options); var discriminatorValue = jsonDocument.RootElement.GetProperty(discriminatorName).GetRawText(); var discriminatorTypedValue = JsonSerializer.Deserialize(discriminatorValue, _discriminatorType, options) ?? throw new JsonException("unable to read deserialize discriminator value"); var discriminatedType = _typeProvider.GetTypeInfo(discriminatorTypedValue); var constructorParams = - _constructorInfo.GetParameters().Select(p => - { + _constructorInfo.GetParameters().Select(p => { var parameterName = p.Name ?? throw new JsonException(); var parameterType = parameterName == _discriminatedField ? discriminatedType : p.ParameterType; var fName = ConvertName(parameterName, options); @@ -283,15 +240,12 @@ private string ConvertName(string name, JsonSerializerOptions options) } } - public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) - { + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { var newOptions = - _options.GetValue(options, k => - { + _options.GetValue(options, k => { var newOptions = new JsonSerializerOptions(k); var thisConverter = newOptions.Converters.FirstOrDefault(c => c.GetType() == typeof(PolymorphicConverterFactory)); - if (thisConverter != null) - { + if (thisConverter != null) { newOptions.Converters.Remove(thisConverter); } @@ -300,4 +254,4 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions JsonSerializer.Serialize(writer, value, newOptions); } -} \ No newline at end of file +} diff --git a/src/ApiService/ApiService/onefuzzlib/orm/EntityConverter.cs b/src/ApiService/ApiService/onefuzzlib/orm/EntityConverter.cs index 63391aa6d63..4e16d8dd166 100644 --- a/src/ApiService/ApiService/onefuzzlib/orm/EntityConverter.cs +++ b/src/ApiService/ApiService/onefuzzlib/orm/EntityConverter.cs @@ -1,15 +1,14 @@ -using Azure.Data.Tables; -using System.Reflection; +using System.Collections.Concurrent; using System.Linq.Expressions; +using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; -using System.Collections.Concurrent; using Azure; +using Azure.Data.Tables; namespace Microsoft.OneFuzz.Service.OneFuzzLib.Orm; -public abstract record EntityBase -{ +public abstract record EntityBase { [JsonIgnore] public ETag? ETag { get; set; } public DateTimeOffset? TimeStamp { get; set; } } @@ -21,16 +20,13 @@ public abstract record StatefulEntityBase([property: JsonIgnore] T State) : E public class SkipRename : Attribute { } public class RowKeyAttribute : Attribute { } public class PartitionKeyAttribute : Attribute { } -public class TypeDiscrimnatorAttribute : Attribute -{ +public class TypeDiscrimnatorAttribute : Attribute { public string FieldName { get; } // the type of a function that takes the value of fieldName as an input and return the type public Type ConverterType { get; } - public TypeDiscrimnatorAttribute(string fieldName, Type converterType) - { - if (!converterType.IsAssignableTo(typeof(ITypeProvider))) - { + public TypeDiscrimnatorAttribute(string fieldName, Type converterType) { + if (!converterType.IsAssignableTo(typeof(ITypeProvider))) { throw new ArgumentException($"the provided type needs to implement ITypeProvider"); } @@ -39,13 +35,11 @@ public TypeDiscrimnatorAttribute(string fieldName, Type converterType) } } -public interface ITypeProvider -{ +public interface ITypeProvider { Type GetTypeInfo(object input); } -public enum EntityPropertyKind -{ +public enum EntityPropertyKind { PartitionKey, RowKey, Column @@ -53,32 +47,26 @@ public enum EntityPropertyKind public record EntityProperty(string name, string columnName, Type type, EntityPropertyKind kind, (TypeDiscrimnatorAttribute, ITypeProvider)? discriminator); public record EntityInfo(Type type, Dictionary properties, Func constructor); -class OnefuzzNamingPolicy : JsonNamingPolicy -{ - public override string ConvertName(string name) - { +class OnefuzzNamingPolicy : JsonNamingPolicy { + public override string ConvertName(string name) { return CaseConverter.PascalToSnake(name); } } -public class EntityConverter -{ +public class EntityConverter { private readonly JsonSerializerOptions _options; private readonly ConcurrentDictionary _cache; private readonly ETag _emptyETag = new ETag(); - public EntityConverter() - { + public EntityConverter() { _options = GetJsonSerializerOptions(); _cache = new ConcurrentDictionary(); } - public static JsonSerializerOptions GetJsonSerializerOptions() - { - var options = new JsonSerializerOptions() - { + public static JsonSerializerOptions GetJsonSerializerOptions() { + var options = new JsonSerializerOptions() { PropertyNamingPolicy = new OnefuzzNamingPolicy(), }; options.Converters.Add(new CustomEnumConverterFactory()); @@ -86,13 +74,11 @@ public static JsonSerializerOptions GetJsonSerializerOptions() return options; } - internal static Func BuildConstructerFrom(ConstructorInfo constructorInfo) - { + internal static Func BuildConstructerFrom(ConstructorInfo constructorInfo) { var constructorParameters = Expression.Parameter(typeof(object?[])); var parameterExpressions = - constructorInfo.GetParameters().Select((parameterInfo, i) => - { + constructorInfo.GetParameters().Select((parameterInfo, i) => { var ithIndex = Expression.Constant(i); var ithParameter = Expression.ArrayIndex(constructorParameters, ithIndex); var unboxedIthParameter = Expression.Convert(ithParameter, parameterInfo.ParameterType); @@ -106,15 +92,12 @@ public static JsonSerializerOptions GetJsonSerializerOptions() return ctor; } - private EntityInfo GetEntityInfo() - { - return _cache.GetOrAdd(typeof(T), type => - { + private EntityInfo GetEntityInfo() { + return _cache.GetOrAdd(typeof(T), type => { var constructor = type.GetConstructors()[0]; var parameterInfos = constructor.GetParameters(); var parameters = - parameterInfos.Select(f => - { + parameterInfos.Select(f => { var name = f.Name.EnsureNotNull($"Invalid paramter {f}"); var parameterType = f.ParameterType.EnsureNotNull($"Invalid paramter {f}"); var isRowkey = f.GetCustomAttribute(typeof(RowKeyAttribute)) != null; @@ -135,8 +118,7 @@ private EntityInfo GetEntityInfo() var discriminatorAttribute = type.GetProperty(name)?.GetCustomAttribute(); (TypeDiscrimnatorAttribute, ITypeProvider)? discriminator = null; - if (discriminatorAttribute != null) - { + if (discriminatorAttribute != null) { var t = (ITypeProvider)(discriminatorAttribute.ConverterType.GetConstructor(new Type[] { })?.Invoke(null) ?? throw new Exception("unable to retrive the type provider")); discriminator = (discriminatorAttribute, t); } @@ -147,73 +129,58 @@ private EntityInfo GetEntityInfo() }); } - public string ToJsonString(T typedEntity) - { + public string ToJsonString(T typedEntity) { var serialized = JsonSerializer.Serialize(typedEntity, _options); return serialized; } - public TableEntity ToTableEntity(T typedEntity) where T : EntityBase - { - if (typedEntity == null) - { + public TableEntity ToTableEntity(T typedEntity) where T : EntityBase { + if (typedEntity == null) { throw new NullReferenceException(); } var type = typeof(T)!; - if (type is null) - { + if (type is null) { throw new NullReferenceException(); } var tableEntity = new TableEntity(); var entityInfo = GetEntityInfo(); - foreach (var kvp in entityInfo.properties) - { + foreach (var kvp in entityInfo.properties) { var prop = kvp.Value; var value = entityInfo.type.GetProperty(prop.name)?.GetValue(typedEntity); - if (prop.kind == EntityPropertyKind.PartitionKey || prop.kind == EntityPropertyKind.RowKey) - { + if (prop.kind == EntityPropertyKind.PartitionKey || prop.kind == EntityPropertyKind.RowKey) { tableEntity.Add(prop.columnName, value?.ToString()); - } - else if (prop.type == typeof(Guid) || prop.type == typeof(Guid?)) - { + } else if (prop.type == typeof(Guid) || prop.type == typeof(Guid?)) { tableEntity.Add(prop.columnName, value?.ToString()); - } - else if (prop.type == typeof(bool) - || prop.type == typeof(bool?) - || prop.type == typeof(string) - || prop.type == typeof(DateTime) - || prop.type == typeof(DateTime?) - || prop.type == typeof(DateTimeOffset) - || prop.type == typeof(DateTimeOffset?) - || prop.type == typeof(int) - || prop.type == typeof(int?) - || prop.type == typeof(Int64) - || prop.type == typeof(Int64?) - || prop.type == typeof(double) - || prop.type == typeof(double?) - - ) - { + } else if (prop.type == typeof(bool) + || prop.type == typeof(bool?) + || prop.type == typeof(string) + || prop.type == typeof(DateTime) + || prop.type == typeof(DateTime?) + || prop.type == typeof(DateTimeOffset) + || prop.type == typeof(DateTimeOffset?) + || prop.type == typeof(int) + || prop.type == typeof(int?) + || prop.type == typeof(Int64) + || prop.type == typeof(Int64?) + || prop.type == typeof(double) + || prop.type == typeof(double?) + + ) { tableEntity.Add(prop.columnName, value); - } - else if (prop.type.IsEnum) - { + } else if (prop.type.IsEnum) { var values = (value?.ToString()?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) .Select(CaseConverter.PascalToSnake)).EnsureNotNull($"Unable to read enum data {value}"); tableEntity.Add(prop.columnName, string.Join(",", values)); - } - else - { + } else { var serialized = JsonSerializer.Serialize(value, _options); tableEntity.Add(prop.columnName, serialized.Trim('"')); } } - if (typedEntity.ETag.HasValue) - { + if (typedEntity.ETag.HasValue) { tableEntity.ETag = typedEntity.ETag.Value; } @@ -221,96 +188,66 @@ public TableEntity ToTableEntity(T typedEntity) where T : EntityBase } - private object? GetFieldValue(EntityInfo info, string name, TableEntity entity) - { + private object? GetFieldValue(EntityInfo info, string name, TableEntity entity) { var ef = info.properties[name]; - if (ef.kind == EntityPropertyKind.PartitionKey || ef.kind == EntityPropertyKind.RowKey) - { + if (ef.kind == EntityPropertyKind.PartitionKey || ef.kind == EntityPropertyKind.RowKey) { if (ef.type == typeof(string)) return entity.GetString(ef.kind.ToString()); else if (ef.type == typeof(Guid)) return Guid.Parse(entity.GetString(ef.kind.ToString())); else if (ef.type == typeof(int)) return int.Parse(entity.GetString(ef.kind.ToString())); - else - { + else { throw new Exception("invalid "); } } var fieldName = ef.columnName; var obj = entity[fieldName]; - if (obj == null) - { + if (obj == null) { return null; } var objType = obj.GetType(); - if (ef.type == typeof(string)) - { + if (ef.type == typeof(string)) { return entity.GetString(fieldName); - } - else if (ef.type == typeof(bool) || ef.type == typeof(bool?)) - { + } else if (ef.type == typeof(bool) || ef.type == typeof(bool?)) { return entity.GetBoolean(fieldName); - } - else if (ef.type == typeof(DateTimeOffset) || ef.type == typeof(DateTimeOffset?)) - { + } else if (ef.type == typeof(DateTimeOffset) || ef.type == typeof(DateTimeOffset?)) { return entity.GetDateTimeOffset(fieldName); - } - else if (ef.type == typeof(DateTime) || ef.type == typeof(DateTime?)) - { + } else if (ef.type == typeof(DateTime) || ef.type == typeof(DateTime?)) { return entity.GetDateTime(fieldName); - } - else if (ef.type == typeof(double) || ef.type == typeof(double?)) - { + } else if (ef.type == typeof(double) || ef.type == typeof(double?)) { return entity.GetDouble(fieldName); - } - else if (ef.type == typeof(Guid) || ef.type == typeof(Guid?)) - { + } else if (ef.type == typeof(Guid) || ef.type == typeof(Guid?)) { return (object?)Guid.Parse(entity.GetString(fieldName)); - } - else if (ef.type == typeof(int) || ef.type == typeof(short) || ef.type == typeof(int?) || ef.type == typeof(short?)) - { + } else if (ef.type == typeof(int) || ef.type == typeof(short) || ef.type == typeof(int?) || ef.type == typeof(short?)) { return entity.GetInt32(fieldName); - } - else if (ef.type == typeof(long) || ef.type == typeof(long?)) - { + } else if (ef.type == typeof(long) || ef.type == typeof(long?)) { return entity.GetInt64(fieldName); - } - else if (ef.type.IsEnum) - { + } else if (ef.type.IsEnum) { var stringValues = entity.GetString(fieldName).Split(",", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) .Select(CaseConverter.SnakeToPascal); return Enum.Parse(ef.type, string.Join(",", stringValues)); - } - else - { + } else { var outputType = ef.type; - if (ef.discriminator != null) - { + if (ef.discriminator != null) { var (attr, typeProvider) = ef.discriminator.Value; var v = GetFieldValue(info, attr.FieldName, entity) ?? throw new Exception($"No value for {attr.FieldName}"); outputType = typeProvider.GetTypeInfo(v); } - if (objType == typeof(string)) - { + if (objType == typeof(string)) { var value = entity.GetString(fieldName); - if (value.StartsWith('[') || value.StartsWith('{') || value == "null") - { + if (value.StartsWith('[') || value.StartsWith('{') || value == "null") { return JsonSerializer.Deserialize(value, outputType, options: _options); - } - else - { + } else { return JsonSerializer.Deserialize($"\"{value}\"", outputType, options: _options); } - } - else - { + } else { var value = entity.GetString(fieldName); return JsonSerializer.Deserialize(value, outputType, options: _options); } @@ -318,16 +255,14 @@ public TableEntity ToTableEntity(T typedEntity) where T : EntityBase } - public T ToRecord(TableEntity entity) where T : EntityBase - { + public T ToRecord(TableEntity entity) where T : EntityBase { var entityInfo = GetEntityInfo(); var parameters = entityInfo.properties.Keys.Select(k => GetFieldValue(entityInfo, k, entity)).ToArray(); var entityRecord = (T)entityInfo.constructor.Invoke(parameters); - if (entity.ETag != _emptyETag) - { + if (entity.ETag != _emptyETag) { entityRecord.ETag = entity.ETag; } entityRecord.TimeStamp = entity.Timestamp; diff --git a/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs b/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs index 51b0f4f7ff7..3377dee69bf 100644 --- a/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs +++ b/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs @@ -1,14 +1,12 @@ -using Azure.Data.Tables; -using Microsoft.OneFuzz.Service; -using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; +using System.Collections.Concurrent; using System.Reflection; using System.Threading.Tasks; -using System.Collections.Concurrent; +using Azure.Data.Tables; +using Microsoft.OneFuzz.Service; +using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; -namespace ApiService.OneFuzzLib.Orm -{ - public interface IOrm where T : EntityBase - { +namespace ApiService.OneFuzzLib.Orm { + public interface IOrm where T : EntityBase { Task GetTableClient(string table, string? accountId = null); IAsyncEnumerable QueryAsync(string? filter = null); Task> Replace(T entity); @@ -20,8 +18,7 @@ public interface IOrm where T : EntityBase } - public class Orm : IOrm where T : EntityBase - { + public class Orm : IOrm where T : EntityBase { protected readonly IStorage _storage; protected readonly EntityConverter _entityConverter; protected readonly ILogTracer _logTracer; @@ -29,87 +26,67 @@ public class Orm : IOrm where T : EntityBase protected readonly IServiceConfig _config; - public Orm(IStorage storage, ILogTracer logTracer, IServiceConfig config) - { + public Orm(IStorage storage, ILogTracer logTracer, IServiceConfig config) { _storage = storage; _entityConverter = new EntityConverter(); _logTracer = logTracer; _config = config; } - public async IAsyncEnumerable QueryAsync(string? filter = null) - { + public async IAsyncEnumerable QueryAsync(string? filter = null) { var tableClient = await GetTableClient(typeof(T).Name); - await foreach (var x in tableClient.QueryAsync(filter).Select(x => _entityConverter.ToRecord(x))) - { + await foreach (var x in tableClient.QueryAsync(filter).Select(x => _entityConverter.ToRecord(x))) { yield return x; } } - public async Task> Insert(T entity) - { + public async Task> Insert(T entity) { var tableClient = await GetTableClient(typeof(T).Name); var tableEntity = _entityConverter.ToTableEntity(entity); var response = await tableClient.AddEntityAsync(tableEntity); - if (response.IsError) - { + if (response.IsError) { return ResultVoid<(int, string)>.Error((response.Status, response.ReasonPhrase)); - } - else - { + } else { return ResultVoid<(int, string)>.Ok(); } } - public async Task> Replace(T entity) - { + public async Task> Replace(T entity) { var tableClient = await GetTableClient(typeof(T).Name); var tableEntity = _entityConverter.ToTableEntity(entity); var response = await tableClient.UpsertEntityAsync(tableEntity); - if (response.IsError) - { + if (response.IsError) { return ResultVoid<(int, string)>.Error((response.Status, response.ReasonPhrase)); - } - else - { + } else { return ResultVoid<(int, string)>.Ok(); } } - public async Task> Update(T entity) - { + public async Task> Update(T entity) { var tableClient = await GetTableClient(typeof(T).Name); var tableEntity = _entityConverter.ToTableEntity(entity); - if (entity.ETag is null) - { + if (entity.ETag is null) { return ResultVoid<(int, string)>.Error((0, "ETag must be set when updating an entity")); - } - else - { + } else { var response = await tableClient.UpdateEntityAsync(tableEntity, entity.ETag.Value); - if (response.IsError) - { + if (response.IsError) { return ResultVoid<(int, string)>.Error((response.Status, response.ReasonPhrase)); - } - else - { + } else { return ResultVoid<(int, string)>.Ok(); } } } - public async Task GetEntityAsync(string partitionKey, string rowKey) - { + public async Task GetEntityAsync(string partitionKey, string rowKey) { var tableClient = await GetTableClient(typeof(T).Name); var tableEntity = await tableClient.GetEntityAsync(partitionKey, rowKey); return _entityConverter.ToRecord(tableEntity); } - public async Task GetTableClient(string table, string? accountId = null) - { + public async Task GetTableClient(string table, string? accountId = null) { var account = accountId ?? _config.OneFuzzFuncStorage ?? throw new ArgumentNullException(nameof(accountId)); var (name, key) = _storage.GetStorageAccountNameAndKey(account); var tableClient = new TableServiceClient(new Uri($"https://{name}.table.core.windows.net"), new TableSharedKeyCredential(name, key)); @@ -117,57 +94,47 @@ public async Task GetTableClient(string table, string? accountId = return tableClient.GetTableClient(table); } - public async Task> Delete(T entity) - { + public async Task> Delete(T entity) { var tableClient = await GetTableClient(typeof(T).Name); var tableEntity = _entityConverter.ToTableEntity(entity); var response = await tableClient.DeleteEntityAsync(tableEntity.PartitionKey, tableEntity.RowKey); - if (response.IsError) - { + if (response.IsError) { return ResultVoid<(int, string)>.Error((response.Status, response.ReasonPhrase)); - } - else - { + } else { return ResultVoid<(int, string)>.Ok(); } } } - public interface IStatefulOrm : IOrm where T : StatefulEntityBase where TState : Enum - { + public interface IStatefulOrm : IOrm where T : StatefulEntityBase where TState : Enum { System.Threading.Tasks.Task ProcessStateUpdate(T entity); System.Threading.Tasks.Task ProcessStateUpdates(T entity, int MaxUpdates = 5); } - public class StatefulOrm : Orm, IStatefulOrm where T : StatefulEntityBase where TState : Enum - { + public class StatefulOrm : Orm, IStatefulOrm where T : StatefulEntityBase where TState : Enum { static Lazy>? _partitionKeyGetter; static Lazy>? _rowKeyGetter; static ConcurrentDictionary>?> _stateFuncs = new ConcurrentDictionary>?>(); - static StatefulOrm() - { + static StatefulOrm() { _partitionKeyGetter = - typeof(T).GetProperties().FirstOrDefault(p => p.GetCustomAttributes(true).OfType().Any())?.GetMethod switch - { + typeof(T).GetProperties().FirstOrDefault(p => p.GetCustomAttributes(true).OfType().Any())?.GetMethod switch { null => null, MethodInfo info => new Lazy>(() => (Func)Delegate.CreateDelegate(typeof(Func), info), true) }; _rowKeyGetter = - typeof(T).GetProperties().FirstOrDefault(p => p.GetCustomAttributes(true).OfType().Any())?.GetMethod switch - { + typeof(T).GetProperties().FirstOrDefault(p => p.GetCustomAttributes(true).OfType().Any())?.GetMethod switch { null => null, MethodInfo info => new Lazy>(() => (Func)Delegate.CreateDelegate(typeof(Func), info), true) }; } - public StatefulOrm(IStorage storage, ILogTracer logTracer, IServiceConfig config) : base(storage, logTracer, config) - { + public StatefulOrm(IStorage storage, ILogTracer logTracer, IServiceConfig config) : base(storage, logTracer, config) { } /// @@ -176,18 +143,15 @@ public StatefulOrm(IStorage storage, ILogTracer logTracer, IServiceConfig config /// /// /// - public async System.Threading.Tasks.Task ProcessStateUpdate(T entity) - { + public async System.Threading.Tasks.Task ProcessStateUpdate(T entity) { TState state = entity.State; var func = _stateFuncs.GetOrAdd(state.ToString(), (string k) => - typeof(T).GetMethod(k) switch - { + typeof(T).GetMethod(k) switch { null => null, MethodInfo info => (Func>)Delegate.CreateDelegate(typeof(Func>), info) }); - if (func != null) - { + if (func != null) { _logTracer.Info($"processing state update: {typeof(T)} - PartitionKey {_partitionKeyGetter?.Value() } {_rowKeyGetter?.Value() } - %s"); return await func(entity); } @@ -201,18 +165,15 @@ public StatefulOrm(IStorage storage, ILogTracer logTracer, IServiceConfig config /// /// /// - public async System.Threading.Tasks.Task ProcessStateUpdates(T entity, int MaxUpdates = 5) - { - for (int i = 0; i < MaxUpdates; i++) - { + public async System.Threading.Tasks.Task ProcessStateUpdates(T entity, int MaxUpdates = 5) { + for (int i = 0; i < MaxUpdates; i++) { var state = entity.State; var newEntity = await ProcessStateUpdate(entity); if (newEntity == null) return null; - if (newEntity.State.Equals(state)) - { + if (newEntity.State.Equals(state)) { return newEntity; } } diff --git a/src/ApiService/Tests/OrmModelsTest.cs b/src/ApiService/Tests/OrmModelsTest.cs index fbbab5beccf..cb9b57f331b 100644 --- a/src/ApiService/Tests/OrmModelsTest.cs +++ b/src/ApiService/Tests/OrmModelsTest.cs @@ -1,21 +1,18 @@ -using FsCheck; -using FsCheck.Xunit; -using Xunit.Abstractions; -using Microsoft.OneFuzz.Service; -using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; +using System; using System.Collections.Generic; -using System; using System.Linq; using System.Security; using System.Text.Json; +using FsCheck; +using FsCheck.Xunit; +using Microsoft.OneFuzz.Service; +using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; +using Xunit.Abstractions; -namespace Tests -{ +namespace Tests { - public class OrmGenerators - { - public static Gen BaseEvent() - { + public class OrmGenerators { + public static Gen BaseEvent() { return Gen.OneOf(new[] { Arb.Generate().Select(e => e as BaseEvent), Arb.Generate().Select(e => e as BaseEvent), @@ -30,15 +27,13 @@ public static Gen BaseEvent() }); } - public static Gen Uri() - { + public static Gen Uri() { return Arb.Generate().Select( arg => new Uri($"https://{arg.Item.ToString()}:8080") ); } - public static Gen WebhookMessageLog() - { + public static Gen WebhookMessageLog() { return Arb.Generate, Tuple>>().Select( arg => new WebhookMessageLog( EventId: arg.Item1.Item1, @@ -52,8 +47,7 @@ public static Gen WebhookMessageLog() )); } - public static Gen Node() - { + public static Gen Node() { return Arb.Generate, Tuple>>().Select( arg => new Node( InitializedAt: arg.Item1.Item1, @@ -69,8 +63,7 @@ public static Gen Node() DebugKeepNode: arg.Item2.Item6)); } - public static Gen ProxyForward() - { + public static Gen ProxyForward() { return Arb.Generate, Tuple>>().Select( arg => new ProxyForward( @@ -86,8 +79,7 @@ public static Gen ProxyForward() ); } - public static Gen Proxy() - { + public static Gen Proxy() { return Arb.Generate, Tuple>>().Select( arg => new Proxy( @@ -105,8 +97,7 @@ public static Gen Proxy() ); } - public static Gen EventMessage() - { + public static Gen EventMessage() { return Arb.Generate>().Select( arg => new EventMessage( @@ -119,8 +110,7 @@ public static Gen EventMessage() ); } - public static Gen NetworkConfig() - { + public static Gen NetworkConfig() { return Arb.Generate>().Select( arg => new NetworkConfig( @@ -130,8 +120,7 @@ public static Gen NetworkConfig() ); } - public static Gen NetworkSecurityGroupConfig() - { + public static Gen NetworkSecurityGroupConfig() { return Arb.Generate>().Select( arg => new NetworkSecurityGroupConfig( @@ -141,8 +130,7 @@ public static Gen NetworkSecurityGroupConfig() ); } - public static Gen InstanceConfig() - { + public static Gen InstanceConfig() { return Arb.Generate, Tuple?, IDictionary?, IDictionary?, IDictionary?>>>().Select( @@ -165,8 +153,7 @@ public static Gen InstanceConfig() ); } - public static Gen Task() - { + public static Gen Task() { return Arb.Generate, Tuple>>().Select( @@ -186,8 +173,7 @@ public static Gen Task() ) ); } - public static Gen Scaleset() - { + public static Gen Scaleset() { return Arb.Generate, Tuple, Guid?, Guid?>, @@ -216,8 +202,7 @@ public static Gen Scaleset() } - public static Gen Webhook() - { + public static Gen Webhook() { return Arb.Generate, string, WebhookMessageFormat>>().Select( arg => new Webhook( @@ -231,8 +216,7 @@ public static Gen Webhook() ); } - public static Gen WebhookMessage() - { + public static Gen WebhookMessage() { return Arb.Generate>().Select( arg => new WebhookMessage( @@ -246,8 +230,7 @@ public static Gen WebhookMessage() ); ; } - public static Gen WebhookMessageEventGrid() - { + public static Gen WebhookMessageEventGrid() { return Arb.Generate>().Select( arg => new WebhookMessageEventGrid( @@ -264,8 +247,7 @@ public static Gen WebhookMessageEventGrid() - public static Gen Report() - { + public static Gen Report() { return Arb.Generate, Guid, int>>().Select( arg => new Report( @@ -292,16 +274,14 @@ public static Gen Report() ); } - public static Gen Container() - { + public static Gen Container() { return Arb.Generate>>().Select( arg => new Container(string.Join("", arg.Item1.Get.Where(c => char.IsLetterOrDigit(c) || c == '-'))!) ); } - public static Gen Notification() - { + public static Gen Notification() { return Arb.Generate>().Select( arg => new Notification( Container: arg.Item1, @@ -311,8 +291,7 @@ public static Gen Notification() ); } - public static Gen Job() - { + public static Gen Job() { return Arb.Generate?, UserInfo>>().Select( arg => new Job( JobId: arg.Item1, @@ -327,106 +306,85 @@ public static Gen Job() } } - public class OrmArb - { - public static Arbitrary Uri() - { + public class OrmArb { + public static Arbitrary Uri() { return Arb.From(OrmGenerators.Uri()); } - public static Arbitrary BaseEvent() - { + public static Arbitrary BaseEvent() { return Arb.From(OrmGenerators.BaseEvent()); } - public static Arbitrary Node() - { + public static Arbitrary Node() { return Arb.From(OrmGenerators.Node()); } - public static Arbitrary ProxyForward() - { + public static Arbitrary ProxyForward() { return Arb.From(OrmGenerators.ProxyForward()); } - public static Arbitrary Proxy() - { + public static Arbitrary Proxy() { return Arb.From(OrmGenerators.Proxy()); } - public static Arbitrary EventMessage() - { + public static Arbitrary EventMessage() { return Arb.From(OrmGenerators.EventMessage()); } - public static Arbitrary NetworkConfig() - { + public static Arbitrary NetworkConfig() { return Arb.From(OrmGenerators.NetworkConfig()); } - public static Arbitrary NetworkSecurityConfig() - { + public static Arbitrary NetworkSecurityConfig() { return Arb.From(OrmGenerators.NetworkSecurityGroupConfig()); } - public static Arbitrary InstanceConfig() - { + public static Arbitrary InstanceConfig() { return Arb.From(OrmGenerators.InstanceConfig()); } - public static Arbitrary WebhookMessageLog() - { + public static Arbitrary WebhookMessageLog() { return Arb.From(OrmGenerators.WebhookMessageLog()); } - public static Arbitrary Task() - { + public static Arbitrary Task() { return Arb.From(OrmGenerators.Task()); } - public static Arbitrary Scaleset() - { + public static Arbitrary Scaleset() { return Arb.From(OrmGenerators.Scaleset()); } - public static Arbitrary Webhook() - { + public static Arbitrary Webhook() { return Arb.From(OrmGenerators.Webhook()); } - public static Arbitrary WebhookMessage() - { + public static Arbitrary WebhookMessage() { return Arb.From(OrmGenerators.WebhookMessage()); } - public static Arbitrary Report() - { + public static Arbitrary Report() { return Arb.From(OrmGenerators.Report()); } - public static Arbitrary Container() - { + public static Arbitrary Container() { return Arb.From(OrmGenerators.Container()); } - public static Arbitrary Notification() - { + public static Arbitrary Notification() { return Arb.From(OrmGenerators.Notification()); } - public static Arbitrary WebhookMessageEventGrid() - { + public static Arbitrary WebhookMessageEventGrid() { return Arb.From(OrmGenerators.WebhookMessageEventGrid()); } - public static Arbitrary Job() - { + public static Arbitrary Job() { return Arb.From(OrmGenerators.Job()); } } - public static class EqualityComparison - { + public static class EqualityComparison { private static HashSet _baseTypes = new HashSet( new[]{ typeof(byte), @@ -445,26 +403,20 @@ public static class EqualityComparison typeof(DateTimeOffset?), typeof(SecureString) }); - static bool IEnumerableEqual(IEnumerable? a, IEnumerable? b) - { - if (a is null && b is null) - { + static bool IEnumerableEqual(IEnumerable? a, IEnumerable? b) { + if (a is null && b is null) { return true; } - if (a!.Count() != b!.Count()) - { + if (a!.Count() != b!.Count()) { return false; } - if (a!.Count() == 0 && b!.Count() == 0) - { + if (a!.Count() == 0 && b!.Count() == 0) { return true; } - foreach (var v in a!.Zip(b!)) - { - if (!AreEqual(v.First, v.Second)) - { + foreach (var v in a!.Zip(b!)) { + if (!AreEqual(v.First, v.Second)) { return false; } } @@ -472,8 +424,7 @@ static bool IEnumerableEqual(IEnumerable? a, IEnumerable? b) return true; } - static bool IDictionaryEqual(IDictionary? a, IDictionary? b, Func cmp) - { + static bool IDictionaryEqual(IDictionary? a, IDictionary? b, Func cmp) { if (a is null && b is null) return true; @@ -486,8 +437,7 @@ static bool IDictionaryEqual(IDictionary? a, IDictio return a!.Any(v => cmp(v.Value, b[v.Key])); } - static bool IDictionaryEqual(IDictionary? a, IDictionary? b) - { + static bool IDictionaryEqual(IDictionary? a, IDictionary? b) { if (a is null && b is null) return true; @@ -501,8 +451,7 @@ static bool IDictionaryEqual(IDictionary? a, IDictio } - public static bool AreEqual(T r1, T r2) - { + public static bool AreEqual(T r1, T r2) { var t = typeof(T); if (r1 is null && r2 is null) @@ -511,8 +460,7 @@ public static bool AreEqual(T r1, T r2) if (_baseTypes.Contains(t)) return r1!.Equals(r2); - foreach (var p in t.GetProperties()) - { + foreach (var p in t.GetProperties()) { var v1 = p.GetValue(r1); var v2 = p.GetValue(r2); var tt = p.PropertyType; @@ -526,14 +474,12 @@ public static bool AreEqual(T r1, T r2) if (_baseTypes.Contains(tt) && !v1!.Equals(v2)) return false; - if (tt.GetInterface("IEnumerable") is not null) - { + if (tt.GetInterface("IEnumerable") is not null) { if (!IEnumerableEqual(v1 as IEnumerable, v2 as IEnumerable)) return false; } - if (tt.GetInterface("IDictionary") is not null) - { + if (tt.GetInterface("IDictionary") is not null) { if (!IDictionaryEqual(v1 as IDictionary, v2 as IDictionary)) return false; } @@ -542,19 +488,16 @@ public static bool AreEqual(T r1, T r2) } } - public class OrmModelsTest - { + public class OrmModelsTest { EntityConverter _converter = new EntityConverter(); ITestOutputHelper _output; - public OrmModelsTest(ITestOutputHelper output) - { + public OrmModelsTest(ITestOutputHelper output) { Arb.Register(); _output = output; } - bool Test(T e) where T : EntityBase - { + bool Test(T e) where T : EntityBase { var v = _converter.ToTableEntity(e); var r = _converter.ToRecord(v); return EqualityComparison.AreEqual(e, r); @@ -562,64 +505,54 @@ bool Test(T e) where T : EntityBase } [Property] - public bool Node(Node node) - { + public bool Node(Node node) { return Test(node); } [Property] - public bool ProxyForward(ProxyForward proxyForward) - { + public bool ProxyForward(ProxyForward proxyForward) { return Test(proxyForward); } [Property] - public bool Proxy(Proxy proxy) - { + public bool Proxy(Proxy proxy) { return Test(proxy); } [Property] - public bool Task(Task task) - { + public bool Task(Task task) { return Test(task); } [Property] - public bool InstanceConfig(InstanceConfig cfg) - { + public bool InstanceConfig(InstanceConfig cfg) { return Test(cfg); } [Property] - public bool Scaleset(Scaleset ss) - { + public bool Scaleset(Scaleset ss) { return Test(ss); } [Property] - public bool WebhookMessageLog(WebhookMessageLog log) - { + public bool WebhookMessageLog(WebhookMessageLog log) { return Test(log); } [Property] - public bool Webhook(Webhook wh) - { + public bool Webhook(Webhook wh) { return Test(wh); } [Property] - public bool Notification(Notification n) - { + public bool Notification(Notification n) { return Test(n); } [Property] - public bool Job(Job j) - { + public bool Job(Job j) { return Test(j); } @@ -637,244 +570,205 @@ void Replay() } - public class OrmJsonSerialization - { + public class OrmJsonSerialization { JsonSerializerOptions _opts = EntityConverter.GetJsonSerializerOptions(); ITestOutputHelper _output; - public OrmJsonSerialization(ITestOutputHelper output) - { + public OrmJsonSerialization(ITestOutputHelper output) { Arb.Register(); _output = output; } - string serialize(T x) - { + string serialize(T x) { return JsonSerializer.Serialize(x, _opts); } - T? deserialize(string json) - { + T? deserialize(string json) { return JsonSerializer.Deserialize(json, _opts); } - bool Test(T v) - { + bool Test(T v) { var j = serialize(v); var r = deserialize(j); return EqualityComparison.AreEqual(v, r); } [Property] - public bool Node(Node node) - { + public bool Node(Node node) { return Test(node); } [Property] - public bool ProxyForward(ProxyForward proxyForward) - { + public bool ProxyForward(ProxyForward proxyForward) { return Test(proxyForward); } [Property] - public bool Proxy(Proxy proxy) - { + public bool Proxy(Proxy proxy) { return Test(proxy); } [Property] - public bool Task(Task task) - { + public bool Task(Task task) { return Test(task); } [Property] - public bool InstanceConfig(InstanceConfig cfg) - { + public bool InstanceConfig(InstanceConfig cfg) { return Test(cfg); } [Property] - public bool Scaleset(Scaleset ss) - { + public bool Scaleset(Scaleset ss) { return Test(ss); } [Property] - public bool WebhookMessageLog(WebhookMessageLog log) - { + public bool WebhookMessageLog(WebhookMessageLog log) { return Test(log); } [Property] - public bool Webhook(Webhook wh) - { + public bool Webhook(Webhook wh) { return Test(wh); } [Property] - public bool WebhookMessageEventGrid(WebhookMessageEventGrid evt) - { + public bool WebhookMessageEventGrid(WebhookMessageEventGrid evt) { return Test(evt); } [Property] - public bool WebhookMessage(WebhookMessage msg) - { + public bool WebhookMessage(WebhookMessage msg) { return Test(msg); } [Property] - public bool TaskHeartbeatEntry(TaskHeartbeatEntry e) - { + public bool TaskHeartbeatEntry(TaskHeartbeatEntry e) { return Test(e); } [Property] - public bool NodeCommand(NodeCommand e) - { + public bool NodeCommand(NodeCommand e) { return Test(e); } [Property] - public bool NodeTasks(NodeTasks e) - { + public bool NodeTasks(NodeTasks e) { return Test(e); } [Property] - public bool ProxyHeartbeat(ProxyHeartbeat e) - { + public bool ProxyHeartbeat(ProxyHeartbeat e) { return Test(e); } [Property] - public bool ProxyConfig(ProxyConfig e) - { + public bool ProxyConfig(ProxyConfig e) { return Test(e); } [Property] - public bool TaskDetails(TaskDetails e) - { + public bool TaskDetails(TaskDetails e) { return Test(e); } [Property] - public bool TaskVm(TaskVm e) - { + public bool TaskVm(TaskVm e) { return Test(e); } [Property] - public bool TaskPool(TaskPool e) - { + public bool TaskPool(TaskPool e) { return Test(e); } [Property] - public bool TaskContainers(TaskContainers e) - { + public bool TaskContainers(TaskContainers e) { return Test(e); } [Property] - public bool TaskConfig(TaskConfig e) - { + public bool TaskConfig(TaskConfig e) { return Test(e); } [Property] - public bool TaskEventSummary(TaskEventSummary e) - { + public bool TaskEventSummary(TaskEventSummary e) { return Test(e); } [Property] - public bool NodeAssignment(NodeAssignment e) - { + public bool NodeAssignment(NodeAssignment e) { return Test(e); } [Property] - public bool KeyvaultExtensionConfig(KeyvaultExtensionConfig e) - { + public bool KeyvaultExtensionConfig(KeyvaultExtensionConfig e) { return Test(e); } [Property] - public bool AzureMonitorExtensionConfig(AzureMonitorExtensionConfig e) - { + public bool AzureMonitorExtensionConfig(AzureMonitorExtensionConfig e) { return Test(e); } [Property] - public bool AzureVmExtensionConfig(AzureVmExtensionConfig e) - { + public bool AzureVmExtensionConfig(AzureVmExtensionConfig e) { return Test(e); } [Property] - public bool NetworkConfig(NetworkConfig e) - { + public bool NetworkConfig(NetworkConfig e) { return Test(e); } [Property] - public bool NetworkSecurityGroupConfig(NetworkSecurityGroupConfig e) - { + public bool NetworkSecurityGroupConfig(NetworkSecurityGroupConfig e) { return Test(e); } [Property] - public bool Report(Report e) - { + public bool Report(Report e) { return Test(e); } [Property] - public bool Notification(Notification e) - { + public bool Notification(Notification e) { return Test(e); } [Property] - public bool NoReproReport(NoReproReport e) - { + public bool NoReproReport(NoReproReport e) { return Test(e); } [Property] - public bool CrashTestResult(CrashTestResult e) - { + public bool CrashTestResult(CrashTestResult e) { return Test(e); } [Property] - public bool NotificationTemplate(NotificationTemplate e) - { + public bool NotificationTemplate(NotificationTemplate e) { return Test(e); } [Property] - public bool RegressionReportOrReport(RegressionReportOrReport e) - { + public bool RegressionReportOrReport(RegressionReportOrReport e) { return Test(e); } [Property] - public bool Job(Job e) - { + public bool Job(Job e) { return Test(e); } diff --git a/src/ApiService/Tests/OrmTest.cs b/src/ApiService/Tests/OrmTest.cs index 97ba10f2626..bd042e608a8 100644 --- a/src/ApiService/Tests/OrmTest.cs +++ b/src/ApiService/Tests/OrmTest.cs @@ -1,33 +1,28 @@ using System; -using Xunit; -using Azure.Data.Tables; +using System.Text.Json; using System.Text.Json.Nodes; using System.Text.Json.Serialization; -using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; +using Azure.Data.Tables; using Microsoft.OneFuzz.Service; -using System.Text.Json; +using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; +using Xunit; -namespace Tests -{ - public class OrmTest - { +namespace Tests { + public class OrmTest { - class TestObject - { + class TestObject { public String? TheName { get; set; } public TestEnum TheEnum { get; set; } public TestFlagEnum TheFlag { get; set; } } - enum TestEnum - { + enum TestEnum { TheOne, TheTwo, } [Flags] - enum TestFlagEnum - { + enum TestFlagEnum { FlagOne = 1, FlagTwo = 2, } @@ -51,8 +46,7 @@ record Entity1( [Fact] - public void TestBothDirections() - { + public void TestBothDirections() { var uriString = "https://localhost:9090"; var converter = new EntityConverter(); var entity1 = new Entity1( @@ -63,8 +57,7 @@ public void TestBothDirections() 12.44, TestEnum.TheTwo, TestFlagEnum.FlagOne | TestFlagEnum.FlagTwo, "renamed", - new TestObject - { + new TestObject { TheName = "testobject", TheEnum = TestEnum.TheTwo, TheFlag = TestFlagEnum.FlagOne | TestFlagEnum.FlagTwo @@ -101,8 +94,7 @@ public void TestBothDirections() [Fact] - public void TestConvertToTableEntity() - { + public void TestConvertToTableEntity() { var uriString = "https://localhost:9090"; var converter = new EntityConverter(); var entity1 = new Entity1( @@ -113,8 +105,7 @@ public void TestConvertToTableEntity() 12.44, TestEnum.TheTwo, TestFlagEnum.FlagOne | TestFlagEnum.FlagTwo, "renamed", - new TestObject - { + new TestObject { TheName = "testobject", TheEnum = TestEnum.TheTwo, TheFlag = TestFlagEnum.FlagOne | TestFlagEnum.FlagTwo @@ -151,8 +142,7 @@ public void TestConvertToTableEntity() } [Fact] - public void TestFromtableEntity() - { + public void TestFromtableEntity() { var converter = new EntityConverter(); var tableEntity = new TableEntity(Guid.NewGuid().ToString(), "test") { {"the_date", DateTimeOffset.UtcNow }, @@ -185,8 +175,7 @@ public void TestFromtableEntity() } [Fact] - public void TestConvertPascalToSnakeCase() - { + public void TestConvertPascalToSnakeCase() { var testCases = new[] { ("simpleTest", "simple_test"), ("easy", "easy"), @@ -203,16 +192,14 @@ public void TestConvertPascalToSnakeCase() ("ALLCAPS", "allcaps"), }; - foreach (var (input, expected) in testCases) - { + foreach (var (input, expected) in testCases) { var actual = CaseConverter.PascalToSnake(input); Assert.Equal(expected, actual); } } [Fact] - public void TestConvertSnakeToPAscalCase() - { + public void TestConvertSnakeToPAscalCase() { var testCases = new[] { ("simple_test" , "SimpleTest"), ("easy" , "Easy"), @@ -226,8 +213,7 @@ public void TestConvertSnakeToPAscalCase() ("the_two" , "TheTwo") }; - foreach (var (input, expected) in testCases) - { + foreach (var (input, expected) in testCases) { var actual = CaseConverter.SnakeToPascal(input); Assert.Equal(expected, actual); } @@ -236,8 +222,7 @@ public void TestConvertSnakeToPAscalCase() [Fact] - public void TestEventSerialization() - { + public void TestEventSerialization() { var expectedEvent = new EventMessage(Guid.NewGuid(), EventType.NodeHeartbeat, new EventNodeHeartbeat(Guid.NewGuid(), Guid.NewGuid(), "test Poool"), Guid.NewGuid(), "test"); var serialized = JsonSerializer.Serialize(expectedEvent, EntityConverter.GetJsonSerializerOptions()); var actualEvent = JsonSerializer.Deserialize(serialized, EntityConverter.GetJsonSerializerOptions()); @@ -251,8 +236,7 @@ [RowKey] string TheName ) : EntityBase(); [Fact] - public void TestIntKey() - { + public void TestIntKey() { var expected = new Entity2(10, "test"); var converter = new EntityConverter(); var tableEntity = converter.ToTableEntity(expected); @@ -264,12 +248,10 @@ public void TestIntKey() [Fact] - public void TestEventSerialization2() - { + public void TestEventSerialization2() { var converter = new EntityConverter(); - var expectedEvent = new EventMessage(Guid.NewGuid(), EventType.NodeHeartbeat, new EventNodeHeartbeat(Guid.NewGuid(), Guid.NewGuid(), "test Poool"), Guid.NewGuid(), "test") - { + var expectedEvent = new EventMessage(Guid.NewGuid(), EventType.NodeHeartbeat, new EventNodeHeartbeat(Guid.NewGuid(), Guid.NewGuid(), "test Poool"), Guid.NewGuid(), "test") { ETag = new Azure.ETag("33a64df551425fcc55e4d42a148795d9f25f89d4") }; var te = converter.ToTableEntity(expectedEvent); @@ -284,8 +266,7 @@ Container Container ) : EntityBase(); [Fact] - public void TestContainerSerialization() - { + public void TestContainerSerialization() { var container = new Container("abc-123"); var expected = new Entity3(123, "abc", container); var converter = new EntityConverter(); @@ -298,8 +279,7 @@ public void TestContainerSerialization() } [Fact] - public void TestContainerSerialization2() - { + public void TestContainerSerialization2() { var entityJson = @"{ ""Id"": 123,