mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-11 01:31:38 +00:00
Refactor notification support (#2363)
* Add teams notifications * . * Fix compilation isues * Checkpoint * Added Ado * Fix some TODOs * Teams messages work! 🎉 * fmt * Bug fix container url generator * Some small ado changes * 🧹 * PR comments * Fix packages * Get more detailed restore information to debug errors * Maybe fixes this issue? * Undo CI change
This commit is contained in:
parent
f375ee719e
commit
ca7b6be43b
@ -1,16 +1,16 @@
|
|||||||
# Azure Devops Work Item creation
|
# Azure Devops Work Item creation
|
||||||
|
|
||||||
Automatic creation of ADO Work Items from OneFuzz allows for the user to
|
Automatic creation of ADO Work Items from OneFuzz allows for the user to
|
||||||
customize any field using [jinja2](https://jinja.palletsprojects.com/)
|
customize any field using [scriban](https://github.com/scriban/scriban)
|
||||||
templates.
|
templates.
|
||||||
|
|
||||||
There are multiple Python objects provided via the template engine that
|
There are multiple objects provided via the template engine that
|
||||||
can be used such that any arbitrary component can be used to flesh out
|
can be used such that any arbitrary component can be used to flesh out
|
||||||
the configuration:
|
the configuration:
|
||||||
|
|
||||||
* task (See [TaskConfig](../../src/pytypes/onefuzztypes/models.py))
|
* task (See [TaskConfig](../../src/ApiService/ApiService/OneFuzzTypes/Model.cs))
|
||||||
* report (See [Report](../../src/pytypes/onefuzztypes/models.py))
|
* report (See [Report](../../src/ApiService/ApiService/OneFuzzTypes/Model.cs))
|
||||||
* job (See [JobConfig](../../src/pytypes/onefuzztypes/models.py))
|
* job (See [JobConfig](../../src/ApiService/ApiService/OneFuzzTypes/Model.cs))
|
||||||
|
|
||||||
Using these objects allows dynamic configuration. As an example, the `project`
|
Using these objects allows dynamic configuration. As an example, the `project`
|
||||||
could be specified directly, or dynamically pulled from a template:
|
could be specified directly, or dynamically pulled from a template:
|
||||||
@ -49,7 +49,7 @@ clickable, make it a link.
|
|||||||
"Microsoft.VSTS.Scheduling.StoryPoints": "1",
|
"Microsoft.VSTS.Scheduling.StoryPoints": "1",
|
||||||
"System.IterationPath": "Iteration\\Path\\Here",
|
"System.IterationPath": "Iteration\\Path\\Here",
|
||||||
"System.Title": "{{ report.crash_site }} - {{ report.executable }}",
|
"System.Title": "{{ report.crash_site }} - {{ report.executable }}",
|
||||||
"Microsoft.VSTS.TCM.ReproSteps": "This is my call stack: <ul> {% for item in report.call_stack %} <li> {{ item }} </li> {% endfor %} </ul>"
|
"Microsoft.VSTS.TCM.ReproSteps": "This is my call stack: <ul> {{ for item in report.call_stack }} <li> {{ item }} </li> {{ endfor }} </ul>"
|
||||||
},
|
},
|
||||||
"comment": "This is my comment. {{ report.input_sha256 }} {{ input_url }} <br> <pre>{{ repro_cmd }}</pre>",
|
"comment": "This is my comment. {{ report.input_sha256 }} {{ input_url }} <br> <pre>{{ repro_cmd }}</pre>",
|
||||||
"unique_fields": ["System.Title", "System.AreaPath"],
|
"unique_fields": ["System.Title", "System.AreaPath"],
|
||||||
@ -140,7 +140,7 @@ onefuzz notifications create_ado oft-my-demo-job-reports \
|
|||||||
Microsoft.VSTS.Scheduling.StoryPoints=1 \
|
Microsoft.VSTS.Scheduling.StoryPoints=1 \
|
||||||
"System.IterationPath=Iteration\\Path\\Here" \
|
"System.IterationPath=Iteration\\Path\\Here" \
|
||||||
"System.Title={{ report.crash_site }} - {{ report.executable }}" \
|
"System.Title={{ report.crash_site }} - {{ report.executable }}" \
|
||||||
"Microsoft.VSTS.TCM.ReproSteps=This is my call stack: <ul> {% for item in report.call_stack %} <li> {{ item }} </li> {% endfor %} </ul>" \
|
"Microsoft.VSTS.TCM.ReproSteps=This is my call stack: <ul> {{ for item in report.call_stack }} <li> {{ item }} </li> {{ end }} </ul>" \
|
||||||
--comment "This is my comment. {{ report.input_sha256 }} {{ input_url }}" \
|
--comment "This is my comment. {{ report.input_sha256 }} {{ input_url }}" \
|
||||||
--on_dup_comment "Another <a href='{{ input_url }}'>POC</a> was found in <a href='{{ target_url }}'>target</a>" \
|
--on_dup_comment "Another <a href='{{ input_url }}'>POC</a> was found in <a href='{{ target_url }}'>target</a>" \
|
||||||
--on_dup_set_state Resolved=Active \
|
--on_dup_set_state Resolved=Active \
|
||||||
|
@ -42,6 +42,8 @@
|
|||||||
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.SignalRService" Version="1.7.0" />
|
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.SignalRService" Version="1.7.0" />
|
||||||
<PackageReference Include="TaskTupleAwaiter" Version="2.0.0" />
|
<PackageReference Include="TaskTupleAwaiter" Version="2.0.0" />
|
||||||
<PackageReference Include="Scriban" Version="5.5.0" />
|
<PackageReference Include="Scriban" Version="5.5.0" />
|
||||||
|
<PackageReference Include="Octokit" Version="2.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.209.0-preview" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="host.json">
|
<None Update="host.json">
|
||||||
|
@ -22,9 +22,9 @@ public class QueueFileChanges {
|
|||||||
_notificationOperations = notificationOperations;
|
_notificationOperations = notificationOperations;
|
||||||
}
|
}
|
||||||
|
|
||||||
//[Function("QueueFileChanges")]
|
[Function("QueueFileChanges")]
|
||||||
public async Async.Task Run(
|
public async Async.Task Run(
|
||||||
[QueueTrigger("file-changes-refactored", Connection = "AzureWebJobsStorage")] string msg,
|
[QueueTrigger("file-changes", Connection = "AzureWebJobsStorage")] string msg,
|
||||||
int dequeueCount) {
|
int dequeueCount) {
|
||||||
var fileChangeEvent = JsonSerializer.Deserialize<JsonDocument>(msg, EntityConverter.GetJsonSerializerOptions());
|
var fileChangeEvent = JsonSerializer.Deserialize<JsonDocument>(msg, EntityConverter.GetJsonSerializerOptions());
|
||||||
var lastTry = dequeueCount == MAX_DEQUEUE_COUNT;
|
var lastTry = dequeueCount == MAX_DEQUEUE_COUNT;
|
||||||
@ -44,10 +44,10 @@ public class QueueFileChanges {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await file_added(_log, fileChangeEvent, lastTry);
|
await FileAdded(_log, fileChangeEvent, lastTry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Async.Task file_added(ILogTracer log, JsonDocument fileChangeEvent, bool failTaskOnTransientError) {
|
private async Async.Task FileAdded(ILogTracer log, JsonDocument fileChangeEvent, bool failTaskOnTransientError) {
|
||||||
var data = fileChangeEvent.RootElement.GetProperty("data");
|
var data = fileChangeEvent.RootElement.GetProperty("data");
|
||||||
var url = data.GetProperty("url").GetString()!;
|
var url = data.GetProperty("url").GetString()!;
|
||||||
var parts = url.Split("/").Skip(3).ToList();
|
var parts = url.Split("/").Skip(3).ToList();
|
||||||
|
@ -84,7 +84,11 @@ public record ProxyHeartbeat
|
|||||||
Guid ProxyId,
|
Guid ProxyId,
|
||||||
List<Forward> Forwards,
|
List<Forward> Forwards,
|
||||||
DateTimeOffset TimeStamp
|
DateTimeOffset TimeStamp
|
||||||
);
|
) {
|
||||||
|
public override string ToString() {
|
||||||
|
return JsonSerializer.Serialize(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public record Node
|
public record Node
|
||||||
(
|
(
|
||||||
@ -412,7 +416,7 @@ public record Notification(
|
|||||||
|
|
||||||
public record BlobRef(
|
public record BlobRef(
|
||||||
string Account,
|
string Account,
|
||||||
Container container,
|
Container Container,
|
||||||
string Name
|
string Name
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -470,21 +474,43 @@ public class NotificationTemplateConverter : JsonConverter<NotificationTemplate>
|
|||||||
public override NotificationTemplate? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
|
public override NotificationTemplate? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
|
||||||
using var templateJson = JsonDocument.ParseValue(ref reader);
|
using var templateJson = JsonDocument.ParseValue(ref reader);
|
||||||
try {
|
try {
|
||||||
return templateJson.Deserialize<AdoTemplate>(options);
|
return ValidateDeserialization(templateJson.Deserialize<AdoTemplate>(options));
|
||||||
} catch (JsonException) {
|
} catch (Exception ex) when (
|
||||||
|
ex is JsonException
|
||||||
|
|| ex is ArgumentNullException
|
||||||
|
|| ex is ArgumentOutOfRangeException
|
||||||
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return templateJson.Deserialize<TeamsTemplate>(options);
|
return ValidateDeserialization(templateJson.Deserialize<TeamsTemplate>(options));
|
||||||
} catch (JsonException) {
|
} catch (Exception ex) when (
|
||||||
|
ex is JsonException
|
||||||
|
|| ex is ArgumentNullException
|
||||||
|
|| ex is ArgumentOutOfRangeException
|
||||||
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return templateJson.Deserialize<GithubIssuesTemplate>(options);
|
return ValidateDeserialization(templateJson.Deserialize<GithubIssuesTemplate>(options));
|
||||||
} catch (JsonException) {
|
} catch (Exception ex) when (
|
||||||
|
ex is JsonException
|
||||||
|
|| ex is ArgumentNullException
|
||||||
|
|| ex is ArgumentOutOfRangeException
|
||||||
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
throw new JsonException("Unsupported notification template");
|
|
||||||
|
var expectedTemplateTypes = new List<Type> {
|
||||||
|
typeof(AdoTemplate),
|
||||||
|
typeof(TeamsTemplate),
|
||||||
|
typeof(GithubIssuesTemplate)
|
||||||
|
}
|
||||||
|
.Select(type => type.ToString());
|
||||||
|
|
||||||
|
throw new JsonException($"Unsupported notification template. Could not deserialize {templateJson} into one of the following template types: {string.Join(", ", expectedTemplateTypes)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write(Utf8JsonWriter writer, NotificationTemplate value, JsonSerializerOptions options) {
|
public override void Write(Utf8JsonWriter writer, NotificationTemplate value, JsonSerializerOptions options) {
|
||||||
@ -499,14 +525,38 @@ public class NotificationTemplateConverter : JsonConverter<NotificationTemplate>
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static T ValidateDeserialization<T>(T? obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
throw new ArgumentNullException($"Failed to deserialize type: {typeof(T)}. It was null.");
|
||||||
|
}
|
||||||
|
var nonNullableParameters = obj.GetType().GetConstructors().First().GetParameters()
|
||||||
|
.Where(parameter => !parameter.HasDefaultValue)
|
||||||
|
.Select(parameter => parameter.Name)
|
||||||
|
.Where(pName => pName != null)
|
||||||
|
.ToHashSet();
|
||||||
|
|
||||||
|
var nullProperties = obj.GetType().GetProperties()
|
||||||
|
.Where(property => property.GetValue(obj) == null)
|
||||||
|
.Select(property => property.Name)
|
||||||
|
.ToHashSet<Endpoint>();
|
||||||
|
|
||||||
|
var nullNonNullableProperties = nonNullableParameters.Intersect(nullProperties);
|
||||||
|
|
||||||
|
if (nullNonNullableProperties.Any()) {
|
||||||
|
throw new ArgumentOutOfRangeException($"Failed to deserialize type: {obj.GetType()}. The following non nullable properties are missing values: {string.Join(", ", nullNonNullableProperties)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public record ADODuplicateTemplate(
|
public record ADODuplicateTemplate(
|
||||||
List<string> Increment,
|
List<string> Increment,
|
||||||
string? Comment,
|
|
||||||
Dictionary<string, string> SetState,
|
Dictionary<string, string> SetState,
|
||||||
Dictionary<string, string> AdoFields
|
Dictionary<string, string> AdoFields,
|
||||||
|
string? Comment = null
|
||||||
);
|
);
|
||||||
|
|
||||||
public record AdoTemplate(
|
public record AdoTemplate(
|
||||||
@ -515,27 +565,26 @@ public record AdoTemplate(
|
|||||||
string Project,
|
string Project,
|
||||||
string Type,
|
string Type,
|
||||||
List<string> UniqueFields,
|
List<string> UniqueFields,
|
||||||
string? Comment,
|
|
||||||
Dictionary<string, string> AdoFields,
|
Dictionary<string, string> AdoFields,
|
||||||
ADODuplicateTemplate OnDuplicate
|
ADODuplicateTemplate OnDuplicate,
|
||||||
|
string? Comment = null
|
||||||
) : NotificationTemplate;
|
) : NotificationTemplate;
|
||||||
|
|
||||||
public record TeamsTemplate(SecretData<string> Url) : NotificationTemplate;
|
public record TeamsTemplate(SecretData<string> Url) : NotificationTemplate;
|
||||||
|
|
||||||
|
|
||||||
public record GithubAuth(string User, string PersonalAccessToken);
|
public record GithubAuth(string User, string PersonalAccessToken);
|
||||||
|
|
||||||
public record GithubIssueSearch(
|
public record GithubIssueSearch(
|
||||||
string? Author,
|
|
||||||
GithubIssueState? State,
|
|
||||||
List<GithubIssueSearchMatch> FieldMatch,
|
List<GithubIssueSearchMatch> FieldMatch,
|
||||||
[property: JsonPropertyName("string")] String str
|
[property: JsonPropertyName("string")] String str,
|
||||||
|
string? Author = null,
|
||||||
|
GithubIssueState? State = null
|
||||||
);
|
);
|
||||||
|
|
||||||
public record GithubIssueDuplicate(
|
public record GithubIssueDuplicate(
|
||||||
string? Comment,
|
|
||||||
List<string> Labels,
|
List<string> Labels,
|
||||||
bool Reopen
|
bool Reopen,
|
||||||
|
string? Comment = null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,6 +102,9 @@ public class Program {
|
|||||||
.AddScoped<INodeMessageOperations, NodeMessageOperations>()
|
.AddScoped<INodeMessageOperations, NodeMessageOperations>()
|
||||||
.AddScoped<IRequestHandling, RequestHandling>()
|
.AddScoped<IRequestHandling, RequestHandling>()
|
||||||
.AddScoped<IImageOperations, ImageOperations>()
|
.AddScoped<IImageOperations, ImageOperations>()
|
||||||
|
.AddScoped<ITeams, Teams>()
|
||||||
|
.AddScoped<IGithubIssues, GithubIssues>()
|
||||||
|
.AddScoped<IAdo, Ado>()
|
||||||
.AddScoped<IOnefuzzContext, OnefuzzContext>()
|
.AddScoped<IOnefuzzContext, OnefuzzContext>()
|
||||||
.AddScoped<IEndpointAuthorization, EndpointAuthorization>()
|
.AddScoped<IEndpointAuthorization, EndpointAuthorization>()
|
||||||
.AddScoped<INodeMessageOperations, NodeMessageOperations>()
|
.AddScoped<INodeMessageOperations, NodeMessageOperations>()
|
||||||
|
@ -29,6 +29,8 @@ public interface IContainers {
|
|||||||
|
|
||||||
public Async.Task<Uri> AddContainerSasUrl(Uri uri, TimeSpan? duration = null);
|
public Async.Task<Uri> AddContainerSasUrl(Uri uri, TimeSpan? duration = null);
|
||||||
public Async.Task<Dictionary<Container, IDictionary<string, string>>> GetContainers(StorageType corpus);
|
public Async.Task<Dictionary<Container, IDictionary<string, string>>> GetContainers(StorageType corpus);
|
||||||
|
|
||||||
|
public string AuthDownloadUrl(Container container, string filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Containers : IContainers {
|
public class Containers : IContainers {
|
||||||
@ -215,4 +217,14 @@ public class Containers : IContainers {
|
|||||||
|
|
||||||
return new(data.SelectMany(x => x));
|
return new(data.SelectMany(x => x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string AuthDownloadUrl(Container container, string filename) {
|
||||||
|
var instance = _config.OneFuzzInstance;
|
||||||
|
|
||||||
|
var queryString = System.Web.HttpUtility.ParseQueryString(string.Empty);
|
||||||
|
queryString.Add("container", container.String);
|
||||||
|
queryString.Add("filename", filename);
|
||||||
|
|
||||||
|
return $"{instance}/api/download?{queryString}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,7 +395,7 @@ public class Extensions : IExtensions {
|
|||||||
BlobSasPermissions.Read
|
BlobSasPermissions.Read
|
||||||
),
|
),
|
||||||
await _context.Containers.GetFileSasUrl(
|
await _context.Containers.GetFileSasUrl(
|
||||||
report?.InputBlob?.container!,
|
report?.InputBlob?.Container!,
|
||||||
report?.InputBlob?.Name!,
|
report?.InputBlob?.Name!,
|
||||||
StorageType.Corpus,
|
StorageType.Corpus,
|
||||||
BlobSasPermissions.Read
|
BlobSasPermissions.Read
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using ApiService.OneFuzzLib.Orm;
|
using ApiService.OneFuzzLib.Orm;
|
||||||
using Azure.Data.Tables;
|
|
||||||
using Azure.Storage.Sas;
|
using Azure.Storage.Sas;
|
||||||
|
|
||||||
namespace Microsoft.OneFuzz.Service;
|
namespace Microsoft.OneFuzz.Service;
|
||||||
@ -36,7 +35,7 @@ public class NotificationOperations : Orm<Notification>, INotificationOperations
|
|||||||
done.Add(notification.Config);
|
done.Add(notification.Config);
|
||||||
|
|
||||||
if (notification.Config is TeamsTemplate teamsTemplate) {
|
if (notification.Config is TeamsTemplate teamsTemplate) {
|
||||||
NotifyTeams(teamsTemplate, container, filename, reportOrRegression!);
|
await _context.Teams.NotifyTeams(teamsTemplate, container, filename, reportOrRegression!);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reportOrRegression == null) {
|
if (reportOrRegression == null) {
|
||||||
@ -44,11 +43,11 @@ public class NotificationOperations : Orm<Notification>, INotificationOperations
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (notification.Config is AdoTemplate adoTemplate) {
|
if (notification.Config is AdoTemplate adoTemplate) {
|
||||||
NotifyAdo(adoTemplate, container, filename, reportOrRegression, failTaskOnTransientError);
|
await _context.Ado.NotifyAdo(adoTemplate, container, filename, reportOrRegression, failTaskOnTransientError);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notification.Config is GithubIssuesTemplate githubIssuesTemplate) {
|
if (notification.Config is GithubIssuesTemplate githubIssuesTemplate) {
|
||||||
GithubIssue(githubIssuesTemplate, container, filename, reportOrRegression);
|
await _context.GithubIssues.GithubIssue(githubIssuesTemplate, container, filename, reportOrRegression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +77,7 @@ public class NotificationOperations : Orm<Notification>, INotificationOperations
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IAsyncEnumerable<Notification> GetNotifications(Container container) {
|
public IAsyncEnumerable<Notification> GetNotifications(Container container) {
|
||||||
return QueryAsync(filter: TableClient.CreateQueryFilter($"container eq {container.String}"));
|
return SearchByRowKeys(new[] { container.String });
|
||||||
}
|
}
|
||||||
|
|
||||||
public IAsyncEnumerable<(Task, IEnumerable<Container>)> GetQueueTasks() {
|
public IAsyncEnumerable<(Task, IEnumerable<Container>)> GetQueueTasks() {
|
||||||
@ -140,16 +139,4 @@ public class NotificationOperations : Orm<Notification>, INotificationOperations
|
|||||||
_logTracer.Error($"unable to find crash_report or no repro entry for report: {JsonSerializer.Serialize(report)}");
|
_logTracer.Error($"unable to find crash_report or no repro entry for report: {JsonSerializer.Serialize(report)}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GithubIssue(GithubIssuesTemplate config, Container container, string filename, IReport report) {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NotifyAdo(AdoTemplate config, Container container, string filename, IReport report, bool failTaskOnTransientError) {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NotifyTeams(TeamsTemplate config, Container container, string filename, IReport report) {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,9 @@ public interface IOnefuzzContext {
|
|||||||
ISubnet Subnet { get; }
|
ISubnet Subnet { get; }
|
||||||
IImageOperations ImageOperations { get; }
|
IImageOperations ImageOperations { get; }
|
||||||
EntityConverter EntityConverter { get; }
|
EntityConverter EntityConverter { get; }
|
||||||
|
ITeams Teams { get; }
|
||||||
|
IGithubIssues GithubIssues { get; }
|
||||||
|
IAdo Ado { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OnefuzzContext : IOnefuzzContext {
|
public class OnefuzzContext : IOnefuzzContext {
|
||||||
@ -89,4 +92,7 @@ public class OnefuzzContext : IOnefuzzContext {
|
|||||||
public ISubnet Subnet => _serviceProvider.GetRequiredService<ISubnet>();
|
public ISubnet Subnet => _serviceProvider.GetRequiredService<ISubnet>();
|
||||||
public IImageOperations ImageOperations => _serviceProvider.GetRequiredService<IImageOperations>();
|
public IImageOperations ImageOperations => _serviceProvider.GetRequiredService<IImageOperations>();
|
||||||
public EntityConverter EntityConverter => _serviceProvider.GetRequiredService<EntityConverter>();
|
public EntityConverter EntityConverter => _serviceProvider.GetRequiredService<EntityConverter>();
|
||||||
|
public ITeams Teams => _serviceProvider.GetRequiredService<ITeams>();
|
||||||
|
public IGithubIssues GithubIssues => _serviceProvider.GetRequiredService<IGithubIssues>();
|
||||||
|
public IAdo Ado => _serviceProvider.GetRequiredService<IAdo>();
|
||||||
}
|
}
|
||||||
|
@ -59,18 +59,6 @@ public class Reports : IReports {
|
|||||||
}
|
}
|
||||||
return regressionReport;
|
return regressionReport;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IReport? ParseReportOrRegression(IEnumerable<byte> 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) {
|
|
||||||
_log.Error($"unable to parse report ({filePath}): unicode decode of report failed - {e.Message} {e.StackTrace}");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IReport { };
|
public interface IReport { };
|
||||||
|
@ -248,7 +248,7 @@ public class Scheduler : IScheduler {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static Container GetSetupContainer(TaskConfig config) {
|
public static Container GetSetupContainer(TaskConfig config) {
|
||||||
|
|
||||||
foreach (var container in config.Containers ?? throw new Exception("Missing containers")) {
|
foreach (var container in config.Containers ?? throw new Exception("Missing containers")) {
|
||||||
if (container.Type == ContainerType.Setup) {
|
if (container.Type == ContainerType.Setup) {
|
||||||
|
283
src/ApiService/ApiService/onefuzzlib/notifications/Ado.cs
Normal file
283
src/ApiService/ApiService/onefuzzlib/notifications/Ado.cs
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
|
||||||
|
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
|
||||||
|
using Microsoft.VisualStudio.Services.Common;
|
||||||
|
using Microsoft.VisualStudio.Services.WebApi.Patch.Json;
|
||||||
|
|
||||||
|
namespace Microsoft.OneFuzz.Service;
|
||||||
|
|
||||||
|
public interface IAdo {
|
||||||
|
public Async.Task NotifyAdo(AdoTemplate config, Container container, string filename, IReport reportable, bool failTaskOnTransientError);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Ado : NotificationsBase, IAdo {
|
||||||
|
public Ado(ILogTracer logTracer, IOnefuzzContext context) : base(logTracer, context) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Async.Task NotifyAdo(AdoTemplate config, Container container, string filename, IReport reportable, bool failTaskOnTransientError) {
|
||||||
|
if (reportable is RegressionReport) {
|
||||||
|
_logTracer.Info($"ado integration does not support regression report. container:{container} filename:{filename}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var report = (Report)reportable;
|
||||||
|
|
||||||
|
var notificationInfo = @$"job_id:{report.JobId} task_id:{report.TaskId}
|
||||||
|
container:{container} filename:{filename}";
|
||||||
|
|
||||||
|
_logTracer.Info($"notify ado: {notificationInfo}");
|
||||||
|
|
||||||
|
try {
|
||||||
|
var ado = await AdoConnector.AdoConnectorCreator(_context, container, filename, config, report, _logTracer);
|
||||||
|
await ado.Process(notificationInfo);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/*
|
||||||
|
TODO: Catch these
|
||||||
|
AzureDevOpsAuthenticationError,
|
||||||
|
AzureDevOpsClientError,
|
||||||
|
AzureDevOpsServiceError,
|
||||||
|
AzureDevOpsClientRequestError,
|
||||||
|
ValueError,
|
||||||
|
*/
|
||||||
|
if (!failTaskOnTransientError && IsTransient(e)) {
|
||||||
|
_logTracer.Error($"transient ADO notification failure {notificationInfo}");
|
||||||
|
throw;
|
||||||
|
} else {
|
||||||
|
await FailTask(report, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsTransient(Exception e) {
|
||||||
|
var errorCodes = new List<string>()
|
||||||
|
{
|
||||||
|
//TF401349: An unexpected error has occurred, please verify your request and try again.
|
||||||
|
"TF401349",
|
||||||
|
//TF26071: This work item has been changed by someone else since you opened it. You will need to refresh it and discard your changes.
|
||||||
|
"TF26071",
|
||||||
|
};
|
||||||
|
|
||||||
|
var errorStr = e.ToString();
|
||||||
|
return errorCodes.Any(code => errorStr.Contains(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
class AdoConnector {
|
||||||
|
private readonly AdoTemplate _config;
|
||||||
|
private readonly Renderer _renderer;
|
||||||
|
private readonly string _project;
|
||||||
|
private readonly WorkItemTrackingHttpClient _client;
|
||||||
|
private readonly Uri _instanceUrl;
|
||||||
|
private readonly ILogTracer _logTracer;
|
||||||
|
public static async Async.Task<AdoConnector> AdoConnectorCreator(IOnefuzzContext context, Container container, string filename, AdoTemplate config, Report report, ILogTracer logTracer, Renderer? renderer = null) {
|
||||||
|
renderer ??= await Renderer.ConstructRenderer(context, container, filename, report);
|
||||||
|
var instanceUrl = context.Creds.GetInstanceUrl();
|
||||||
|
var project = await renderer.Render(config.Project, instanceUrl);
|
||||||
|
|
||||||
|
var authToken = await context.SecretsOperations.GetSecretStringValue(config.AuthToken);
|
||||||
|
var client = GetAdoClient(config.BaseUrl, authToken!);
|
||||||
|
return new AdoConnector(container, filename, config, report, renderer, project!, client, instanceUrl, logTracer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static WorkItemTrackingHttpClient GetAdoClient(Uri baseUrl, string token) {
|
||||||
|
return new WorkItemTrackingHttpClient(baseUrl, new VssBasicCredential("PAT", token));
|
||||||
|
}
|
||||||
|
public AdoConnector(Container container, string filename, AdoTemplate config, Report report, Renderer renderer, string project, WorkItemTrackingHttpClient client, Uri instanceUrl, ILogTracer logTracer) {
|
||||||
|
_config = config;
|
||||||
|
_renderer = renderer;
|
||||||
|
_project = project;
|
||||||
|
_client = client;
|
||||||
|
_instanceUrl = instanceUrl;
|
||||||
|
_logTracer = logTracer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Async.Task<string> Render(string template) {
|
||||||
|
return await _renderer.Render(template, _instanceUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async IAsyncEnumerable<WorkItem> ExistingWorkItems() {
|
||||||
|
var filters = new Dictionary<string, string>();
|
||||||
|
foreach (var key in _config.UniqueFields) {
|
||||||
|
var filter = string.Empty;
|
||||||
|
if (string.Equals("System.TeamProject", key)) {
|
||||||
|
filter = await Render(_config.Project);
|
||||||
|
} else {
|
||||||
|
filter = await Render(_config.AdoFields[key]);
|
||||||
|
}
|
||||||
|
filters.Add(key.ToLowerInvariant(), filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
var validFields = await GetValidFields(filters["system.teamproject"]);
|
||||||
|
|
||||||
|
var postQueryFilter = new Dictionary<string, string>();
|
||||||
|
/*
|
||||||
|
# WIQL (Work Item Query Language) is an SQL like query language that
|
||||||
|
# doesn't support query params, safe quoting, or any other SQL-injection
|
||||||
|
# protection mechanisms.
|
||||||
|
#
|
||||||
|
# As such, build the WIQL with a those fields we can pre-determine are
|
||||||
|
# "safe" and otherwise use post-query filtering.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var parts = new List<string>();
|
||||||
|
foreach (var key in filters.Keys) {
|
||||||
|
//# Only add pre-system approved fields to the query
|
||||||
|
if (!validFields.Contains(key)) {
|
||||||
|
postQueryFilter.Add(key, filters[key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
# WIQL supports wrapping values in ' or " and escaping ' by doubling it
|
||||||
|
#
|
||||||
|
# For this System.Title: hi'there
|
||||||
|
# use this query fragment: [System.Title] = 'hi''there'
|
||||||
|
#
|
||||||
|
# For this System.Title: hi"there
|
||||||
|
# use this query fragment: [System.Title] = 'hi"there'
|
||||||
|
#
|
||||||
|
# For this System.Title: hi'"there
|
||||||
|
# use this query fragment: [System.Title] = 'hi''"there'
|
||||||
|
*/
|
||||||
|
var single = "'";
|
||||||
|
parts.Add($"[{key}] = '{filters[key].Replace(single, single + single)}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
var query = "select [System.Id] from WorkItems";
|
||||||
|
if (parts != null && parts.Any()) {
|
||||||
|
query += " where " + string.Join(" AND ", parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
var wiql = new Wiql() {
|
||||||
|
Query = query
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var workItemReference in (await _client.QueryByWiqlAsync(wiql)).WorkItems) {
|
||||||
|
var item = await _client.GetWorkItemAsync(_project, workItemReference.Id, expand: WorkItemExpand.Fields);
|
||||||
|
|
||||||
|
var loweredFields = item.Fields.ToDictionary(kvp => kvp.Key.ToLowerInvariant(), kvp => JsonSerializer.Serialize(kvp.Value));
|
||||||
|
if (postQueryFilter.Any() && !postQueryFilter.All(kvp => {
|
||||||
|
var lowerKey = kvp.Key.ToLowerInvariant();
|
||||||
|
return loweredFields.ContainsKey(lowerKey) && loweredFields[lowerKey] == postQueryFilter[kvp.Key];
|
||||||
|
})) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Async.Task UpdateExisting(WorkItem item, string notificationInfo) {
|
||||||
|
if (_config.OnDuplicate.Comment != null) {
|
||||||
|
var comment = await Render(_config.OnDuplicate.Comment);
|
||||||
|
await _client.AddCommentAsync(
|
||||||
|
new CommentCreate() {
|
||||||
|
Text = comment
|
||||||
|
},
|
||||||
|
_project,
|
||||||
|
(int)(item.Id!)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var document = new JsonPatchDocument();
|
||||||
|
foreach (var field in _config.OnDuplicate.Increment) {
|
||||||
|
var value = item.Fields.ContainsKey(field) ? int.Parse(JsonSerializer.Serialize(item.Fields[field])) : 0;
|
||||||
|
value++;
|
||||||
|
document.Add(new JsonPatchOperation() {
|
||||||
|
Operation = VisualStudio.Services.WebApi.Patch.Operation.Replace,
|
||||||
|
Path = $"/fields/{field}",
|
||||||
|
Value = value.ToString()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var field in _config.OnDuplicate.AdoFields) {
|
||||||
|
var fieldValue = await Render(_config.OnDuplicate.AdoFields[field.Key]);
|
||||||
|
document.Add(new JsonPatchOperation() {
|
||||||
|
Operation = VisualStudio.Services.WebApi.Patch.Operation.Replace,
|
||||||
|
Path = $"/fields/{field}",
|
||||||
|
Value = fieldValue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var systemState = JsonSerializer.Serialize(item.Fields["System.State"]);
|
||||||
|
if (_config.OnDuplicate.SetState.ContainsKey(systemState)) {
|
||||||
|
document.Add(new JsonPatchOperation() {
|
||||||
|
Operation = VisualStudio.Services.WebApi.Patch.Operation.Replace,
|
||||||
|
Path = "/fields/System.State",
|
||||||
|
Value = _config.OnDuplicate.SetState[systemState]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.Any()) {
|
||||||
|
await _client.UpdateWorkItemAsync(document, _project, (int)(item.Id!));
|
||||||
|
_logTracer.Info($"notify ado: updated work item {item.Id} - {notificationInfo}");
|
||||||
|
} else {
|
||||||
|
_logTracer.Info($"notify ado: no update for work item {item.Id} - {notificationInfo}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Async.Task<List<string>> GetValidFields(string? project) {
|
||||||
|
return (await _client.GetFieldsAsync(project, expand: GetFieldsExpand.ExtensionFields))
|
||||||
|
.Select(field => field.ReferenceName.ToLowerInvariant())
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Async.Task<WorkItem> CreateNew() {
|
||||||
|
var (taskType, document) = await RenderNew();
|
||||||
|
var entry = await _client.CreateWorkItemAsync(document, _project, taskType);
|
||||||
|
|
||||||
|
if (_config.Comment != null) {
|
||||||
|
var comment = await Render(_config.Comment);
|
||||||
|
await _client.AddCommentAsync(
|
||||||
|
new CommentCreate() {
|
||||||
|
Text = comment,
|
||||||
|
},
|
||||||
|
_project,
|
||||||
|
(int)(entry.Id!)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Async.Task<(string, JsonPatchDocument)> RenderNew() {
|
||||||
|
var taskType = await Render(_config.Type);
|
||||||
|
var document = new JsonPatchDocument();
|
||||||
|
if (!_config.AdoFields.ContainsKey("System.Tags")) {
|
||||||
|
document.Add(new JsonPatchOperation() {
|
||||||
|
Operation = VisualStudio.Services.WebApi.Patch.Operation.Add,
|
||||||
|
Path = "/fields/System.Tags",
|
||||||
|
Value = "Onefuzz"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var field in _config.AdoFields.Keys) {
|
||||||
|
var value = await Render(_config.AdoFields[field]);
|
||||||
|
|
||||||
|
if (string.Equals(field, "System.Tags")) {
|
||||||
|
value += ";Onefuzz";
|
||||||
|
}
|
||||||
|
|
||||||
|
document.Add(new JsonPatchOperation() {
|
||||||
|
Operation = VisualStudio.Services.WebApi.Patch.Operation.Add,
|
||||||
|
Path = $"/fields/{field}",
|
||||||
|
Value = value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (taskType, document);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Async.Task Process(string notificationInfo) {
|
||||||
|
var seen = false;
|
||||||
|
await foreach (var workItem in ExistingWorkItems()) {
|
||||||
|
await UpdateExisting(workItem, notificationInfo);
|
||||||
|
seen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!seen) {
|
||||||
|
var entry = await CreateNew();
|
||||||
|
_logTracer.Info($"notify ado: created new work item {entry.Id} - {notificationInfo}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,160 @@
|
|||||||
|
using Octokit;
|
||||||
|
|
||||||
|
namespace Microsoft.OneFuzz.Service;
|
||||||
|
|
||||||
|
public interface IGithubIssues {
|
||||||
|
Async.Task GithubIssue(GithubIssuesTemplate config, Container container, string filename, IReport? reportable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GithubIssues : NotificationsBase, IGithubIssues {
|
||||||
|
|
||||||
|
public GithubIssues(ILogTracer logTracer, IOnefuzzContext context)
|
||||||
|
: base(logTracer, context) { }
|
||||||
|
|
||||||
|
public async Async.Task GithubIssue(GithubIssuesTemplate config, Container container, string filename, IReport? reportable) {
|
||||||
|
if (reportable == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reportable is RegressionReport) {
|
||||||
|
_logTracer.Info($"github issue integration does not support regression reports. container:{container} filename:{filename}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var report = (Report)reportable;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Process(config, container, filename, report);
|
||||||
|
} catch (ApiException e) {
|
||||||
|
await FailTask(report, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Async.Task Process(GithubIssuesTemplate config, Container container, string filename, Report report) {
|
||||||
|
var renderer = await Renderer.ConstructRenderer(_context, container, filename, report);
|
||||||
|
var handler = await GithubConnnector.GithubConnnectorCreator(config, container, filename, renderer, _context.Creds.GetInstanceUrl(), _context, _logTracer);
|
||||||
|
await handler.Process();
|
||||||
|
}
|
||||||
|
class GithubConnnector {
|
||||||
|
private readonly GitHubClient _gh;
|
||||||
|
private readonly GithubIssuesTemplate _config;
|
||||||
|
private readonly Renderer _renderer;
|
||||||
|
private readonly Uri _instanceUrl;
|
||||||
|
private readonly ILogTracer _logTracer;
|
||||||
|
|
||||||
|
public static async Async.Task<GithubConnnector> GithubConnnectorCreator(GithubIssuesTemplate config, Container container, string filename, Renderer renderer, Uri instanceUrl, IOnefuzzContext context, ILogTracer logTracer) {
|
||||||
|
var auth = config.Auth.Secret switch {
|
||||||
|
SecretAddress<GithubAuth> sa => await context.SecretsOperations.GetSecretObj<GithubAuth>(sa.Url),
|
||||||
|
SecretValue<GithubAuth> sv => sv.Value,
|
||||||
|
_ => throw new ArgumentException($"Unexpected secret type {config.Auth.Secret.GetType()}")
|
||||||
|
};
|
||||||
|
return new GithubConnnector(config, container, filename, renderer, instanceUrl, auth!, logTracer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GithubConnnector(GithubIssuesTemplate config, Container container, string filename, Renderer renderer, Uri instanceUrl, GithubAuth auth, ILogTracer logTracer) {
|
||||||
|
_config = config;
|
||||||
|
_gh = new GitHubClient(new ProductHeaderValue("microsoft/OneFuzz")) {
|
||||||
|
Credentials = new Credentials(auth.User, auth.PersonalAccessToken)
|
||||||
|
};
|
||||||
|
_renderer = renderer;
|
||||||
|
_instanceUrl = instanceUrl;
|
||||||
|
_logTracer = logTracer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Async.Task Process() {
|
||||||
|
var issues = await Existing();
|
||||||
|
if (issues.Any()) {
|
||||||
|
await Update(issues.First());
|
||||||
|
} else {
|
||||||
|
await Create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Async.Task<string> Render(string field) {
|
||||||
|
return await _renderer.Render(field, _instanceUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Async.Task<List<Issue>> Existing() {
|
||||||
|
var query = new List<string>() {
|
||||||
|
await Render(_config.UniqueSearch.str),
|
||||||
|
$"repo:{_config.Organization}/{_config.Repository}"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_config.UniqueSearch.Author != null) {
|
||||||
|
query.Add($"author:{await Render(_config.UniqueSearch.Author)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_config.UniqueSearch.State != null) {
|
||||||
|
query.Add($"state:{_config.UniqueSearch.State}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var title = await Render(_config.Title);
|
||||||
|
var body = await Render(_config.Body);
|
||||||
|
var issues = new List<Issue>();
|
||||||
|
var t = await _gh.Search.SearchIssues(new SearchIssuesRequest(string.Join(' ', query)));
|
||||||
|
foreach (var issue in t.Items) {
|
||||||
|
var skip = false;
|
||||||
|
foreach (var field in _config.UniqueSearch.FieldMatch) {
|
||||||
|
if (field == GithubIssueSearchMatch.Title && issue.Title != title) {
|
||||||
|
skip = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (field == GithubIssueSearchMatch.Body && issue.Body != body) {
|
||||||
|
skip = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!skip) {
|
||||||
|
issues.Add(issue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return issues;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Async.Task Update(Issue issue) {
|
||||||
|
_logTracer.Info($"updating issue: {issue}");
|
||||||
|
if (_config.OnDuplicate.Comment != null) {
|
||||||
|
await _gh.Issue.Comment.Create(issue.Repository.Id, issue.Number, await Render(_config.OnDuplicate.Comment));
|
||||||
|
}
|
||||||
|
if (_config.OnDuplicate.Labels.Any()) {
|
||||||
|
var labels = await _config.OnDuplicate.Labels.ToAsyncEnumerable()
|
||||||
|
.SelectAwait(async label => await Render(label))
|
||||||
|
.ToArrayAsync();
|
||||||
|
|
||||||
|
await _gh.Issue.Labels.ReplaceAllForIssue(issue.Repository.Id, issue.Number, labels);
|
||||||
|
}
|
||||||
|
if (_config.OnDuplicate.Reopen && issue.State != ItemState.Open) {
|
||||||
|
await _gh.Issue.Update(issue.Repository.Id, issue.Number, new IssueUpdate() {
|
||||||
|
State = ItemState.Open
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Async.Task Create() {
|
||||||
|
_logTracer.Info($"creating issue");
|
||||||
|
var assignees = await _config.Assignees.ToAsyncEnumerable()
|
||||||
|
.SelectAwait(async assignee => await Render(assignee))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var labels = await _config.Labels.ToAsyncEnumerable()
|
||||||
|
.SelectAwait(async label => await Render(label))
|
||||||
|
.ToHashSetAsync();
|
||||||
|
|
||||||
|
labels.Add("OneFuzz");
|
||||||
|
|
||||||
|
var newIssue = new NewIssue(await Render(_config.Title)) {
|
||||||
|
Body = await Render(_config.Body),
|
||||||
|
};
|
||||||
|
|
||||||
|
labels.ToList().ForEach(label => newIssue.Labels.Add(label));
|
||||||
|
assignees.ForEach(assignee => newIssue.Assignees.Add(assignee));
|
||||||
|
|
||||||
|
await _gh.Issue.Create(
|
||||||
|
await Render(_config.Organization),
|
||||||
|
await Render(_config.Repository),
|
||||||
|
newIssue
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,99 @@
|
|||||||
|
using Scriban;
|
||||||
|
|
||||||
|
namespace Microsoft.OneFuzz.Service;
|
||||||
|
|
||||||
|
public abstract class NotificationsBase {
|
||||||
|
|
||||||
|
#pragma warning disable CA1051 // permit visible instance fields
|
||||||
|
protected readonly ILogTracer _logTracer;
|
||||||
|
protected readonly IOnefuzzContext _context;
|
||||||
|
#pragma warning restore CA1051
|
||||||
|
public NotificationsBase(ILogTracer logTracer, IOnefuzzContext context) {
|
||||||
|
_logTracer = logTracer;
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Async.Task FailTask(Report report, Exception error) {
|
||||||
|
_logTracer.Error($"notification failed: job_id:{report.JobId} task_id:{report.TaskId} err:{error}");
|
||||||
|
|
||||||
|
var task = await _context.TaskOperations.GetByJobIdAndTaskId(report.JobId, report.TaskId);
|
||||||
|
if (task != null) {
|
||||||
|
await _context.TaskOperations.MarkFailed(task, new Error(ErrorCode.NOTIFICATION_FAILURE, new string[] {
|
||||||
|
"notification failed",
|
||||||
|
error.ToString()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ReplaceFirstSetup(string executable) {
|
||||||
|
var setup = "setup/";
|
||||||
|
int index = executable.IndexOf(setup, StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
var setupFileName = (index < 0) ? executable : executable.Remove(index, setup.Length);
|
||||||
|
return setupFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class Renderer {
|
||||||
|
private readonly Report _report;
|
||||||
|
private readonly Container _container;
|
||||||
|
private readonly string _filename;
|
||||||
|
private readonly TaskConfig _taskConfig;
|
||||||
|
private readonly JobConfig _jobConfig;
|
||||||
|
private readonly Uri _targetUrl;
|
||||||
|
private readonly Uri _inputUrl;
|
||||||
|
private readonly Uri _reportUrl;
|
||||||
|
|
||||||
|
public static async Async.Task<Renderer> ConstructRenderer(IOnefuzzContext context, Container container, string filename, Report report, Task? task = null, Job? job = null, Uri? targetUrl = null, Uri? inputUrl = null, Uri? reportUrl = null) {
|
||||||
|
task ??= await context.TaskOperations.GetByJobIdAndTaskId(report.JobId, report.TaskId);
|
||||||
|
task.EnsureNotNull($"invalid task {report.TaskId}");
|
||||||
|
|
||||||
|
job ??= await context.JobOperations.Get(report.JobId);
|
||||||
|
job.EnsureNotNull($"invalid job {report.JobId}");
|
||||||
|
|
||||||
|
if (targetUrl == null) {
|
||||||
|
var setupContainer = Scheduler.GetSetupContainer(task?.Config!);
|
||||||
|
targetUrl = new Uri(context.Containers.AuthDownloadUrl(setupContainer, ReplaceFirstSetup(report.Executable)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reportUrl == null) {
|
||||||
|
reportUrl = new Uri(context.Containers.AuthDownloadUrl(container, filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputUrl == null && report.InputBlob != null) {
|
||||||
|
inputUrl = new Uri(context.Containers.AuthDownloadUrl(report.InputBlob.Container, report.InputBlob.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Renderer(container, filename, report, task!, job!, targetUrl, inputUrl!, reportUrl);
|
||||||
|
}
|
||||||
|
public Renderer(Container container, string filename, Report report, Task task, Job job, Uri targetUrl, Uri inputUrl, Uri reportUrl) {
|
||||||
|
_report = report;
|
||||||
|
_container = container;
|
||||||
|
_filename = filename;
|
||||||
|
_taskConfig = task.Config;
|
||||||
|
_jobConfig = job.Config;
|
||||||
|
_reportUrl = reportUrl;
|
||||||
|
_targetUrl = targetUrl;
|
||||||
|
_inputUrl = inputUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This function is fallible but the python
|
||||||
|
// implementation doesn't have that so I'm trying to match it.
|
||||||
|
// We should probably propagate any errors up
|
||||||
|
public async Async.Task<string> Render(string templateString, Uri instanceUrl) {
|
||||||
|
var template = Template.Parse(templateString);
|
||||||
|
if (template != null) {
|
||||||
|
return await template.RenderAsync(new {
|
||||||
|
Report = this._report,
|
||||||
|
Task = this._taskConfig,
|
||||||
|
Job = this._jobConfig,
|
||||||
|
ReportUrl = this._reportUrl,
|
||||||
|
InputUrl = _inputUrl,
|
||||||
|
TargetUrl = _targetUrl,
|
||||||
|
ReportContainer = _container,
|
||||||
|
ReportFilename = _filename,
|
||||||
|
ReproCmd = $"onefuzz --endpoint {instanceUrl} repro create_and_connect {_container} {_filename}"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
124
src/ApiService/ApiService/onefuzzlib/notifications/Teams.cs
Normal file
124
src/ApiService/ApiService/onefuzzlib/notifications/Teams.cs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
using System.Net.Http;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace Microsoft.OneFuzz.Service;
|
||||||
|
|
||||||
|
public interface ITeams {
|
||||||
|
Async.Task NotifyTeams(TeamsTemplate config, Container container, string filename, IReport reportOrRegression);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Teams : ITeams {
|
||||||
|
private readonly ILogTracer _logTracer;
|
||||||
|
private readonly IOnefuzzContext _context;
|
||||||
|
private readonly IHttpClientFactory _httpFactory;
|
||||||
|
|
||||||
|
public Teams(IHttpClientFactory httpFactory, ILogTracer logTracer, IOnefuzzContext context) {
|
||||||
|
_logTracer = logTracer;
|
||||||
|
_context = context;
|
||||||
|
_httpFactory = httpFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string CodeBlock(string data) {
|
||||||
|
data = data.Replace("`", "``");
|
||||||
|
return $"\n```\n{data}\n```\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Async.Task SendTeamsWebhook(TeamsTemplate config, string title, IList<Dictionary<string, string>> facts, string? text) {
|
||||||
|
title = MarkdownEscape(title);
|
||||||
|
|
||||||
|
var sections = new List<Dictionary<string, object>>() {
|
||||||
|
new() {
|
||||||
|
{"activityTitle", title},
|
||||||
|
{"facts", facts}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (text != null) {
|
||||||
|
sections.Add(new() {
|
||||||
|
{ "text", text }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = new Dictionary<string, object>() {
|
||||||
|
{"@type", "MessageCard"},
|
||||||
|
{"@context", "https://schema.org/extensions"},
|
||||||
|
{"summary", title},
|
||||||
|
{"sections", sections}
|
||||||
|
};
|
||||||
|
|
||||||
|
var configUrl = await _context.SecretsOperations.GetSecretStringValue(config.Url);
|
||||||
|
var client = new Request(_httpFactory.CreateClient());
|
||||||
|
var response = await client.Post(url: new Uri(configUrl!), JsonSerializer.Serialize(message));
|
||||||
|
if (response == null || !response.IsSuccessStatusCode) {
|
||||||
|
_logTracer.Error($"webhook failed {response?.StatusCode} {response?.Content}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Async.Task NotifyTeams(TeamsTemplate config, Container container, string filename, IReport reportOrRegression) {
|
||||||
|
var facts = new List<Dictionary<string, string>>();
|
||||||
|
string? text = null;
|
||||||
|
var title = string.Empty;
|
||||||
|
|
||||||
|
if (reportOrRegression is Report report) {
|
||||||
|
var task = await _context.TaskOperations.GetByJobIdAndTaskId(report.JobId, report.TaskId);
|
||||||
|
if (task == null) {
|
||||||
|
_logTracer.Error($"report with invalid task {report.JobId}:{report.TaskId}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
title = $"new crash in {report.Executable}: {report.CrashType} @ {report.CrashSite}";
|
||||||
|
|
||||||
|
var links = new List<string> {
|
||||||
|
$"[report]({_context.Containers.AuthDownloadUrl(container, filename)})"
|
||||||
|
};
|
||||||
|
|
||||||
|
var setupContainer = Scheduler.GetSetupContainer(task.Config);
|
||||||
|
if (setupContainer != null) {
|
||||||
|
var setupFileName = NotificationsBase.ReplaceFirstSetup(report.Executable);
|
||||||
|
links.Add(
|
||||||
|
$"[executable]({_context.Containers.AuthDownloadUrl(setupContainer, setupFileName)})"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (report.InputBlob != null) {
|
||||||
|
links.Add(
|
||||||
|
$"[input]({_context.Containers.AuthDownloadUrl(report.InputBlob.Container, report.InputBlob.Name)})"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
facts.AddRange(new List<Dictionary<string, string>> {
|
||||||
|
new() {{"name", "Files"}, {"value", string.Join(" | ", links)}},
|
||||||
|
new() {
|
||||||
|
{"name", "Task"},
|
||||||
|
{"value", MarkdownEscape(
|
||||||
|
$"job_id: {report.JobId} task_id: {report.TaskId}"
|
||||||
|
)}
|
||||||
|
},
|
||||||
|
new() {
|
||||||
|
{"name", "Repro"},
|
||||||
|
{"value", CodeBlock($"onefuzz repro create_and_connect {container} {filename}")}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
text = "## Call Stack\n" + string.Join("\n", report.CallStack.Select(cs => CodeBlock(cs)));
|
||||||
|
} else {
|
||||||
|
title = "new file found";
|
||||||
|
var fileUrl = _context.Containers.AuthDownloadUrl(container, filename);
|
||||||
|
|
||||||
|
facts.Add(new Dictionary<string, string>() {
|
||||||
|
{"name", "file"},
|
||||||
|
{"value", $"[{MarkdownEscape(container.String)}/{MarkdownEscape(filename)}]({fileUrl})"}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await SendTeamsWebhook(config, title, facts, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string MarkdownEscape(string data) {
|
||||||
|
var values = "\\*_{}[]()#+-.!";
|
||||||
|
foreach (var c in values) {
|
||||||
|
data = data.Replace(c.ToString(), "\\" + c);
|
||||||
|
}
|
||||||
|
data = data.Replace("`", "``");
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
@ -302,6 +302,25 @@
|
|||||||
"System.Text.Encodings.Web": "5.0.1"
|
"System.Text.Encodings.Web": "5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.TeamFoundationServer.Client": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[19.209.0-preview, )",
|
||||||
|
"resolved": "19.209.0-preview",
|
||||||
|
"contentHash": "dglVgITWfsps8pWA//2mBGVt/keD3UGdAVBXd50k9nVZiThUwWnaAoUzRf4fay/avLGXdvfkz6x9dBf6zGtfxg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.AspNet.WebApi.Client": "5.2.7",
|
||||||
|
"Microsoft.TeamFoundation.DistributedTask.Common.Contracts": "[19.209.0-preview]",
|
||||||
|
"Microsoft.VisualStudio.Services.Client": "[19.209.0-preview]",
|
||||||
|
"Newtonsoft.Json": "12.0.3",
|
||||||
|
"System.ComponentModel.Annotations": "4.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Octokit": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[2.0.1, )",
|
||||||
|
"resolved": "2.0.1",
|
||||||
|
"contentHash": "JVlfUY+sfItl6RSyVKDJTutuy28cDydUwKKfzcelwNMor2Sa18pYVKna6phO8lug1b+ep+pcuFh/FPayuImsQw=="
|
||||||
|
},
|
||||||
"Scriban": {
|
"Scriban": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[5.5.0, )",
|
"requested": "[5.5.0, )",
|
||||||
@ -399,6 +418,15 @@
|
|||||||
"System.Diagnostics.DiagnosticSource": "5.0.0"
|
"System.Diagnostics.DiagnosticSource": "5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.AspNet.WebApi.Client": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "5.2.7",
|
||||||
|
"contentHash": "/76fAHknzvFqbznS6Uj2sOyE9rJB3PltY+f53TH8dX9RiGhk02EhuFCWljSj5nnqKaTsmma8DFR50OGyQ4yJ1g==",
|
||||||
|
"dependencies": {
|
||||||
|
"Newtonsoft.Json": "10.0.1",
|
||||||
|
"Newtonsoft.Json.Bson": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.AspNetCore.Cryptography.Internal": {
|
"Microsoft.AspNetCore.Cryptography.Internal": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "5.0.8",
|
"resolved": "5.0.8",
|
||||||
@ -869,6 +897,30 @@
|
|||||||
"Newtonsoft.Json": "10.0.3"
|
"Newtonsoft.Json": "10.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.TeamFoundation.DistributedTask.Common.Contracts": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "19.209.0-preview",
|
||||||
|
"contentHash": "32lLZPU8pZg+mVfA2smHso6fhWPSFXJPPyawvOFsFoNz9Yj5y2fsAR7O4zPwE3c/z2zzi8BMfiXRKOcbW6cdIg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.VisualStudio.Services.Client": "[19.209.0-preview]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.VisualStudio.Services.Client": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "19.209.0-preview",
|
||||||
|
"contentHash": "eQWZb5BhtOgywARvfHGGZsYuuZvFmJiXyE7P/EqKTLUplrUFmSVxo0J/KUC8GWJWmdarxH2vXZTAz9uW7BwRDQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.AspNet.WebApi.Client": "5.2.7",
|
||||||
|
"Newtonsoft.Json": "12.0.3",
|
||||||
|
"System.Configuration.ConfigurationManager": "4.4.1",
|
||||||
|
"System.Data.SqlClient": "4.4.2",
|
||||||
|
"System.Security.Cryptography.Cng": "4.4.0",
|
||||||
|
"System.Security.Cryptography.OpenSsl": "4.4.0",
|
||||||
|
"System.Security.Cryptography.ProtectedData": "4.4.0",
|
||||||
|
"System.Security.Principal.Windows": "4.4.1",
|
||||||
|
"System.Xml.XPath.XmlDocument": "4.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Win32.Primitives": {
|
"Microsoft.Win32.Primitives": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -949,15 +1001,16 @@
|
|||||||
},
|
},
|
||||||
"Newtonsoft.Json": {
|
"Newtonsoft.Json": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "10.0.3",
|
"resolved": "12.0.3",
|
||||||
"contentHash": "hSXaFmh7hNCuEoC4XNY5DrRkLDzYHqPx/Ik23R4J86Z7PE/Y6YidhG602dFVdLBRSdG6xp9NabH3dXpcoxWvww==",
|
"contentHash": "6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg=="
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json.Bson": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "1.0.1",
|
||||||
|
"contentHash": "5PYT/IqQ+UK31AmZiSS102R6EsTo+LGTSI8bp7WAUqDKaF4wHXD8U9u4WxTI1vc64tYi++8p3dk3WWNqPFgldw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.CSharp": "4.3.0",
|
|
||||||
"NETStandard.Library": "1.6.1",
|
"NETStandard.Library": "1.6.1",
|
||||||
"System.ComponentModel.TypeConverter": "4.3.0",
|
"Newtonsoft.Json": "10.0.1"
|
||||||
"System.Runtime.Serialization.Formatters": "4.3.0",
|
|
||||||
"System.Runtime.Serialization.Primitives": "4.3.0",
|
|
||||||
"System.Xml.XmlDocument": "4.3.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
|
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
|
||||||
@ -984,6 +1037,16 @@
|
|||||||
"Microsoft.NETCore.Targets": "1.1.0"
|
"Microsoft.NETCore.Targets": "1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"runtime.native.System.Data.SqlClient.sni": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "A8v6PGmk+UGbfWo5Ixup0lPM4swuSwOiayJExZwKIOjTlFFQIsu3QnDXECosBEyrWSPryxBVrdqtJyhK3BaupQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"runtime.win-arm64.runtime.native.System.Data.SqlClient.sni": "4.4.0",
|
||||||
|
"runtime.win-x64.runtime.native.System.Data.SqlClient.sni": "4.4.0",
|
||||||
|
"runtime.win-x86.runtime.native.System.Data.SqlClient.sni": "4.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"runtime.native.System.IO.Compression": {
|
"runtime.native.System.IO.Compression": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -1067,6 +1130,21 @@
|
|||||||
"resolved": "4.3.2",
|
"resolved": "4.3.2",
|
||||||
"contentHash": "leXiwfiIkW7Gmn7cgnNcdtNAU70SjmKW3jxGj1iKHOvdn0zRWsgv/l2OJUO5zdGdiv2VRFnAsxxhDgMzofPdWg=="
|
"contentHash": "leXiwfiIkW7Gmn7cgnNcdtNAU70SjmKW3jxGj1iKHOvdn0zRWsgv/l2OJUO5zdGdiv2VRFnAsxxhDgMzofPdWg=="
|
||||||
},
|
},
|
||||||
|
"runtime.win-arm64.runtime.native.System.Data.SqlClient.sni": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "LbrynESTp3bm5O/+jGL8v0Qg5SJlTV08lpIpFesXjF6uGNMWqFnUQbYBJwZTeua6E/Y7FIM1C54Ey1btLWupdg=="
|
||||||
|
},
|
||||||
|
"runtime.win-x64.runtime.native.System.Data.SqlClient.sni": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "38ugOfkYJqJoX9g6EYRlZB5U2ZJH51UP8ptxZgdpS07FgOEToV+lS11ouNK2PM12Pr6X/PpT5jK82G3DwH/SxQ=="
|
||||||
|
},
|
||||||
|
"runtime.win-x86.runtime.native.System.Data.SqlClient.sni": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA=="
|
||||||
|
},
|
||||||
"System.AppContext": {
|
"System.AppContext": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -1114,71 +1192,17 @@
|
|||||||
"System.Threading.Tasks": "4.3.0"
|
"System.Threading.Tasks": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"System.Collections.NonGeneric": {
|
"System.ComponentModel.Annotations": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.4.1",
|
||||||
"contentHash": "prtjIEMhGUnQq6RnPEYLpFt8AtLbp9yq2zxOSrY7KJJZrw25Fi97IzBqY7iqssbM61Ek5b8f3MG/sG1N2sN5KA==",
|
"contentHash": "ToiYqSCioqhtspq2O/jYKtyTC/T0uwWHBTYlzCi6PRbSSHArN1IaRWeHffDamvms5sye5FDUWCfNZgubQpNRsA=="
|
||||||
"dependencies": {
|
|
||||||
"System.Diagnostics.Debug": "4.3.0",
|
|
||||||
"System.Globalization": "4.3.0",
|
|
||||||
"System.Resources.ResourceManager": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0",
|
|
||||||
"System.Runtime.Extensions": "4.3.0",
|
|
||||||
"System.Threading": "4.3.0"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"System.Collections.Specialized": {
|
"System.Configuration.ConfigurationManager": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.4.1",
|
||||||
"contentHash": "Epx8PoVZR0iuOnJJDzp7pWvdfMMOAvpUo95pC4ScH2mJuXkKA2Y4aR3cG9qt2klHgSons1WFh4kcGW7cSXvrxg==",
|
"contentHash": "jz3TWKMAeuDEyrPCK5Jyt4bzQcmzUIMcY9Ud6PkElFxTfnsihV+9N/UCqvxe1z5gc7jMYAnj7V1COMS9QKIuHQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"System.Collections.NonGeneric": "4.3.0",
|
"System.Security.Cryptography.ProtectedData": "4.4.0"
|
||||||
"System.Globalization": "4.3.0",
|
|
||||||
"System.Globalization.Extensions": "4.3.0",
|
|
||||||
"System.Resources.ResourceManager": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0",
|
|
||||||
"System.Runtime.Extensions": "4.3.0",
|
|
||||||
"System.Threading": "4.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"System.ComponentModel": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "4.3.0",
|
|
||||||
"contentHash": "VyGn1jGRZVfxnh8EdvDCi71v3bMXrsu8aYJOwoV7SNDLVhiEqwP86pPMyRGsDsxhXAm2b3o9OIqeETfN5qfezw==",
|
|
||||||
"dependencies": {
|
|
||||||
"System.Runtime": "4.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"System.ComponentModel.Primitives": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "4.3.0",
|
|
||||||
"contentHash": "j8GUkCpM8V4d4vhLIIoBLGey2Z5bCkMVNjEZseyAlm4n5arcsJOeI3zkUP+zvZgzsbLTYh4lYeP/ZD/gdIAPrw==",
|
|
||||||
"dependencies": {
|
|
||||||
"System.ComponentModel": "4.3.0",
|
|
||||||
"System.Resources.ResourceManager": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"System.ComponentModel.TypeConverter": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "4.3.0",
|
|
||||||
"contentHash": "16pQ6P+EdhcXzPiEK4kbA953Fu0MNG2ovxTZU81/qsCd1zPRsKc3uif5NgvllCY598k6bI0KUyKW8fanlfaDQg==",
|
|
||||||
"dependencies": {
|
|
||||||
"System.Collections": "4.3.0",
|
|
||||||
"System.Collections.NonGeneric": "4.3.0",
|
|
||||||
"System.Collections.Specialized": "4.3.0",
|
|
||||||
"System.ComponentModel": "4.3.0",
|
|
||||||
"System.ComponentModel.Primitives": "4.3.0",
|
|
||||||
"System.Globalization": "4.3.0",
|
|
||||||
"System.Linq": "4.3.0",
|
|
||||||
"System.Reflection": "4.3.0",
|
|
||||||
"System.Reflection.Extensions": "4.3.0",
|
|
||||||
"System.Reflection.Primitives": "4.3.0",
|
|
||||||
"System.Reflection.TypeExtensions": "4.3.0",
|
|
||||||
"System.Resources.ResourceManager": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0",
|
|
||||||
"System.Runtime.Extensions": "4.3.0",
|
|
||||||
"System.Threading": "4.3.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"System.Console": {
|
"System.Console": {
|
||||||
@ -1193,6 +1217,17 @@
|
|||||||
"System.Text.Encoding": "4.3.0"
|
"System.Text.Encoding": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.Data.SqlClient": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.2",
|
||||||
|
"contentHash": "Bv5J2EBAdP7FSgehKYN4O6iw1AaZrw4rFFqwt9vZSjRvC70FpwP2d9UG4aTaI2wh3vfrBKK+tjewowGM2Y6c1w==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Win32.Registry": "4.4.0",
|
||||||
|
"System.Security.Principal.Windows": "4.4.0",
|
||||||
|
"System.Text.Encoding.CodePages": "4.4.0",
|
||||||
|
"runtime.native.System.Data.SqlClient.sni": "4.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"System.Diagnostics.Debug": {
|
"System.Diagnostics.Debug": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -1646,27 +1681,6 @@
|
|||||||
"System.Runtime.Extensions": "4.3.0"
|
"System.Runtime.Extensions": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"System.Runtime.Serialization.Formatters": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "4.3.0",
|
|
||||||
"contentHash": "KT591AkTNFOTbhZlaeMVvfax3RqhH1EJlcwF50Wm7sfnBLuHiOeZRRKrr1ns3NESkM20KPZ5Ol/ueMq5vg4QoQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"System.Collections": "4.3.0",
|
|
||||||
"System.Reflection": "4.3.0",
|
|
||||||
"System.Resources.ResourceManager": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0",
|
|
||||||
"System.Runtime.Serialization.Primitives": "4.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"System.Runtime.Serialization.Primitives": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "4.3.0",
|
|
||||||
"contentHash": "Wz+0KOukJGAlXjtKr+5Xpuxf8+c8739RI1C+A2BoQZT+wMCCoMDDdO8/4IRHfaVINqL78GO8dW8G2lW/e45Mcw==",
|
|
||||||
"dependencies": {
|
|
||||||
"System.Resources.ResourceManager": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"System.Security.AccessControl": {
|
"System.Security.AccessControl": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "5.0.0",
|
"resolved": "5.0.0",
|
||||||
@ -1760,22 +1774,10 @@
|
|||||||
},
|
},
|
||||||
"System.Security.Cryptography.OpenSsl": {
|
"System.Security.Cryptography.OpenSsl": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.4.0",
|
||||||
"contentHash": "h4CEgOgv5PKVF/HwaHzJRiVboL2THYCou97zpmhjghx5frc7fIvlkY1jL+lnIQyChrJDMNEXS6r7byGif8Cy4w==",
|
"contentHash": "is11qLXIHKIvbTipyB1an8FT1ZKavmgf/qJUSIz7ZP830ALRRhPSt5NhplW0/wMk0tNDQWQLluVap6HsQN4HMg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"System.Collections": "4.3.0",
|
"Microsoft.NETCore.Platforms": "2.0.0"
|
||||||
"System.IO": "4.3.0",
|
|
||||||
"System.Resources.ResourceManager": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0",
|
|
||||||
"System.Runtime.Extensions": "4.3.0",
|
|
||||||
"System.Runtime.Handles": "4.3.0",
|
|
||||||
"System.Runtime.InteropServices": "4.3.0",
|
|
||||||
"System.Runtime.Numerics": "4.3.0",
|
|
||||||
"System.Security.Cryptography.Algorithms": "4.3.0",
|
|
||||||
"System.Security.Cryptography.Encoding": "4.3.0",
|
|
||||||
"System.Security.Cryptography.Primitives": "4.3.0",
|
|
||||||
"System.Text.Encoding": "4.3.0",
|
|
||||||
"runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"System.Security.Cryptography.Pkcs": {
|
"System.Security.Cryptography.Pkcs": {
|
||||||
@ -1879,6 +1881,14 @@
|
|||||||
"System.Runtime": "4.3.0"
|
"System.Runtime": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.Text.Encoding.CodePages": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "6JX7ZdaceBiLKLkYt8zJcp4xTJd1uYyXXEkPw6mnlUIjh1gZPIVKPtRXPmY5kLf6DwZmf5YLwR3QUrRonl7l0A==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.NETCore.Platforms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"System.Text.Encoding.Extensions": {
|
"System.Text.Encoding.Extensions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -2014,6 +2024,39 @@
|
|||||||
"System.Threading": "4.3.0",
|
"System.Threading": "4.3.0",
|
||||||
"System.Xml.ReaderWriter": "4.3.0"
|
"System.Xml.ReaderWriter": "4.3.0"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"System.Xml.XPath": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.3.0",
|
||||||
|
"contentHash": "v1JQ5SETnQusqmS3RwStF7vwQ3L02imIzl++sewmt23VGygix04pEH+FCj1yWb+z4GDzKiljr1W7Wfvrx0YwgA==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Collections": "4.3.0",
|
||||||
|
"System.Diagnostics.Debug": "4.3.0",
|
||||||
|
"System.Globalization": "4.3.0",
|
||||||
|
"System.IO": "4.3.0",
|
||||||
|
"System.Resources.ResourceManager": "4.3.0",
|
||||||
|
"System.Runtime": "4.3.0",
|
||||||
|
"System.Runtime.Extensions": "4.3.0",
|
||||||
|
"System.Threading": "4.3.0",
|
||||||
|
"System.Xml.ReaderWriter": "4.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Xml.XPath.XmlDocument": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.3.0",
|
||||||
|
"contentHash": "A/uxsWi/Ifzkmd4ArTLISMbfFs6XpRPsXZonrIqyTY70xi8t+mDtvSM5Os0RqyRDobjMBwIDHDL4NOIbkDwf7A==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Collections": "4.3.0",
|
||||||
|
"System.Globalization": "4.3.0",
|
||||||
|
"System.IO": "4.3.0",
|
||||||
|
"System.Resources.ResourceManager": "4.3.0",
|
||||||
|
"System.Runtime": "4.3.0",
|
||||||
|
"System.Runtime.Extensions": "4.3.0",
|
||||||
|
"System.Threading": "4.3.0",
|
||||||
|
"System.Xml.ReaderWriter": "4.3.0",
|
||||||
|
"System.Xml.XPath": "4.3.0",
|
||||||
|
"System.Xml.XmlDocument": "4.3.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,9 @@ public sealed class TestContext : IOnefuzzContext {
|
|||||||
public ISubnet Subnet => throw new NotImplementedException();
|
public ISubnet Subnet => throw new NotImplementedException();
|
||||||
|
|
||||||
public IImageOperations ImageOperations => throw new NotImplementedException();
|
public IImageOperations ImageOperations => throw new NotImplementedException();
|
||||||
|
public ITeams Teams => throw new NotImplementedException();
|
||||||
|
public IGithubIssues GithubIssues => throw new NotImplementedException();
|
||||||
|
public IAdo Ado => throw new NotImplementedException();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -281,6 +281,15 @@
|
|||||||
"System.Diagnostics.DiagnosticSource": "5.0.0"
|
"System.Diagnostics.DiagnosticSource": "5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.AspNet.WebApi.Client": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "5.2.7",
|
||||||
|
"contentHash": "/76fAHknzvFqbznS6Uj2sOyE9rJB3PltY+f53TH8dX9RiGhk02EhuFCWljSj5nnqKaTsmma8DFR50OGyQ4yJ1g==",
|
||||||
|
"dependencies": {
|
||||||
|
"Newtonsoft.Json": "10.0.1",
|
||||||
|
"Newtonsoft.Json.Bson": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.AspNetCore.Cryptography.Internal": {
|
"Microsoft.AspNetCore.Cryptography.Internal": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "5.0.8",
|
"resolved": "5.0.8",
|
||||||
@ -878,6 +887,26 @@
|
|||||||
"Newtonsoft.Json": "10.0.3"
|
"Newtonsoft.Json": "10.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.TeamFoundation.DistributedTask.Common.Contracts": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "19.209.0-preview",
|
||||||
|
"contentHash": "32lLZPU8pZg+mVfA2smHso6fhWPSFXJPPyawvOFsFoNz9Yj5y2fsAR7O4zPwE3c/z2zzi8BMfiXRKOcbW6cdIg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.VisualStudio.Services.Client": "[19.209.0-preview]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.TeamFoundationServer.Client": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "19.209.0-preview",
|
||||||
|
"contentHash": "dglVgITWfsps8pWA//2mBGVt/keD3UGdAVBXd50k9nVZiThUwWnaAoUzRf4fay/avLGXdvfkz6x9dBf6zGtfxg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.AspNet.WebApi.Client": "5.2.7",
|
||||||
|
"Microsoft.TeamFoundation.DistributedTask.Common.Contracts": "[19.209.0-preview]",
|
||||||
|
"Microsoft.VisualStudio.Services.Client": "[19.209.0-preview]",
|
||||||
|
"Newtonsoft.Json": "12.0.3",
|
||||||
|
"System.ComponentModel.Annotations": "4.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.TestPlatform.ObjectModel": {
|
"Microsoft.TestPlatform.ObjectModel": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "17.1.0",
|
"resolved": "17.1.0",
|
||||||
@ -896,6 +925,22 @@
|
|||||||
"Newtonsoft.Json": "9.0.1"
|
"Newtonsoft.Json": "9.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.VisualStudio.Services.Client": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "19.209.0-preview",
|
||||||
|
"contentHash": "eQWZb5BhtOgywARvfHGGZsYuuZvFmJiXyE7P/EqKTLUplrUFmSVxo0J/KUC8GWJWmdarxH2vXZTAz9uW7BwRDQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.AspNet.WebApi.Client": "5.2.7",
|
||||||
|
"Newtonsoft.Json": "12.0.3",
|
||||||
|
"System.Configuration.ConfigurationManager": "4.4.1",
|
||||||
|
"System.Data.SqlClient": "4.4.2",
|
||||||
|
"System.Security.Cryptography.Cng": "4.4.0",
|
||||||
|
"System.Security.Cryptography.OpenSsl": "4.4.0",
|
||||||
|
"System.Security.Cryptography.ProtectedData": "4.4.0",
|
||||||
|
"System.Security.Principal.Windows": "4.4.1",
|
||||||
|
"System.Xml.XPath.XmlDocument": "4.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Win32.Primitives": {
|
"Microsoft.Win32.Primitives": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -976,15 +1021,16 @@
|
|||||||
},
|
},
|
||||||
"Newtonsoft.Json": {
|
"Newtonsoft.Json": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "10.0.3",
|
"resolved": "12.0.3",
|
||||||
"contentHash": "hSXaFmh7hNCuEoC4XNY5DrRkLDzYHqPx/Ik23R4J86Z7PE/Y6YidhG602dFVdLBRSdG6xp9NabH3dXpcoxWvww==",
|
"contentHash": "6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg=="
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json.Bson": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "1.0.1",
|
||||||
|
"contentHash": "5PYT/IqQ+UK31AmZiSS102R6EsTo+LGTSI8bp7WAUqDKaF4wHXD8U9u4WxTI1vc64tYi++8p3dk3WWNqPFgldw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.CSharp": "4.3.0",
|
|
||||||
"NETStandard.Library": "1.6.1",
|
"NETStandard.Library": "1.6.1",
|
||||||
"System.ComponentModel.TypeConverter": "4.3.0",
|
"Newtonsoft.Json": "10.0.1"
|
||||||
"System.Runtime.Serialization.Formatters": "4.3.0",
|
|
||||||
"System.Runtime.Serialization.Primitives": "4.3.0",
|
|
||||||
"System.Xml.XmlDocument": "4.3.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"NuGet.Frameworks": {
|
"NuGet.Frameworks": {
|
||||||
@ -992,6 +1038,11 @@
|
|||||||
"resolved": "5.11.0",
|
"resolved": "5.11.0",
|
||||||
"contentHash": "eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q=="
|
"contentHash": "eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q=="
|
||||||
},
|
},
|
||||||
|
"Octokit": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "2.0.1",
|
||||||
|
"contentHash": "JVlfUY+sfItl6RSyVKDJTutuy28cDydUwKKfzcelwNMor2Sa18pYVKna6phO8lug1b+ep+pcuFh/FPayuImsQw=="
|
||||||
|
},
|
||||||
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
|
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.2",
|
"resolved": "4.3.2",
|
||||||
@ -1016,6 +1067,16 @@
|
|||||||
"Microsoft.NETCore.Targets": "1.1.0"
|
"Microsoft.NETCore.Targets": "1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"runtime.native.System.Data.SqlClient.sni": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "A8v6PGmk+UGbfWo5Ixup0lPM4swuSwOiayJExZwKIOjTlFFQIsu3QnDXECosBEyrWSPryxBVrdqtJyhK3BaupQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"runtime.win-arm64.runtime.native.System.Data.SqlClient.sni": "4.4.0",
|
||||||
|
"runtime.win-x64.runtime.native.System.Data.SqlClient.sni": "4.4.0",
|
||||||
|
"runtime.win-x86.runtime.native.System.Data.SqlClient.sni": "4.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"runtime.native.System.IO.Compression": {
|
"runtime.native.System.IO.Compression": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -1099,6 +1160,21 @@
|
|||||||
"resolved": "4.3.2",
|
"resolved": "4.3.2",
|
||||||
"contentHash": "leXiwfiIkW7Gmn7cgnNcdtNAU70SjmKW3jxGj1iKHOvdn0zRWsgv/l2OJUO5zdGdiv2VRFnAsxxhDgMzofPdWg=="
|
"contentHash": "leXiwfiIkW7Gmn7cgnNcdtNAU70SjmKW3jxGj1iKHOvdn0zRWsgv/l2OJUO5zdGdiv2VRFnAsxxhDgMzofPdWg=="
|
||||||
},
|
},
|
||||||
|
"runtime.win-arm64.runtime.native.System.Data.SqlClient.sni": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "LbrynESTp3bm5O/+jGL8v0Qg5SJlTV08lpIpFesXjF6uGNMWqFnUQbYBJwZTeua6E/Y7FIM1C54Ey1btLWupdg=="
|
||||||
|
},
|
||||||
|
"runtime.win-x64.runtime.native.System.Data.SqlClient.sni": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "38ugOfkYJqJoX9g6EYRlZB5U2ZJH51UP8ptxZgdpS07FgOEToV+lS11ouNK2PM12Pr6X/PpT5jK82G3DwH/SxQ=="
|
||||||
|
},
|
||||||
|
"runtime.win-x86.runtime.native.System.Data.SqlClient.sni": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA=="
|
||||||
|
},
|
||||||
"Scriban": {
|
"Scriban": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "5.5.0",
|
"resolved": "5.5.0",
|
||||||
@ -1191,6 +1267,11 @@
|
|||||||
"System.Runtime": "4.3.0"
|
"System.Runtime": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.ComponentModel.Annotations": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.1",
|
||||||
|
"contentHash": "ToiYqSCioqhtspq2O/jYKtyTC/T0uwWHBTYlzCi6PRbSSHArN1IaRWeHffDamvms5sye5FDUWCfNZgubQpNRsA=="
|
||||||
|
},
|
||||||
"System.ComponentModel.Primitives": {
|
"System.ComponentModel.Primitives": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -1225,8 +1306,8 @@
|
|||||||
},
|
},
|
||||||
"System.Configuration.ConfigurationManager": {
|
"System.Configuration.ConfigurationManager": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.4.0",
|
"resolved": "4.4.1",
|
||||||
"contentHash": "gWwQv/Ug1qWJmHCmN17nAbxJYmQBM/E94QxKLksvUiiKB1Ld3Sc/eK1lgmbSjDFxkQhVuayI/cGFZhpBSodLrg==",
|
"contentHash": "jz3TWKMAeuDEyrPCK5Jyt4bzQcmzUIMcY9Ud6PkElFxTfnsihV+9N/UCqvxe1z5gc7jMYAnj7V1COMS9QKIuHQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"System.Security.Cryptography.ProtectedData": "4.4.0"
|
"System.Security.Cryptography.ProtectedData": "4.4.0"
|
||||||
}
|
}
|
||||||
@ -1243,6 +1324,17 @@
|
|||||||
"System.Text.Encoding": "4.3.0"
|
"System.Text.Encoding": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.Data.SqlClient": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.2",
|
||||||
|
"contentHash": "Bv5J2EBAdP7FSgehKYN4O6iw1AaZrw4rFFqwt9vZSjRvC70FpwP2d9UG4aTaI2wh3vfrBKK+tjewowGM2Y6c1w==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Win32.Registry": "4.4.0",
|
||||||
|
"System.Security.Principal.Windows": "4.4.0",
|
||||||
|
"System.Text.Encoding.CodePages": "4.4.0",
|
||||||
|
"runtime.native.System.Data.SqlClient.sni": "4.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"System.Diagnostics.Debug": {
|
"System.Diagnostics.Debug": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -1755,27 +1847,6 @@
|
|||||||
"System.Runtime.Extensions": "4.3.0"
|
"System.Runtime.Extensions": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"System.Runtime.Serialization.Formatters": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "4.3.0",
|
|
||||||
"contentHash": "KT591AkTNFOTbhZlaeMVvfax3RqhH1EJlcwF50Wm7sfnBLuHiOeZRRKrr1ns3NESkM20KPZ5Ol/ueMq5vg4QoQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"System.Collections": "4.3.0",
|
|
||||||
"System.Reflection": "4.3.0",
|
|
||||||
"System.Resources.ResourceManager": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0",
|
|
||||||
"System.Runtime.Serialization.Primitives": "4.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"System.Runtime.Serialization.Primitives": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "4.3.0",
|
|
||||||
"contentHash": "Wz+0KOukJGAlXjtKr+5Xpuxf8+c8739RI1C+A2BoQZT+wMCCoMDDdO8/4IRHfaVINqL78GO8dW8G2lW/e45Mcw==",
|
|
||||||
"dependencies": {
|
|
||||||
"System.Resources.ResourceManager": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"System.Security.AccessControl": {
|
"System.Security.AccessControl": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "5.0.0",
|
"resolved": "5.0.0",
|
||||||
@ -1869,22 +1940,10 @@
|
|||||||
},
|
},
|
||||||
"System.Security.Cryptography.OpenSsl": {
|
"System.Security.Cryptography.OpenSsl": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.4.0",
|
||||||
"contentHash": "h4CEgOgv5PKVF/HwaHzJRiVboL2THYCou97zpmhjghx5frc7fIvlkY1jL+lnIQyChrJDMNEXS6r7byGif8Cy4w==",
|
"contentHash": "is11qLXIHKIvbTipyB1an8FT1ZKavmgf/qJUSIz7ZP830ALRRhPSt5NhplW0/wMk0tNDQWQLluVap6HsQN4HMg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"System.Collections": "4.3.0",
|
"Microsoft.NETCore.Platforms": "2.0.0"
|
||||||
"System.IO": "4.3.0",
|
|
||||||
"System.Resources.ResourceManager": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0",
|
|
||||||
"System.Runtime.Extensions": "4.3.0",
|
|
||||||
"System.Runtime.Handles": "4.3.0",
|
|
||||||
"System.Runtime.InteropServices": "4.3.0",
|
|
||||||
"System.Runtime.Numerics": "4.3.0",
|
|
||||||
"System.Security.Cryptography.Algorithms": "4.3.0",
|
|
||||||
"System.Security.Cryptography.Encoding": "4.3.0",
|
|
||||||
"System.Security.Cryptography.Primitives": "4.3.0",
|
|
||||||
"System.Text.Encoding": "4.3.0",
|
|
||||||
"runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"System.Security.Cryptography.Pkcs": {
|
"System.Security.Cryptography.Pkcs": {
|
||||||
@ -1988,6 +2047,14 @@
|
|||||||
"System.Runtime": "4.3.0"
|
"System.Runtime": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.Text.Encoding.CodePages": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "6JX7ZdaceBiLKLkYt8zJcp4xTJd1uYyXXEkPw6mnlUIjh1gZPIVKPtRXPmY5kLf6DwZmf5YLwR3QUrRonl7l0A==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.NETCore.Platforms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"System.Text.Encoding.Extensions": {
|
"System.Text.Encoding.Extensions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -2124,6 +2191,39 @@
|
|||||||
"System.Xml.ReaderWriter": "4.3.0"
|
"System.Xml.ReaderWriter": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.Xml.XPath": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.3.0",
|
||||||
|
"contentHash": "v1JQ5SETnQusqmS3RwStF7vwQ3L02imIzl++sewmt23VGygix04pEH+FCj1yWb+z4GDzKiljr1W7Wfvrx0YwgA==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Collections": "4.3.0",
|
||||||
|
"System.Diagnostics.Debug": "4.3.0",
|
||||||
|
"System.Globalization": "4.3.0",
|
||||||
|
"System.IO": "4.3.0",
|
||||||
|
"System.Resources.ResourceManager": "4.3.0",
|
||||||
|
"System.Runtime": "4.3.0",
|
||||||
|
"System.Runtime.Extensions": "4.3.0",
|
||||||
|
"System.Threading": "4.3.0",
|
||||||
|
"System.Xml.ReaderWriter": "4.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Xml.XPath.XmlDocument": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.3.0",
|
||||||
|
"contentHash": "A/uxsWi/Ifzkmd4ArTLISMbfFs6XpRPsXZonrIqyTY70xi8t+mDtvSM5Os0RqyRDobjMBwIDHDL4NOIbkDwf7A==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Collections": "4.3.0",
|
||||||
|
"System.Globalization": "4.3.0",
|
||||||
|
"System.IO": "4.3.0",
|
||||||
|
"System.Resources.ResourceManager": "4.3.0",
|
||||||
|
"System.Runtime": "4.3.0",
|
||||||
|
"System.Runtime.Extensions": "4.3.0",
|
||||||
|
"System.Threading": "4.3.0",
|
||||||
|
"System.Xml.ReaderWriter": "4.3.0",
|
||||||
|
"System.Xml.XPath": "4.3.0",
|
||||||
|
"System.Xml.XmlDocument": "4.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"TaskTupleAwaiter": {
|
"TaskTupleAwaiter": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "2.0.0",
|
"resolved": "2.0.0",
|
||||||
@ -2177,39 +2277,41 @@
|
|||||||
"apiservice": {
|
"apiservice": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "[1.25.0, )",
|
"Azure.Core": "1.25.0",
|
||||||
"Azure.Data.Tables": "[12.5.0, )",
|
"Azure.Data.Tables": "12.5.0",
|
||||||
"Azure.Identity": "[1.6.0, )",
|
"Azure.Identity": "1.6.0",
|
||||||
"Azure.Messaging.EventGrid": "[4.10.0, )",
|
"Azure.Messaging.EventGrid": "4.10.0",
|
||||||
"Azure.ResourceManager": "[1.3.1, )",
|
"Azure.ResourceManager": "1.3.1",
|
||||||
"Azure.ResourceManager.Compute": "[1.0.0-beta.8, )",
|
"Azure.ResourceManager.Compute": "1.0.0-beta.8",
|
||||||
"Azure.ResourceManager.Monitor": "[1.0.0-beta.2, )",
|
"Azure.ResourceManager.Monitor": "1.0.0-beta.2",
|
||||||
"Azure.ResourceManager.Network": "[1.0.0, )",
|
"Azure.ResourceManager.Network": "1.0.0",
|
||||||
"Azure.ResourceManager.Resources": "[1.3.0, )",
|
"Azure.ResourceManager.Resources": "1.3.0",
|
||||||
"Azure.ResourceManager.Storage": "[1.0.0-beta.11, )",
|
"Azure.ResourceManager.Storage": "1.0.0-beta.11",
|
||||||
"Azure.Security.KeyVault.Secrets": "[4.3.0, )",
|
"Azure.Security.KeyVault.Secrets": "4.3.0",
|
||||||
"Azure.Storage.Blobs": "[12.13.0, )",
|
"Azure.Storage.Blobs": "12.13.0",
|
||||||
"Azure.Storage.Queues": "[12.11.0, )",
|
"Azure.Storage.Queues": "12.11.0",
|
||||||
"Faithlife.Utility": "[0.12.2, )",
|
"Faithlife.Utility": "0.12.2",
|
||||||
"Microsoft.ApplicationInsights.DependencyCollector": "[2.21.0, )",
|
"Microsoft.ApplicationInsights.DependencyCollector": "2.21.0",
|
||||||
"Microsoft.Azure.Functions.Worker": "[1.6.0, )",
|
"Microsoft.Azure.Functions.Worker": "1.6.0",
|
||||||
"Microsoft.Azure.Functions.Worker.Extensions.EventGrid": "[2.1.0, )",
|
"Microsoft.Azure.Functions.Worker.Extensions.EventGrid": "2.1.0",
|
||||||
"Microsoft.Azure.Functions.Worker.Extensions.Http": "[3.0.13, )",
|
"Microsoft.Azure.Functions.Worker.Extensions.Http": "3.0.13",
|
||||||
"Microsoft.Azure.Functions.Worker.Extensions.SignalRService": "[1.7.0, )",
|
"Microsoft.Azure.Functions.Worker.Extensions.SignalRService": "1.7.0",
|
||||||
"Microsoft.Azure.Functions.Worker.Extensions.Storage": "[5.0.0, )",
|
"Microsoft.Azure.Functions.Worker.Extensions.Storage": "5.0.0",
|
||||||
"Microsoft.Azure.Functions.Worker.Extensions.Timer": "[4.1.0, )",
|
"Microsoft.Azure.Functions.Worker.Extensions.Timer": "4.1.0",
|
||||||
"Microsoft.Azure.Functions.Worker.Sdk": "[1.3.0, )",
|
"Microsoft.Azure.Functions.Worker.Sdk": "1.3.0",
|
||||||
"Microsoft.Azure.Management.Monitor": "[0.28.0-preview, )",
|
"Microsoft.Azure.Management.Monitor": "0.28.0-preview",
|
||||||
"Microsoft.Azure.Management.OperationalInsights": "[0.24.0-preview, )",
|
"Microsoft.Azure.Management.OperationalInsights": "0.24.0-preview",
|
||||||
"Microsoft.Extensions.Logging.ApplicationInsights": "[2.21.0, )",
|
"Microsoft.Extensions.Logging.ApplicationInsights": "2.21.0",
|
||||||
"Microsoft.Graph": "[4.37.0, )",
|
"Microsoft.Graph": "4.37.0",
|
||||||
"Microsoft.Identity.Client": "[4.46.2, )",
|
"Microsoft.Identity.Client": "4.46.2",
|
||||||
"Microsoft.Identity.Web.TokenCache": "[1.23.1, )",
|
"Microsoft.Identity.Web.TokenCache": "1.23.1",
|
||||||
"Scriban": "[5.5.0, )",
|
"Microsoft.TeamFoundationServer.Client": "19.209.0-preview",
|
||||||
"Semver": "[2.1.0, )",
|
"Octokit": "2.0.1",
|
||||||
"System.IdentityModel.Tokens.Jwt": "[6.22.1, )",
|
"Scriban": "5.5.0",
|
||||||
"System.Linq.Async": "[6.0.1, )",
|
"Semver": "2.1.0",
|
||||||
"TaskTupleAwaiter": "[2.0.0, )"
|
"System.IdentityModel.Tokens.Jwt": "6.22.1",
|
||||||
|
"System.Linq.Async": "6.0.1",
|
||||||
|
"TaskTupleAwaiter": "2.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,11 +368,87 @@ namespace Tests {
|
|||||||
where Container.TryParse(nameString, out var _)
|
where Container.TryParse(nameString, out var _)
|
||||||
select Container.Parse(nameString);
|
select Container.Parse(nameString);
|
||||||
|
|
||||||
|
public static Gen<ADODuplicateTemplate> AdoDuplicateTemplate() {
|
||||||
|
return Arb.Generate<Tuple<List<string>, Dictionary<string, string>, string?>>().Select(
|
||||||
|
arg =>
|
||||||
|
new ADODuplicateTemplate(
|
||||||
|
arg.Item1,
|
||||||
|
arg.Item2,
|
||||||
|
arg.Item2,
|
||||||
|
arg.Item3
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Gen<AdoTemplate> AdoTemplate() {
|
||||||
|
return Arb.Generate<Tuple<Uri, SecretData<string>, NonEmptyString, List<string>, Dictionary<string, string>, ADODuplicateTemplate, string?>>().Select(
|
||||||
|
arg =>
|
||||||
|
new AdoTemplate(
|
||||||
|
arg.Item1,
|
||||||
|
arg.Item2,
|
||||||
|
arg.Item3.Item,
|
||||||
|
arg.Item3.Item,
|
||||||
|
arg.Item4,
|
||||||
|
arg.Item5,
|
||||||
|
AdoDuplicateTemplate().Sample(1, 1).First(),
|
||||||
|
arg.Item7
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Gen<TeamsTemplate> TeamsTemplate() {
|
||||||
|
return Arb.Generate<Tuple<SecretData<string>>>().Select(
|
||||||
|
arg =>
|
||||||
|
new TeamsTemplate(
|
||||||
|
arg.Item1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Gen<GithubAuth> GithubAuth() {
|
||||||
|
return Arb.Generate<Tuple<string>>().Select(
|
||||||
|
arg =>
|
||||||
|
new GithubAuth(
|
||||||
|
arg.Item1,
|
||||||
|
arg.Item1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Gen<GithubIssueSearch> GithubIssueSearch() {
|
||||||
|
return Arb.Generate<Tuple<List<GithubIssueSearchMatch>, string, string?, GithubIssueState?>>().Select(
|
||||||
|
arg =>
|
||||||
|
new GithubIssueSearch(
|
||||||
|
arg.Item1,
|
||||||
|
arg.Item2,
|
||||||
|
arg.Item3,
|
||||||
|
arg.Item4
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Gen<GithubIssuesTemplate> GithubIssuesTemplate() {
|
||||||
|
return Arb.Generate<Tuple<SecretData<GithubAuth>, NonEmptyString, GithubIssueSearch, List<string>, GithubIssueDuplicate>>().Select(
|
||||||
|
arg =>
|
||||||
|
new GithubIssuesTemplate(
|
||||||
|
arg.Item1,
|
||||||
|
arg.Item2.Item,
|
||||||
|
arg.Item2.Item,
|
||||||
|
arg.Item2.Item,
|
||||||
|
arg.Item2.Item,
|
||||||
|
arg.Item3,
|
||||||
|
arg.Item4,
|
||||||
|
arg.Item4,
|
||||||
|
arg.Item5
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static Gen<NotificationTemplate> NotificationTemplate() {
|
public static Gen<NotificationTemplate> NotificationTemplate() {
|
||||||
return Gen.OneOf(new[] {
|
return Gen.OneOf(new[] {
|
||||||
Arb.Generate<AdoTemplate>().Select(e => e as NotificationTemplate),
|
AdoTemplate().Select(a => a as NotificationTemplate),
|
||||||
Arb.Generate<TeamsTemplate>().Select(e => e as NotificationTemplate),
|
TeamsTemplate().Select(e => e as NotificationTemplate),
|
||||||
Arb.Generate<GithubIssuesTemplate>().Select(e => e as NotificationTemplate)
|
GithubIssuesTemplate().Select(e => e as NotificationTemplate)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1006,17 +1082,15 @@ namespace Tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
//Sample function on how repro a failing test run, using Replay
|
//Sample function on how repro a failing test run, using Replay
|
||||||
//functionality of FsCheck. Feel free to
|
//functionality of FsCheck. Feel free to
|
||||||
[Property]
|
[Property]
|
||||||
void Replay()
|
void Replay() {
|
||||||
{
|
var seed = FsCheck.Random.StdGen.NewStdGen(811038773, 297085737);
|
||||||
var seed = FsCheck.Random.StdGen.NewStdGen(4570702, 297027754);
|
var p = Prop.ForAll((NotificationTemplate x) => NotificationTemplate(x));
|
||||||
var p = Prop.ForAll((WebhookMessageEventGrid x) => WebhookMessageEventGrid(x) );
|
|
||||||
p.Check(new Configuration { Replay = seed });
|
p.Check(new Configuration { Replay = seed });
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Json;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Microsoft.OneFuzz.Service;
|
using Microsoft.OneFuzz.Service;
|
||||||
|
using Microsoft.OneFuzz.Service.OneFuzzLib.Orm;
|
||||||
using Scriban;
|
using Scriban;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -115,6 +117,19 @@ public class TemplateTests {
|
|||||||
output.Should().NotContainAny(report.CallStack);
|
output.Should().NotContainAny(report.CallStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TemplatesShouldDeserializeAppropriately() {
|
||||||
|
var teamsTemplate = @"{""url"": {""secret"": {""url"": ""https://example.com""}}}";
|
||||||
|
var template = JsonSerializer.Deserialize<NotificationTemplate>(teamsTemplate, EntityConverter.GetJsonSerializerOptions());
|
||||||
|
var a = template is AdoTemplate;
|
||||||
|
var t = template is TeamsTemplate;
|
||||||
|
var g = template is GithubIssuesTemplate;
|
||||||
|
|
||||||
|
a.Should().BeFalse();
|
||||||
|
t.Should().BeTrue();
|
||||||
|
g.Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
private static Report GetReport() {
|
private static Report GetReport() {
|
||||||
return new Report(
|
return new Report(
|
||||||
"https://example.com",
|
"https://example.com",
|
||||||
|
@ -330,6 +330,15 @@
|
|||||||
"System.Diagnostics.DiagnosticSource": "5.0.0"
|
"System.Diagnostics.DiagnosticSource": "5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.AspNet.WebApi.Client": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "5.2.7",
|
||||||
|
"contentHash": "/76fAHknzvFqbznS6Uj2sOyE9rJB3PltY+f53TH8dX9RiGhk02EhuFCWljSj5nnqKaTsmma8DFR50OGyQ4yJ1g==",
|
||||||
|
"dependencies": {
|
||||||
|
"Newtonsoft.Json": "10.0.1",
|
||||||
|
"Newtonsoft.Json.Bson": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.AspNetCore.Cryptography.Internal": {
|
"Microsoft.AspNetCore.Cryptography.Internal": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "5.0.8",
|
"resolved": "5.0.8",
|
||||||
@ -927,6 +936,26 @@
|
|||||||
"Newtonsoft.Json": "10.0.3"
|
"Newtonsoft.Json": "10.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.TeamFoundation.DistributedTask.Common.Contracts": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "19.209.0-preview",
|
||||||
|
"contentHash": "32lLZPU8pZg+mVfA2smHso6fhWPSFXJPPyawvOFsFoNz9Yj5y2fsAR7O4zPwE3c/z2zzi8BMfiXRKOcbW6cdIg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.VisualStudio.Services.Client": "[19.209.0-preview]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.TeamFoundationServer.Client": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "19.209.0-preview",
|
||||||
|
"contentHash": "dglVgITWfsps8pWA//2mBGVt/keD3UGdAVBXd50k9nVZiThUwWnaAoUzRf4fay/avLGXdvfkz6x9dBf6zGtfxg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.AspNet.WebApi.Client": "5.2.7",
|
||||||
|
"Microsoft.TeamFoundation.DistributedTask.Common.Contracts": "[19.209.0-preview]",
|
||||||
|
"Microsoft.VisualStudio.Services.Client": "[19.209.0-preview]",
|
||||||
|
"Newtonsoft.Json": "12.0.3",
|
||||||
|
"System.ComponentModel.Annotations": "4.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.TestPlatform.ObjectModel": {
|
"Microsoft.TestPlatform.ObjectModel": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "17.1.0",
|
"resolved": "17.1.0",
|
||||||
@ -945,6 +974,22 @@
|
|||||||
"Newtonsoft.Json": "9.0.1"
|
"Newtonsoft.Json": "9.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.VisualStudio.Services.Client": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "19.209.0-preview",
|
||||||
|
"contentHash": "eQWZb5BhtOgywARvfHGGZsYuuZvFmJiXyE7P/EqKTLUplrUFmSVxo0J/KUC8GWJWmdarxH2vXZTAz9uW7BwRDQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.AspNet.WebApi.Client": "5.2.7",
|
||||||
|
"Newtonsoft.Json": "12.0.3",
|
||||||
|
"System.Configuration.ConfigurationManager": "4.4.1",
|
||||||
|
"System.Data.SqlClient": "4.4.2",
|
||||||
|
"System.Security.Cryptography.Cng": "4.4.0",
|
||||||
|
"System.Security.Cryptography.OpenSsl": "4.4.0",
|
||||||
|
"System.Security.Cryptography.ProtectedData": "4.4.0",
|
||||||
|
"System.Security.Principal.Windows": "4.4.1",
|
||||||
|
"System.Xml.XPath.XmlDocument": "4.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Win32.Primitives": {
|
"Microsoft.Win32.Primitives": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -1025,15 +1070,16 @@
|
|||||||
},
|
},
|
||||||
"Newtonsoft.Json": {
|
"Newtonsoft.Json": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "10.0.3",
|
"resolved": "12.0.3",
|
||||||
"contentHash": "hSXaFmh7hNCuEoC4XNY5DrRkLDzYHqPx/Ik23R4J86Z7PE/Y6YidhG602dFVdLBRSdG6xp9NabH3dXpcoxWvww==",
|
"contentHash": "6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg=="
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json.Bson": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "1.0.1",
|
||||||
|
"contentHash": "5PYT/IqQ+UK31AmZiSS102R6EsTo+LGTSI8bp7WAUqDKaF4wHXD8U9u4WxTI1vc64tYi++8p3dk3WWNqPFgldw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.CSharp": "4.3.0",
|
|
||||||
"NETStandard.Library": "1.6.1",
|
"NETStandard.Library": "1.6.1",
|
||||||
"System.ComponentModel.TypeConverter": "4.3.0",
|
"Newtonsoft.Json": "10.0.1"
|
||||||
"System.Runtime.Serialization.Formatters": "4.3.0",
|
|
||||||
"System.Runtime.Serialization.Primitives": "4.3.0",
|
|
||||||
"System.Xml.XmlDocument": "4.3.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"NuGet.Frameworks": {
|
"NuGet.Frameworks": {
|
||||||
@ -1041,6 +1087,11 @@
|
|||||||
"resolved": "5.11.0",
|
"resolved": "5.11.0",
|
||||||
"contentHash": "eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q=="
|
"contentHash": "eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q=="
|
||||||
},
|
},
|
||||||
|
"Octokit": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "2.0.1",
|
||||||
|
"contentHash": "JVlfUY+sfItl6RSyVKDJTutuy28cDydUwKKfzcelwNMor2Sa18pYVKna6phO8lug1b+ep+pcuFh/FPayuImsQw=="
|
||||||
|
},
|
||||||
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
|
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.2",
|
"resolved": "4.3.2",
|
||||||
@ -1065,6 +1116,16 @@
|
|||||||
"Microsoft.NETCore.Targets": "1.1.0"
|
"Microsoft.NETCore.Targets": "1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"runtime.native.System.Data.SqlClient.sni": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "A8v6PGmk+UGbfWo5Ixup0lPM4swuSwOiayJExZwKIOjTlFFQIsu3QnDXECosBEyrWSPryxBVrdqtJyhK3BaupQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"runtime.win-arm64.runtime.native.System.Data.SqlClient.sni": "4.4.0",
|
||||||
|
"runtime.win-x64.runtime.native.System.Data.SqlClient.sni": "4.4.0",
|
||||||
|
"runtime.win-x86.runtime.native.System.Data.SqlClient.sni": "4.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"runtime.native.System.IO.Compression": {
|
"runtime.native.System.IO.Compression": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -1148,6 +1209,21 @@
|
|||||||
"resolved": "4.3.2",
|
"resolved": "4.3.2",
|
||||||
"contentHash": "leXiwfiIkW7Gmn7cgnNcdtNAU70SjmKW3jxGj1iKHOvdn0zRWsgv/l2OJUO5zdGdiv2VRFnAsxxhDgMzofPdWg=="
|
"contentHash": "leXiwfiIkW7Gmn7cgnNcdtNAU70SjmKW3jxGj1iKHOvdn0zRWsgv/l2OJUO5zdGdiv2VRFnAsxxhDgMzofPdWg=="
|
||||||
},
|
},
|
||||||
|
"runtime.win-arm64.runtime.native.System.Data.SqlClient.sni": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "LbrynESTp3bm5O/+jGL8v0Qg5SJlTV08lpIpFesXjF6uGNMWqFnUQbYBJwZTeua6E/Y7FIM1C54Ey1btLWupdg=="
|
||||||
|
},
|
||||||
|
"runtime.win-x64.runtime.native.System.Data.SqlClient.sni": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "38ugOfkYJqJoX9g6EYRlZB5U2ZJH51UP8ptxZgdpS07FgOEToV+lS11ouNK2PM12Pr6X/PpT5jK82G3DwH/SxQ=="
|
||||||
|
},
|
||||||
|
"runtime.win-x86.runtime.native.System.Data.SqlClient.sni": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA=="
|
||||||
|
},
|
||||||
"Scriban": {
|
"Scriban": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "5.5.0",
|
"resolved": "5.5.0",
|
||||||
@ -1240,6 +1316,11 @@
|
|||||||
"System.Runtime": "4.3.0"
|
"System.Runtime": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.ComponentModel.Annotations": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.1",
|
||||||
|
"contentHash": "ToiYqSCioqhtspq2O/jYKtyTC/T0uwWHBTYlzCi6PRbSSHArN1IaRWeHffDamvms5sye5FDUWCfNZgubQpNRsA=="
|
||||||
|
},
|
||||||
"System.ComponentModel.Primitives": {
|
"System.ComponentModel.Primitives": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -1274,8 +1355,8 @@
|
|||||||
},
|
},
|
||||||
"System.Configuration.ConfigurationManager": {
|
"System.Configuration.ConfigurationManager": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.4.0",
|
"resolved": "4.4.1",
|
||||||
"contentHash": "gWwQv/Ug1qWJmHCmN17nAbxJYmQBM/E94QxKLksvUiiKB1Ld3Sc/eK1lgmbSjDFxkQhVuayI/cGFZhpBSodLrg==",
|
"contentHash": "jz3TWKMAeuDEyrPCK5Jyt4bzQcmzUIMcY9Ud6PkElFxTfnsihV+9N/UCqvxe1z5gc7jMYAnj7V1COMS9QKIuHQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"System.Security.Cryptography.ProtectedData": "4.4.0"
|
"System.Security.Cryptography.ProtectedData": "4.4.0"
|
||||||
}
|
}
|
||||||
@ -1292,6 +1373,17 @@
|
|||||||
"System.Text.Encoding": "4.3.0"
|
"System.Text.Encoding": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.Data.SqlClient": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.2",
|
||||||
|
"contentHash": "Bv5J2EBAdP7FSgehKYN4O6iw1AaZrw4rFFqwt9vZSjRvC70FpwP2d9UG4aTaI2wh3vfrBKK+tjewowGM2Y6c1w==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Win32.Registry": "4.4.0",
|
||||||
|
"System.Security.Principal.Windows": "4.4.0",
|
||||||
|
"System.Text.Encoding.CodePages": "4.4.0",
|
||||||
|
"runtime.native.System.Data.SqlClient.sni": "4.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"System.Diagnostics.Debug": {
|
"System.Diagnostics.Debug": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -1850,27 +1942,6 @@
|
|||||||
"System.Runtime.Extensions": "4.3.0"
|
"System.Runtime.Extensions": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"System.Runtime.Serialization.Formatters": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "4.3.0",
|
|
||||||
"contentHash": "KT591AkTNFOTbhZlaeMVvfax3RqhH1EJlcwF50Wm7sfnBLuHiOeZRRKrr1ns3NESkM20KPZ5Ol/ueMq5vg4QoQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"System.Collections": "4.3.0",
|
|
||||||
"System.Reflection": "4.3.0",
|
|
||||||
"System.Resources.ResourceManager": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0",
|
|
||||||
"System.Runtime.Serialization.Primitives": "4.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"System.Runtime.Serialization.Primitives": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "4.3.0",
|
|
||||||
"contentHash": "Wz+0KOukJGAlXjtKr+5Xpuxf8+c8739RI1C+A2BoQZT+wMCCoMDDdO8/4IRHfaVINqL78GO8dW8G2lW/e45Mcw==",
|
|
||||||
"dependencies": {
|
|
||||||
"System.Resources.ResourceManager": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"System.Security.AccessControl": {
|
"System.Security.AccessControl": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "5.0.0",
|
"resolved": "5.0.0",
|
||||||
@ -1964,22 +2035,10 @@
|
|||||||
},
|
},
|
||||||
"System.Security.Cryptography.OpenSsl": {
|
"System.Security.Cryptography.OpenSsl": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.4.0",
|
||||||
"contentHash": "h4CEgOgv5PKVF/HwaHzJRiVboL2THYCou97zpmhjghx5frc7fIvlkY1jL+lnIQyChrJDMNEXS6r7byGif8Cy4w==",
|
"contentHash": "is11qLXIHKIvbTipyB1an8FT1ZKavmgf/qJUSIz7ZP830ALRRhPSt5NhplW0/wMk0tNDQWQLluVap6HsQN4HMg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"System.Collections": "4.3.0",
|
"Microsoft.NETCore.Platforms": "2.0.0"
|
||||||
"System.IO": "4.3.0",
|
|
||||||
"System.Resources.ResourceManager": "4.3.0",
|
|
||||||
"System.Runtime": "4.3.0",
|
|
||||||
"System.Runtime.Extensions": "4.3.0",
|
|
||||||
"System.Runtime.Handles": "4.3.0",
|
|
||||||
"System.Runtime.InteropServices": "4.3.0",
|
|
||||||
"System.Runtime.Numerics": "4.3.0",
|
|
||||||
"System.Security.Cryptography.Algorithms": "4.3.0",
|
|
||||||
"System.Security.Cryptography.Encoding": "4.3.0",
|
|
||||||
"System.Security.Cryptography.Primitives": "4.3.0",
|
|
||||||
"System.Text.Encoding": "4.3.0",
|
|
||||||
"runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"System.Security.Cryptography.Pkcs": {
|
"System.Security.Cryptography.Pkcs": {
|
||||||
@ -2083,6 +2142,14 @@
|
|||||||
"System.Runtime": "4.3.0"
|
"System.Runtime": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.Text.Encoding.CodePages": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.0",
|
||||||
|
"contentHash": "6JX7ZdaceBiLKLkYt8zJcp4xTJd1uYyXXEkPw6mnlUIjh1gZPIVKPtRXPmY5kLf6DwZmf5YLwR3QUrRonl7l0A==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.NETCore.Platforms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"System.Text.Encoding.Extensions": {
|
"System.Text.Encoding.Extensions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@ -2251,6 +2318,39 @@
|
|||||||
"System.Xml.ReaderWriter": "4.3.0"
|
"System.Xml.ReaderWriter": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.Xml.XPath": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.3.0",
|
||||||
|
"contentHash": "v1JQ5SETnQusqmS3RwStF7vwQ3L02imIzl++sewmt23VGygix04pEH+FCj1yWb+z4GDzKiljr1W7Wfvrx0YwgA==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Collections": "4.3.0",
|
||||||
|
"System.Diagnostics.Debug": "4.3.0",
|
||||||
|
"System.Globalization": "4.3.0",
|
||||||
|
"System.IO": "4.3.0",
|
||||||
|
"System.Resources.ResourceManager": "4.3.0",
|
||||||
|
"System.Runtime": "4.3.0",
|
||||||
|
"System.Runtime.Extensions": "4.3.0",
|
||||||
|
"System.Threading": "4.3.0",
|
||||||
|
"System.Xml.ReaderWriter": "4.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Xml.XPath.XmlDocument": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.3.0",
|
||||||
|
"contentHash": "A/uxsWi/Ifzkmd4ArTLISMbfFs6XpRPsXZonrIqyTY70xi8t+mDtvSM5Os0RqyRDobjMBwIDHDL4NOIbkDwf7A==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Collections": "4.3.0",
|
||||||
|
"System.Globalization": "4.3.0",
|
||||||
|
"System.IO": "4.3.0",
|
||||||
|
"System.Resources.ResourceManager": "4.3.0",
|
||||||
|
"System.Runtime": "4.3.0",
|
||||||
|
"System.Runtime.Extensions": "4.3.0",
|
||||||
|
"System.Threading": "4.3.0",
|
||||||
|
"System.Xml.ReaderWriter": "4.3.0",
|
||||||
|
"System.Xml.XPath": "4.3.0",
|
||||||
|
"System.Xml.XmlDocument": "4.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"TaskTupleAwaiter": {
|
"TaskTupleAwaiter": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "2.0.0",
|
"resolved": "2.0.0",
|
||||||
@ -2304,39 +2404,41 @@
|
|||||||
"apiservice": {
|
"apiservice": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Azure.Core": "[1.25.0, )",
|
"Azure.Core": "1.25.0",
|
||||||
"Azure.Data.Tables": "[12.5.0, )",
|
"Azure.Data.Tables": "12.5.0",
|
||||||
"Azure.Identity": "[1.6.0, )",
|
"Azure.Identity": "1.6.0",
|
||||||
"Azure.Messaging.EventGrid": "[4.10.0, )",
|
"Azure.Messaging.EventGrid": "4.10.0",
|
||||||
"Azure.ResourceManager": "[1.3.1, )",
|
"Azure.ResourceManager": "1.3.1",
|
||||||
"Azure.ResourceManager.Compute": "[1.0.0-beta.8, )",
|
"Azure.ResourceManager.Compute": "1.0.0-beta.8",
|
||||||
"Azure.ResourceManager.Monitor": "[1.0.0-beta.2, )",
|
"Azure.ResourceManager.Monitor": "1.0.0-beta.2",
|
||||||
"Azure.ResourceManager.Network": "[1.0.0, )",
|
"Azure.ResourceManager.Network": "1.0.0",
|
||||||
"Azure.ResourceManager.Resources": "[1.3.0, )",
|
"Azure.ResourceManager.Resources": "1.3.0",
|
||||||
"Azure.ResourceManager.Storage": "[1.0.0-beta.11, )",
|
"Azure.ResourceManager.Storage": "1.0.0-beta.11",
|
||||||
"Azure.Security.KeyVault.Secrets": "[4.3.0, )",
|
"Azure.Security.KeyVault.Secrets": "4.3.0",
|
||||||
"Azure.Storage.Blobs": "[12.13.0, )",
|
"Azure.Storage.Blobs": "12.13.0",
|
||||||
"Azure.Storage.Queues": "[12.11.0, )",
|
"Azure.Storage.Queues": "12.11.0",
|
||||||
"Faithlife.Utility": "[0.12.2, )",
|
"Faithlife.Utility": "0.12.2",
|
||||||
"Microsoft.ApplicationInsights.DependencyCollector": "[2.21.0, )",
|
"Microsoft.ApplicationInsights.DependencyCollector": "2.21.0",
|
||||||
"Microsoft.Azure.Functions.Worker": "[1.6.0, )",
|
"Microsoft.Azure.Functions.Worker": "1.6.0",
|
||||||
"Microsoft.Azure.Functions.Worker.Extensions.EventGrid": "[2.1.0, )",
|
"Microsoft.Azure.Functions.Worker.Extensions.EventGrid": "2.1.0",
|
||||||
"Microsoft.Azure.Functions.Worker.Extensions.Http": "[3.0.13, )",
|
"Microsoft.Azure.Functions.Worker.Extensions.Http": "3.0.13",
|
||||||
"Microsoft.Azure.Functions.Worker.Extensions.SignalRService": "[1.7.0, )",
|
"Microsoft.Azure.Functions.Worker.Extensions.SignalRService": "1.7.0",
|
||||||
"Microsoft.Azure.Functions.Worker.Extensions.Storage": "[5.0.0, )",
|
"Microsoft.Azure.Functions.Worker.Extensions.Storage": "5.0.0",
|
||||||
"Microsoft.Azure.Functions.Worker.Extensions.Timer": "[4.1.0, )",
|
"Microsoft.Azure.Functions.Worker.Extensions.Timer": "4.1.0",
|
||||||
"Microsoft.Azure.Functions.Worker.Sdk": "[1.3.0, )",
|
"Microsoft.Azure.Functions.Worker.Sdk": "1.3.0",
|
||||||
"Microsoft.Azure.Management.Monitor": "[0.28.0-preview, )",
|
"Microsoft.Azure.Management.Monitor": "0.28.0-preview",
|
||||||
"Microsoft.Azure.Management.OperationalInsights": "[0.24.0-preview, )",
|
"Microsoft.Azure.Management.OperationalInsights": "0.24.0-preview",
|
||||||
"Microsoft.Extensions.Logging.ApplicationInsights": "[2.21.0, )",
|
"Microsoft.Extensions.Logging.ApplicationInsights": "2.21.0",
|
||||||
"Microsoft.Graph": "[4.37.0, )",
|
"Microsoft.Graph": "4.37.0",
|
||||||
"Microsoft.Identity.Client": "[4.46.2, )",
|
"Microsoft.Identity.Client": "4.46.2",
|
||||||
"Microsoft.Identity.Web.TokenCache": "[1.23.1, )",
|
"Microsoft.Identity.Web.TokenCache": "1.23.1",
|
||||||
"Scriban": "[5.5.0, )",
|
"Microsoft.TeamFoundationServer.Client": "19.209.0-preview",
|
||||||
"Semver": "[2.1.0, )",
|
"Octokit": "2.0.1",
|
||||||
"System.IdentityModel.Tokens.Jwt": "[6.22.1, )",
|
"Scriban": "5.5.0",
|
||||||
"System.Linq.Async": "[6.0.1, )",
|
"Semver": "2.1.0",
|
||||||
"TaskTupleAwaiter": "[2.0.0, )"
|
"System.IdentityModel.Tokens.Jwt": "6.22.1",
|
||||||
|
"System.Linq.Async": "6.0.1",
|
||||||
|
"TaskTupleAwaiter": "2.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user