Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# erdserteer ertt
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"appService.preDeployTask": "publish-release",
"appService.deploySubpath": "bin/Release/net9.0/publish"
"appService.deploySubpath": "bin/Release/net9.0/publish",
"codeQL.createQuery.qlPackLocation": "c:\\Users\\jomyburg\\OneDrive - Microsoft\\Documents\\Content\\repos\\AzureIntegration"
}
10 changes: 6 additions & 4 deletions AzureIntegration.csproj
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
</PropertyGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.1" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.67.2" />
</ItemGroup>

<ItemGroup>
<Compile Remove="Controllers\ResourceGroupsControllerTest.cs" />
</ItemGroup>

</Project>
24 changes: 24 additions & 0 deletions AzureResourceGroups.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Azure Subscriptions and Resource Groups

## PROD Subscription

**ID:** fe040da2-5247-41cd-a8d7-3755d235fda7

| Resource Group | Location |
| ------------------------- | ------------- |
| AI | swedencentral |
| DefaultResourceGroup-SUK | uksouth |
| Default-ActivityLogAlerts | eastus |
| alwayson | eastus |

---

## DEV Subscription

**ID:** cd2a8d75-0982-4292-be56-6142df44c75f

| Resource Group | Location |
| ------------------------- | -------- |
| AlwaysOn | uksouth |
| IoT | uksouth |
| Default-ActivityLogAlerts | eastus |
206 changes: 206 additions & 0 deletions Controllers/ResourceGroupsControllerTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
using AzureIntegration.Controllers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Moq;
using Moq.Protected;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace AzureIntegration.Tests.Controllers
{
public class ResourceGroupsControllerTest
{
private readonly Mock<IHttpClientFactory> _mockHttpClientFactory;
private readonly Mock<IConfiguration> _mockConfiguration;

public ResourceGroupsControllerTest()
{
_mockHttpClientFactory = new Mock<IHttpClientFactory>();
_mockConfiguration = new Mock<IConfiguration>();
}

[Fact]
public async Task GetAzureManagementGroups_ReturnsManagementGroups_WhenApiCallSucceeds()
{
// Arrange
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
var response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(@"
{
""value"": [
{
""id"": ""/providers/Microsoft.Management/managementGroups/mg1"",
""type"": ""Microsoft.Management/managementGroups"",
""properties"": {
""displayName"": ""Management Group 1""
}
},
{
""id"": ""/providers/Microsoft.Management/managementGroups/mg2"",
""type"": ""Microsoft.Management/managementGroups"",
""properties"": {
""displayName"": ""Management Group 2""
}
}
]
}")
};

mockHttpMessageHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(response);

var httpClient = new HttpClient(mockHttpMessageHandler.Object);
_mockHttpClientFactory
.Setup(factory => factory.CreateClient("AzureServices"))
.Returns(httpClient);

var controller = new ResourceGroupsController(_mockHttpClientFactory.Object, _mockConfiguration.Object);

// Act
var result = await controller.ManagementGroups();

// Assert
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsAssignableFrom<List<AzureManagementGroup>>(viewResult.Model);
Assert.Equal(2, model.Count);
Assert.Equal("Management Group 1", model[0].Name);
Assert.Equal("/providers/Microsoft.Management/managementGroups/mg1", model[0].Id);
Assert.Equal("Microsoft.Management/managementGroups", model[0].Type);
Assert.Equal("Management Group 2", model[1].Name);
}

[Fact]
public async Task GetAzureManagementGroups_ReturnsEmptyList_WhenNoValuePropertyInResponse()
{
// Arrange
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
var response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(@"{ ""someOtherProperty"": [] }")
};

mockHttpMessageHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(response);

var httpClient = new HttpClient(mockHttpMessageHandler.Object);
_mockHttpClientFactory
.Setup(factory => factory.CreateClient("AzureServices"))
.Returns(httpClient);

var controller = new ResourceGroupsController(_mockHttpClientFactory.Object, _mockConfiguration.Object);

// Act
var result = await controller.ManagementGroups();

// Assert
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsAssignableFrom<List<AzureManagementGroup>>(viewResult.Model);
Assert.Empty(model);
}

[Fact]
public async Task GetAzureManagementGroups_HandlesNullValues_InResponseProperties()
{
// Arrange
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
var response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(@"
{
""value"": [
{
""id"": null,
""type"": null,
""properties"": {
""displayName"": null
}
}
]
}")
};

mockHttpMessageHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(response);

var httpClient = new HttpClient(mockHttpMessageHandler.Object);
_mockHttpClientFactory
.Setup(factory => factory.CreateClient("AzureServices"))
.Returns(httpClient);

var controller = new ResourceGroupsController(_mockHttpClientFactory.Object, _mockConfiguration.Object);

// Act
var result = await controller.ManagementGroups();

// Assert
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsAssignableFrom<List<AzureManagementGroup>>(viewResult.Model);
Assert.Single(model);
Assert.Equal(string.Empty, model[0].Name);
Assert.Equal(string.Empty, model[0].Id);
Assert.Equal(string.Empty, model[0].Type);
}

[Fact]
public async Task GetAzureManagementGroups_CallsCorrectEndpoint()
{
// Arrange
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
HttpRequestMessage capturedRequest = null;

mockHttpMessageHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.Callback<HttpRequestMessage, CancellationToken>((request, _) => capturedRequest = request)
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(@"{ ""value"": [] }")
});

