diff --git a/.github/workflows/build-and-push-image.yml b/.github/workflows/build-and-push-image.yml index edf78ea8d..d8b2449ab 100644 --- a/.github/workflows/build-and-push-image.yml +++ b/.github/workflows/build-and-push-image.yml @@ -91,7 +91,7 @@ jobs: git push origin ${{ needs.set-env.outputs.release }} - name: Create release - uses: "actions/github-script@v6" + uses: "actions/github-script@v7" with: github-token: "${{ secrets.GITHUB_TOKEN }}" script: | @@ -149,7 +149,7 @@ jobs: ref: ${{ github.ref }} - name: Setup node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} diff --git a/.github/workflows/continuous-integration-dotnet.yml b/.github/workflows/continuous-integration-dotnet.yml index f02a9c0f4..06b9f80e0 100644 --- a/.github/workflows/continuous-integration-dotnet.yml +++ b/.github/workflows/continuous-integration-dotnet.yml @@ -40,18 +40,18 @@ jobs: docker compose -f "docker-compose.yml" up -d --build db - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} - name: Setup JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'microsoft' java-version: ${{ env.JAVA_VERSION }} - name: Cache SonarCloud packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~\sonar\cache key: ${{ runner.os }}-sonar diff --git a/.github/workflows/continuous-integration-terraform.yml b/.github/workflows/continuous-integration-terraform.yml index 7496ad14b..a9db4f98b 100644 --- a/.github/workflows/continuous-integration-terraform.yml +++ b/.github/workflows/continuous-integration-terraform.yml @@ -40,19 +40,19 @@ jobs: run: rm ./terraform/backend.tf - name: Run a Terraform init - uses: docker://hashicorp/terraform:1.6.6 + uses: docker://hashicorp/terraform:1.7.3 with: entrypoint: terraform args: -chdir=terraform init - name: Run a Terraform validate - uses: docker://hashicorp/terraform:1.6.6 + uses: docker://hashicorp/terraform:1.7.3 with: entrypoint: terraform args: -chdir=terraform validate - name: Run a Terraform format check - uses: docker://hashicorp/terraform:1.6.6 + uses: docker://hashicorp/terraform:1.7.3 with: entrypoint: terraform args: -chdir=terraform fmt -check=true -diff=true diff --git a/.github/workflows/security-tests.yml b/.github/workflows/security-tests.yml index 04300f99b..04119cf5b 100644 --- a/.github/workflows/security-tests.yml +++ b/.github/workflows/security-tests.yml @@ -33,7 +33,7 @@ jobs: - name: Restore ZAP container from cache if exists id: cache-docker-zap - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/ci/cache/docker/softwaresecurityproject key: cache-docker-zap-${{ env.ZAP_VERSION }} @@ -52,7 +52,7 @@ jobs: run: docker run --name zap_container --rm -d -v ${{ github.workspace }}/zapoutput/:/zap/wrk:rw -u zap -p ${{ env.ZAP_PORT }}:${{ env.ZAP_PORT }} -i softwaresecurityproject/zap-stable zap.sh -daemon -port ${{ env.ZAP_PORT }} -host 0.0.0.0 -config api.key=${{ secrets.ZAP_API_KEY }} -config api.addrs.addr.name=.* -config api.addrs.addr.regex=true -config network.localServers.mainProxy.alpn.enabled=false -config network.localServers.mainProxy.address=0.0.0.0 - name: Set up NodeJS - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 diff --git a/TramsDataApi.Test/FakeApi/FakeMfspApi.cs b/TramsDataApi.Test/FakeApi/FakeMfspApi.cs index 1ccaa4563..511211581 100644 --- a/TramsDataApi.Test/FakeApi/FakeMfspApi.cs +++ b/TramsDataApi.Test/FakeApi/FakeMfspApi.cs @@ -14,26 +14,29 @@ public class FakeMfspApi public void Start() { - _server = new WebHostBuilder().UseKestrel(x => x.ListenLocalhost(5003)).Configure(app => + _server = new WebHostBuilder().UseKestrel(x => x.ListenLocalhost(6784)).Configure(app => { app.Run(async context => { - if (context.Request.Method == HttpMethods.Get && context.Request.Path == "/v2/fss/projects") + if (context.Request.Method == HttpMethods.Get && context.Request.Path == "/api/v1/construct/projects") { - var response = new List() + var response = new ApiResponseV2() { - new FssProjectResponse() + Data = new List() { - CurrentFreeSchoolName = "This is my free school", - AgeRange = "5-11", - ProjectStatus = "Open", - }, - new FssProjectResponse() - { - CurrentFreeSchoolName = "This is another free school", - AgeRange = "11-16", - ProjectStatus = "Open", - }, + new FssProjectResponse() + { + CurrentFreeSchoolName = "This is my free school", + AgeRange = "5-11", + ProjectStatus = "Open", + }, + new FssProjectResponse() + { + CurrentFreeSchoolName = "This is another free school", + AgeRange = "11-16", + ProjectStatus = "Open", + }, + } }; await context.Response.WriteAsJsonAsync(response); diff --git a/TramsDataApi.Test/Integration/V3/TrustsV3IntegrationTests.cs b/TramsDataApi.Test/Integration/V3/TrustsV3IntegrationTests.cs index 7c0a0c0d0..406e3a3cc 100644 --- a/TramsDataApi.Test/Integration/V3/TrustsV3IntegrationTests.cs +++ b/TramsDataApi.Test/Integration/V3/TrustsV3IntegrationTests.cs @@ -355,7 +355,7 @@ public async Task ShouldReturnSubsetOfTrusts_WhenSearchingTrusts_ByGroupName() [Theory] [InlineData("123456789")] - [InlineData("123")] + [InlineData("12345")] public async Task ShouldReturnSubsetOfTrusts_WhenSearchingTrusts_ByCompaniesHouseNumber(string searchString) { var companiesHouseNumber = "123456789"; diff --git a/TramsDataApi.Test/integration_settings.json b/TramsDataApi.Test/integration_settings.json index ac08cff66..a550761f9 100644 --- a/TramsDataApi.Test/integration_settings.json +++ b/TramsDataApi.Test/integration_settings.json @@ -12,7 +12,7 @@ "DefaultConnection": "Server=127.0.0.1,1433;Database=sip;User Id=sa;TrustServerCertificate=True;Password=StrongPassword905" }, "Mfsp": { - "ApiEndpoint": "http://localhost:5003" + "ApiEndpoint": "http://localhost:6784" }, "FeatureManagement": { "IsGetProjectsFromMfspEnabled": true diff --git a/TramsDataApi/Configuration/MfspOptions.cs b/TramsDataApi/Configuration/MfspOptions.cs index 516d58b13..e7ee8759e 100644 --- a/TramsDataApi/Configuration/MfspOptions.cs +++ b/TramsDataApi/Configuration/MfspOptions.cs @@ -3,5 +3,7 @@ public class MfspOptions { public string ApiEndpoint { get; set; } + + public string ApiKey { get; set; } } } diff --git a/TramsDataApi/Startup.cs b/TramsDataApi/Startup.cs index f555d700a..1aea3b82f 100644 --- a/TramsDataApi/Startup.cs +++ b/TramsDataApi/Startup.cs @@ -52,6 +52,7 @@ public void ConfigureServices(IServiceCollection services) { MfspOptions mfspOptions = GetTypedConfigurationFor(); client.BaseAddress = new Uri(mfspOptions.ApiEndpoint); + client.DefaultRequestHeaders.Add("ApiKey", mfspOptions.ApiKey); }); services.AddScoped(); diff --git a/TramsDataApi/TramsDataApi.csproj b/TramsDataApi/TramsDataApi.csproj index e11cde922..96add2719 100644 --- a/TramsDataApi/TramsDataApi.csproj +++ b/TramsDataApi/TramsDataApi.csproj @@ -4,6 +4,12 @@ 1ce62ee2-ff0b-4f40-9066-cfbdae2e889f true + + 1701;1702;1591 + + + 1701;1702;1591 + diff --git a/TramsDataApi/UseCases/GetAllFssProjects.cs b/TramsDataApi/UseCases/GetAllFssProjects.cs index 22d09ee46..e98ee9b9e 100644 --- a/TramsDataApi/UseCases/GetAllFssProjects.cs +++ b/TramsDataApi/UseCases/GetAllFssProjects.cs @@ -31,9 +31,9 @@ public async Task> Execute() if (useMfspApi) { - var mfspProjects = await _mfspApiClient.Get>("/v2/fss/projects"); + var mfspProjects = await _mfspApiClient.Get>("/api/v1/construct/projects"); - return mfspProjects; + return mfspProjects.Data.ToList(); } return _fssProjectGateway.GetAll().Select(fssProject => FssProjectResponseFactory.Create(fssProject)).ToList(); diff --git a/TramsDataApi/appsettings.json b/TramsDataApi/appsettings.json index 2b8962174..66233968b 100644 --- a/TramsDataApi/appsettings.json +++ b/TramsDataApi/appsettings.json @@ -39,7 +39,8 @@ } }, "Mfsp": { - "ApiEndpoint": "" + "ApiEndpoint": "", + "ApiKey": "" }, "FeatureManagement": { "IsGetProjectsFromMfspEnabled": false diff --git a/terraform/.terraform-version b/terraform/.terraform-version index ec70f7556..661e7aead 100644 --- a/terraform/.terraform-version +++ b/terraform/.terraform-version @@ -1 +1 @@ -1.6.6 +1.7.3 diff --git a/terraform/.terraform.lock.hcl b/terraform/.terraform.lock.hcl index ccae05be6..5630d213e 100644 --- a/terraform/.terraform.lock.hcl +++ b/terraform/.terraform.lock.hcl @@ -42,31 +42,31 @@ provider "registry.terraform.io/hashicorp/azuread" { } provider "registry.terraform.io/hashicorp/azurerm" { - version = "3.85.0" + version = "3.92.0" constraints = ">= 3.52.0, >= 3.76.0" hashes = [ - "h1:2Dsdz/nR/duRVK7yzAgBY70ZdWbFRtOAjU7z6f60diE=", - "h1:BX6+m8KJATrpqlwBSyA63Fmwjvgwcs/v1qwB7B5GLCU=", - "h1:C1bO2bAI4vJ1dP/6oELgtpoawPUYSbdMo6BpvYNrMuM=", - "h1:DIROF27wqlxkSceiMFUOVpk9Aa2cZFkg0d1C8VI63Gk=", - "h1:JLkmrm6Jcy4m0a3SrT26EU7b0njwFuhfflBZWUij7mA=", - "h1:JhJwx+Zn/DPHMY7qWPHJz7QUovoyxnmXvxT9W8Cj7LU=", - "h1:UW2HuNrkVexKwNYbkI1Xr/B3ip/cCgizIjfKN+ulpPs=", - "h1:j78JLG45+qHKsQvpo1nMe5P/QioO91IowAGdMN2u+rk=", - "h1:nlR1IGkyzCuMzgwmtEBssSyfp9JhOFCprUsjH3R27Vg=", - "h1:vPlaTsywMaTyPPYPy0t8twBwrYOGckDFg4kQ5yyJG0U=", - "h1:wcPRNQKHyR5boMFYQblUqVCbPyxuLlXpVgzMK3cLAPo=", - "zh:1ae6c0d82b5801641a17094b84f2ec1dcac699c1c4e40669a267511061414a34", - "zh:259e9386a43aabecb1205b0ceea2d205223637c09b66d806a89fed04f3343253", - "zh:4d940f9c14fece4f1d9219ac9d104202e5561bddc5024e5ac97f3f93eea20110", - "zh:530bca70b950e835f63c796c694106d701e5de0e2cf096fa35f08afd5c254594", - "zh:69e6b7f44ffbe0383b6485bb9db26781eb7869503889303e202967900a6b35ed", - "zh:8528e7d054254daae06eeb2bf343d566d3908a024fdfb5e515fbdbe0669c15eb", - "zh:98d66edfa89ed9a431ca37be384e5dfe7fa20bdc732c6e7d30f3f922ca3b29dc", - "zh:b8d37cedeffeb6bd37d4ec79fc2da19ed6b57d1ac08d835395dfa4fb3cfdf447", - "zh:bbc94e89cd6c0d59c2e5ed0bce852cac8435b6dc2e979691ee84af4c8b2c9bb8", - "zh:ceb4c624e8bb56bbcfe53e3c4ed4b4d27c3a5b62e5f4890b32c98b60b83c7827", - "zh:f08c5bf19eb25f668633964c6bfa823aa0ead785824082533c4a6cff3959e3d0", + "h1:+bZPRgjpUA6LivvMIS1UdwRWUgzoYBp/nhEpbL4aXHM=", + "h1:1pPoDcpXQXbKvbJbt1vbtlJTQEKiscUVDRvpGu/YvYo=", + "h1:2FpB5WtU5mlWVf4kszp0BU7hcbocbX5+KJVt+IJxmsQ=", + "h1:D5lngW1uKlPM2EUCdNG1f2FvPGHYRklDFN8b2jPCIpM=", + "h1:DnSRgZAcjjFnd6tjq12UiP/fI8GyebYy8ax0VrCrxic=", + "h1:cPh4BObf7WxKV4cYFmdgX7EkV9MoEl3Gh75d/3Xnmv0=", + "h1:knKUM9RJmvBYWBatnNn6NuHLawP50Mk1KIPo4o5QHqg=", + "h1:ltmICoIZzDTSwLFARvahWMRc2Q6AhFhLiDKC5r8kXDs=", + "h1:nTP2ZYfuEpMP+PkkgRdhQphNmWWJuKdE9Z4TzeC7ydo=", + "h1:sqVZftg9rJGDiiPiY9l1V/a+5CWkxNcj22sBu8HsJBY=", + "h1:swoRk2drVrD8v7GrW/2OJSk06v2I2zGk3XPAgBDbw9A=", + "zh:04292e149676ba956d738e85faeb6d6ebd3759e8310f1c4155e67402eb5ae0f7", + "zh:0963b4528f25d01d5c733e17de31e2c0b94790fd02931b2a47cd051b20dd0d96", + "zh:133563e16e8a4a7139ac11d94e68de8d1d5e3a62a532e64ac936735d7b1e04db", + "zh:2b219f1b40881d3bdd89257c916f255a7e36904ddc65dbbafee80763661b4636", + "zh:4b4e11a4e3716b290b3b173dfd15b06814b2f6f148f663e3c67a677c95526339", + "zh:5607c7bff3019c3b31488be1a8a9d77a96d27b199a1d8b789e4c2d4c90805674", + "zh:6469aef7728947dacb47785e6082d2d95ebd336a8798f3be6cece5a13145108c", + "zh:69e563f4e6397e1ebaef6f554d296238ec1d9dadc4b865c36743bd8366a888da", + "zh:887a223b7a9ec4e66634dbb65d9dcc53f0be06d058d9a209927ad49702ae790c", + "zh:b03c273367885c5489a24c31859af81ea58cb169431c0da97a175945ec968f53", + "zh:dd7b704ceaf98ce591e111a9c5085465c946f4f8f357089c0e27e990a669ba39", "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", ] } diff --git a/terraform/README.md b/terraform/README.md index e4faae404..93f0cafff 100644 --- a/terraform/README.md +++ b/terraform/README.md @@ -136,8 +136,8 @@ No providers. | Name | Source | Version | |------|--------|---------| -| [azure\_container\_apps\_hosting](#module\_azure\_container\_apps\_hosting) | github.com/DFE-Digital/terraform-azurerm-container-apps-hosting | v1.4.7 | -| [azurerm\_key\_vault](#module\_azurerm\_key\_vault) | github.com/DFE-Digital/terraform-azurerm-key-vault-tfvars | v0.3.0 | +| [azure\_container\_apps\_hosting](#module\_azure\_container\_apps\_hosting) | github.com/DFE-Digital/terraform-azurerm-container-apps-hosting | v1.4.9 | +| [azurerm\_key\_vault](#module\_azurerm\_key\_vault) | github.com/DFE-Digital/terraform-azurerm-key-vault-tfvars | v0.4.0 | | [statuscake-tls-monitor](#module\_statuscake-tls-monitor) | github.com/dfe-digital/terraform-statuscake-tls-monitor | v0.1.2 | ## Resources @@ -159,6 +159,7 @@ No resources. | [container\_apps\_allow\_ips\_inbound](#input\_container\_apps\_allow\_ips\_inbound) | Restricts access to the Container Apps by creating a network security group rule that only allow inbound traffic from the provided list of IPs | `list(string)` | `[]` | no | | [container\_command](#input\_container\_command) | Container command | `list(any)` | n/a | yes | | [container\_health\_probe\_path](#input\_container\_health\_probe\_path) | Specifies the path that is used to determine the liveness of the Container | `string` | n/a | yes | +| [container\_scale\_http\_concurrency](#input\_container\_scale\_http\_concurrency) | When the number of concurrent HTTP requests exceeds this value, then another replica is added. Replicas continue to add to the pool up to the max-replicas amount. | `number` | `10` | no | | [container\_secret\_environment\_variables](#input\_container\_secret\_environment\_variables) | Container secret environment variables | `map(string)` | n/a | yes | | [dns\_ns\_records](#input\_dns\_ns\_records) | DNS NS records to add to the DNS Zone |
map(
object({
ttl : optional(number, 300),
records : list(string)
})
)
| n/a | yes | | [dns\_txt\_records](#input\_dns\_txt\_records) | DNS TXT records to add to the DNS Zone |
map(
object({
ttl : optional(number, 300),
records : list(string)
})
)
| n/a | yes | @@ -176,7 +177,6 @@ No resources. | [existing\_network\_watcher\_resource\_group\_name](#input\_existing\_network\_watcher\_resource\_group\_name) | Existing network watcher resource group. | `string` | n/a | yes | | [image\_name](#input\_image\_name) | Image name | `string` | n/a | yes | | [key\_vault\_access\_ipv4](#input\_key\_vault\_access\_ipv4) | List of IPv4 Addresses that are permitted to access the Key Vault | `list(string)` | n/a | yes | -| [key\_vault\_access\_users](#input\_key\_vault\_access\_users) | List of users that require access to the Key Vault where tfvars are stored. This should be a list of User Principle Names (Found in Active Directory) that need to run terraform | `list(string)` | n/a | yes | | [monitor\_email\_receivers](#input\_monitor\_email\_receivers) | A list of email addresses that should be notified by monitoring alerts | `list(string)` | n/a | yes | | [monitor\_endpoint\_healthcheck](#input\_monitor\_endpoint\_healthcheck) | Specify a route that should be monitored for a 200 OK status | `string` | n/a | yes | | [project\_name](#input\_project\_name) | Project name. Will be used along with `environment` as a prefix for all resources. | `string` | n/a | yes | diff --git a/terraform/container-apps-hosting.tf b/terraform/container-apps-hosting.tf index 11d3997c1..e4eeb32b2 100644 --- a/terraform/container-apps-hosting.tf +++ b/terraform/container-apps-hosting.tf @@ -1,5 +1,5 @@ module "azure_container_apps_hosting" { - source = "github.com/DFE-Digital/terraform-azurerm-container-apps-hosting?ref=v1.4.7" + source = "github.com/DFE-Digital/terraform-azurerm-container-apps-hosting?ref=v1.4.9" environment = local.environment project_name = local.project_name @@ -21,6 +21,7 @@ module "azure_container_apps_hosting" { image_name = local.image_name container_command = local.container_command container_secret_environment_variables = local.container_secret_environment_variables + container_scale_http_concurrency = local.container_scale_http_concurrency enable_cdn_frontdoor = local.enable_cdn_frontdoor cdn_frontdoor_forwarding_protocol = local.cdn_frontdoor_forwarding_protocol diff --git a/terraform/key-vault-tfvars-secrets.tf b/terraform/key-vault-tfvars-secrets.tf index 0b8a5a008..dad3faf4a 100644 --- a/terraform/key-vault-tfvars-secrets.tf +++ b/terraform/key-vault-tfvars-secrets.tf @@ -1,14 +1,15 @@ module "azurerm_key_vault" { - source = "github.com/DFE-Digital/terraform-azurerm-key-vault-tfvars?ref=v0.3.0" + source = "github.com/DFE-Digital/terraform-azurerm-key-vault-tfvars?ref=v0.4.0" - environment = local.environment - project_name = local.project_name - existing_resource_group = module.azure_container_apps_hosting.azurerm_resource_group_default.name - azure_location = local.azure_location - key_vault_access_users = local.key_vault_access_users - key_vault_access_ipv4 = local.key_vault_access_ipv4 - tfvars_filename = local.tfvars_filename - diagnostic_log_analytics_workspace_id = module.azure_container_apps_hosting.azurerm_log_analytics_workspace_container_app.id - diagnostic_eventhub_name = local.enable_event_hub ? module.azure_container_apps_hosting.azurerm_eventhub_container_app.name : "" - tags = local.tags + environment = local.environment + project_name = local.project_name + existing_resource_group = module.azure_container_apps_hosting.azurerm_resource_group_default.name + azure_location = local.azure_location + key_vault_access_use_rbac_authorization = true + key_vault_access_users = [] + key_vault_access_ipv4 = local.key_vault_access_ipv4 + tfvars_filename = local.tfvars_filename + diagnostic_log_analytics_workspace_id = module.azure_container_apps_hosting.azurerm_log_analytics_workspace_container_app.id + diagnostic_eventhub_name = local.enable_event_hub ? module.azure_container_apps_hosting.azurerm_eventhub_container_app.name : "" + tags = local.tags } diff --git a/terraform/locals.tf b/terraform/locals.tf index fd048c93f..03dc6ce74 100644 --- a/terraform/locals.tf +++ b/terraform/locals.tf @@ -11,6 +11,7 @@ locals { image_name = var.image_name container_command = var.container_command container_secret_environment_variables = var.container_secret_environment_variables + container_scale_http_concurrency = var.container_scale_http_concurrency enable_cdn_frontdoor = var.enable_cdn_frontdoor enable_event_hub = var.enable_event_hub enable_logstash_consumer = var.enable_logstash_consumer @@ -19,7 +20,6 @@ locals { dns_zone_domain_name = var.dns_zone_domain_name dns_ns_records = var.dns_ns_records dns_txt_records = var.dns_txt_records - key_vault_access_users = toset(var.key_vault_access_users) key_vault_access_ipv4 = var.key_vault_access_ipv4 tfvars_filename = var.tfvars_filename enable_monitoring = var.enable_monitoring diff --git a/terraform/statuscake-tls-monitor.tf b/terraform/statuscake-tls-monitor.tf index 02a9b0af4..a859d1818 100644 --- a/terraform/statuscake-tls-monitor.tf +++ b/terraform/statuscake-tls-monitor.tf @@ -3,7 +3,7 @@ module "statuscake-tls-monitor" { statuscake_monitored_resource_addresses = local.statuscake_monitored_resource_addresses statuscake_alert_at = [ # days to alert on - 14, 7, 3 + 40, 20, 5 ] statuscake_contact_group_name = local.statuscake_contact_group_name statuscake_contact_group_integrations = local.statuscake_contact_group_integrations diff --git a/terraform/variables.tf b/terraform/variables.tf index 6e027af94..055ca1b04 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -3,11 +3,6 @@ variable "environment" { type = string } -variable "key_vault_access_users" { - description = "List of users that require access to the Key Vault where tfvars are stored. This should be a list of User Principle Names (Found in Active Directory) that need to run terraform" - type = list(string) -} - variable "key_vault_access_ipv4" { description = "List of IPv4 Addresses that are permitted to access the Key Vault" type = list(string) @@ -77,6 +72,12 @@ variable "container_secret_environment_variables" { sensitive = true } +variable "container_scale_http_concurrency" { + description = "When the number of concurrent HTTP requests exceeds this value, then another replica is added. Replicas continue to add to the pool up to the max-replicas amount." + type = number + default = 10 +} + variable "enable_dns_zone" { description = "Conditionally create a DNS zone" type = bool