var httpClient = new HttpClient(mockHttpMessageHandler.Object);
_mockHttpClientFactory
.Setup(factory => factory.CreateClient("AzureServices"))
.Returns(httpClient);

var controller = new ResourceGroupsController(_mockHttpClientFactory.Object, _mockConfiguration.Object);

// Act
await controller.ManagementGroups();

// Assert
Assert.NotNull(capturedRequest);
Assert.Equal(HttpMethod.Get, capturedRequest.Method);
Assert.Equal("providers/Microsoft.Management/managementGroups?api-version=2020-05-01",
capturedRequest.RequestUri.ToString());
}
}
}
2 changes: 1 addition & 1 deletion Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
// Register the HTTP client
builder.Services.AddHttpClient();

builder.Services.AddSingleton(new Subscription(subscriptionId));
builder.Services.AddSingleton(new Subscription(subscriptionId ?? throw new InvalidOperationException("SubscriptionId is required")));
// Register the configuration
builder.Services.AddSingleton<IConfiguration>(builder.Configuration);
builder.Services.AddDistributedMemoryCache();
Expand Down
27 changes: 27 additions & 0 deletions Views/Shared/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,37 @@
&copy; 2025 - AzureIntegration - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>

<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>

<script type="text/javascript" src="https://js.monitor.azure.com/scripts/b/ext/ai.clck.2.min.js"></script>
<script type="text/javascript">
var clickPluginInstance = new Microsoft.ApplicationInsights.ClickAnalyticsPlugin();
// Click Analytics configuration
var clickPluginConfig = {
autoCapture: true,
dataTags: {
useDefaultContentNameOrId: true
}
}
// Application Insights configuration
var configObj = {
//connectionString: "YOUR_CONNECTION_STRING",
// Alternatively, you can pass in the instrumentation key,
// but support for instrumentation key ingestion will end on March 31, 2025.
instrumentationKey: "14532cba-f01d-4cab-8c27-2f353bcd2707",
extensions: [
clickPluginInstance
],
extensionConfig: { [clickPluginInstance.identifier]: clickPluginConfig
},
};
// Application Insights tracking removed for demo
</script>
@await RenderSectionAsync("Scripts", required: false)

</body>

</html>
24 changes: 24 additions & 0 deletions codeql-custom-queries-csharp/codeql-pack.lock.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
lockVersion: 1.0.0
dependencies:
codeql/controlflow:
version: 2.0.23
codeql/csharp-all:
version: 5.4.4
codeql/dataflow:
version: 2.0.23
codeql/mad:
version: 1.0.39
codeql/ssa:
version: 2.0.15
codeql/threat-models:
version: 1.0.39
codeql/tutorial:
version: 1.0.39
codeql/typetracking:
version: 2.0.23
codeql/util:
version: 2.0.26
codeql/xml:
version: 1.0.39
compiled: false
7 changes: 7 additions & 0 deletions codeql-custom-queries-csharp/codeql-pack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
library: false
warnOnImplicitThis: false
name: getting-started/codeql-extra-queries-csharp
version: 1.0.0
dependencies:
codeql/csharp-all: ^5.4.4
12 changes: 12 additions & 0 deletions codeql-custom-queries-csharp/example.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* This is an automatically generated file
* @name Hello world
* @kind problem
* @problem.severity warning
* @id csharp/example/hello-world
*/

import csharp

from File f
select f, "Hello, world!"