From 8415a18c2aa758d43b1ae715a5bce53e77c862ad Mon Sep 17 00:00:00 2001 From: "ricky.gummadi" Date: Mon, 8 Jul 2024 23:02:37 +1200 Subject: [PATCH 01/46] fix skeleton structure --- .github/workflows/configuration.prod.yaml | 1 + .github/workflows/configuration.uat.yaml | 1 + .github/workflows/run-extractor.yaml | 2 +- .github/workflows/run-publisher.yaml | 41 ++++++-- .../apis/public-ip-api/apiInformation.json | 22 ----- .../operations/get-ipv4/policy.xml | 65 ------------- .../apis/public-ip-api/specification.yaml | 94 ------------------- apimartifacts/policy.xml | 17 ---- docs/api/api.md | 1 - docs/{setup => }/deployment.md | 0 infra/main.bicep | 0 infra/modules/apim/apim.bicep | 0 infra/modules/frontdoor/frontdoorConfig.json | 0 infra/modules/networking/networkConfig.json | 0 scripts/deployment/deploy.sh | 1 - scripts/maintenance/cleanup.sh | 1 - src/{api => apis}/api-specs.yml | 0 17 files changed, 34 insertions(+), 212 deletions(-) create mode 100644 .github/workflows/configuration.prod.yaml create mode 100644 .github/workflows/configuration.uat.yaml delete mode 100644 apimartifacts/apis/public-ip-api/apiInformation.json delete mode 100644 apimartifacts/apis/public-ip-api/operations/get-ipv4/policy.xml delete mode 100644 apimartifacts/apis/public-ip-api/specification.yaml delete mode 100644 apimartifacts/policy.xml delete mode 100644 docs/api/api.md rename docs/{setup => }/deployment.md (100%) delete mode 100644 infra/main.bicep delete mode 100644 infra/modules/apim/apim.bicep delete mode 100644 infra/modules/frontdoor/frontdoorConfig.json delete mode 100644 infra/modules/networking/networkConfig.json delete mode 100644 scripts/deployment/deploy.sh delete mode 100644 scripts/maintenance/cleanup.sh rename src/{api => apis}/api-specs.yml (100%) diff --git a/.github/workflows/configuration.prod.yaml b/.github/workflows/configuration.prod.yaml new file mode 100644 index 0000000..308a900 --- /dev/null +++ b/.github/workflows/configuration.prod.yaml @@ -0,0 +1 @@ +apimServiceName: ipsimple-apim-prod-eastus \ No newline at end of file diff --git a/.github/workflows/configuration.uat.yaml b/.github/workflows/configuration.uat.yaml new file mode 100644 index 0000000..346dd57 --- /dev/null +++ b/.github/workflows/configuration.uat.yaml @@ -0,0 +1 @@ +apimServiceName: ipsimple-apim-uat-eastus \ No newline at end of file diff --git a/.github/workflows/run-extractor.yaml b/.github/workflows/run-extractor.yaml index f8ca550..3fbcaa6 100644 --- a/.github/workflows/run-extractor.yaml +++ b/.github/workflows/run-extractor.yaml @@ -39,7 +39,7 @@ jobs: AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} AZURE_RESOURCE_GROUP_NAME: ${{ secrets.AZURE_RESOURCE_GROUP_NAME }} API_MANAGEMENT_SERVICE_NAME: ${{ secrets.API_MANAGEMENT_SERVICE_NAME }} - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/apimartifacts # change this to the artifacts folder + API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder API_SPECIFICATION_FORMAT: ${{ github.event.inputs.API_SPECIFICATION_FORMAT }} run: | Set-StrictMode -Version Latest diff --git a/.github/workflows/run-publisher.yaml b/.github/workflows/run-publisher.yaml index 516171e..3f7ae4b 100644 --- a/.github/workflows/run-publisher.yaml +++ b/.github/workflows/run-publisher.yaml @@ -30,34 +30,55 @@ jobs: outputs: commit_id: ${{ steps.commit.outputs.commit_id }} #Publish with Commit ID - Push-Changes-To-APIM-Dev-With-Commit-ID: + Push-Changes-To-APIM-Test-With-Commit-ID: if: (github.event.inputs.COMMIT_ID_CHOICE == 'publish-artifacts-in-last-commit' || github.event.inputs.COMMIT_ID_CHOICE == '') needs: get-commit uses: ./.github/workflows/run-publisher-with-env.yaml with: - API_MANAGEMENT_ENVIRONMENT: dev # change this to match the dev environment created in settings + API_MANAGEMENT_ENVIRONMENT: Test # change this to match the dev environment created in settings COMMIT_ID: ${{ needs.get-commit.outputs.commit_id }} - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: apimartifacts # change this to the artifacts folder + API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder secrets: inherit #Publish without Commit ID. Publishes all artifacts that reside in the artifacts forlder - Push-Changes-To-APIM-Dev-Without-Commit-ID: + Push-Changes-To-APIM-Test-Without-Commit-ID: if: ( github.event.inputs.COMMIT_ID_CHOICE == 'publish-all-artifacts-in-repo' ) needs: get-commit uses: ./.github/workflows/run-publisher-with-env.yaml with: - API_MANAGEMENT_ENVIRONMENT: dev # change this to match the dev environment created in settings - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: apimartifacts # change this to the artifacts folder + API_MANAGEMENT_ENVIRONMENT: Test + API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder secrets: inherit + # Push-Changes-To-APIM-UAT-With-Commit-ID: + # if: (github.event.inputs.COMMIT_ID_CHOICE == 'publish-artifacts-in-last-commit' || github.event.inputs.COMMIT_ID_CHOICE == '') + # needs: [get-commit, Push-Changes-To-APIM-Dev-With-Commit-ID] + # uses: ./.github/workflows/run-publisher-with-env.yaml + # with: + # API_MANAGEMENT_ENVIRONMENT: UAT + # CONFIGURATION_YAML_PATH: configuration.uat.yaml # make sure the file is available at the root + # API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder + # COMMIT_ID: ${{ needs.get-commit.outputs.commit_id }} + # secrets: inherit + + # Push-Changes-To-APIM-UAT-Without-Commit-ID: + # if: ( github.event.inputs.COMMIT_ID_CHOICE == 'publish-all-artifacts-in-repo' ) + # needs: [get-commit, Push-Changes-To-APIM-Dev-Without-Commit-ID] + # uses: ./.github/workflows/run-publisher-with-env.yaml + # with: + # API_MANAGEMENT_ENVIRONMENT: UAT + # CONFIGURATION_YAML_PATH: configuration.uat.yaml # make sure the file is available at the root + # API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder + # secrets: inherit + Push-Changes-To-APIM-Prod-With-Commit-ID: if: (github.event.inputs.COMMIT_ID_CHOICE == 'publish-artifacts-in-last-commit' || github.event.inputs.COMMIT_ID_CHOICE == '') needs: [get-commit, Push-Changes-To-APIM-Dev-With-Commit-ID] uses: ./.github/workflows/run-publisher-with-env.yaml with: - API_MANAGEMENT_ENVIRONMENT: prod # change this to match the prod environment created in settings + API_MANAGEMENT_ENVIRONMENT: Prod CONFIGURATION_YAML_PATH: configuration.prod.yaml # make sure the file is available at the root - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: apimartifacts # change this to the artifacts folder + API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder COMMIT_ID: ${{ needs.get-commit.outputs.commit_id }} secrets: inherit @@ -66,7 +87,7 @@ jobs: needs: [get-commit, Push-Changes-To-APIM-Dev-Without-Commit-ID] uses: ./.github/workflows/run-publisher-with-env.yaml with: - API_MANAGEMENT_ENVIRONMENT: prod # change this to match the prod environment created in settings + API_MANAGEMENT_ENVIRONMENT: Prod CONFIGURATION_YAML_PATH: configuration.prod.yaml # make sure the file is available at the root - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: apimartifacts # change this to the artifacts folder + API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder secrets: inherit diff --git a/apimartifacts/apis/public-ip-api/apiInformation.json b/apimartifacts/apis/public-ip-api/apiInformation.json deleted file mode 100644 index 22d8e15..0000000 --- a/apimartifacts/apis/public-ip-api/apiInformation.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "properties": { - "apiRevision": "1", - "authenticationSettings": {}, - "contact": { - "email": "support@ipsimple.org" - }, - "description": "This API allows clients to retrieve their own public IPv4 and IPv6 addresses. It\u0027s a simple and effective tool for a clients public IP address detection and troubleshooting network issues.", - "displayName": "Public IP API", - "isCurrent": true, - "path": "", - "protocols": [ - "https" - ], - "subscriptionKeyParameterNames": { - "header": "Ocp-Apim-Subscription-Key", - "query": "subscription-key" - }, - "subscriptionRequired": true, - "termsOfServiceUrl": "https://ipsimple.org/terms/" - } -} \ No newline at end of file diff --git a/apimartifacts/apis/public-ip-api/operations/get-ipv4/policy.xml b/apimartifacts/apis/public-ip-api/operations/get-ipv4/policy.xml deleted file mode 100644 index 77b55e9..0000000 --- a/apimartifacts/apis/public-ip-api/operations/get-ipv4/policy.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - application/json - - - { - "ip": "@{{context.Variables.clientIp}}" - } - - - - - - - - - text/plain - - - "@{{context.Variables.clientIp}}" - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/apimartifacts/apis/public-ip-api/specification.yaml b/apimartifacts/apis/public-ip-api/specification.yaml deleted file mode 100644 index dba4631..0000000 --- a/apimartifacts/apis/public-ip-api/specification.yaml +++ /dev/null @@ -1,94 +0,0 @@ -openapi: 3.0.1 -info: - title: Public IP API - description: This API allows clients to retrieve their own public IPv4 and IPv6 addresses. It's a simple and effective tool for a clients public IP address detection and troubleshooting network issues. - termsOfService: https://ipsimple.org/terms/ - contact: - email: support@ipsimple.org - version: '1.0' -servers: - - url: https://ipsimple-apim-test-eastus.azure-api.net -paths: - /ipv4: - get: - summary: Public IPv4 address - description: This endpoint returns the public IPv4 address of the client making the request. - operationId: get-ipv4 - parameters: - - name: format - in: query - schema: - enum: - - json - - plain - type: string - responses: - '200': - description: Successful response - content: - text/plain: - schema: - type: string - example: 98.207.254.136 - examples: - default: - value: - application/json: - schema: - type: object - properties: - ip: - type: string - example: 98.207.254.136 - example: - ip: 98.207.254.136 - '429': - description: Too many requests - /ipv6: - get: - summary: Public IPv6 address - description: This endpoint returns the public IPv6 address of the client making the request. - operationId: get-ipv6 - parameters: - - name: format - in: query - schema: - enum: - - json - - plain - type: string - responses: - '200': - description: Successful response - content: - text/plain: - schema: - type: string - example: 2a00:1450:400f:80d::200e - examples: - default: - value: - application/json: - schema: - type: object - properties: - ip: - type: string - example: 2a00:1450:400f:80d::200e - example: - ip: 2a00:1450:400f:80d::200e - '429': - description: Too many requests -components: - securitySchemes: - apiKeyHeader: - type: apiKey - name: Ocp-Apim-Subscription-Key - in: header - apiKeyQuery: - type: apiKey - name: subscription-key - in: query -security: - - apiKeyHeader: [ ] - - apiKeyQuery: [ ] \ No newline at end of file diff --git a/apimartifacts/policy.xml b/apimartifacts/policy.xml deleted file mode 100644 index 0e84c5b..0000000 --- a/apimartifacts/policy.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/docs/api/api.md b/docs/api/api.md deleted file mode 100644 index bc4e2a6..0000000 --- a/docs/api/api.md +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/setup/deployment.md b/docs/deployment.md similarity index 100% rename from docs/setup/deployment.md rename to docs/deployment.md diff --git a/infra/main.bicep b/infra/main.bicep deleted file mode 100644 index e69de29..0000000 diff --git a/infra/modules/apim/apim.bicep b/infra/modules/apim/apim.bicep deleted file mode 100644 index e69de29..0000000 diff --git a/infra/modules/frontdoor/frontdoorConfig.json b/infra/modules/frontdoor/frontdoorConfig.json deleted file mode 100644 index e69de29..0000000 diff --git a/infra/modules/networking/networkConfig.json b/infra/modules/networking/networkConfig.json deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/deployment/deploy.sh b/scripts/deployment/deploy.sh deleted file mode 100644 index 17498c8..0000000 --- a/scripts/deployment/deploy.sh +++ /dev/null @@ -1 +0,0 @@ -TODO: \ No newline at end of file diff --git a/scripts/maintenance/cleanup.sh b/scripts/maintenance/cleanup.sh deleted file mode 100644 index 17498c8..0000000 --- a/scripts/maintenance/cleanup.sh +++ /dev/null @@ -1 +0,0 @@ -TODO: \ No newline at end of file diff --git a/src/api/api-specs.yml b/src/apis/api-specs.yml similarity index 100% rename from src/api/api-specs.yml rename to src/apis/api-specs.yml From ac03d59783a69e27077e5a451027c63fc947ecbb Mon Sep 17 00:00:00 2001 From: "ricky.gummadi" Date: Fri, 12 Jul 2024 17:27:29 +1200 Subject: [PATCH 02/46] revamp solution and first cut of code --- .github/workflows/configuration.prod.yaml | 1 - .github/workflows/configuration.uat.yaml | 1 - .github/workflows/run-extractor.yaml | 150 ------ .github/workflows/run-publisher-with-env.yaml | 244 --------- .github/workflows/run-publisher.yaml | 93 ---- docs/contributing.md | 0 src/.dockerignore | 30 ++ src/.editorconfig | 473 ++++++++++++++++++ .../IpSimple.Domain.Tests.csproj | 23 + src/IpSimple.Domain/Constants.cs | 22 + src/IpSimple.Domain/IpSimple.Domain.csproj | 13 + src/IpSimple.Domain/Models/IpAddress.cs | 6 + .../Settings/JsonSerializerSettings.cs | 12 + .../HttpContextExtensionsTests.cs | 75 +++ .../IpSimple.Extensions.Tests.csproj | 32 ++ .../HttpContextExtensions.cs | 66 +++ .../IpSimple.Extensions.csproj | 17 + src/IpSimple.Platform.sln | 68 +++ .../ApiBenchmark.cs | 44 ++ ...hmarkTesting.ApiBenchmark-report-github.md | 16 + ...i.BenchmarkTesting.ApiBenchmark-report.csv | 5 + ....BenchmarkTesting.ApiBenchmark-report.html | 33 ++ ...imple.PublicIp.Api.BenchmarkTesting.csproj | 14 + .../Program.cs | 8 + .../IpSimple.PublicIp.Api.Tests.csproj | 32 ++ .../Services/IpAddressServiceTests.cs | 82 +++ src/IpSimple.PublicIp.Api/Dockerfile | 24 + .../IpSimple.PublicIp.Api.csproj | 29 ++ .../IpSimple.PublicIp.Api.env.json | 8 + .../IpSimple.PublicIp.Api.http | 48 ++ src/IpSimple.PublicIp.Api/Program.cs | 70 +++ .../Properties/launchSettings.json | 40 ++ .../Services/IIpAddressService.cs | 7 + .../Services/IpAddressService.cs | 25 + .../api-spec.yml} | 62 ++- .../appsettings.Development.json | 8 + src/IpSimple.PublicIp.Api/appsettings.json | 9 + 37 files changed, 1400 insertions(+), 490 deletions(-) delete mode 100644 .github/workflows/configuration.prod.yaml delete mode 100644 .github/workflows/configuration.uat.yaml delete mode 100644 .github/workflows/run-extractor.yaml delete mode 100644 .github/workflows/run-publisher-with-env.yaml delete mode 100644 .github/workflows/run-publisher.yaml create mode 100644 docs/contributing.md create mode 100644 src/.dockerignore create mode 100644 src/.editorconfig create mode 100644 src/IpSimple.Domain.Tests/IpSimple.Domain.Tests.csproj create mode 100644 src/IpSimple.Domain/Constants.cs create mode 100644 src/IpSimple.Domain/IpSimple.Domain.csproj create mode 100644 src/IpSimple.Domain/Models/IpAddress.cs create mode 100644 src/IpSimple.Domain/Settings/JsonSerializerSettings.cs create mode 100644 src/IpSimple.Extensions.Tests/HttpContextExtensionsTests.cs create mode 100644 src/IpSimple.Extensions.Tests/IpSimple.Extensions.Tests.csproj create mode 100644 src/IpSimple.Extensions/HttpContextExtensions.cs create mode 100644 src/IpSimple.Extensions/IpSimple.Extensions.csproj create mode 100644 src/IpSimple.Platform.sln create mode 100644 src/IpSimple.PublicIp.Api.BenchmarkTesting/ApiBenchmark.cs create mode 100644 src/IpSimple.PublicIp.Api.BenchmarkTesting/BenchmarkDotNet.Artifacts/results/IpSimple.PublicIp.Api.BenchmarkTesting.ApiBenchmark-report-github.md create mode 100644 src/IpSimple.PublicIp.Api.BenchmarkTesting/BenchmarkDotNet.Artifacts/results/IpSimple.PublicIp.Api.BenchmarkTesting.ApiBenchmark-report.csv create mode 100644 src/IpSimple.PublicIp.Api.BenchmarkTesting/BenchmarkDotNet.Artifacts/results/IpSimple.PublicIp.Api.BenchmarkTesting.ApiBenchmark-report.html create mode 100644 src/IpSimple.PublicIp.Api.BenchmarkTesting/IpSimple.PublicIp.Api.BenchmarkTesting.csproj create mode 100644 src/IpSimple.PublicIp.Api.BenchmarkTesting/Program.cs create mode 100644 src/IpSimple.PublicIp.Api.Tests/IpSimple.PublicIp.Api.Tests.csproj create mode 100644 src/IpSimple.PublicIp.Api.Tests/Services/IpAddressServiceTests.cs create mode 100644 src/IpSimple.PublicIp.Api/Dockerfile create mode 100644 src/IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.csproj create mode 100644 src/IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.env.json create mode 100644 src/IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.http create mode 100644 src/IpSimple.PublicIp.Api/Program.cs create mode 100644 src/IpSimple.PublicIp.Api/Properties/launchSettings.json create mode 100644 src/IpSimple.PublicIp.Api/Services/IIpAddressService.cs create mode 100644 src/IpSimple.PublicIp.Api/Services/IpAddressService.cs rename src/{apis/api-specs.yml => IpSimple.PublicIp.Api/api-spec.yml} (50%) create mode 100644 src/IpSimple.PublicIp.Api/appsettings.Development.json create mode 100644 src/IpSimple.PublicIp.Api/appsettings.json diff --git a/.github/workflows/configuration.prod.yaml b/.github/workflows/configuration.prod.yaml deleted file mode 100644 index 308a900..0000000 --- a/.github/workflows/configuration.prod.yaml +++ /dev/null @@ -1 +0,0 @@ -apimServiceName: ipsimple-apim-prod-eastus \ No newline at end of file diff --git a/.github/workflows/configuration.uat.yaml b/.github/workflows/configuration.uat.yaml deleted file mode 100644 index 346dd57..0000000 --- a/.github/workflows/configuration.uat.yaml +++ /dev/null @@ -1 +0,0 @@ -apimServiceName: ipsimple-apim-uat-eastus \ No newline at end of file diff --git a/.github/workflows/run-extractor.yaml b/.github/workflows/run-extractor.yaml deleted file mode 100644 index 3fbcaa6..0000000 --- a/.github/workflows/run-extractor.yaml +++ /dev/null @@ -1,150 +0,0 @@ -name: Run - Extractor - -on: - workflow_dispatch: - inputs: - CONFIGURATION_YAML_PATH: - description: 'Choose Wether to extract all Apis or extract apis listed an extraction configuration file' - required: true - type: choice - options: - - Extract All APIs - - configuration.extractor.yaml - API_SPECIFICATION_FORMAT: - description: 'API Specification Format' - required: true - type: choice - options: - - OpenAPIV3Yaml - - OpenAPIV3Json - - OpenAPIV2Yaml - - OpenAPIV2Json - -env: - apiops_release_version: v5.1.4 - -jobs: - extract: - runs-on: ubuntu-latest - environment: Test # change this to match the dev environment created in settings - steps: - - uses: actions/checkout@v3 - - - name: Run extractor without Config Yaml - if: ${{ github.event.inputs.CONFIGURATION_YAML_PATH == 'Extract All APIs' }} - env: - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - AZURE_RESOURCE_GROUP_NAME: ${{ secrets.AZURE_RESOURCE_GROUP_NAME }} - API_MANAGEMENT_SERVICE_NAME: ${{ secrets.API_MANAGEMENT_SERVICE_NAME }} - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder - API_SPECIFICATION_FORMAT: ${{ github.event.inputs.API_SPECIFICATION_FORMAT }} - run: | - Set-StrictMode -Version Latest - $ErrorActionPreference = "Stop" - $VerbosePreference = "Continue" - $InformationPreference = "Continue" - - Write-Information "Downloading extractor..." - $extractorFileName = "extractor.linux-x64" - $extractorFinalFileName = "extractor" - if ("${{ runner.os }}" -like "*win*") { - $extractorFileName = "extractor.win-x64.exe" - $extractorFinalFileName = "extractor.exe" - } - elseif ("${{ runner.os }}" -like "*mac*" -and "${{ runner.arch }}" -like "*arm*") { - $extractorFileName = "extractor.osx-arm64" - } - elseif ("${{ runner.os }}" -like "*mac*" -and "${{ runner.arch }}" -like "*x86_64*") { - $extractorFileName = "extractor.osx-x64" - } - - $uri = "https://github.com/Azure/apiops/releases/download/${{ env.apiops_release_version }}/$extractorFileName" - $destinationFilePath = Join-Path "${{ runner.temp }}" $extractorFinalFileName - Invoke-WebRequest -Uri "$uri" -OutFile "$destinationFilePath" - - if ("${{ runner.os }}" -like "*linux*") - { - Write-Information "Setting file permissions..." - & chmod +x "$destinationFilePath" - if ($LASTEXITCODE -ne 0) { throw "Setting file permissions failed."} - } - - & "$destinationFilePath" - if ($LASTEXITCODE -ne 0) { throw "Running extractor failed."} - - Write-Information "Execution complete." - shell: pwsh - - - name: Run extractor with Config Yaml - if: ${{ github.event.inputs.CONFIGURATION_YAML_PATH != 'Extract All APIs' }} - env: - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - AZURE_RESOURCE_GROUP_NAME: ${{ secrets.AZURE_RESOURCE_GROUP_NAME }} - API_MANAGEMENT_SERVICE_NAME: ${{ secrets.API_MANAGEMENT_SERVICE_NAME }} - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/apimartifacts # change this to the artifacts folder - API_SPECIFICATION_FORMAT: ${{ github.event.inputs.API_SPECIFICATION_FORMAT }} - CONFIGURATION_YAML_PATH: ${{ GITHUB.WORKSPACE }}/${{ github.event.inputs.CONFIGURATION_YAML_PATH }} - run: | - Set-StrictMode -Version Latest - $ErrorActionPreference = "Stop" - $VerbosePreference = "Continue" - $InformationPreference = "Continue" - - Write-Information "Downloading extractor..." - $extractorFileName = "${{ runner.os }}" -like "*win*" ? "extractor.win-x64.exe" : "extractor.linux-x64.exe" - $uri = "https://github.com/Azure/apiops/releases/download/${{ env.apiops_release_version }}/$extractorFileName" - $destinationFilePath = Join-Path "${{ runner.temp }}" "extractor.exe" - Invoke-WebRequest -Uri "$uri" -OutFile "$destinationFilePath" - - if ("${{ runner.os }}" -like "*linux*") - { - Write-Information "Setting file permissions..." - & chmod +x "$destinationFilePath" - if ($LASTEXITCODE -ne 0) { throw "Setting file permissions failed."} - } - - & "$destinationFilePath" - if ($LASTEXITCODE -ne 0) { throw "Running extractor failed."} - - Write-Information "Execution complete." - shell: pwsh - - - name: publish artifact - uses: actions/upload-artifact@v2 - env: - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: apimartifacts # change this to the artifacts folder - with: - name: artifacts-from-portal - path: ${{ GITHUB.WORKSPACE }}/${{ env.API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH }} - - create-pull-request: - needs: extract - runs-on: [ubuntu-latest] - steps: - - uses: actions/checkout@v3 - - - name: Download artifacts-from-portal - uses: actions/download-artifact@v2 - env: - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: apimartifacts # change this to the artifacts folder - with: - name: artifacts-from-portal - path: "${{ GITHUB.WORKSPACE }}/${{ env.API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH }}" - - - name: Create artifacts pull request - uses: peter-evans/create-pull-request@v3 - env: - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: apimartifacts # change this to the artifacts folder - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: "updated extract from apim instance ${{ env.API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH }}" - title: "${{ env.API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH }} - extract" - body: > - This PR is auto-generated by Github actions workflow - labels: extract, automated pr diff --git a/.github/workflows/run-publisher-with-env.yaml b/.github/workflows/run-publisher-with-env.yaml deleted file mode 100644 index 42946b1..0000000 --- a/.github/workflows/run-publisher-with-env.yaml +++ /dev/null @@ -1,244 +0,0 @@ -name: Run Publisher with Environment - -on: - workflow_call: - inputs: - API_MANAGEMENT_ENVIRONMENT: - required: true - type: string - CONFIGURATION_YAML_PATH: - required: false - type: string - COMMIT_ID: - required: false - type: string - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: - required: true - type: string - -env: - apiops_release_version: v5.1.4 - #By default, this will be Information but if you want something different you will need to add a variable in the Settings -> Environment -> Environment variables section - Logging__LogLevel__Default: ${{ vars.LOG_LEVEL }} - -jobs: - build: - runs-on: ubuntu-latest - environment: ${{ inputs.API_MANAGEMENT_ENVIRONMENT }} - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3 - with: - fetch-depth: 2 - - # Run Spectral - - uses: actions/setup-node@v3 - with: - node-version: "14" - - run: npm install -g @stoplight/spectral - - run: spectral lint "${{ GITHUB.WORKSPACE }}/${{ inputs.API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH }}\apis\*.{json,yml,yaml}" --ruleset https://raw.githubusercontent.com/connectedcircuits/devops-api-linter/main/rules.yaml - - # Add this step for each APIM environment and pass specific set of secrets that you want replaced in the env section below - - name: "Perform namevalue secret substitution in configuration.${{ inputs.API_MANAGEMENT_ENVIRONMENT}}.yaml" - if: (inputs.API_MANAGEMENT_ENVIRONMENT == 'prod' ) - uses: cschleiden/replace-tokens@v1.1 - with: - tokenPrefix: "{#" - tokenSuffix: "#}" - files: ${{ format('["**/configuration.{0}.yaml"]', inputs.API_MANAGEMENT_ENVIRONMENT) }} - # specify environment specific secrets to be replaced. For example the QA environment could have a different set sercrets to - # replace within the configuration.[environment].yaml file - env: - testSecretValue: ${{ secrets.AZURE_RESOURCE_GROUP_NAME }} - - - name: Run publisher without Config Yaml but with Commit ID - if: ( inputs.CONFIGURATION_YAML_PATH == '' && inputs.COMMIT_ID != '') - env: - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - AZURE_RESOURCE_GROUP_NAME: ${{ secrets.AZURE_RESOURCE_GROUP_NAME }} - API_MANAGEMENT_SERVICE_NAME: ${{ secrets.API_MANAGEMENT_SERVICE_NAME }} - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/${{ inputs.API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH }} - COMMIT_ID: ${{ inputs.COMMIT_ID }} - run: | - Set-StrictMode -Version Latest - $ErrorActionPreference = "Stop" - $VerbosePreference = "Continue" - $InformationPreference = "Continue" - - Write-Information "Downloading publisher..." - $publisherFileName = "publisher.linux-x64" - $publisherFinalFileName = "publisher" - if ("${{ runner.os }}" -like "*win*") { - $publisherFileName = "publisher.win-x64.exe" - $publisherFinalFileName = "publisher.exe" - } - elseif ("${{ runner.os }}" -like "*mac*" -and "${{ runner.arch }}" -like "*arm*") { - $publisherFileName = "publisher.osx-arm64" - } - elseif ("${{ runner.os }}" -like "*mac*" -and "${{ runner.arch }}" -like "*x86_64*") { - $publisherFileName = "publisher.osx-x64" - } - - $uri = "https://github.com/Azure/apiops/releases/download/${{ env.apiops_release_version }}/$publisherFileName" - $destinationFilePath = Join-Path "${{ runner.temp }}" $publisherFinalFileName - Invoke-WebRequest -Uri "$uri" -OutFile "$destinationFilePath" - - if ("${{ runner.os }}" -like "*linux*") - { - Write-Information "Setting file permissions..." - & chmod +x "$destinationFilePath" - if ($LASTEXITCODE -ne 0) { throw "Setting file permissions failed."} - } - - & "$destinationFilePath" - if ($LASTEXITCODE -ne 0) { throw "Running publisher failed."} - - Write-Information "Execution complete." - shell: pwsh - - - name: Run publisher without Config Yaml or Commit ID - if: ( inputs.CONFIGURATION_YAML_PATH == '' && inputs.COMMIT_ID == '') - env: - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - AZURE_RESOURCE_GROUP_NAME: ${{ secrets.AZURE_RESOURCE_GROUP_NAME }} - API_MANAGEMENT_SERVICE_NAME: ${{ secrets.API_MANAGEMENT_SERVICE_NAME }} - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/${{ inputs.API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH }} - run: | - Set-StrictMode -Version Latest - $ErrorActionPreference = "Stop" - $VerbosePreference = "Continue" - $InformationPreference = "Continue" - - Write-Information "Downloading publisher..." - $publisherFileName = "publisher.linux-x64" - $publisherFinalFileName = "publisher" - if("${{ runner.os }}" -like "*win*"){ - $publisherFileName = "publisher.win-x64.exe" - $publisherFinalFileName = "publisher.exe" - } - elseif("${{ runner.os }}" -like "*mac*" -and "${{ runner.arch }}" -like "*arm*"){ - $publisherFileName = "publisher.osx-arm64" - } - elseif ("${{ runner.os }}" -like "*mac*" -and "${{ runner.arch }}" -like "*x86_64*") { - $publisherFileName = "publisher.osx-x64" - } - - $uri = "https://github.com/Azure/apiops/releases/download/${{ env.apiops_release_version }}/$publisherFileName" - $destinationFilePath = Join-Path "${{ runner.temp }}" $publisherFinalFileName - Invoke-WebRequest -Uri "$uri" -OutFile "$destinationFilePath" - - if ("${{ runner.os }}" -like "*linux*") - { - Write-Information "Setting file permissions..." - & chmod +x "$destinationFilePath" - if ($LASTEXITCODE -ne 0) { throw "Setting file permissions failed."} - } - - & "$destinationFilePath" - if ($LASTEXITCODE -ne 0) { throw "Running publisher failed."} - - Write-Information "Execution complete." - shell: pwsh - - - name: Run publisher with Config Yaml and Commit id - if: ( inputs.CONFIGURATION_YAML_PATH != '' && inputs.COMMIT_ID != '') - env: - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - AZURE_RESOURCE_GROUP_NAME: ${{ secrets.AZURE_RESOURCE_GROUP_NAME }} - API_MANAGEMENT_SERVICE_NAME: ${{ secrets.API_MANAGEMENT_SERVICE_NAME }} - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/${{ inputs.API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH }} - CONFIGURATION_YAML_PATH: ${{ GITHUB.WORKSPACE }}/${{ inputs.CONFIGURATION_YAML_PATH }} - COMMIT_ID: ${{ inputs.COMMIT_ID }} - run: | - Set-StrictMode -Version Latest - $ErrorActionPreference = "Stop" - $VerbosePreference = "Continue" - $InformationPreference = "Continue" - - Write-Information "Downloading publisher..." - $publisherFileName = "publisher.linux-x64" - $publisherFinalFileName = "publisher" - if("${{ runner.os }}" -like "*win*"){ - $publisherFileName = "publisher.win-x64.exe" - $publisherFinalFileName = "publisher.exe" - } - elseif("${{ runner.os }}" -like "*mac*" -and "${{ runner.arch }}" -like "*arm*"){ - $publisherFileName = "publisher.osx-arm64" - } - elseif ("${{ runner.os }}" -like "*mac*" -and "${{ runner.arch }}" -like "*x86_64*") { - $publisherFileName = "publisher.osx-x64" - } - - $uri = "https://github.com/Azure/apiops/releases/download/${{ env.apiops_release_version }}/$publisherFileName" - $destinationFilePath = Join-Path "${{ runner.temp }}" $publisherFinalFileName - Invoke-WebRequest -Uri "$uri" -OutFile "$destinationFilePath" - - if ("${{ runner.os }}" -like "*linux*") - { - Write-Information "Setting file permissions..." - & chmod +x "$destinationFilePath" - if ($LASTEXITCODE -ne 0) { throw "Setting file permissions failed."} - } - - & "$destinationFilePath" - if ($LASTEXITCODE -ne 0) { throw "Running publisher failed."} - - Write-Information "Execution complete." - shell: pwsh - - - name: Run publisher with Config Yaml but without Commit id - if: ( inputs.CONFIGURATION_YAML_PATH != '' && inputs.COMMIT_ID == '') - env: - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - AZURE_RESOURCE_GROUP_NAME: ${{ secrets.AZURE_RESOURCE_GROUP_NAME }} - API_MANAGEMENT_SERVICE_NAME: ${{ secrets.API_MANAGEMENT_SERVICE_NAME }} - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/${{ inputs.API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH }} - CONFIGURATION_YAML_PATH: ${{ GITHUB.WORKSPACE }}/${{ inputs.CONFIGURATION_YAML_PATH }} - run: | - Set-StrictMode -Version Latest - $ErrorActionPreference = "Stop" - $VerbosePreference = "Continue" - $InformationPreference = "Continue" - - Write-Information "Downloading publisher..." - $publisherFileName = "publisher.linux-x64" - $publisherFinalFileName = "publisher" - if("${{ runner.os }}" -like "*win*"){ - $publisherFileName = "publisher.win-x64.exe" - $publisherFinalFileName = "publisher.exe" - } - elseif("${{ runner.os }}" -like "*mac*" -and "${{ runner.arch }}" -like "*arm*"){ - $publisherFileName = "publisher.osx-arm64" - } - elseif ("${{ runner.os }}" -like "*mac*" -and "${{ runner.arch }}" -like "*x86_64*") { - $publisherFileName = "publisher.osx-x64" - } - - $uri = "https://github.com/Azure/apiops/releases/download/${{ env.apiops_release_version }}/$publisherFileName" - $destinationFilePath = Join-Path "${{ runner.temp }}" $publisherFinalFileName - Invoke-WebRequest -Uri "$uri" -OutFile "$destinationFilePath" - - if ("${{ runner.os }}" -like "*linux*") - { - Write-Information "Setting file permissions..." - & chmod +x "$destinationFilePath" - if ($LASTEXITCODE -ne 0) { throw "Setting file permissions failed."} - } - - & "$destinationFilePath" - if ($LASTEXITCODE -ne 0) { throw "Running publisher failed."} - - Write-Information "Execution complete." - shell: pwsh diff --git a/.github/workflows/run-publisher.yaml b/.github/workflows/run-publisher.yaml deleted file mode 100644 index 3f7ae4b..0000000 --- a/.github/workflows/run-publisher.yaml +++ /dev/null @@ -1,93 +0,0 @@ -name: Run - Publisher - -on: - # Triggers the workflow on pull request events but only for the main branch - pull_request: - branches: [main] - types: [closed] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - inputs: - COMMIT_ID_CHOICE: - description: 'Choose "publish-all-artifacts-in-repo" only when you want to force republishing all artifacts (e.g. after build failure). Otherwise stick with the default behavior of "publish-artifacts-in-last-commit"' - required: true - type: choice - default: "publish-artifacts-in-last-commit" - options: - - "publish-artifacts-in-last-commit" - - "publish-all-artifacts-in-repo" - -jobs: - get-commit: - runs-on: ubuntu-latest - steps: - # Set the COMMIT_ID env variable - - name: Set the Commit Id - id: commit - run: | - echo "::set-output name=commit_id::${{ github.sha }}" - outputs: - commit_id: ${{ steps.commit.outputs.commit_id }} - #Publish with Commit ID - Push-Changes-To-APIM-Test-With-Commit-ID: - if: (github.event.inputs.COMMIT_ID_CHOICE == 'publish-artifacts-in-last-commit' || github.event.inputs.COMMIT_ID_CHOICE == '') - needs: get-commit - uses: ./.github/workflows/run-publisher-with-env.yaml - with: - API_MANAGEMENT_ENVIRONMENT: Test # change this to match the dev environment created in settings - COMMIT_ID: ${{ needs.get-commit.outputs.commit_id }} - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder - secrets: inherit - - #Publish without Commit ID. Publishes all artifacts that reside in the artifacts forlder - Push-Changes-To-APIM-Test-Without-Commit-ID: - if: ( github.event.inputs.COMMIT_ID_CHOICE == 'publish-all-artifacts-in-repo' ) - needs: get-commit - uses: ./.github/workflows/run-publisher-with-env.yaml - with: - API_MANAGEMENT_ENVIRONMENT: Test - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder - secrets: inherit - - # Push-Changes-To-APIM-UAT-With-Commit-ID: - # if: (github.event.inputs.COMMIT_ID_CHOICE == 'publish-artifacts-in-last-commit' || github.event.inputs.COMMIT_ID_CHOICE == '') - # needs: [get-commit, Push-Changes-To-APIM-Dev-With-Commit-ID] - # uses: ./.github/workflows/run-publisher-with-env.yaml - # with: - # API_MANAGEMENT_ENVIRONMENT: UAT - # CONFIGURATION_YAML_PATH: configuration.uat.yaml # make sure the file is available at the root - # API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder - # COMMIT_ID: ${{ needs.get-commit.outputs.commit_id }} - # secrets: inherit - - # Push-Changes-To-APIM-UAT-Without-Commit-ID: - # if: ( github.event.inputs.COMMIT_ID_CHOICE == 'publish-all-artifacts-in-repo' ) - # needs: [get-commit, Push-Changes-To-APIM-Dev-Without-Commit-ID] - # uses: ./.github/workflows/run-publisher-with-env.yaml - # with: - # API_MANAGEMENT_ENVIRONMENT: UAT - # CONFIGURATION_YAML_PATH: configuration.uat.yaml # make sure the file is available at the root - # API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder - # secrets: inherit - - Push-Changes-To-APIM-Prod-With-Commit-ID: - if: (github.event.inputs.COMMIT_ID_CHOICE == 'publish-artifacts-in-last-commit' || github.event.inputs.COMMIT_ID_CHOICE == '') - needs: [get-commit, Push-Changes-To-APIM-Dev-With-Commit-ID] - uses: ./.github/workflows/run-publisher-with-env.yaml - with: - API_MANAGEMENT_ENVIRONMENT: Prod - CONFIGURATION_YAML_PATH: configuration.prod.yaml # make sure the file is available at the root - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder - COMMIT_ID: ${{ needs.get-commit.outputs.commit_id }} - secrets: inherit - - Push-Changes-To-APIM-Prod-Without-Commit-ID: - if: ( github.event.inputs.COMMIT_ID_CHOICE == 'publish-all-artifacts-in-repo' ) - needs: [get-commit, Push-Changes-To-APIM-Dev-Without-Commit-ID] - uses: ./.github/workflows/run-publisher-with-env.yaml - with: - API_MANAGEMENT_ENVIRONMENT: Prod - CONFIGURATION_YAML_PATH: configuration.prod.yaml # make sure the file is available at the root - API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH: ${{ GITHUB.WORKSPACE }}/src/apis/apimartifacts # change this to the artifacts folder - secrets: inherit diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..e69de29 diff --git a/src/.dockerignore b/src/.dockerignore new file mode 100644 index 0000000..fe1152b --- /dev/null +++ b/src/.dockerignore @@ -0,0 +1,30 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +!**/.gitignore +!.git/HEAD +!.git/config +!.git/packed-refs +!.git/refs/heads/** \ No newline at end of file diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 0000000..1655003 --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,473 @@ +########################################## +# Common Settings +########################################## + +# This file is the top-most EditorConfig file +root = true + +# All Files +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true +csharp_indent_labels = no_change +csharp_using_directive_placement = outside_namespace:warning +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:warning +csharp_style_namespace_declarations = file_scoped:warning +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_expression_bodied_methods = true:warning +csharp_style_expression_bodied_constructors = true:warning +csharp_style_expression_bodied_operators = true:warning +csharp_style_expression_bodied_properties = true:warning +csharp_style_expression_bodied_indexers = true:warning +csharp_style_expression_bodied_accessors = true:warning +csharp_style_expression_bodied_lambdas = true:warning +csharp_style_expression_bodied_local_functions = true:warning +csharp_style_throw_expression = true:warning +csharp_style_prefer_null_check_over_type_check = true:warning +csharp_prefer_simple_default_expression = true:warning +csharp_style_prefer_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:warning +csharp_style_prefer_range_operator = true:warning +csharp_style_implicit_object_creation_when_type_is_apparent = true:warning +csharp_style_prefer_tuple_swap = true:suggestion +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_style_inlined_variable_declaration = true:warning + +########################################## +# File Extension Settings +########################################## + +# Visual Studio Solution Files +[*.sln] +indent_style = tab + +# Visual Studio XML Project Files +[*.{csproj,vbproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# XML Configuration Files +[*.{xml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}] +indent_size = 2 + +# JSON Files +[*.{json,json5,webmanifest}] +indent_size = 2 + +# YAML Files +[*.{yml,yaml}] +indent_size = 2 + +# Markdown Files +[*.{md,mdx}] +trim_trailing_whitespace = false + +# Web Files +[*.{htm,html,js,jsm,ts,tsx,cjs,cts,ctsx,mjs,mts,mtsx,css,sass,scss,less,pcss,svg,vue}] +indent_size = 2 + +# Batch Files +[*.{cmd,bat}] +end_of_line = crlf + +# Bash Files +[*.sh] +end_of_line = lf + +# Makefiles +[Makefile] +indent_style = tab + +########################################## +# Default .NET Code Style Severities +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/configuration-options#scope +########################################## + +[*.{cs,csx,cake,vb,vbx}] +# Default Severity for all .NET Code Style rules below +dotnet_analyzer_diagnostic.severity = warning + +########################################## +# Language Rules +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules +########################################## + +# .NET Style Rules +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules#net-style-rules +[*.{cs,csx,cake,vb,vbx}] +# "this." and "Me." qualifiers +dotnet_style_qualification_for_field = true:warning +dotnet_style_qualification_for_property = true:warning +dotnet_style_qualification_for_method = true:warning +dotnet_style_qualification_for_event = true:warning +# Language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true:warning +dotnet_style_predefined_type_for_member_access = true:warning +# Modifier preferences +dotnet_style_require_accessibility_modifiers = always:warning +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning +visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:warning +dotnet_style_readonly_field = true:warning +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:warning +# Expression-level preferences +dotnet_style_object_initializer = true:warning +dotnet_style_collection_initializer = true:warning +dotnet_style_explicit_tuple_names = true:warning +dotnet_style_prefer_inferred_tuple_names = true:warning +dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning +dotnet_style_prefer_auto_properties = true:warning +dotnet_style_prefer_conditional_expression_over_assignment = false:suggestion +dotnet_diagnostic.IDE0045.severity = suggestion +dotnet_style_prefer_conditional_expression_over_return = false:suggestion +dotnet_diagnostic.IDE0046.severity = suggestion +dotnet_style_prefer_compound_assignment = true:warning +dotnet_style_prefer_simplified_interpolation = true:warning +dotnet_style_prefer_simplified_boolean_expressions = true:warning +# Null-checking preferences +dotnet_style_coalesce_expression = true:warning +dotnet_style_null_propagation = true:warning +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning +# File header preferences +# file_header_template = \n� PROJECT-AUTHOR\n +# If you use StyleCop, you'll need to disable SA1636: File header copyright text should match. +# dotnet_diagnostic.SA1636.severity = none +# Undocumented +dotnet_style_operator_placement_when_wrapping = end_of_line +csharp_style_prefer_null_check_over_type_check = true:warning + +# C# Style Rules +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/language-rules#c-style-rules +[*.{cs,csx,cake}] +# 'var' preferences +csharp_style_var_for_built_in_types = true:warning +csharp_style_var_when_type_is_apparent = true:warning +csharp_style_var_elsewhere = true:warning +# Expression-bodied members +csharp_style_expression_bodied_methods = true:warning +csharp_style_expression_bodied_constructors = true:warning +csharp_style_expression_bodied_operators = true:warning +csharp_style_expression_bodied_properties = true:warning +csharp_style_expression_bodied_indexers = true:warning +csharp_style_expression_bodied_accessors = true:warning +csharp_style_expression_bodied_lambdas = true:warning +csharp_style_expression_bodied_local_functions = true:warning +# Pattern matching preferences +csharp_style_pattern_matching_over_is_with_cast_check = true:warning +csharp_style_pattern_matching_over_as_with_null_check = true:warning +csharp_style_prefer_switch_expression = true:warning +csharp_style_prefer_pattern_matching = true:warning +csharp_style_prefer_not_pattern = true:warning +# Expression-level preferences +csharp_style_inlined_variable_declaration = true:warning +csharp_prefer_simple_default_expression = true:warning +csharp_style_pattern_local_over_anonymous_function = true:warning +csharp_style_deconstructed_variable_declaration = true:warning +csharp_style_prefer_index_operator = true:warning +csharp_style_prefer_range_operator = true:warning +csharp_style_implicit_object_creation_when_type_is_apparent = true:warning +# "Null" checking preferences +csharp_style_throw_expression = true:warning +csharp_style_conditional_delegate_call = true:warning +# Code block preferences +csharp_prefer_braces = true:warning +csharp_prefer_simple_using_statement = true:suggestion +dotnet_diagnostic.IDE0063.severity = suggestion +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:warning +# Modifier preferences +csharp_prefer_static_local_function = true:warning + +########################################## +# Unnecessary Code Rules +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/unnecessary-code-rules +########################################## + +# .NET Unnecessary code rules +[*.{cs,csx,cake,vb,vbx}] +dotnet_code_quality_unused_parameters = all:warning +dotnet_remove_unnecessary_suppression_exclusions = none:warning + +# C# Unnecessary code rules +[*.{cs,csx,cake}] +csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion +dotnet_diagnostic.IDE0058.severity = suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +dotnet_diagnostic.IDE0059.severity = suggestion + +########################################## +# Formatting Rules +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules +########################################## + +# .NET formatting rules +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#net-formatting-rules +[*.{cs,csx,cake,vb,vbx}] +# Organize using directives +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = false +# Dotnet namespace options +dotnet_style_namespace_match_folder = true:suggestion +dotnet_diagnostic.IDE0130.severity = suggestion + +# C# formatting rules +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#c-formatting-rules +[*.{cs,csx,cake}] +# Newline options +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#new-line-options +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true +# Indentation options +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#indentation-options +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = no_change +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents_when_block = false +# Spacing options +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#spacing-options +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_after_comma = true +csharp_space_before_comma = false +csharp_space_after_dot = false +csharp_space_before_dot = false +csharp_space_after_semicolon_in_for_statement = true +csharp_space_before_semicolon_in_for_statement = false +csharp_space_around_declaration_statements = false +csharp_space_before_open_square_brackets = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_square_brackets = false +# Wrap options +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#wrap-options +csharp_preserve_single_line_statements = false +csharp_preserve_single_line_blocks = true +# Namespace options +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#namespace-options +csharp_style_namespace_declarations = file_scoped:warning + +########################################## +# .NET Naming Rules +# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/naming-rules +########################################## + +[*.{cs,csx,cake,vb,vbx}] + +########################################## +# Styles +########################################## + +# camel_case_style - Define the camelCase style +dotnet_naming_style.camel_case_style.capitalization = camel_case +# pascal_case_style - Define the PascalCase style +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +# first_upper_style - The first character must start with an upper-case character +dotnet_naming_style.first_upper_style.capitalization = first_word_upper +# prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I' +dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case +dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I +# prefix_type_parameters_with_t_style - Generic Type Parameters must be PascalCase and the first character must be a 'T' +dotnet_naming_style.prefix_type_parameters_with_t_style.capitalization = pascal_case +dotnet_naming_style.prefix_type_parameters_with_t_style.required_prefix = T +# disallowed_style - Anything that has this style applied is marked as disallowed +dotnet_naming_style.disallowed_style.capitalization = pascal_case +dotnet_naming_style.disallowed_style.required_prefix = ____RULE_VIOLATION____ +dotnet_naming_style.disallowed_style.required_suffix = ____RULE_VIOLATION____ +# internal_error_style - This style should never occur... if it does, it indicates a bug in file or in the parser using the file +dotnet_naming_style.internal_error_style.capitalization = pascal_case +dotnet_naming_style.internal_error_style.required_prefix = ____INTERNAL_ERROR____ +dotnet_naming_style.internal_error_style.required_suffix = ____INTERNAL_ERROR____ + +########################################## +# .NET Design Guideline Field Naming Rules +# Naming rules for fields follow the .NET Framework design guidelines +# https://docs.microsoft.com/dotnet/standard/design-guidelines/index +########################################## + +# All public/protected/protected_internal constant fields must be PascalCase +# https://docs.microsoft.com/dotnet/standard/design-guidelines/field +dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected, protected_internal +dotnet_naming_symbols.public_protected_constant_fields_group.required_modifiers = const +dotnet_naming_symbols.public_protected_constant_fields_group.applicable_kinds = field +dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.symbols = public_protected_constant_fields_group +dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.style = pascal_case_style +dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.severity = warning + +# All public/protected/protected_internal static readonly fields must be PascalCase +# https://docs.microsoft.com/dotnet/standard/design-guidelines/field +dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_accessibilities = public, protected, protected_internal +dotnet_naming_symbols.public_protected_static_readonly_fields_group.required_modifiers = static, readonly +dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_kinds = field +dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.symbols = public_protected_static_readonly_fields_group +dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style +dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.severity = warning + +# No other public/protected/protected_internal fields are allowed +# https://docs.microsoft.com/dotnet/standard/design-guidelines/field +dotnet_naming_symbols.other_public_protected_fields_group.applicable_accessibilities = public, protected, protected_internal +dotnet_naming_symbols.other_public_protected_fields_group.applicable_kinds = field +dotnet_naming_rule.other_public_protected_fields_disallowed_rule.symbols = other_public_protected_fields_group +dotnet_naming_rule.other_public_protected_fields_disallowed_rule.style = disallowed_style +dotnet_naming_rule.other_public_protected_fields_disallowed_rule.severity = error + +########################################## +# StyleCop Field Naming Rules +# Naming rules for fields follow the StyleCop analyzers +# This does not override any rules using disallowed_style above +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers +########################################## + +# All constant fields must be PascalCase +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1303.md +dotnet_naming_symbols.stylecop_constant_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private +dotnet_naming_symbols.stylecop_constant_fields_group.required_modifiers = const +dotnet_naming_symbols.stylecop_constant_fields_group.applicable_kinds = field +dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.symbols = stylecop_constant_fields_group +dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.style = pascal_case_style +dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.severity = warning + +# All static readonly fields must be PascalCase +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1311.md +dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private +dotnet_naming_symbols.stylecop_static_readonly_fields_group.required_modifiers = static, readonly +dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_kinds = field +dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.symbols = stylecop_static_readonly_fields_group +dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style +dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.severity = warning + +# No non-private instance fields are allowed +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md +dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected +dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_kinds = field +dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.symbols = stylecop_fields_must_be_private_group +dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.style = disallowed_style +dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.severity = error + +# Private fields must be camelCase +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1306.md +dotnet_naming_symbols.stylecop_private_fields_group.applicable_accessibilities = private +dotnet_naming_symbols.stylecop_private_fields_group.applicable_kinds = field +dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.symbols = stylecop_private_fields_group +dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.style = camel_case_style +dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.severity = warning + +# Local variables must be camelCase +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md +dotnet_naming_symbols.stylecop_local_fields_group.applicable_accessibilities = local +dotnet_naming_symbols.stylecop_local_fields_group.applicable_kinds = local +dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.symbols = stylecop_local_fields_group +dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.style = camel_case_style +dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.severity = silent + +# This rule should never fire. However, it's included for at least two purposes: +# First, it helps to understand, reason about, and root-case certain types of issues, such as bugs in .editorconfig parsers. +# Second, it helps to raise immediate awareness if a new field type is added (as occurred recently in C#). +dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_accessibilities = * +dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_kinds = field +dotnet_naming_rule.sanity_check_uncovered_field_case_rule.symbols = sanity_check_uncovered_field_case_group +dotnet_naming_rule.sanity_check_uncovered_field_case_rule.style = internal_error_style +dotnet_naming_rule.sanity_check_uncovered_field_case_rule.severity = error + + +########################################## +# Other Naming Rules +########################################## + +# All of the following must be PascalCase: +# - Namespaces +# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-namespaces +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md +# - Classes and Enumerations +# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md +# - Delegates +# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces#names-of-common-types +# - Constructors, Properties, Events, Methods +# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-type-members +dotnet_naming_symbols.element_group.applicable_kinds = namespace, class, enum, struct, delegate, event, method, property +dotnet_naming_rule.element_rule.symbols = element_group +dotnet_naming_rule.element_rule.style = pascal_case_style +dotnet_naming_rule.element_rule.severity = warning + +# Interfaces use PascalCase and are prefixed with uppercase 'I' +# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces +dotnet_naming_symbols.interface_group.applicable_kinds = interface +dotnet_naming_rule.interface_rule.symbols = interface_group +dotnet_naming_rule.interface_rule.style = prefix_interface_with_i_style +dotnet_naming_rule.interface_rule.severity = warning + +# Generics Type Parameters use PascalCase and are prefixed with uppercase 'T' +# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces +dotnet_naming_symbols.type_parameter_group.applicable_kinds = type_parameter +dotnet_naming_rule.type_parameter_rule.symbols = type_parameter_group +dotnet_naming_rule.type_parameter_rule.style = prefix_type_parameters_with_t_style +dotnet_naming_rule.type_parameter_rule.severity = warning + +# Function parameters use camelCase +# https://docs.microsoft.com/dotnet/standard/design-guidelines/naming-parameters +dotnet_naming_symbols.parameters_group.applicable_kinds = parameter +dotnet_naming_rule.parameters_rule.symbols = parameters_group +dotnet_naming_rule.parameters_rule.style = camel_case_style +dotnet_naming_rule.parameters_rule.severity = warning +tab_width = 4 +end_of_line = crlf +dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion + +########################################## +# License +########################################## +# The following applies as to the .editorconfig file ONLY, and is +# included below for reference, per the requirements of the license +# corresponding to this .editorconfig file. +# See: https://github.com/RehanSaeed/EditorConfig +# +# MIT License +# +# Copyright (c) 2017-2019 Muhammad Rehan Saeed +# Copyright (c) 2019 Henry Gabryjelski +# +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, +# sublicense, and/or sell copies of the Software, and to permit +# persons to whom the Software is furnished to do so, subject +# to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +########################################## diff --git a/src/IpSimple.Domain.Tests/IpSimple.Domain.Tests.csproj b/src/IpSimple.Domain.Tests/IpSimple.Domain.Tests.csproj new file mode 100644 index 0000000..9c5b30a --- /dev/null +++ b/src/IpSimple.Domain.Tests/IpSimple.Domain.Tests.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + diff --git a/src/IpSimple.Domain/Constants.cs b/src/IpSimple.Domain/Constants.cs new file mode 100644 index 0000000..65b4631 --- /dev/null +++ b/src/IpSimple.Domain/Constants.cs @@ -0,0 +1,22 @@ +namespace IpSimple.Domain; + +public static class Constants +{ + public static class HttpHeaders + { + public const string XAzureClientIPHeader = "X-Azure-ClientIP"; + public const string XForwardedForHeader = "X-Forwarded-For"; + public const string ViaHeader = "Via"; + public const string XAzureSocketIPHeader = "X-Azure-SocketIP"; + public const string XAzureRefHeader = "X-Azure-Ref"; + public const string XAzureRequestChainHeader = "X-Azure-RequestChain"; + public const string XForwardedHostHeader = "X-Forwarded-Host"; + public const string XForwardedProtoHeader = "X-Forwarded-Proto"; + public const string XFDHealthProbeHeader = "X-FD-HealthProbe"; + } + + public static class ErrorMessages + { + public const string NoClientIpFound = "No client IP address found in the request (X-Forwarded-For header is missing)."; + } +} diff --git a/src/IpSimple.Domain/IpSimple.Domain.csproj b/src/IpSimple.Domain/IpSimple.Domain.csproj new file mode 100644 index 0000000..307ec47 --- /dev/null +++ b/src/IpSimple.Domain/IpSimple.Domain.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/src/IpSimple.Domain/Models/IpAddress.cs b/src/IpSimple.Domain/Models/IpAddress.cs new file mode 100644 index 0000000..09d09e5 --- /dev/null +++ b/src/IpSimple.Domain/Models/IpAddress.cs @@ -0,0 +1,6 @@ +namespace IpSimple.PublicIp.Api; + +public class IpAddress(string ip) +{ + public string Ip { get; } = ip; +} diff --git a/src/IpSimple.Domain/Settings/JsonSerializerSettings.cs b/src/IpSimple.Domain/Settings/JsonSerializerSettings.cs new file mode 100644 index 0000000..2547169 --- /dev/null +++ b/src/IpSimple.Domain/Settings/JsonSerializerSettings.cs @@ -0,0 +1,12 @@ +using System.Text.Json; + +namespace IpSimple.Domain.Settings; + +public static class JsonSerializerSettings +{ + public static readonly JsonSerializerOptions DefaultJsonSerializer = new() + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = false // Set to false for performance reasons + }; +} diff --git a/src/IpSimple.Extensions.Tests/HttpContextExtensionsTests.cs b/src/IpSimple.Extensions.Tests/HttpContextExtensionsTests.cs new file mode 100644 index 0000000..5c5e68e --- /dev/null +++ b/src/IpSimple.Extensions.Tests/HttpContextExtensionsTests.cs @@ -0,0 +1,75 @@ +using IpSimple.Domain; +using Microsoft.AspNetCore.Http; + +namespace IpSimple.Extensions.Tests; + +public class HttpContextExtensionsTests +{ + [Fact] + public void GetClientIpAddress_XAzureClientIPHeaderPresent_ReturnsAzureClientIP() + { + // Arrange + var context = new DefaultHttpContext(); + context.Request.Headers[Constants.HttpHeaders.XAzureClientIPHeader] = "203.211.106.230"; + + // Act + var result = HttpContextExtensions.GetClientIpAddress(context); + + // Assert + Assert.Equal("203.211.106.230", result); + } + + [Fact] + public void GetClientIpAddress_XForwardedForHeaderPresent_ReturnsFirstForwardedForIP() + { + // Arrange + var context = new DefaultHttpContext(); + context.Request.Headers[Constants.HttpHeaders.XForwardedForHeader] = "203.211.106.230,147.243.18.238:45498,147.243.18.238"; + + // Act + var result = HttpContextExtensions.GetClientIpAddress(context); + + // Assert + Assert.Equal("203.211.106.230", result); + } + + [Fact] + public void GetClientIpAddress_NoRelevantHeadersPresent_ReturnsNull() + { + // Arrange + var context = new DefaultHttpContext(); + + // Act + var result = HttpContextExtensions.GetClientIpAddress(context); + + // Assert + Assert.Null(result); + } + + [Fact] + public void GetAllPossibleClientIpAddresses_XForwardedForHeaderPresent_ReturnsAllForwardedForIPs() + { + // Arrange + var context = new DefaultHttpContext(); + context.Request.Headers[Constants.HttpHeaders.XForwardedForHeader] = "203.211.106.230,147.243.18.238:45498,147.243.18.238"; + + // Act + var result = HttpContextExtensions.GetAllPossibleClientIpAddresses(context); + + // Assert + Assert.Equal("203.211.106.230,147.243.18.238:45498,147.243.18.238", result); + } + + [Fact] + public void GetAllPossibleClientIpAddresses_NoRelevantHeadersPresent_ReturnsNull() + { + // Arrange + var context = new DefaultHttpContext(); + + // Act + var result = HttpContextExtensions.GetAllPossibleClientIpAddresses(context); + + // Assert + Assert.Null(result); + } +} diff --git a/src/IpSimple.Extensions.Tests/IpSimple.Extensions.Tests.csproj b/src/IpSimple.Extensions.Tests/IpSimple.Extensions.Tests.csproj new file mode 100644 index 0000000..0b0ba0e --- /dev/null +++ b/src/IpSimple.Extensions.Tests/IpSimple.Extensions.Tests.csproj @@ -0,0 +1,32 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/IpSimple.Extensions/HttpContextExtensions.cs b/src/IpSimple.Extensions/HttpContextExtensions.cs new file mode 100644 index 0000000..c09f2e9 --- /dev/null +++ b/src/IpSimple.Extensions/HttpContextExtensions.cs @@ -0,0 +1,66 @@ +using IpSimple.Domain; +using Microsoft.AspNetCore.Http; + +namespace IpSimple.Extensions; + +public static class HttpContextExtensions +{ + /// + /// Gets the client IP address from the HttpContext. + /// If the request is forwarded by Azure Front Door, it will have the below headers + /// + /// "Via": "HTTP/1.1 Azure", + /// "X-Azure-ClientIP": "203.211.106.230", + /// "X-Azure-SocketIP": "203.211.106.230", + /// "X-Azure-Ref": "20240711T031409Z-16f8dbf69ccxc7nz3vdync91ac00000001hg00000000d6vf", + /// "X-Azure-RequestChain": "", + /// "X-Forwarded-For": "203.211.106.230,147.243.18.238:45498,147.243.18.238", + /// "X-Forwarded-Host": "api.ipsimple.org", + /// "X-Forwarded-Proto": "https", + /// "X-FD-HealthProbe": "" + /// + /// If X-Azure-ClientIP is present, it will be used as the client IP address. If not then the X-Forwarded-For header will be used. + /// + /// + /// The client IP address if found, otherwise null. + public static string? GetClientIpAddress(this HttpContext httpContext) + { + // If we found the X-Azure-ClientIP header, we use the client IP address + var xAzureClientIPHeaderFound = httpContext.Request.Headers.TryGetValue(Constants.HttpHeaders.XAzureClientIPHeader, out var azureClientIp); + if (xAzureClientIPHeaderFound) + { + return azureClientIp.ToString(); + } + + // If we have something else instead of Azure Front Door, we use the X-Forwarded-For header + var xForwardedForHeaderFound = httpContext.Request.Headers.TryGetValue(Constants.HttpHeaders.XForwardedForHeader, out var forwardedFor); + if (xForwardedForHeaderFound) + { + //The first IP is always the original client IP address + return forwardedFor.ToString().Split(',')[0]; + } + + //If we don't have any of the above headers, return null and let the caller decide what to do (either the caller can throw the exception or return something back to the client) + return null; + } + + /// + /// Gets all possible client IP addresses from the X-forwarded-for header. + /// + /// This is useful in some cases where the proxy server might be appending the ip address of the client to the X-forwarded-for header in the wrong order + /// and it is not the first IP address in the header + /// + /// + /// All possible client IP addresses if found, otherwise null. + public static string? GetAllPossibleClientIpAddresses(this HttpContext httpContext) + { + var xForwardedForHeaderFound = httpContext.Request.Headers.TryGetValue(Constants.HttpHeaders.XForwardedForHeader, out var forwardedFor); + if (xForwardedForHeaderFound) + { + return forwardedFor.ToString(); + } + + //If we don't actually have the x-forwarded-for header, return null and let the caller decide what to do (either the caller can throw the exception or return something back to the client) + return null; + } +} diff --git a/src/IpSimple.Extensions/IpSimple.Extensions.csproj b/src/IpSimple.Extensions/IpSimple.Extensions.csproj new file mode 100644 index 0000000..2fd4b92 --- /dev/null +++ b/src/IpSimple.Extensions/IpSimple.Extensions.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + diff --git a/src/IpSimple.Platform.sln b/src/IpSimple.Platform.sln new file mode 100644 index 0000000..696e7b1 --- /dev/null +++ b/src/IpSimple.Platform.sln @@ -0,0 +1,68 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.35013.160 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpSimple.Domain", "IpSimple.Domain\IpSimple.Domain.csproj", "{60A8DFF4-41E1-4CCA-BF3E-2DF1DD28A801}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpSimple.Extensions", "IpSimple.Extensions\IpSimple.Extensions.csproj", "{72206E2D-FAEC-459A-BB37-7415768036DE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpSimple.PublicIp.Api", "IpSimple.PublicIp.Api\IpSimple.PublicIp.Api.csproj", "{97B36A0F-F8E0-4E7F-9173-C1F6EDCFF40B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F34E5B9F-7E19-4684-B192-71F2EF59CD9D}" + ProjectSection(SolutionItems) = preProject + .dockerignore = .dockerignore + .editorconfig = .editorconfig + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{17FCB810-7102-49BA-8377-F2B17A4603C1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpSimple.PublicIp.Api.Tests", "IpSimple.PublicIp.Api.Tests\IpSimple.PublicIp.Api.Tests.csproj", "{D81D21FB-1F2F-4051-A8D1-C2FDC900C3CB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpSimple.Extensions.Tests", "IpSimple.Extensions.Tests\IpSimple.Extensions.Tests.csproj", "{B79AD7F8-6E71-4E78-BB62-F71AADB8ABAA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpSimple.Domain.Tests", "IpSimple.Domain.Tests\IpSimple.Domain.Tests.csproj", "{AC3A2C72-CDDA-45FF-843B-9AA7D3BE6B40}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {60A8DFF4-41E1-4CCA-BF3E-2DF1DD28A801}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60A8DFF4-41E1-4CCA-BF3E-2DF1DD28A801}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60A8DFF4-41E1-4CCA-BF3E-2DF1DD28A801}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60A8DFF4-41E1-4CCA-BF3E-2DF1DD28A801}.Release|Any CPU.Build.0 = Release|Any CPU + {72206E2D-FAEC-459A-BB37-7415768036DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {72206E2D-FAEC-459A-BB37-7415768036DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {72206E2D-FAEC-459A-BB37-7415768036DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {72206E2D-FAEC-459A-BB37-7415768036DE}.Release|Any CPU.Build.0 = Release|Any CPU + {97B36A0F-F8E0-4E7F-9173-C1F6EDCFF40B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {97B36A0F-F8E0-4E7F-9173-C1F6EDCFF40B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {97B36A0F-F8E0-4E7F-9173-C1F6EDCFF40B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {97B36A0F-F8E0-4E7F-9173-C1F6EDCFF40B}.Release|Any CPU.Build.0 = Release|Any CPU + {D81D21FB-1F2F-4051-A8D1-C2FDC900C3CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D81D21FB-1F2F-4051-A8D1-C2FDC900C3CB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D81D21FB-1F2F-4051-A8D1-C2FDC900C3CB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D81D21FB-1F2F-4051-A8D1-C2FDC900C3CB}.Release|Any CPU.Build.0 = Release|Any CPU + {B79AD7F8-6E71-4E78-BB62-F71AADB8ABAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B79AD7F8-6E71-4E78-BB62-F71AADB8ABAA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B79AD7F8-6E71-4E78-BB62-F71AADB8ABAA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B79AD7F8-6E71-4E78-BB62-F71AADB8ABAA}.Release|Any CPU.Build.0 = Release|Any CPU + {AC3A2C72-CDDA-45FF-843B-9AA7D3BE6B40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC3A2C72-CDDA-45FF-843B-9AA7D3BE6B40}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC3A2C72-CDDA-45FF-843B-9AA7D3BE6B40}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC3A2C72-CDDA-45FF-843B-9AA7D3BE6B40}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D81D21FB-1F2F-4051-A8D1-C2FDC900C3CB} = {17FCB810-7102-49BA-8377-F2B17A4603C1} + {B79AD7F8-6E71-4E78-BB62-F71AADB8ABAA} = {17FCB810-7102-49BA-8377-F2B17A4603C1} + {AC3A2C72-CDDA-45FF-843B-9AA7D3BE6B40} = {17FCB810-7102-49BA-8377-F2B17A4603C1} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {99501301-09F2-4716-BCA5-C3FD086B75DB} + EndGlobalSection +EndGlobal diff --git a/src/IpSimple.PublicIp.Api.BenchmarkTesting/ApiBenchmark.cs b/src/IpSimple.PublicIp.Api.BenchmarkTesting/ApiBenchmark.cs new file mode 100644 index 0000000..3ea87a1 --- /dev/null +++ b/src/IpSimple.PublicIp.Api.BenchmarkTesting/ApiBenchmark.cs @@ -0,0 +1,44 @@ +using BenchmarkDotNet.Attributes; + +namespace IpSimple.PublicIp.Api.BenchmarkTesting; + +public class ApiBenchmark +{ + private static readonly HttpClient Client = new() { BaseAddress = new Uri("http://localhost:5021") }; + + [Benchmark] + public async Task GetIpv4() + { + var request = new HttpRequestMessage(HttpMethod.Get, "/ipv4"); + request.Headers.Add("X-Forwarded-For", "98.207.254.136"); + request.Headers.Add("X-Azure-ClientIP", "203.0.113.195"); + await Client.SendAsync(request); + } + + [Benchmark] + public async Task GetIpv4All() + { + var request = new HttpRequestMessage(HttpMethod.Get, "/ipv4/all"); + request.Headers.Add("X-Forwarded-For", "98.207.254.136, 203.0.113.195"); + request.Headers.Add("X-Azure-ClientIP", "203.0.113.195"); + await Client.SendAsync(request); + } + + [Benchmark] + public async Task GetIpv6() + { + var request = new HttpRequestMessage(HttpMethod.Get, "/ipv6"); + request.Headers.Add("X-Forwarded-For", "2a00:1450:400f:80d::200e"); + request.Headers.Add("X-Azure-ClientIP", "2a00:1450:400f:80d::200e"); + await Client.SendAsync(request); + } + + [Benchmark] + public async Task GetIpv6All() + { + var request = new HttpRequestMessage(HttpMethod.Get, "/ipv6/all"); + request.Headers.Add("X-Forwarded-For", "2a00:1450:400f:80d::200e, 2a00:1450:400f:80d::200f"); + request.Headers.Add("X-Azure-ClientIP", "2a00:1450:400f:80d::200e"); + await Client.SendAsync(request); + } +} diff --git a/src/IpSimple.PublicIp.Api.BenchmarkTesting/BenchmarkDotNet.Artifacts/results/IpSimple.PublicIp.Api.BenchmarkTesting.ApiBenchmark-report-github.md b/src/IpSimple.PublicIp.Api.BenchmarkTesting/BenchmarkDotNet.Artifacts/results/IpSimple.PublicIp.Api.BenchmarkTesting.ApiBenchmark-report-github.md new file mode 100644 index 0000000..b908bdc --- /dev/null +++ b/src/IpSimple.PublicIp.Api.BenchmarkTesting/BenchmarkDotNet.Artifacts/results/IpSimple.PublicIp.Api.BenchmarkTesting.ApiBenchmark-report-github.md @@ -0,0 +1,16 @@ +``` + +BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3880/23H2/2023Update/SunValley3) +11th Gen Intel Core i7-11700K 3.60GHz, 1 CPU, 16 logical and 8 physical cores +.NET SDK 8.0.302 + [Host] : .NET 8.0.6 (8.0.624.26715), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI + DefaultJob : .NET 8.0.6 (8.0.624.26715), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI + + +``` +| Method | Mean | Error | StdDev | +|----------- |---------:|--------:|--------:| +| GetIpv4 | 109.0 μs | 1.98 μs | 3.57 μs | +| GetIpv4All | 108.3 μs | 2.09 μs | 3.44 μs | +| GetIpv6 | 107.8 μs | 2.15 μs | 3.41 μs | +| GetIpv6All | 108.2 μs | 2.15 μs | 2.80 μs | diff --git a/src/IpSimple.PublicIp.Api.BenchmarkTesting/BenchmarkDotNet.Artifacts/results/IpSimple.PublicIp.Api.BenchmarkTesting.ApiBenchmark-report.csv b/src/IpSimple.PublicIp.Api.BenchmarkTesting/BenchmarkDotNet.Artifacts/results/IpSimple.PublicIp.Api.BenchmarkTesting.ApiBenchmark-report.csv new file mode 100644 index 0000000..cd9904a --- /dev/null +++ b/src/IpSimple.PublicIp.Api.BenchmarkTesting/BenchmarkDotNet.Artifacts/results/IpSimple.PublicIp.Api.BenchmarkTesting.ApiBenchmark-report.csv @@ -0,0 +1,5 @@ +Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,LargeAddressAware,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Mean,Error,StdDev +GetIpv4,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,109.0 μs,1.98 μs,3.57 μs +GetIpv4All,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,108.3 μs,2.09 μs,3.44 μs +GetIpv6,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,107.8 μs,2.15 μs,3.41 μs +GetIpv6All,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,108.2 μs,2.15 μs,2.80 μs diff --git a/src/IpSimple.PublicIp.Api.BenchmarkTesting/BenchmarkDotNet.Artifacts/results/IpSimple.PublicIp.Api.BenchmarkTesting.ApiBenchmark-report.html b/src/IpSimple.PublicIp.Api.BenchmarkTesting/BenchmarkDotNet.Artifacts/results/IpSimple.PublicIp.Api.BenchmarkTesting.ApiBenchmark-report.html new file mode 100644 index 0000000..1ef994b --- /dev/null +++ b/src/IpSimple.PublicIp.Api.BenchmarkTesting/BenchmarkDotNet.Artifacts/results/IpSimple.PublicIp.Api.BenchmarkTesting.ApiBenchmark-report.html @@ -0,0 +1,33 @@ + + + + +IpSimple.PublicIp.Api.BenchmarkTesting.ApiBenchmark-20240711-184648 + + + + +

+BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3880/23H2/2023Update/SunValley3)
+11th Gen Intel Core i7-11700K 3.60GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 8.0.302
+  [Host]     : .NET 8.0.6 (8.0.624.26715), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
+  DefaultJob : .NET 8.0.6 (8.0.624.26715), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
+
+
+ + + + + + + + +
MethodMeanErrorStdDev
GetIpv4109.0 μs1.98 μs3.57 μs
GetIpv4All108.3 μs2.09 μs3.44 μs
GetIpv6107.8 μs2.15 μs3.41 μs
GetIpv6All108.2 μs2.15 μs2.80 μs
+ + diff --git a/src/IpSimple.PublicIp.Api.BenchmarkTesting/IpSimple.PublicIp.Api.BenchmarkTesting.csproj b/src/IpSimple.PublicIp.Api.BenchmarkTesting/IpSimple.PublicIp.Api.BenchmarkTesting.csproj new file mode 100644 index 0000000..7a51816 --- /dev/null +++ b/src/IpSimple.PublicIp.Api.BenchmarkTesting/IpSimple.PublicIp.Api.BenchmarkTesting.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/src/IpSimple.PublicIp.Api.BenchmarkTesting/Program.cs b/src/IpSimple.PublicIp.Api.BenchmarkTesting/Program.cs new file mode 100644 index 0000000..f9a1cac --- /dev/null +++ b/src/IpSimple.PublicIp.Api.BenchmarkTesting/Program.cs @@ -0,0 +1,8 @@ +using BenchmarkDotNet.Running; + +namespace IpSimple.PublicIp.Api.BenchmarkTesting; + +public class Program +{ + public static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); +} diff --git a/src/IpSimple.PublicIp.Api.Tests/IpSimple.PublicIp.Api.Tests.csproj b/src/IpSimple.PublicIp.Api.Tests/IpSimple.PublicIp.Api.Tests.csproj new file mode 100644 index 0000000..538b31a --- /dev/null +++ b/src/IpSimple.PublicIp.Api.Tests/IpSimple.PublicIp.Api.Tests.csproj @@ -0,0 +1,32 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/IpSimple.PublicIp.Api.Tests/Services/IpAddressServiceTests.cs b/src/IpSimple.PublicIp.Api.Tests/Services/IpAddressServiceTests.cs new file mode 100644 index 0000000..57c0398 --- /dev/null +++ b/src/IpSimple.PublicIp.Api.Tests/Services/IpAddressServiceTests.cs @@ -0,0 +1,82 @@ +using IpSimple.PublicIp.Api.Services; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.HttpResults; + +namespace IpSimple.PublicIp.Api.Tests; + +public class IpAddressServiceTests +{ + private readonly IIpAddressService ipAddressService; + + public IpAddressServiceTests() => ipAddressService = new IpAddressService(); + + [Fact] + public void GetClientIp_WithoutFormat_ReturnsPlainText() + { + // Arrange + var context = new DefaultHttpContext(); + context.Request.Headers["X-Forwarded-For"] = "98.207.254.136"; + + // Act + var result = ipAddressService.GetClientIp(context); + + // Assert + Assert.NotNull(result); + var textResult = Assert.IsType(result); + Assert.Equal("text/plain", textResult.ContentType); + Assert.Equal("98.207.254.136", textResult.ResponseContent); + } + + [Fact] + public void GetClientIp_WithFormatJson_ReturnsJson() + { + // Arrange + var context = new DefaultHttpContext(); + context.Request.Headers["X-Forwarded-For"] = "98.207.254.136"; + context.Request.QueryString = new QueryString("?format=json"); + + // Act + var result = ipAddressService.GetClientIp(context); + + // Assert + Assert.NotNull(result); + var jsonResult = Assert.IsType>(result); + var ip = jsonResult.Value.Ip; + Assert.Equal("98.207.254.136", ip); + } + + [Fact] + public void GetAllClientIps_WithoutFormat_ReturnsPlainText() + { + // Arrange + var context = new DefaultHttpContext(); + context.Request.Headers["X-Forwarded-For"] = "98.207.254.136, 203.0.113.195"; + + // Act + var result = ipAddressService.GetAllClientIps(context); + + // Assert + Assert.NotNull(result); + var textResult = Assert.IsType(result); + Assert.Equal("text/plain", textResult.ContentType); + Assert.Equal("98.207.254.136, 203.0.113.195", textResult.ResponseContent); + } + + [Fact] + public void GetAllClientIps_WithFormatJson_ReturnsJson() + { + // Arrange + var context = new DefaultHttpContext(); + context.Request.Headers["X-Forwarded-For"] = "98.207.254.136, 203.0.113.195"; + context.Request.QueryString = new QueryString("?format=json"); + + // Act + var result = ipAddressService.GetAllClientIps(context); + + // Assert + Assert.NotNull(result); + var jsonResult = Assert.IsType>(result); + var ip = jsonResult.Value.Ip; + Assert.Equal("98.207.254.136, 203.0.113.195", ip); + } +} diff --git a/src/IpSimple.PublicIp.Api/Dockerfile b/src/IpSimple.PublicIp.Api/Dockerfile new file mode 100644 index 0000000..986fd16 --- /dev/null +++ b/src/IpSimple.PublicIp.Api/Dockerfile @@ -0,0 +1,24 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +USER app +WORKDIR /app +EXPOSE 8080 + +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.csproj", "IpSimple.PublicIp.Api/"] +RUN dotnet restore "./IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.csproj" +COPY . . +WORKDIR "/src/IpSimple.PublicIp.Api" +RUN dotnet build "./IpSimple.PublicIp.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./IpSimple.PublicIp.Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "IpSimple.PublicIp.Api.dll"] \ No newline at end of file diff --git a/src/IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.csproj b/src/IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.csproj new file mode 100644 index 0000000..d6d4258 --- /dev/null +++ b/src/IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.csproj @@ -0,0 +1,29 @@ + + + + net8.0 + enable + enable + Linux + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.env.json b/src/IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.env.json new file mode 100644 index 0000000..f5d6638 --- /dev/null +++ b/src/IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.env.json @@ -0,0 +1,8 @@ +{ + "dev": { + "HostAddress": "http://localhost:5021" + }, + "prod": { + "HostAddress": "https://api.ipsimple.org" + } +} diff --git a/src/IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.http b/src/IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.http new file mode 100644 index 0000000..ff99ca3 --- /dev/null +++ b/src/IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.http @@ -0,0 +1,48 @@ +@baseUrl = http://localhost:5021 +### Test Public IPv4 Address in Plain Text Format +GET {{baseUrl}}/ipv4 +Accept: text/plain +X-Forwarded-For: 98.207.254.136 +X-Azure-ClientIP: 203.0.113.195 + +### Test Public IPv4 Address in JSON Format +GET {{baseUrl}}/ipv4?format=json +Accept: application/json +X-Forwarded-For: 98.207.254.136 +X-Azure-ClientIP: 203.0.113.195 + +### Test Public IPv4 Address in Plain Text Format (All IPs) +GET {{baseUrl}}/ipv4/all +Accept: text/plain +X-Forwarded-For: 98.207.254.136, 203.0.113.195 +X-Azure-ClientIP: 203.0.113.195 + +### Test Public IPv4 Address in JSON Format (All IPs) +GET {{baseUrl}}/ipv4/all?format=json +Accept: application/json +X-Forwarded-For: 98.207.254.136, 203.0.113.195 +X-Azure-ClientIP: 203.0.113.195 + +### Test Public IPv6 Address in Plain Text Format +GET {{baseUrl}}/ipv6 +Accept: text/plain +X-Forwarded-For: 2a00:1450:400f:80d::200e +X-Azure-ClientIP: 2a00:1450:400f:80d::200e + +### Test Public IPv6 Address in JSON Format +GET {{baseUrl}}/ipv6?format=json +Accept: application/json +X-Forwarded-For: 2a00:1450:400f:80d::200e +X-Azure-ClientIP: 2a00:1450:400f:80d::200e + +### Test Public IPv6 Address in Plain Text Format (All IPs) +GET {{baseUrl}}/ipv6/all +Accept: text/plain +X-Forwarded-For: 2a00:1450:400f:80d::200e, 2a00:1450:400f:80d::200f +X-Azure-ClientIP: 2a00:1450:400f:80d::200e + +### Test Public IPv6 Address in JSON Format (All IPs) +GET {{baseUrl}}/ipv6/all?format=json +Accept: application/json +X-Forwarded-For: 2a00:1450:400f:80d::200e, 2a00:1450:400f:80d::200f +X-Azure-ClientIP: 2a00:1450:400f:80d::200e diff --git a/src/IpSimple.PublicIp.Api/Program.cs b/src/IpSimple.PublicIp.Api/Program.cs new file mode 100644 index 0000000..55fb1d1 --- /dev/null +++ b/src/IpSimple.PublicIp.Api/Program.cs @@ -0,0 +1,70 @@ +using IpSimple.PublicIp.Api.Services; + +namespace IpSimple.PublicIp.Api; + +public class Program +{ + public static void Main(string[] args) + { + var app = CreateWebApp(args); + app.Run(); + } + + public static WebApplication CreateWebApp(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + builder.Services.AddAuthorization(); + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); + builder.Services.AddSingleton(); + + var app = builder.Build(); + + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + } + + var ipAddressService = app.Services.GetRequiredService(); + + app.MapGet("/ipv4", ipAddressService.GetClientIp) + .WithName("GetPublicIPv4") + .WithOpenApi(operation => + { + operation.Summary = "Public IPv4 address"; + operation.Description = "This endpoint returns the public IPv4 address of the client making the request."; + return operation; + }); + + app.MapGet("/ipv4/all", ipAddressService.GetAllClientIps) + .WithName("GetAllPublicIPv4") + .WithOpenApi(operation => + { + operation.Summary = "All Public IPv4 addresses"; + operation.Description = "This endpoint returns all public IPv4 addresses from the X-Forwarded-For header."; + return operation; + }); + + app.MapGet("/ipv6", ipAddressService.GetClientIp) + .WithName("GetPublicIPv6") + .WithOpenApi(operation => + { + operation.Summary = "Public IPv6 address"; + operation.Description = "This endpoint returns the public IPv6 address of the client making the request."; + return operation; + }); + + app.MapGet("/ipv6/all", ipAddressService.GetAllClientIps) + .WithName("GetAllPublicIPv6") + .WithOpenApi(operation => + { + operation.Summary = "All Public IPv6 addresses"; + operation.Description = "This endpoint returns all public IPv6 addresses from the X-Forwarded-For header."; + return operation; + }); + + return app; + } +} diff --git a/src/IpSimple.PublicIp.Api/Properties/launchSettings.json b/src/IpSimple.PublicIp.Api/Properties/launchSettings.json new file mode 100644 index 0000000..913a71a --- /dev/null +++ b/src/IpSimple.PublicIp.Api/Properties/launchSettings.json @@ -0,0 +1,40 @@ +{ + "profiles": { + "http": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5021" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Container (Dockerfile)": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", + "environmentVariables": { + "ASPNETCORE_HTTP_PORTS": "8080" + }, + "publishAllPorts": true + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:21858", + "sslPort": 0 + } + } +} \ No newline at end of file diff --git a/src/IpSimple.PublicIp.Api/Services/IIpAddressService.cs b/src/IpSimple.PublicIp.Api/Services/IIpAddressService.cs new file mode 100644 index 0000000..3429db3 --- /dev/null +++ b/src/IpSimple.PublicIp.Api/Services/IIpAddressService.cs @@ -0,0 +1,7 @@ +namespace IpSimple.PublicIp.Api.Services; + +public interface IIpAddressService +{ + IResult GetClientIp(HttpContext httpContext, bool getAllXForwardedForIpAddresses = false); + IResult GetAllClientIps(HttpContext httpContext); +} diff --git a/src/IpSimple.PublicIp.Api/Services/IpAddressService.cs b/src/IpSimple.PublicIp.Api/Services/IpAddressService.cs new file mode 100644 index 0000000..7d52b8b --- /dev/null +++ b/src/IpSimple.PublicIp.Api/Services/IpAddressService.cs @@ -0,0 +1,25 @@ +using IpSimple.Domain; +using IpSimple.Domain.Settings; +using IpSimple.Extensions; + +namespace IpSimple.PublicIp.Api.Services; + +public class IpAddressService : IIpAddressService +{ + public IResult GetClientIp(HttpContext httpContext, bool getAllXForwardedForIpAddresses = false) + { + var clientIp = getAllXForwardedForIpAddresses ? httpContext.GetAllPossibleClientIpAddresses() : httpContext.GetClientIpAddress(); + clientIp ??= Constants.ErrorMessages.NoClientIpFound; + + var format = httpContext.Request.Query["format"].ToString(); + + if (string.Equals(format, "json", StringComparison.OrdinalIgnoreCase)) + { + return Results.Json(new IpAddress(clientIp), JsonSerializerSettings.DefaultJsonSerializer, "application/json"); + } + + return Results.Text(clientIp, "text/plain"); + } + + public IResult GetAllClientIps(HttpContext httpContext) => GetClientIp(httpContext, true); +} diff --git a/src/apis/api-specs.yml b/src/IpSimple.PublicIp.Api/api-spec.yml similarity index 50% rename from src/apis/api-specs.yml rename to src/IpSimple.PublicIp.Api/api-spec.yml index 13ed0ce..e6906da 100644 --- a/src/apis/api-specs.yml +++ b/src/IpSimple.PublicIp.Api/api-spec.yml @@ -35,6 +35,36 @@ paths: example: "98.207.254.136" '429': description: Too many requests + /ipv4/all: + get: + summary: All Public IPv4 addresses + description: This endpoint returns all public IPv4 addresses from the X-Forwarded-For header. + parameters: + - in: query + name: format + schema: + type: string + enum: [json, plain] + required: false + responses: + '200': + description: Successful response + content: + text/plain: + schema: + type: string + example: "98.207.254.136, 203.0.113.195" + application/json: + schema: + type: object + properties: + ips: + type: array + items: + type: string + example: ["98.207.254.136", "203.0.113.195"] + '429': + description: Too many requests /ipv6: get: summary: Public IPv6 address @@ -62,4 +92,34 @@ paths: type: string example: "2a00:1450:400f:80d::200e" '429': - description: Too many requests \ No newline at end of file + description: Too many requests + /ipv6/all: + get: + summary: All Public IPv6 addresses + description: This endpoint returns all public IPv6 addresses from the X-Forwarded-For header. + parameters: + - in: query + name: format + schema: + type: string + enum: [json, plain] + required: false + responses: + '200': + description: Successful response + content: + text/plain: + schema: + type: string + example: "2a00:1450:400f:80d::200e, 2a00:1450:400f:80d::200f" + application/json: + schema: + type: object + properties: + ips: + type: array + items: + type: string + example: ["2a00:1450:400f:80d::200e", "2a00:1450:400f:80d::200f"] + '429': + description: Too many requests diff --git a/src/IpSimple.PublicIp.Api/appsettings.Development.json b/src/IpSimple.PublicIp.Api/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/src/IpSimple.PublicIp.Api/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/IpSimple.PublicIp.Api/appsettings.json b/src/IpSimple.PublicIp.Api/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/src/IpSimple.PublicIp.Api/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} From 943179bdd83106952ada80436fde7a4bf92d89c4 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 3 Aug 2024 18:43:43 +1200 Subject: [PATCH 03/46] udpate build file --- .../workflows/build-publish-baseimages.yml | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 .github/workflows/build-publish-baseimages.yml diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml new file mode 100644 index 0000000..608a7af --- /dev/null +++ b/.github/workflows/build-publish-baseimages.yml @@ -0,0 +1,75 @@ +name: Build & Publish Base Images + +on: + workflow_dispatch: + +jobs: + fetch-scan-push: + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + attestations: write + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Log in to GitHub Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Fetch base image + run: | + docker pull mcr.microsoft.com/dotnet/aspnet:8.0 + docker pull mcr.microsoft.com/dotnet/sdk:8.0 + + - name: Install Syft + run: | + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + + - name: Scan dotnet base image with Trivy + uses: aquasecurity/trivy-action@master + with: + image-ref: mcr.microsoft.com/dotnet/aspnet:8.0 + format: 'table' + exit-code: '1' # Exit code 1 if vulnerabilities are found + + - name: Scan dotnet sdk image with Trivy + uses: aquasecurity/trivy-action@master + with: + image-ref: mcr.microsoft.com/dotnet/sdk:8.0 + format: 'table' + exit-code: '1' # Exit code 1 if vulnerabilities are found + + - name: Tag and push base image to GitHub Packages + run: | + docker tag mcr.microsoft.com/dotnet/aspnet:8.0 ghcr.io/ipsimple/aspnet:8.0 + docker tag mcr.microsoft.com/dotnet/sdk:8.0 ghcr.io/ipsimple/sdk:8.0 + docker push ghcr.io/ipsimple/aspnet:8.0 + docker push ghcr.io/ipsimple/sdk:8.0 + + - name: Generate SBOM for ASP.NET + run: | + syft packages docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json + + - name: Generate SBOM for SDK + run: | + syft packages docker:ghcr.io/ipsimple/sdk:8.0 -o syft-json > sbom-sdk.json + + - name: Upload SBOM for ASP.NET + uses: actions/upload-artifact@v2 + with: + name: sbom-aspnet + path: sbom-aspnet.json + + - name: Upload SBOM for SDK + uses: actions/upload-artifact@v2 + with: + name: sbom-sdk + path: sbom-sdk.json From fd110a66b640bec6c6eee9bf0d80660267dcb4d2 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 3 Aug 2024 20:00:09 +1200 Subject: [PATCH 04/46] update base image build file --- .../workflows/build-publish-baseimages.yml | 53 ++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index 608a7af..26b303e 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -47,13 +47,6 @@ jobs: format: 'table' exit-code: '1' # Exit code 1 if vulnerabilities are found - - name: Tag and push base image to GitHub Packages - run: | - docker tag mcr.microsoft.com/dotnet/aspnet:8.0 ghcr.io/ipsimple/aspnet:8.0 - docker tag mcr.microsoft.com/dotnet/sdk:8.0 ghcr.io/ipsimple/sdk:8.0 - docker push ghcr.io/ipsimple/aspnet:8.0 - docker push ghcr.io/ipsimple/sdk:8.0 - - name: Generate SBOM for ASP.NET run: | syft packages docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json @@ -73,3 +66,49 @@ jobs: with: name: sbom-sdk path: sbom-sdk.json + + - name: Build and push ASP.NET base image + id: build_aspnet + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ghcr.io/ipsimple/aspnet:8.0 + + - name: Build and push SDK base image + id: build_sdk + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ghcr.io/ipsimple/sdk:8.0 + + - name: Generate artifact attestation for ASP.NET + uses: actions/attest-build-provenance@v1 + with: + subject-name: ghcr.io/ipsimple/aspnet + subject-digest: ${{ steps.build_aspnet.outputs.digest }} + push-to-registry: true + + - name: Generate artifact attestation for SDK + uses: actions/attest-build-provenance@v1 + with: + subject-name: ghcr.io/ipsimple/sdk + subject-digest: ${{ steps.build_sdk.outputs.digest }} + push-to-registry: true + + - name: Generate SBOM attestation for ASP.NET + uses: actions/attest-sbom@v1 + with: + subject-name: ghcr.io/ipsimple/aspnet + subject-digest: ${{ steps.build_aspnet.outputs.digest }} + sbom-path: sbom-aspnet.json + push-to-registry: true + + - name: Generate SBOM attestation for SDK + uses: actions/attest-sbom@v1 + with: + subject-name: ghcr.io/ipsimple/sdk + subject-digest: ${{ steps.build_sdk.outputs.digest }} + sbom-path: sbom-sdk.json + push-to-registry: true From 1d585e62dc81b31fedfa219fe270d277ded60c0b Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 3 Aug 2024 20:21:18 +1200 Subject: [PATCH 05/46] update build file --- .../workflows/build-publish-baseimages.yml | 235 ++++++++++-------- 1 file changed, 134 insertions(+), 101 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index 26b303e..85d959f 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -2,113 +2,146 @@ name: Build & Publish Base Images on: workflow_dispatch: + # schedule: + # - cron: '0 0 * * *' # Runs daily at midnight jobs: - fetch-scan-push: + fetch-base-images: runs-on: ubuntu-latest - + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Log in to GitHub Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Fetch base images + run: | + docker pull mcr.microsoft.com/dotnet/aspnet:8.0 + docker pull mcr.microsoft.com/dotnet/sdk:8.0 + + scan-base-images: + runs-on: ubuntu-latest + needs: fetch-base-images + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Log in to GitHub Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Scan dotnet base image with Trivy + uses: aquasecurity/trivy-action@master + with: + image-ref: mcr.microsoft.com/dotnet/aspnet:8.0 + format: 'table' + exit-code: '1' # Exit code 1 if vulnerabilities are found + + - name: Scan dotnet sdk image with Trivy + uses: aquasecurity/trivy-action@master + with: + image-ref: mcr.microsoft.com/dotnet/sdk:8.0 + format: 'table' + exit-code: '1' # Exit code 1 if vulnerabilities are found + + generate-sbom: + runs-on: ubuntu-latest + needs: scan-base-images + steps: + - name: Install Syft + run: | + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + + - name: Generate SBOM for ASP.NET + run: | + syft packages docker:mcr.microsoft.com/dotnet/aspnet:8.0 -o syft-json > sbom-aspnet.json + + - name: Generate SBOM for SDK + run: | + syft packages docker:mcr.microsoft.com/dotnet/sdk:8.0 -o syft-json > sbom-sdk.json + + - name: Upload SBOM for ASP.NET + uses: actions/upload-artifact@v2 + with: + name: sbom-aspnet + path: sbom-aspnet.json + + - name: Upload SBOM for SDK + uses: actions/upload-artifact@v2 + with: + name: sbom-sdk + path: sbom-sdk.json + + push-base-images: + runs-on: ubuntu-latest + needs: generate-sbom + steps: + - name: Log in to GitHub Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push ASP.NET base image + id: build_aspnet + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ghcr.io/ipsimple/aspnet:8.0 + + - name: Build and push SDK base image + id: build_sdk + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ghcr.io/ipsimple/sdk:8.0 + + generate-attestations: + runs-on: ubuntu-latest + needs: push-base-images permissions: contents: read packages: write attestations: write id-token: write - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Log in to GitHub Docker registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Fetch base image - run: | - docker pull mcr.microsoft.com/dotnet/aspnet:8.0 - docker pull mcr.microsoft.com/dotnet/sdk:8.0 - - - name: Install Syft - run: | - curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin - - - name: Scan dotnet base image with Trivy - uses: aquasecurity/trivy-action@master - with: - image-ref: mcr.microsoft.com/dotnet/aspnet:8.0 - format: 'table' - exit-code: '1' # Exit code 1 if vulnerabilities are found - - - name: Scan dotnet sdk image with Trivy - uses: aquasecurity/trivy-action@master - with: - image-ref: mcr.microsoft.com/dotnet/sdk:8.0 - format: 'table' - exit-code: '1' # Exit code 1 if vulnerabilities are found - - - name: Generate SBOM for ASP.NET - run: | - syft packages docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json - - - name: Generate SBOM for SDK - run: | - syft packages docker:ghcr.io/ipsimple/sdk:8.0 -o syft-json > sbom-sdk.json - - - name: Upload SBOM for ASP.NET - uses: actions/upload-artifact@v2 - with: - name: sbom-aspnet - path: sbom-aspnet.json - - - name: Upload SBOM for SDK - uses: actions/upload-artifact@v2 - with: - name: sbom-sdk - path: sbom-sdk.json - - - name: Build and push ASP.NET base image - id: build_aspnet - uses: docker/build-push-action@v6 - with: - context: . - push: true - tags: ghcr.io/ipsimple/aspnet:8.0 - - - name: Build and push SDK base image - id: build_sdk - uses: docker/build-push-action@v6 - with: - context: . - push: true - tags: ghcr.io/ipsimple/sdk:8.0 - - - name: Generate artifact attestation for ASP.NET - uses: actions/attest-build-provenance@v1 - with: - subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ steps.build_aspnet.outputs.digest }} - push-to-registry: true - - - name: Generate artifact attestation for SDK - uses: actions/attest-build-provenance@v1 - with: - subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ steps.build_sdk.outputs.digest }} - push-to-registry: true - - - name: Generate SBOM attestation for ASP.NET - uses: actions/attest-sbom@v1 - with: - subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ steps.build_aspnet.outputs.digest }} - sbom-path: sbom-aspnet.json - push-to-registry: true - - - name: Generate SBOM attestation for SDK - uses: actions/attest-sbom@v1 - with: - subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ steps.build_sdk.outputs.digest }} - sbom-path: sbom-sdk.json - push-to-registry: true + - name: Generate artifact attestation for ASP.NET + uses: actions/attest-build-provenance@v1 + with: + subject-name: ghcr.io/ipsimple/aspnet + subject-digest: ${{ steps.build_aspnet.outputs.digest }} + push-to-registry: true + + - name: Generate artifact attestation for SDK + uses: actions/attest-build-provenance@v1 + with: + subject-name: ghcr.io/ipsimple/sdk + subject-digest: ${{ steps.build_sdk.outputs.digest }} + push-to-registry: true + + - name: Generate SBOM attestation for ASP.NET + uses: actions/attest-sbom@v1 + with: + subject-name: ghcr.io/ipsimple/aspnet + subject-digest: ${{ steps.build_aspnet.outputs.digest }} + sbom-path: sbom-aspnet.json + push-to-registry: true + + - name: Generate SBOM attestation for SDK + uses: actions/attest-sbom@v1 + with: + subject-name: ghcr.io/ipsimple/sdk + subject-digest: ${{ steps.build_sdk.outputs.digest }} + sbom-path: sbom-sdk.json + push-to-registry: true From 5bffbbd6bd077ae139ce7631b5223f6b917969f4 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 4 Aug 2024 17:31:48 +1200 Subject: [PATCH 06/46] update --- .../workflows/build-publish-baseimages.yml | 235 +++++++++--------- 1 file changed, 116 insertions(+), 119 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index 85d959f..5dc0dce 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -2,146 +2,143 @@ name: Build & Publish Base Images on: workflow_dispatch: - # schedule: - # - cron: '0 0 * * *' # Runs daily at midnight jobs: fetch-base-images: runs-on: ubuntu-latest + steps: - - name: Checkout repository - uses: actions/checkout@v2 + - name: Checkout repository + uses: actions/checkout@v2 - - name: Log in to GitHub Docker registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + - name: Log in to GitHub Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: Fetch base images - run: | - docker pull mcr.microsoft.com/dotnet/aspnet:8.0 - docker pull mcr.microsoft.com/dotnet/sdk:8.0 + - name: Fetch base image + run: | + docker pull mcr.microsoft.com/dotnet/aspnet:8.0 + docker pull mcr.microsoft.com/dotnet/sdk:8.0 scan-base-images: runs-on: ubuntu-latest needs: fetch-base-images + continue-on-error: true + steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Log in to GitHub Docker registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Scan dotnet base image with Trivy - uses: aquasecurity/trivy-action@master - with: - image-ref: mcr.microsoft.com/dotnet/aspnet:8.0 - format: 'table' - exit-code: '1' # Exit code 1 if vulnerabilities are found - - - name: Scan dotnet sdk image with Trivy - uses: aquasecurity/trivy-action@master - with: - image-ref: mcr.microsoft.com/dotnet/sdk:8.0 - format: 'table' - exit-code: '1' # Exit code 1 if vulnerabilities are found + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Log in to GitHub Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Scan dotnet base image with Trivy + uses: aquasecurity/trivy-action@master + with: + image-ref: mcr.microsoft.com/dotnet/aspnet:8.0 + format: 'table' + exit-code: '1' # Exit code 1 if vulnerabilities are found + + - name: Scan dotnet sdk image with Trivy + uses: aquasecurity/trivy-action@master + with: + image-ref: mcr.microsoft.com/dotnet/sdk:8.0 + format: 'table' + exit-code: '1' # Exit code 1 if vulnerabilities are found generate-sbom: runs-on: ubuntu-latest - needs: scan-base-images + needs: [fetch-base-images] + steps: - - name: Install Syft - run: | - curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin - - - name: Generate SBOM for ASP.NET - run: | - syft packages docker:mcr.microsoft.com/dotnet/aspnet:8.0 -o syft-json > sbom-aspnet.json - - - name: Generate SBOM for SDK - run: | - syft packages docker:mcr.microsoft.com/dotnet/sdk:8.0 -o syft-json > sbom-sdk.json - - - name: Upload SBOM for ASP.NET - uses: actions/upload-artifact@v2 - with: - name: sbom-aspnet - path: sbom-aspnet.json - - - name: Upload SBOM for SDK - uses: actions/upload-artifact@v2 - with: - name: sbom-sdk - path: sbom-sdk.json + - name: Install Syft + run: | + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + + - name: Generate SBOM for ASP.NET + run: | + syft packages docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json + + - name: Generate SBOM for SDK + run: | + syft packages docker:ghcr.io/ipsimple/sdk:8.0 -o syft-json > sbom-sdk.json + + - name: Upload SBOM for ASP.NET + uses: actions/upload-artifact@v2 + with: + name: sbom-aspnet + path: sbom-aspnet.json + + - name: Upload SBOM for SDK + uses: actions/upload-artifact@v2 + with: + name: sbom-sdk + path: sbom-sdk.json push-base-images: runs-on: ubuntu-latest - needs: generate-sbom + needs: [fetch-base-images, generate-sbom] + steps: - - name: Log in to GitHub Docker registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push ASP.NET base image - id: build_aspnet - uses: docker/build-push-action@v6 - with: - context: . - push: true - tags: ghcr.io/ipsimple/aspnet:8.0 - - - name: Build and push SDK base image - id: build_sdk - uses: docker/build-push-action@v6 - with: - context: . - push: true - tags: ghcr.io/ipsimple/sdk:8.0 + - name: Log in to GitHub Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push ASP.NET base image + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ghcr.io/ipsimple/aspnet:8.0 + + - name: Build and push SDK base image + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ghcr.io/ipsimple/sdk:8.0 generate-attestations: runs-on: ubuntu-latest - needs: push-base-images - permissions: - contents: read - packages: write - attestations: write - id-token: write + needs: [push-base-images] + steps: - - name: Generate artifact attestation for ASP.NET - uses: actions/attest-build-provenance@v1 - with: - subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ steps.build_aspnet.outputs.digest }} - push-to-registry: true - - - name: Generate artifact attestation for SDK - uses: actions/attest-build-provenance@v1 - with: - subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ steps.build_sdk.outputs.digest }} - push-to-registry: true - - - name: Generate SBOM attestation for ASP.NET - uses: actions/attest-sbom@v1 - with: - subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ steps.build_aspnet.outputs.digest }} - sbom-path: sbom-aspnet.json - push-to-registry: true - - - name: Generate SBOM attestation for SDK - uses: actions/attest-sbom@v1 - with: - subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ steps.build_sdk.outputs.digest }} - sbom-path: sbom-sdk.json - push-to-registry: true + - name: Generate artifact attestation for ASP.NET + uses: actions/attest-build-provenance@v1 + with: + subject-name: ghcr.io/ipsimple/aspnet + subject-digest: ${{ needs.push-base-images.outputs.digest }} + push-to-registry: true + + - name: Generate artifact attestation for SDK + uses: actions/attest-build-provenance@v1 + with: + subject-name: ghcr.io/ipsimple/sdk + subject-digest: ${{ needs.push-base-images.outputs.digest }} + push-to-registry: true + + - name: Generate SBOM attestation for ASP.NET + uses: actions/attest-sbom@v1 + with: + subject-name: ghcr.io/ipsimple/aspnet + subject-digest: ${{ needs.push-base-images.outputs.digest }} + sbom-path: sbom-aspnet.json + push-to-registry: true + + - name: Generate SBOM attestation for SDK + uses: actions/attest-sbom@v1 + with: + subject-name: ghcr.io/ipsimple/sdk + subject-digest: ${{ needs.push-base-images.outputs.digest }} + sbom-path: sbom-sdk.json + push-to-registry: true From ccdf6ca78f200584b1e246f225aa9e71cae7136a Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 4 Aug 2024 17:39:42 +1200 Subject: [PATCH 07/46] no message --- .../workflows/build-publish-baseimages.yml | 89 ++++++++----------- 1 file changed, 35 insertions(+), 54 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index 5dc0dce..617e9d2 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -29,16 +29,6 @@ jobs: continue-on-error: true steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Log in to GitHub Docker registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Scan dotnet base image with Trivy uses: aquasecurity/trivy-action@master with: @@ -53,40 +43,14 @@ jobs: format: 'table' exit-code: '1' # Exit code 1 if vulnerabilities are found - generate-sbom: - runs-on: ubuntu-latest - needs: [fetch-base-images] - - steps: - - name: Install Syft - run: | - curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin - - - name: Generate SBOM for ASP.NET - run: | - syft packages docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json - - - name: Generate SBOM for SDK - run: | - syft packages docker:ghcr.io/ipsimple/sdk:8.0 -o syft-json > sbom-sdk.json - - - name: Upload SBOM for ASP.NET - uses: actions/upload-artifact@v2 - with: - name: sbom-aspnet - path: sbom-aspnet.json - - - name: Upload SBOM for SDK - uses: actions/upload-artifact@v2 - with: - name: sbom-sdk - path: sbom-sdk.json - push-base-images: runs-on: ubuntu-latest - needs: [fetch-base-images, generate-sbom] + needs: fetch-base-images steps: + - name: Checkout repository + uses: actions/checkout@v2 + - name: Log in to GitHub Docker registry uses: docker/login-action@v2 with: @@ -95,6 +59,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push ASP.NET base image + id: build_aspnet uses: docker/build-push-action@v6 with: context: . @@ -102,36 +67,52 @@ jobs: tags: ghcr.io/ipsimple/aspnet:8.0 - name: Build and push SDK base image + id: build_sdk uses: docker/build-push-action@v6 with: context: . push: true tags: ghcr.io/ipsimple/sdk:8.0 - generate-attestations: + generate-sbom: runs-on: ubuntu-latest - needs: [push-base-images] + needs: push-base-images steps: - - name: Generate artifact attestation for ASP.NET - uses: actions/attest-build-provenance@v1 + - name: Install Syft + run: | + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + + - name: Generate SBOM for ASP.NET + run: | + syft docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json + + - name: Generate SBOM for SDK + run: | + syft docker:ghcr.io/ipsimple/sdk:8.0 -o syft-json > sbom-sdk.json + + - name: Upload SBOM for ASP.NET + uses: actions/upload-artifact@v2 with: - subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ needs.push-base-images.outputs.digest }} - push-to-registry: true + name: sbom-aspnet + path: sbom-aspnet.json - - name: Generate artifact attestation for SDK - uses: actions/attest-build-provenance@v1 + - name: Upload SBOM for SDK + uses: actions/upload-artifact@v2 with: - subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ needs.push-base-images.outputs.digest }} - push-to-registry: true + name: sbom-sdk + path: sbom-sdk.json + generate-attestations: + runs-on: ubuntu-latest + needs: [push-base-images, generate-sbom] + + steps: - name: Generate SBOM attestation for ASP.NET uses: actions/attest-sbom@v1 with: subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ needs.push-base-images.outputs.digest }} + subject-digest: ${{ needs.push-base-images.outputs['build_aspnet'].digest }} sbom-path: sbom-aspnet.json push-to-registry: true @@ -139,6 +120,6 @@ jobs: uses: actions/attest-sbom@v1 with: subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ needs.push-base-images.outputs.digest }} + subject-digest: ${{ needs.push-base-images.outputs['build_sdk'].digest }} sbom-path: sbom-sdk.json push-to-registry: true From 3ca5495645beef822d1b3f4880114d035c4fedac Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 4 Aug 2024 17:49:29 +1200 Subject: [PATCH 08/46] no message --- .../workflows/build-publish-baseimages.yml | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index 617e9d2..27e30b5 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -35,6 +35,9 @@ jobs: image-ref: mcr.microsoft.com/dotnet/aspnet:8.0 format: 'table' exit-code: '1' # Exit code 1 if vulnerabilities are found + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' - name: Scan dotnet sdk image with Trivy uses: aquasecurity/trivy-action@master @@ -42,6 +45,9 @@ jobs: image-ref: mcr.microsoft.com/dotnet/sdk:8.0 format: 'table' exit-code: '1' # Exit code 1 if vulnerabilities are found + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' push-base-images: runs-on: ubuntu-latest @@ -58,21 +64,15 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push ASP.NET base image - id: build_aspnet - uses: docker/build-push-action@v6 - with: - context: . - push: true - tags: ghcr.io/ipsimple/aspnet:8.0 + - name: Tag and push ASP.NET base image + run: | + docker tag mcr.microsoft.com/dotnet/aspnet:8.0 ghcr.io/ipsimple/aspnet:8.0 + docker push ghcr.io/ipsimple/aspnet:8.0 - - name: Build and push SDK base image - id: build_sdk - uses: docker/build-push-action@v6 - with: - context: . - push: true - tags: ghcr.io/ipsimple/sdk:8.0 + - name: Tag and push SDK base image + run: | + docker tag mcr.microsoft.com/dotnet/sdk:8.0 ghcr.io/ipsimple/sdk:8.0 + docker push ghcr.io/ipsimple/sdk:8.0 generate-sbom: runs-on: ubuntu-latest From 8aa5087f622d5463619f795247f2c229fdbbee85 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 4 Aug 2024 18:37:00 +1200 Subject: [PATCH 09/46] no message --- .../workflows/build-publish-baseimages.yml | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index 27e30b5..e8d14cf 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -18,10 +18,16 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Fetch base image + - name: Fetch ASP.NET base image + run: docker pull mcr.microsoft.com/dotnet/aspnet:8.0 + + - name: Fetch SDK base image + run: docker pull mcr.microsoft.com/dotnet/sdk:8.0 + + - name: Verify fetched images run: | - docker pull mcr.microsoft.com/dotnet/aspnet:8.0 - docker pull mcr.microsoft.com/dotnet/sdk:8.0 + docker images mcr.microsoft.com/dotnet/aspnet:8.0 + docker images mcr.microsoft.com/dotnet/sdk:8.0 scan-base-images: runs-on: ubuntu-latest @@ -29,25 +35,19 @@ jobs: continue-on-error: true steps: - - name: Scan dotnet base image with Trivy + - name: Scan ASP.NET base image with Trivy uses: aquasecurity/trivy-action@master with: image-ref: mcr.microsoft.com/dotnet/aspnet:8.0 format: 'table' exit-code: '1' # Exit code 1 if vulnerabilities are found - ignore-unfixed: true - vuln-type: 'os,library' - severity: 'CRITICAL,HIGH' - - name: Scan dotnet sdk image with Trivy + - name: Scan SDK base image with Trivy uses: aquasecurity/trivy-action@master with: image-ref: mcr.microsoft.com/dotnet/sdk:8.0 format: 'table' exit-code: '1' # Exit code 1 if vulnerabilities are found - ignore-unfixed: true - vuln-type: 'os,library' - severity: 'CRITICAL,HIGH' push-base-images: runs-on: ubuntu-latest From e7cfd9a2e86d8754199d97d14c2247c502936ba7 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 4 Aug 2024 18:47:39 +1200 Subject: [PATCH 10/46] no message --- .../workflows/build-publish-baseimages.yml | 208 +++++++++--------- 1 file changed, 110 insertions(+), 98 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index e8d14cf..57abace 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -4,122 +4,134 @@ on: workflow_dispatch: jobs: - fetch-base-images: + fetch-and-push: runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Log in to GitHub Docker registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Fetch ASP.NET base image - run: docker pull mcr.microsoft.com/dotnet/aspnet:8.0 - - - name: Fetch SDK base image - run: docker pull mcr.microsoft.com/dotnet/sdk:8.0 + permissions: + contents: read + packages: write + attestations: write + id-token: write - - name: Verify fetched images - run: | - docker images mcr.microsoft.com/dotnet/aspnet:8.0 - docker images mcr.microsoft.com/dotnet/sdk:8.0 + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Log in to GitHub Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Fetch base image + run: | + docker pull mcr.microsoft.com/dotnet/aspnet:8.0 + docker pull mcr.microsoft.com/dotnet/sdk:8.0 + + - name: Tag and push ASP.NET base image + run: | + docker tag mcr.microsoft.com/dotnet/aspnet:8.0 ghcr.io/ipsimple/aspnet:8.0 + docker push ghcr.io/ipsimple/aspnet:8.0 + + - name: Tag and push SDK base image + run: | + docker tag mcr.microsoft.com/dotnet/sdk:8.0 ghcr.io/ipsimple/sdk:8.0 + docker push ghcr.io/ipsimple/sdk:8.0 scan-base-images: runs-on: ubuntu-latest - needs: fetch-base-images + needs: fetch-and-push continue-on-error: true steps: - - name: Scan ASP.NET base image with Trivy - uses: aquasecurity/trivy-action@master - with: - image-ref: mcr.microsoft.com/dotnet/aspnet:8.0 - format: 'table' - exit-code: '1' # Exit code 1 if vulnerabilities are found - - - name: Scan SDK base image with Trivy - uses: aquasecurity/trivy-action@master - with: - image-ref: mcr.microsoft.com/dotnet/sdk:8.0 - format: 'table' - exit-code: '1' # Exit code 1 if vulnerabilities are found - - push-base-images: - runs-on: ubuntu-latest - needs: fetch-base-images - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Log in to GitHub Docker registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Tag and push ASP.NET base image - run: | - docker tag mcr.microsoft.com/dotnet/aspnet:8.0 ghcr.io/ipsimple/aspnet:8.0 - docker push ghcr.io/ipsimple/aspnet:8.0 - - - name: Tag and push SDK base image - run: | - docker tag mcr.microsoft.com/dotnet/sdk:8.0 ghcr.io/ipsimple/sdk:8.0 - docker push ghcr.io/ipsimple/sdk:8.0 + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install Syft + run: | + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + + - name: Scan dotnet base image with Trivy + uses: aquasecurity/trivy-action@master + with: + image-ref: mcr.microsoft.com/dotnet/aspnet:8.0 + format: 'table' + exit-code: '1' # Exit code 1 if vulnerabilities are found + + - name: Scan dotnet sdk image with Trivy + uses: aquasecurity/trivy-action@master + with: + image-ref: mcr.microsoft.com/dotnet/sdk:8.0 + format: 'table' + exit-code: '1' # Exit code 1 if vulnerabilities are found generate-sbom: runs-on: ubuntu-latest needs: push-base-images steps: - - name: Install Syft - run: | - curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin - - - name: Generate SBOM for ASP.NET - run: | - syft docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json - - - name: Generate SBOM for SDK - run: | - syft docker:ghcr.io/ipsimple/sdk:8.0 -o syft-json > sbom-sdk.json - - - name: Upload SBOM for ASP.NET - uses: actions/upload-artifact@v2 - with: - name: sbom-aspnet - path: sbom-aspnet.json - - - name: Upload SBOM for SDK - uses: actions/upload-artifact@v2 - with: - name: sbom-sdk - path: sbom-sdk.json + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install Syft + run: | + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + + - name: Generate SBOM for ASP.NET + run: | + syft packages docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json + + - name: Generate SBOM for SDK + run: | + syft packages docker:ghcr.io/ipsimple/sdk:8.0 -o syft-json > sbom-sdk.json + + - name: Upload SBOM for ASP.NET + uses: actions/upload-artifact@v2 + with: + name: sbom-aspnet + path: sbom-aspnet.json + + - name: Upload SBOM for SDK + uses: actions/upload-artifact@v2 + with: + name: sbom-sdk + path: sbom-sdk.json generate-attestations: runs-on: ubuntu-latest needs: [push-base-images, generate-sbom] steps: - - name: Generate SBOM attestation for ASP.NET - uses: actions/attest-sbom@v1 - with: - subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ needs.push-base-images.outputs['build_aspnet'].digest }} - sbom-path: sbom-aspnet.json - push-to-registry: true - - - name: Generate SBOM attestation for SDK - uses: actions/attest-sbom@v1 - with: - subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ needs.push-base-images.outputs['build_sdk'].digest }} - sbom-path: sbom-sdk.json - push-to-registry: true + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Generate artifact attestation for ASP.NET + uses: actions/attest-build-provenance@v1 + with: + subject-name: ghcr.io/ipsimple/aspnet + subject-digest: ${{ needs.push-base-images.outputs.digest }} + push-to-registry: true + + - name: Generate artifact attestation for SDK + uses: actions/attest-build-provenance@v1 + with: + subject-name: ghcr.io/ipsimple/sdk + subject-digest: ${{ needs.push-base-images.outputs.digest }} + push-to-registry: true + + - name: Generate SBOM attestation for ASP.NET + uses: actions/attest-sbom@v1 + with: + subject-name: ghcr.io/ipsimple/aspnet + subject-digest: ${{ needs.push-base-images.outputs.digest }} + sbom-path: sbom-aspnet.json + push-to-registry: true + + - name: Generate SBOM attestation for SDK + uses: actions/attest-sbom@v1 + with: + subject-name: ghcr.io/ipsimple/sdk + subject-digest: ${{ needs.push-base-images.outputs.digest }} + sbom-path: sbom-sdk.json + push-to-registry: true From 271583e1eb830a02a2dfe04ea918cbbdc31d2df9 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 4 Aug 2024 18:48:37 +1200 Subject: [PATCH 11/46] no message --- .github/workflows/build-publish-baseimages.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index 57abace..673dfe4 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -68,7 +68,7 @@ jobs: generate-sbom: runs-on: ubuntu-latest - needs: push-base-images + needs: fetch-and-push steps: - name: Checkout repository @@ -100,7 +100,7 @@ jobs: generate-attestations: runs-on: ubuntu-latest - needs: [push-base-images, generate-sbom] + needs: [fetch-and-push, generate-sbom] steps: - name: Checkout repository @@ -110,21 +110,21 @@ jobs: uses: actions/attest-build-provenance@v1 with: subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ needs.push-base-images.outputs.digest }} + subject-digest: ${{ needs.fetch-and-push.outputs.digest }} push-to-registry: true - name: Generate artifact attestation for SDK uses: actions/attest-build-provenance@v1 with: subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ needs.push-base-images.outputs.digest }} + subject-digest: ${{ needs.fetch-and-push.outputs.digest }} push-to-registry: true - name: Generate SBOM attestation for ASP.NET uses: actions/attest-sbom@v1 with: subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ needs.push-base-images.outputs.digest }} + subject-digest: ${{ needs.fetch-and-push.outputs.digest }} sbom-path: sbom-aspnet.json push-to-registry: true @@ -132,6 +132,6 @@ jobs: uses: actions/attest-sbom@v1 with: subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ needs.push-base-images.outputs.digest }} + subject-digest: ${{ needs.fetch-and-push.outputs.digest }} sbom-path: sbom-sdk.json push-to-registry: true From 02608287e0938135ad2e622c21c4f64fb7dc16ea Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 4 Aug 2024 19:01:18 +1200 Subject: [PATCH 12/46] no message --- .../workflows/build-publish-baseimages.yml | 219 +++++++++--------- 1 file changed, 111 insertions(+), 108 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index 673dfe4..f992c2d 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -14,124 +14,127 @@ jobs: id-token: write steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Log in to GitHub Docker registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Fetch base image - run: | - docker pull mcr.microsoft.com/dotnet/aspnet:8.0 - docker pull mcr.microsoft.com/dotnet/sdk:8.0 - - - name: Tag and push ASP.NET base image - run: | - docker tag mcr.microsoft.com/dotnet/aspnet:8.0 ghcr.io/ipsimple/aspnet:8.0 - docker push ghcr.io/ipsimple/aspnet:8.0 - - - name: Tag and push SDK base image - run: | - docker tag mcr.microsoft.com/dotnet/sdk:8.0 ghcr.io/ipsimple/sdk:8.0 - docker push ghcr.io/ipsimple/sdk:8.0 - - scan-base-images: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Log in to GitHub Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Fetch base images + run: | + docker pull mcr.microsoft.com/dotnet/aspnet:8.0 + docker pull mcr.microsoft.com/dotnet/sdk:8.0 + + - name: Tag and push ASP.NET base image + run: | + docker tag mcr.microsoft.com/dotnet/aspnet:8.0 ghcr.io/ipsimple/aspnet:8.0 + docker push ghcr.io/ipsimple/aspnet:8.0 + + - name: Tag and push SDK base image + run: | + docker tag mcr.microsoft.com/dotnet/sdk:8.0 ghcr.io/ipsimple/sdk:8.0 + docker push ghcr.io/ipsimple/sdk:8.0 + + scan-aspnet-image: runs-on: ubuntu-latest needs: fetch-and-push - continue-on-error: true - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Install Syft - run: | - curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin - - - name: Scan dotnet base image with Trivy - uses: aquasecurity/trivy-action@master - with: - image-ref: mcr.microsoft.com/dotnet/aspnet:8.0 - format: 'table' - exit-code: '1' # Exit code 1 if vulnerabilities are found - - - name: Scan dotnet sdk image with Trivy - uses: aquasecurity/trivy-action@master - with: - image-ref: mcr.microsoft.com/dotnet/sdk:8.0 - format: 'table' - exit-code: '1' # Exit code 1 if vulnerabilities are found - - generate-sbom: + - name: Scan ASP.NET base image with Trivy + uses: aquasecurity/trivy-action@master + with: + image-ref: ghcr.io/ipsimple/aspnet:8.0 + format: 'table' + exit-code: '1' + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' + + scan-sdk-image: runs-on: ubuntu-latest needs: fetch-and-push - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Install Syft - run: | - curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + - name: Scan SDK base image with Trivy + uses: aquasecurity/trivy-action@master + with: + image-ref: ghcr.io/ipsimple/sdk:8.0 + format: 'table' + exit-code: '1' + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' - - name: Generate SBOM for ASP.NET - run: | - syft packages docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json - - - name: Generate SBOM for SDK - run: | - syft packages docker:ghcr.io/ipsimple/sdk:8.0 -o syft-json > sbom-sdk.json - - - name: Upload SBOM for ASP.NET - uses: actions/upload-artifact@v2 - with: - name: sbom-aspnet - path: sbom-aspnet.json - - - name: Upload SBOM for SDK - uses: actions/upload-artifact@v2 - with: - name: sbom-sdk - path: sbom-sdk.json + generate-sbom: + runs-on: ubuntu-latest + needs: [fetch-and-push] + steps: + - name: Install Syft + run: | + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + + - name: Generate SBOM for ASP.NET + run: | + syft packages docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json + + - name: Generate SBOM for SDK + run: | + syft packages docker:ghcr.io/ipsimple/sdk:8.0 -o syft-json > sbom-sdk.json + + - name: Upload SBOM for ASP.NET + uses: actions/upload-artifact@v2 + with: + name: sbom-aspnet + path: sbom-aspnet.json + + - name: Upload SBOM for SDK + uses: actions/upload-artifact@v2 + with: + name: sbom-sdk + path: sbom-sdk.json generate-attestations: runs-on: ubuntu-latest needs: [fetch-and-push, generate-sbom] + permissions: + id-token: write + contents: read + packages: write + attestations: write + steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Generate artifact attestation for ASP.NET - uses: actions/attest-build-provenance@v1 - with: - subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ needs.fetch-and-push.outputs.digest }} - push-to-registry: true - - - name: Generate artifact attestation for SDK - uses: actions/attest-build-provenance@v1 - with: - subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ needs.fetch-and-push.outputs.digest }} - push-to-registry: true - - - name: Generate SBOM attestation for ASP.NET - uses: actions/attest-sbom@v1 - with: - subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ needs.fetch-and-push.outputs.digest }} - sbom-path: sbom-aspnet.json - push-to-registry: true - - - name: Generate SBOM attestation for SDK - uses: actions/attest-sbom@v1 - with: - subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ needs.fetch-and-push.outputs.digest }} - sbom-path: sbom-sdk.json - push-to-registry: true + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Generate artifact attestation for ASP.NET + uses: actions/attest-build-provenance@v1 + with: + subject-name: ghcr.io/ipsimple/aspnet + subject-digest: ${{ needs.fetch-and-push.outputs.digest }} + push-to-registry: true + + - name: Generate artifact attestation for SDK + uses: actions/attest-build-provenance@v1 + with: + subject-name: ghcr.io/ipsimple/sdk + subject-digest: ${{ needs.fetch-and-push.outputs.digest }} + push-to-registry: true + + - name: Generate SBOM attestation for ASP.NET + uses: actions/attest-sbom@v1 + with: + subject-name: ghcr.io/ipsimple/aspnet + subject-digest: ${{ needs.fetch-and-push.outputs.digest }} + sbom-path: sbom-aspnet.json + push-to-registry: true + + - name: Generate SBOM attestation for SDK + uses: actions/attest-sbom@v1 + with: + subject-name: ghcr.io/ipsimple/sdk + subject-digest: ${{ needs.fetch-and-push.outputs.digest }} + sbom-path: sbom-sdk.json + push-to-registry: true From ca6f756398bc589b01a3a1727688b61aefd7e886 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 4 Aug 2024 19:09:15 +1200 Subject: [PATCH 13/46] no message --- .../workflows/build-publish-baseimages.yml | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index f992c2d..77d146b 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -10,8 +10,12 @@ jobs: permissions: contents: read packages: write - attestations: write id-token: write + attestations: write + + outputs: + aspnet_digest: ${{ steps.push_aspnet.outputs.digest }} + sdk_digest: ${{ steps.push_sdk.outputs.digest }} steps: - name: Checkout repository @@ -30,14 +34,18 @@ jobs: docker pull mcr.microsoft.com/dotnet/sdk:8.0 - name: Tag and push ASP.NET base image + id: push_aspnet run: | docker tag mcr.microsoft.com/dotnet/aspnet:8.0 ghcr.io/ipsimple/aspnet:8.0 docker push ghcr.io/ipsimple/aspnet:8.0 + echo "::set-output name=digest::$(docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/ipsimple/aspnet:8.0 | cut -d'@' -f2)" - name: Tag and push SDK base image + id: push_sdk run: | docker tag mcr.microsoft.com/dotnet/sdk:8.0 ghcr.io/ipsimple/sdk:8.0 docker push ghcr.io/ipsimple/sdk:8.0 + echo "::set-output name=digest::$(docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/ipsimple/sdk:8.0 | cut -d'@' -f2)" scan-aspnet-image: runs-on: ubuntu-latest @@ -104,7 +112,7 @@ jobs: contents: read packages: write attestations: write - + steps: - name: Checkout repository uses: actions/checkout@v2 @@ -113,21 +121,21 @@ jobs: uses: actions/attest-build-provenance@v1 with: subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ needs.fetch-and-push.outputs.digest }} + subject-digest: ${{ needs.fetch-and-push.outputs.aspnet_digest }} push-to-registry: true - name: Generate artifact attestation for SDK uses: actions/attest-build-provenance@v1 with: subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ needs.fetch-and-push.outputs.digest }} + subject-digest: ${{ needs.fetch-and-push.outputs.sdk_digest }} push-to-registry: true - name: Generate SBOM attestation for ASP.NET uses: actions/attest-sbom@v1 with: subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ needs.fetch-and-push.outputs.digest }} + subject-digest: ${{ needs.fetch-and-push.outputs.aspnet_digest }} sbom-path: sbom-aspnet.json push-to-registry: true @@ -135,6 +143,6 @@ jobs: uses: actions/attest-sbom@v1 with: subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ needs.fetch-and-push.outputs.digest }} + subject-digest: ${{ needs.fetch-and-push.outputs.sdk_digest }} sbom-path: sbom-sdk.json push-to-registry: true From 9544eec260c869bded522bb0135456bca0559ce7 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 4 Aug 2024 19:17:55 +1200 Subject: [PATCH 14/46] no message --- .github/workflows/build-publish-baseimages.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index 77d146b..269a5ef 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -117,6 +117,13 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 + - name: Log in to GitHub Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Generate artifact attestation for ASP.NET uses: actions/attest-build-provenance@v1 with: From e991485ce28610a5fe11bc096361a290935fa8c3 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 4 Aug 2024 19:28:24 +1200 Subject: [PATCH 15/46] no message --- .../workflows/build-publish-baseimages.yml | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index 269a5ef..fa4478d 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -77,11 +77,24 @@ jobs: generate-sbom: runs-on: ubuntu-latest - needs: [fetch-and-push] + needs: fetch-and-push + + permissions: + contents: read + packages: write + id-token: write + attestations: write + steps: - - name: Install Syft - run: | - curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Log in to GitHub Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Generate SBOM for ASP.NET run: | @@ -124,6 +137,18 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Download SBOM for ASP.NET + uses: actions/download-artifact@v2 + with: + name: sbom-aspnet + path: . + + - name: Download SBOM for SDK + uses: actions/download-artifact@v2 + with: + name: sbom-sdk + path: . + - name: Generate artifact attestation for ASP.NET uses: actions/attest-build-provenance@v1 with: @@ -143,7 +168,7 @@ jobs: with: subject-name: ghcr.io/ipsimple/aspnet subject-digest: ${{ needs.fetch-and-push.outputs.aspnet_digest }} - sbom-path: sbom-aspnet.json + sbom-path: sbom-aspnet/sbom-aspnet.json push-to-registry: true - name: Generate SBOM attestation for SDK @@ -151,5 +176,5 @@ jobs: with: subject-name: ghcr.io/ipsimple/sdk subject-digest: ${{ needs.fetch-and-push.outputs.sdk_digest }} - sbom-path: sbom-sdk.json + sbom-path: sbom-sdk/sbom-sdk.json push-to-registry: true From 7be5d0deec11c1d638c258a52506469b7aa3feab Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 4 Aug 2024 19:32:33 +1200 Subject: [PATCH 16/46] no message --- .github/workflows/build-publish-baseimages.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index fa4478d..ad5c352 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -96,6 +96,10 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Install Syft + run: | + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sudo sh -s -- -b /usr/local/bin + - name: Generate SBOM for ASP.NET run: | syft packages docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json @@ -119,13 +123,11 @@ jobs: generate-attestations: runs-on: ubuntu-latest needs: [fetch-and-push, generate-sbom] - permissions: id-token: write contents: read packages: write attestations: write - steps: - name: Checkout repository uses: actions/checkout@v2 @@ -168,7 +170,7 @@ jobs: with: subject-name: ghcr.io/ipsimple/aspnet subject-digest: ${{ needs.fetch-and-push.outputs.aspnet_digest }} - sbom-path: sbom-aspnet/sbom-aspnet.json + sbom-path: sbom-aspnet.json push-to-registry: true - name: Generate SBOM attestation for SDK @@ -176,5 +178,5 @@ jobs: with: subject-name: ghcr.io/ipsimple/sdk subject-digest: ${{ needs.fetch-and-push.outputs.sdk_digest }} - sbom-path: sbom-sdk/sbom-sdk.json + sbom-path: sbom-sdk.json push-to-registry: true From 65bd7ea4928a31dbeda7fcf788e58b08ebeb0600 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 4 Aug 2024 21:32:28 +1200 Subject: [PATCH 17/46] no message --- .../workflows/build-publish-baseimages.yml | 72 +------------------ 1 file changed, 2 insertions(+), 70 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index ad5c352..e077ea9 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -11,11 +11,6 @@ jobs: contents: read packages: write id-token: write - attestations: write - - outputs: - aspnet_digest: ${{ steps.push_aspnet.outputs.digest }} - sdk_digest: ${{ steps.push_sdk.outputs.digest }} steps: - name: Checkout repository @@ -82,8 +77,6 @@ jobs: permissions: contents: read packages: write - id-token: write - attestations: write steps: - name: Checkout repository @@ -102,11 +95,11 @@ jobs: - name: Generate SBOM for ASP.NET run: | - syft packages docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json + syft docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json - name: Generate SBOM for SDK run: | - syft packages docker:ghcr.io/ipsimple/sdk:8.0 -o syft-json > sbom-sdk.json + syft docker:ghcr.io/ipsimple/sdk:8.0 -o syft-json > sbom-sdk.json - name: Upload SBOM for ASP.NET uses: actions/upload-artifact@v2 @@ -119,64 +112,3 @@ jobs: with: name: sbom-sdk path: sbom-sdk.json - - generate-attestations: - runs-on: ubuntu-latest - needs: [fetch-and-push, generate-sbom] - permissions: - id-token: write - contents: read - packages: write - attestations: write - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Log in to GitHub Docker registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Download SBOM for ASP.NET - uses: actions/download-artifact@v2 - with: - name: sbom-aspnet - path: . - - - name: Download SBOM for SDK - uses: actions/download-artifact@v2 - with: - name: sbom-sdk - path: . - - - name: Generate artifact attestation for ASP.NET - uses: actions/attest-build-provenance@v1 - with: - subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ needs.fetch-and-push.outputs.aspnet_digest }} - push-to-registry: true - - - name: Generate artifact attestation for SDK - uses: actions/attest-build-provenance@v1 - with: - subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ needs.fetch-and-push.outputs.sdk_digest }} - push-to-registry: true - - - name: Generate SBOM attestation for ASP.NET - uses: actions/attest-sbom@v1 - with: - subject-name: ghcr.io/ipsimple/aspnet - subject-digest: ${{ needs.fetch-and-push.outputs.aspnet_digest }} - sbom-path: sbom-aspnet.json - push-to-registry: true - - - name: Generate SBOM attestation for SDK - uses: actions/attest-sbom@v1 - with: - subject-name: ghcr.io/ipsimple/sdk - subject-digest: ${{ needs.fetch-and-push.outputs.sdk_digest }} - sbom-path: sbom-sdk.json - push-to-registry: true From 029ad81ac5d236121d56fd3fab1cacbfe898c569 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 4 Aug 2024 21:34:31 +1200 Subject: [PATCH 18/46] no message --- .github/workflows/build-publish-baseimages.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-publish-baseimages.yml b/.github/workflows/build-publish-baseimages.yml index e077ea9..20b5f36 100644 --- a/.github/workflows/build-publish-baseimages.yml +++ b/.github/workflows/build-publish-baseimages.yml @@ -11,6 +11,11 @@ jobs: contents: read packages: write id-token: write + attestations: write + + outputs: + aspnet_digest: ${{ steps.push_aspnet.outputs.digest }} + sdk_digest: ${{ steps.push_sdk.outputs.digest }} steps: - name: Checkout repository @@ -77,6 +82,8 @@ jobs: permissions: contents: read packages: write + id-token: write + attestations: write steps: - name: Checkout repository @@ -95,11 +102,11 @@ jobs: - name: Generate SBOM for ASP.NET run: | - syft docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json + syft packages docker:ghcr.io/ipsimple/aspnet:8.0 -o syft-json > sbom-aspnet.json - name: Generate SBOM for SDK run: | - syft docker:ghcr.io/ipsimple/sdk:8.0 -o syft-json > sbom-sdk.json + syft packages docker:ghcr.io/ipsimple/sdk:8.0 -o syft-json > sbom-sdk.json - name: Upload SBOM for ASP.NET uses: actions/upload-artifact@v2 From cc3bfc008ff7c5644a194c2e3a340a9423b55d2f Mon Sep 17 00:00:00 2001 From: ricky-g Date: Mon, 12 Aug 2024 09:27:18 +1200 Subject: [PATCH 19/46] wip --- .github/workflows/build-publish-app.yml | 149 ++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 .github/workflows/build-publish-app.yml diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml new file mode 100644 index 0000000..60462a8 --- /dev/null +++ b/.github/workflows/build-publish-app.yml @@ -0,0 +1,149 @@ +name: Build & Release + +on: + workflow_dispatch: + +jobs: + determine-version: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.determine_version.outputs.version }} + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Determine the version + id: determine_version + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git fetch --tags + LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`) + if [ -z "$LATEST_TAG" ]; then + NEW_TAG="1.0.0" + else + VERSION_REGEX="^([0-9]+)\.([0-9]+)\.([0-9]+)$" + if [[ $LATEST_TAG =~ $VERSION_REGEX ]]; then + MAJOR="${BASH_REMATCH[1]}" + MINOR="${BASH_REMATCH[2]}" + PATCH="${BASH_REMATCH[3]}" + MINOR=$((MINOR + 1)) + if [ $MINOR -eq 100 ]; then + MINOR=0 + MAJOR=$((MAJOR + 1)) + fi + NEW_TAG="$MAJOR.$MINOR.$PATCH" + else + echo "Latest tag is not in the expected format: $LATEST_TAG" + exit 1 + fi + fi + echo "version=$NEW_TAG" >> $GITHUB_ENV + echo "::set-output name=version::$NEW_TAG" + + build-and-test: + runs-on: ubuntu-latest + needs: determine-version + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '8.0.x' + + - name: Build the application + run: dotnet build --configuration Release + + - name: Run tests + run: dotnet test --no-build --verbosity normal + + publish-release: + runs-on: ubuntu-latest + needs: [determine-version, build-and-test] + steps: + - name: Create GitHub release + uses: actions/create-release@v1 + with: + tag_name: ${{ needs.determine-version.outputs.version }} + release_name: Release ${{ needs.determine-version.outputs.version }} + draft: false + prerelease: false + generate_release_notes: true + + - name: Upload .NET binaries + uses: actions/upload-artifact@v2 + with: + name: dotnet-binaries + path: '**/bin/Release/**' + + build-and-push-docker: + runs-on: ubuntu-latest + needs: publish-release + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Log in to GitHub Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + run: | + docker build -t ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} . + docker push ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} + + - name: Attach Docker image to release + uses: softprops/action-gh-release@v1 + with: + files: ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} + + generate-sbom: + runs-on: ubuntu-latest + needs: build-and-push-docker + steps: + - name: Install Syft + run: | + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sudo sh -s -- -b /usr/local/bin + + - name: Generate SBOM + run: | + syft packages docker:ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} -o syft-json > sbom.json + + - name: Upload SBOM + uses: actions/upload-artifact@v2 + with: + name: sbom + path: sbom.json + + scan-sdk-image: + runs-on: ubuntu-latest + needs: determine-version + steps: + - name: Scan SDK base image with Trivy + uses: aquasecurity/trivy-action@master + with: + image-ref: ghcr.io/ipsimple/sdk:8.0 + format: 'table' + exit-code: '1' + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' + + scan-aspnet-image: + runs-on: ubuntu-latest + needs: determine-version + steps: + - name: Scan ASP.NET base image with Trivy + uses: aquasecurity/trivy-action@master + with: + image-ref: ghcr.io/ipsimple/aspnet:8.0 + format: 'table' + exit-code: '1' + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' From 3d69b7fc8893276caf2811489e0d2d1d6f9ab915 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Fri, 23 Aug 2024 23:34:49 +1200 Subject: [PATCH 20/46] add new build file --- .github/workflows/build-publish-app.yml | 30 +------------------------ 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 60462a8..2be8b4f 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -118,32 +118,4 @@ jobs: uses: actions/upload-artifact@v2 with: name: sbom - path: sbom.json - - scan-sdk-image: - runs-on: ubuntu-latest - needs: determine-version - steps: - - name: Scan SDK base image with Trivy - uses: aquasecurity/trivy-action@master - with: - image-ref: ghcr.io/ipsimple/sdk:8.0 - format: 'table' - exit-code: '1' - ignore-unfixed: true - vuln-type: 'os,library' - severity: 'CRITICAL,HIGH' - - scan-aspnet-image: - runs-on: ubuntu-latest - needs: determine-version - steps: - - name: Scan ASP.NET base image with Trivy - uses: aquasecurity/trivy-action@master - with: - image-ref: ghcr.io/ipsimple/aspnet:8.0 - format: 'table' - exit-code: '1' - ignore-unfixed: true - vuln-type: 'os,library' - severity: 'CRITICAL,HIGH' + path: sbom.json \ No newline at end of file From 381a5927ae3e8394ca40344639221eb1d4606407 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Fri, 23 Aug 2024 23:55:30 +1200 Subject: [PATCH 21/46] udpate build and docker file to point to right location --- .github/workflows/build-publish-app.yml | 4 ++-- src/IpSimple.PublicIp.Api/Dockerfile | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 2be8b4f..d33cf06 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -18,9 +18,9 @@ jobs: git config --global user.email "github-actions[bot]@users.noreply.github.com" git config --global user.name "github-actions[bot]" git fetch --tags - LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`) + LATEST_TAG=$(git tag --list | sort -V | tail -n 1) if [ -z "$LATEST_TAG" ]; then - NEW_TAG="1.0.0" + NEW_TAG="0.0.1" else VERSION_REGEX="^([0-9]+)\.([0-9]+)\.([0-9]+)$" if [[ $LATEST_TAG =~ $VERSION_REGEX ]]; then diff --git a/src/IpSimple.PublicIp.Api/Dockerfile b/src/IpSimple.PublicIp.Api/Dockerfile index 986fd16..d658be7 100644 --- a/src/IpSimple.PublicIp.Api/Dockerfile +++ b/src/IpSimple.PublicIp.Api/Dockerfile @@ -1,11 +1,11 @@ #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM ghcr.io/ipsimple/aspnet:8.0 AS base USER app WORKDIR /app EXPOSE 8080 -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM ghcr.io/ipsimple/sdk:8.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src COPY ["IpSimple.PublicIp.Api/IpSimple.PublicIp.Api.csproj", "IpSimple.PublicIp.Api/"] @@ -21,4 +21,4 @@ RUN dotnet publish "./IpSimple.PublicIp.Api.csproj" -c $BUILD_CONFIGURATION -o / FROM base AS final WORKDIR /app COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "IpSimple.PublicIp.Api.dll"] \ No newline at end of file +ENTRYPOINT ["dotnet", "IpSimple.PublicIp.Api.dll"] From d49d01f778f8611393bd6e6a0cd4698a1e028258 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 00:00:34 +1200 Subject: [PATCH 22/46] fix build --- .github/workflows/build-publish-app.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index d33cf06..ce54315 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -53,11 +53,18 @@ jobs: with: dotnet-version: '8.0.x' - - name: Build the application - run: dotnet build --configuration Release - + - name: Build solution + run: dotnet build src/IpSimple.Platform.sln --configuration Release + - name: Run tests - run: dotnet test --no-build --verbosity normal + run: dotnet test src/IpSimple.Platform.sln --configuration Release --no-build + + + # - name: Build the application + # run: dotnet build --configuration Release + + # - name: Run tests + # run: dotnet test --no-build --verbosity normal publish-release: runs-on: ubuntu-latest From ca61aa057387e736c25b936d3c12ea5a136ff757 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 15:16:03 +1200 Subject: [PATCH 23/46] fix build --- .github/workflows/build-publish-app.yml | 43 ++++++++++++------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index ce54315..d6d80db 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -41,13 +41,20 @@ jobs: echo "version=$NEW_TAG" >> $GITHUB_ENV echo "::set-output name=version::$NEW_TAG" - build-and-test: + checkout: runs-on: ubuntu-latest needs: determine-version + outputs: + source-directory: ${{ steps.checkout.outputs.source-directory }} steps: - name: Checkout repository + id: checkout uses: actions/checkout@v2 + build: + runs-on: ubuntu-latest + needs: checkout + steps: - name: Setup .NET uses: actions/setup-dotnet@v1 with: @@ -55,29 +62,26 @@ jobs: - name: Build solution run: dotnet build src/IpSimple.Platform.sln --configuration Release - + + test: + runs-on: ubuntu-latest + needs: build + steps: - name: Run tests run: dotnet test src/IpSimple.Platform.sln --configuration Release --no-build - - - # - name: Build the application - # run: dotnet build --configuration Release - - # - name: Run tests - # run: dotnet test --no-build --verbosity normal publish-release: runs-on: ubuntu-latest - needs: [determine-version, build-and-test] + needs: [determine-version, test] steps: - - name: Create GitHub release - uses: actions/create-release@v1 + - name: Create GitHub Release + id: create_release + uses: softprops/action-gh-release@v2 with: tag_name: ${{ needs.determine-version.outputs.version }} - release_name: Release ${{ needs.determine-version.outputs.version }} - draft: false - prerelease: false - generate_release_notes: true + name: Release ${{ needs.determine-version.outputs.version }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload .NET binaries uses: actions/upload-artifact@v2 @@ -104,11 +108,6 @@ jobs: docker build -t ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} . docker push ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} - - name: Attach Docker image to release - uses: softprops/action-gh-release@v1 - with: - files: ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} - generate-sbom: runs-on: ubuntu-latest needs: build-and-push-docker @@ -125,4 +124,4 @@ jobs: uses: actions/upload-artifact@v2 with: name: sbom - path: sbom.json \ No newline at end of file + path: sbom.json From 87877a6458c3113507490a3022d8d4a8b07d385b Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 15:24:41 +1200 Subject: [PATCH 24/46] fix build --- .github/workflows/build-publish-app.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index d6d80db..0386060 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -10,7 +10,7 @@ jobs: version: ${{ steps.determine_version.outputs.version }} steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Determine the version id: determine_version @@ -38,8 +38,7 @@ jobs: exit 1 fi fi - echo "version=$NEW_TAG" >> $GITHUB_ENV - echo "::set-output name=version::$NEW_TAG" + echo "version=$NEW_TAG" >> $GITHUB_ENV checkout: runs-on: ubuntu-latest @@ -49,14 +48,17 @@ jobs: steps: - name: Checkout repository id: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 + + - name: List files + run: ls -R build: runs-on: ubuntu-latest needs: checkout steps: - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v4 with: dotnet-version: '8.0.x' @@ -94,7 +96,7 @@ jobs: needs: publish-release steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Log in to GitHub Docker registry uses: docker/login-action@v2 From b14e04baf04369c14ac637b3a853c22ab2050e9f Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 15:27:52 +1200 Subject: [PATCH 25/46] fix build --- .github/workflows/build-publish-app.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 0386060..d5d5713 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -50,7 +50,7 @@ jobs: id: checkout uses: actions/checkout@v4 - - name: List files + - name: List files #For troubleshooting purposes, list out the directory structure run: ls -R build: @@ -62,6 +62,9 @@ jobs: with: dotnet-version: '8.0.x' + - name: Change directory to src + run: cd src + - name: Build solution run: dotnet build src/IpSimple.Platform.sln --configuration Release From 4d88339fe32698996cd9ac5a8437cdd1fab8bbc3 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 15:34:36 +1200 Subject: [PATCH 26/46] fix build --- .github/workflows/build-publish-app.yml | 28 ++++++++++--------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index d5d5713..d71dd18 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -38,33 +38,27 @@ jobs: exit 1 fi fi - echo "version=$NEW_TAG" >> $GITHUB_ENV + echo "version=$NEW_TAG" >> $GITHUB_ENV - checkout: + setup-dotnet: runs-on: ubuntu-latest needs: determine-version outputs: - source-directory: ${{ steps.checkout.outputs.source-directory }} - steps: - - name: Checkout repository - id: checkout - uses: actions/checkout@v4 - - - name: List files #For troubleshooting purposes, list out the directory structure - run: ls -R - - build: - runs-on: ubuntu-latest - needs: checkout + dotnet-installed: ${{ steps.setup_dotnet.outputs.success }} steps: - name: Setup .NET + id: setup_dotnet uses: actions/setup-dotnet@v4 with: dotnet-version: '8.0.x' - - name: Change directory to src - run: cd src - + build: + runs-on: ubuntu-latest + needs: setup-dotnet + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Build solution run: dotnet build src/IpSimple.Platform.sln --configuration Release From ddf8316c08fcef75c12f71e22a3cda84e8f82488 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 15:49:42 +1200 Subject: [PATCH 27/46] fix build --- .github/workflows/build-publish-app.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index d71dd18..f57a9bb 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -42,7 +42,6 @@ jobs: setup-dotnet: runs-on: ubuntu-latest - needs: determine-version outputs: dotnet-installed: ${{ steps.setup_dotnet.outputs.success }} steps: @@ -54,7 +53,7 @@ jobs: build: runs-on: ubuntu-latest - needs: setup-dotnet + needs: [determine-version, setup-dotnet] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -66,6 +65,9 @@ jobs: runs-on: ubuntu-latest needs: build steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Run tests run: dotnet test src/IpSimple.Platform.sln --configuration Release --no-build From 0a0d025ef435dbbebf37748e61e16d1b22c01f29 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 22:31:17 +1200 Subject: [PATCH 28/46] fix build --- .github/workflows/build-publish-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index f57a9bb..bacd193 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -69,7 +69,7 @@ jobs: uses: actions/checkout@v4 - name: Run tests - run: dotnet test src/IpSimple.Platform.sln --configuration Release --no-build + run: dotnet test **/*.Tests.csproj --configuration Release --no-build publish-release: runs-on: ubuntu-latest From 32650be32579f82ce151ec88f6ab66c22d44a5f6 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 22:56:00 +1200 Subject: [PATCH 29/46] fix build --- .github/workflows/build-publish-app.yml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index bacd193..90606d9 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -68,8 +68,18 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Run tests - run: dotnet test **/*.Tests.csproj --configuration Release --no-build + - name: Find and run all test projects + run: | + for test_project in $(find . -name "*.Tests.csproj"); do + dotnet test "$test_project" --configuration Release --no-build --logger "trx;LogFileName=test_results.trx" --results-directory "TestResults" + done + + - name: Publish Test Results + uses: actions/upload-artifact@v4 + with: + name: dotnet-results + path: TestResults/ + if: ${{ always() }} publish-release: runs-on: ubuntu-latest @@ -85,7 +95,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload .NET binaries - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: dotnet-binaries path: '**/bin/Release/**' @@ -122,7 +132,7 @@ jobs: syft packages docker:ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} -o syft-json > sbom.json - name: Upload SBOM - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: sbom path: sbom.json From 1b963aeec159618e7444dc428a63fc44b5a7c69a Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 22:59:23 +1200 Subject: [PATCH 30/46] fix build --- .github/workflows/build-publish-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 90606d9..23a420a 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -71,7 +71,7 @@ jobs: - name: Find and run all test projects run: | for test_project in $(find . -name "*.Tests.csproj"); do - dotnet test "$test_project" --configuration Release --no-build --logger "trx;LogFileName=test_results.trx" --results-directory "TestResults" + dotnet test "$test_project" --configuration Release --logger "trx;LogFileName=test_results.trx" --results-directory "TestResults" done - name: Publish Test Results From a0742d37a5393aff3d42ec0e56a8c4921814218f Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 23:04:08 +1200 Subject: [PATCH 31/46] fix build --- .github/workflows/build-publish-app.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 23a420a..19515e0 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -85,21 +85,30 @@ jobs: runs-on: ubuntu-latest needs: [determine-version, test] steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Create Git Tag + run: | + git tag -a v${{ needs.determine-version.outputs.version }} -m "Release version ${{ needs.determine-version.outputs.version }}" + git push origin v${{ needs.determine-version.outputs.version }} + - name: Create GitHub Release id: create_release uses: softprops/action-gh-release@v2 with: - tag_name: ${{ needs.determine-version.outputs.version }} + tag_name: v${{ needs.determine-version.outputs.version }} name: Release ${{ needs.determine-version.outputs.version }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload .NET binaries - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v2 with: name: dotnet-binaries path: '**/bin/Release/**' + build-and-push-docker: runs-on: ubuntu-latest needs: publish-release From f8143a6ec5dd1bb84108416b70bd93d8741668a9 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 23:10:44 +1200 Subject: [PATCH 32/46] fix build --- .github/workflows/build-publish-app.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 19515e0..d6476aa 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -88,6 +88,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + - name: Configure Git user + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "GitHub Actions Bot" + - name: Create Git Tag run: | git tag -a v${{ needs.determine-version.outputs.version }} -m "Release version ${{ needs.determine-version.outputs.version }}" @@ -108,7 +113,6 @@ jobs: name: dotnet-binaries path: '**/bin/Release/**' - build-and-push-docker: runs-on: ubuntu-latest needs: publish-release From 9eba0e6b59e9886af7da5f9552986bb84007fef5 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 23:23:54 +1200 Subject: [PATCH 33/46] fix build --- .github/workflows/build-publish-app.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index d6476aa..78ce893 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -129,6 +129,7 @@ jobs: - name: Build and push Docker image run: | + echo "Using version: ${{ needs.determine-version.outputs.version }}" docker build -t ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} . docker push ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} From b35e7d50ae597dfedcea3c3b61c8970bed803ca9 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 23:30:07 +1200 Subject: [PATCH 34/46] fix build --- .github/workflows/build-publish-app.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 78ce893..faf3372 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -18,11 +18,14 @@ jobs: git config --global user.email "github-actions[bot]@users.noreply.github.com" git config --global user.name "github-actions[bot]" git fetch --tags - LATEST_TAG=$(git tag --list | sort -V | tail -n 1) + + # Fetch the latest valid tag that matches the expected pattern + LATEST_TAG=$(git tag --list | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1) + if [ -z "$LATEST_TAG" ]; then - NEW_TAG="0.0.1" + NEW_TAG="v0.0.1" else - VERSION_REGEX="^([0-9]+)\.([0-9]+)\.([0-9]+)$" + VERSION_REGEX="^v([0-9]+)\.([0-9]+)\.([0-9]+)$" if [[ $LATEST_TAG =~ $VERSION_REGEX ]]; then MAJOR="${BASH_REMATCH[1]}" MINOR="${BASH_REMATCH[2]}" @@ -32,12 +35,13 @@ jobs: MINOR=0 MAJOR=$((MAJOR + 1)) fi - NEW_TAG="$MAJOR.$MINOR.$PATCH" + NEW_TAG="v$MAJOR.$MINOR.$PATCH" else echo "Latest tag is not in the expected format: $LATEST_TAG" exit 1 fi fi + echo "version=$NEW_TAG" >> $GITHUB_ENV setup-dotnet: From e2ffb467bd1598ce3f0ea1adfbc9cb1026cdcd46 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 23:35:31 +1200 Subject: [PATCH 35/46] fix build --- .github/workflows/build-publish-app.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index faf3372..d36a33b 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -18,10 +18,10 @@ jobs: git config --global user.email "github-actions[bot]@users.noreply.github.com" git config --global user.name "github-actions[bot]" git fetch --tags - + # Fetch the latest valid tag that matches the expected pattern LATEST_TAG=$(git tag --list | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1) - + if [ -z "$LATEST_TAG" ]; then NEW_TAG="v0.0.1" else @@ -37,12 +37,18 @@ jobs: fi NEW_TAG="v$MAJOR.$MINOR.$PATCH" else - echo "Latest tag is not in the expected format: $LATEST_TAG" + echo "Error: Latest tag is not in the expected format: $LATEST_TAG" exit 1 fi fi - + + # Output the version to GitHub Actions log + echo "Generated version: $NEW_TAG" + + # Set the version as an output echo "version=$NEW_TAG" >> $GITHUB_ENV + echo "::set-output name=version::$NEW_TAG" + setup-dotnet: runs-on: ubuntu-latest From b6ca340948f5e2f2651c8c63700aa1f67547b8e1 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 23:45:51 +1200 Subject: [PATCH 36/46] fix build --- .github/workflows/build-publish-app.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index d36a33b..5d6b095 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -105,14 +105,14 @@ jobs: - name: Create Git Tag run: | - git tag -a v${{ needs.determine-version.outputs.version }} -m "Release version ${{ needs.determine-version.outputs.version }}" - git push origin v${{ needs.determine-version.outputs.version }} + git tag -a ${{ needs.determine-version.outputs.version }} -m "Release version ${{ needs.determine-version.outputs.version }}" + git push origin ${{ needs.determine-version.outputs.version }} - name: Create GitHub Release id: create_release uses: softprops/action-gh-release@v2 with: - tag_name: v${{ needs.determine-version.outputs.version }} + tag_name: ${{ needs.determine-version.outputs.version }} name: Release ${{ needs.determine-version.outputs.version }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -125,7 +125,7 @@ jobs: build-and-push-docker: runs-on: ubuntu-latest - needs: publish-release + needs: [determine-version, publish-release] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -145,7 +145,7 @@ jobs: generate-sbom: runs-on: ubuntu-latest - needs: build-and-push-docker + needs: [determine-version, build-and-push-docker] steps: - name: Install Syft run: | From 335062c8117dcf6f7cd1b9732707184116179d30 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sat, 24 Aug 2024 23:52:30 +1200 Subject: [PATCH 37/46] fix build --- .github/workflows/build-publish-app.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 5d6b095..7237e94 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -140,6 +140,7 @@ jobs: - name: Build and push Docker image run: | echo "Using version: ${{ needs.determine-version.outputs.version }}" + cd src/IpSimple.PublicIp.Api docker build -t ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} . docker push ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} From d43560081adebbd990a36634a72a729c1bbadb6e Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 25 Aug 2024 18:07:29 +1200 Subject: [PATCH 38/46] fix build --- .github/workflows/build-publish-app.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 7237e94..55abe40 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -140,8 +140,7 @@ jobs: - name: Build and push Docker image run: | echo "Using version: ${{ needs.determine-version.outputs.version }}" - cd src/IpSimple.PublicIp.Api - docker build -t ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} . + docker build -f src/IpSimple.PublicIp.Api/Dockerfile -t ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} src/IpSimple.PublicIp.Api docker push ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} generate-sbom: From 6e6ff618f315555537670b2fc1ca2f841b55bebf Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 25 Aug 2024 18:13:12 +1200 Subject: [PATCH 39/46] fix build --- .github/workflows/build-publish-app.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 55abe40..eb29450 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -139,9 +139,9 @@ jobs: - name: Build and push Docker image run: | - echo "Using version: ${{ needs.determine-version.outputs.version }}" - docker build -f src/IpSimple.PublicIp.Api/Dockerfile -t ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} src/IpSimple.PublicIp.Api - docker push ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} + echo "Using version: ${{ needs.determine-version.outputs.version }}" + docker build -f src/IpSimple.PublicIp.Api/Dockerfile -t ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} src/ + docker push ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} generate-sbom: runs-on: ubuntu-latest From 3e355cae7942c00ed0bc5faef6c42a28cb8010da Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 25 Aug 2024 19:05:03 +1200 Subject: [PATCH 40/46] fix build --- .github/workflows/build-publish-app.yml | 25 +++++++++++++++++-------- src/IpSimple.PublicIp.Api/Dockerfile | 11 +++++++++-- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index eb29450..e84ecd8 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -73,7 +73,7 @@ jobs: test: runs-on: ubuntu-latest - needs: build + needs: [determine-version, build] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -87,7 +87,7 @@ jobs: - name: Publish Test Results uses: actions/upload-artifact@v4 with: - name: dotnet-results + name: ipsimple-unit-test-results-${{ needs.determine-version.outputs.version }} path: TestResults/ if: ${{ always() }} @@ -114,14 +114,23 @@ jobs: with: tag_name: ${{ needs.determine-version.outputs.version }} name: Release ${{ needs.determine-version.outputs.version }} + generate_release_notes: true + append_body: | + ## Docker Image + + [Docker Image on GitHub Packages](https://github.com/ipsimple/platform/pkgs/container/ipsimple-app/versions) page will list all the available versions, please refer to the version ${{ needs.determine-version.outputs.version }} for this release + env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: List bin/Release directory contents for troubleshooting + run: ls -R src/**/bin/Release + - name: Upload .NET binaries - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: dotnet-binaries - path: '**/bin/Release/**' + path: src/**/bin/Release/** build-and-push-docker: runs-on: ubuntu-latest @@ -131,7 +140,7 @@ jobs: uses: actions/checkout@v4 - name: Log in to GitHub Docker registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} @@ -140,8 +149,8 @@ jobs: - name: Build and push Docker image run: | echo "Using version: ${{ needs.determine-version.outputs.version }}" - docker build -f src/IpSimple.PublicIp.Api/Dockerfile -t ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} src/ - docker push ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} + docker build -f src/IpSimple.PublicIp.Api/Dockerfile -t ghcr.io/ipsimple/ipsimple-app:${{ needs.determine-version.outputs.version }} src/ + docker push ghcr.io/ipsimple/ipsimple-app:${{ needs.determine-version.outputs.version }} generate-sbom: runs-on: ubuntu-latest @@ -158,5 +167,5 @@ jobs: - name: Upload SBOM uses: actions/upload-artifact@v4 with: - name: sbom + name: ipsimple-${{ needs.determine-version.outputs.version }}-sbom path: sbom.json diff --git a/src/IpSimple.PublicIp.Api/Dockerfile b/src/IpSimple.PublicIp.Api/Dockerfile index d658be7..576dad2 100644 --- a/src/IpSimple.PublicIp.Api/Dockerfile +++ b/src/IpSimple.PublicIp.Api/Dockerfile @@ -1,6 +1,13 @@ -#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. - FROM ghcr.io/ipsimple/aspnet:8.0 AS base + +LABEL org.opencontainers.image.title="IpSimple App" +LABEL org.opencontainers.image.description="A reliable and scalable public IP address API, designed for seamless integration into any application. It offers unlimited usage, compatibility with IPv4 and IPv6, high availability, open-source transparency, privacy focus, and future-proof reliability. Use cases include network management, cloud infrastructure, security applications, and developer tools." +LABEL org.opencontainers.image.url="https://github.com/ipsimple/platform" +LABEL org.opencontainers.image.authors="ipsimple org" +LABEL org.opencontainers.image.licenses="MIT" +LABEL org.opencontainers.image.vendor="ipsimple org" +LABEL org.opencontainers.image.source="https://github.com/ipsimple/platform" + USER app WORKDIR /app EXPOSE 8080 From ee2a51424ff69c12f01802d516c78215c2802f16 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 25 Aug 2024 19:12:02 +1200 Subject: [PATCH 41/46] fix build --- .github/workflows/build-publish-app.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index e84ecd8..f9c068b 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -3,6 +3,11 @@ name: Build & Release on: workflow_dispatch: +# on: +# push: +# branches: +# - main + jobs: determine-version: runs-on: ubuntu-latest @@ -69,7 +74,7 @@ jobs: uses: actions/checkout@v4 - name: Build solution - run: dotnet build src/IpSimple.Platform.sln --configuration Release + run: dotnet build src/IpSimple.Platform.sln --configuration Release --output src/IpSimple.Platform/bin/Release test: runs-on: ubuntu-latest @@ -123,14 +128,14 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: List bin/Release directory contents for troubleshooting - run: ls -R src/**/bin/Release + - name: List all files in the src directory for troubleshooting + run: ls -R src/ - name: Upload .NET binaries uses: actions/upload-artifact@v4 with: name: dotnet-binaries - path: src/**/bin/Release/** + path: src/IpSimple.Platform/bin/Release/** build-and-push-docker: runs-on: ubuntu-latest From 88065886a56c194e49908490fe3c89592693fd52 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 25 Aug 2024 19:22:05 +1200 Subject: [PATCH 42/46] fix build --- .github/workflows/build-publish-app.yml | 2 +- .github/workflows/pull_request_template.md | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/pull_request_template.md diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index f9c068b..7cc6773 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -167,7 +167,7 @@ jobs: - name: Generate SBOM run: | - syft packages docker:ghcr.io/ipsimple/app:${{ needs.determine-version.outputs.version }} -o syft-json > sbom.json + syft scan docker:ghcr.io/ipsimple/ipsimple-app:${{ needs.determine-version.outputs.version }} -o syft-json > sbom.json - name: Upload SBOM uses: actions/upload-artifact@v4 diff --git a/.github/workflows/pull_request_template.md b/.github/workflows/pull_request_template.md new file mode 100644 index 0000000..7dace31 --- /dev/null +++ b/.github/workflows/pull_request_template.md @@ -0,0 +1,17 @@ +# Pull Request Title + +**Description:** + + +**Comments/Questions:** + + +**Checklist:** +- [ ] Code is up-to-date with the `main` branch +- [ ] No merge conflicts +- [ ] Code has been properly tested +- [ ] Documentation has been updated (if applicable) +- [ ] Reviewers have been added (if applicable) + +**Related Issues:** + From 111e583bb17db2f4e02257f973a14cbe78a1c9bc Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 25 Aug 2024 22:36:56 +1200 Subject: [PATCH 43/46] fix build --- .github/workflows/build-publish-app.yml | 28 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 7cc6773..2cd171b 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -3,10 +3,9 @@ name: Build & Release on: workflow_dispatch: -# on: -# push: -# branches: -# - main + # push: + # branches: + # - main jobs: determine-version: @@ -36,7 +35,7 @@ jobs: MINOR="${BASH_REMATCH[2]}" PATCH="${BASH_REMATCH[3]}" MINOR=$((MINOR + 1)) - if [ $MINOR -eq 100 ]; then + if [ $MINOR -eq 100]; then MINOR=0 MAJOR=$((MAJOR + 1)) fi @@ -96,13 +95,30 @@ jobs: path: TestResults/ if: ${{ always() }} - publish-release: + codeql-scan: + name: CodeQL Analysis runs-on: ubuntu-latest needs: [determine-version, test] steps: - name: Checkout repository uses: actions/checkout@v4 + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: 'csharp' + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + + publish-release: + runs-on: ubuntu-latest + needs: [determine-version, codeql-scan] + if: success() + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Configure Git user run: | git config --global user.email "github-actions[bot]@users.noreply.github.com" From 53cf6ff3fc76ac03c394bbb71fb5b5f86f66000a Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 25 Aug 2024 22:45:19 +1200 Subject: [PATCH 44/46] fix build --- .github/workflows/build-publish-app.yml | 39 +++++++++++++------------ 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 2cd171b..717a24a 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -65,9 +65,26 @@ jobs: with: dotnet-version: '8.0.x' + codeql-scan: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: 'csharp' + + - name: Build the code + run: dotnet build src/IpSimple.Platform.sln --configuration Release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + build: runs-on: ubuntu-latest - needs: [determine-version, setup-dotnet] + needs: [determine-version, setup-dotnet, codeql-scan] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -77,7 +94,7 @@ jobs: test: runs-on: ubuntu-latest - needs: [determine-version, build] + needs: [determine-version, build, codeql-scan] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -95,25 +112,9 @@ jobs: path: TestResults/ if: ${{ always() }} - codeql-scan: - name: CodeQL Analysis - runs-on: ubuntu-latest - needs: [determine-version, test] - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: 'csharp' - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - publish-release: runs-on: ubuntu-latest - needs: [determine-version, codeql-scan] + needs: [determine-version, build, test, codeql-scan] if: success() steps: - name: Checkout repository From 6ca04bdb990c2fa00582bae9858f95ba9d4ec49e Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 25 Aug 2024 22:53:12 +1200 Subject: [PATCH 45/46] fix build --- .github/workflows/build-publish-app.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 717a24a..3c2da4f 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -67,6 +67,7 @@ jobs: codeql-scan: runs-on: ubuntu-latest + needs: [determine-version, setup-dotnet] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -156,7 +157,7 @@ jobs: build-and-push-docker: runs-on: ubuntu-latest - needs: [determine-version, publish-release] + needs: [determine-version, publish-release, codeql-scan] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -176,7 +177,7 @@ jobs: generate-sbom: runs-on: ubuntu-latest - needs: [determine-version, build-and-push-docker] + needs: [determine-version, build-and-push-docker, codeql-scan] steps: - name: Install Syft run: | From fa4cf0659a91a7c4003b67ccfd865c4a3ace9665 Mon Sep 17 00:00:00 2001 From: ricky-g Date: Sun, 25 Aug 2024 23:17:25 +1200 Subject: [PATCH 46/46] fix build --- .github/workflows/build-publish-app.yml | 22 ++++--- .github/workflows/pr-checks.yml | 87 +++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/pr-checks.yml diff --git a/.github/workflows/build-publish-app.yml b/.github/workflows/build-publish-app.yml index 3c2da4f..57777a2 100644 --- a/.github/workflows/build-publish-app.yml +++ b/.github/workflows/build-publish-app.yml @@ -2,10 +2,9 @@ name: Build & Release on: workflow_dispatch: - - # push: - # branches: - # - main + push: + branches: + - main jobs: determine-version: @@ -73,7 +72,7 @@ jobs: uses: actions/checkout@v4 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: 'csharp' @@ -81,11 +80,11 @@ jobs: run: dotnet build src/IpSimple.Platform.sln --configuration Release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 build: runs-on: ubuntu-latest - needs: [determine-version, setup-dotnet, codeql-scan] + needs: [determine-version, codeql-scan] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -140,9 +139,12 @@ jobs: generate_release_notes: true append_body: | ## Docker Image - - [Docker Image on GitHub Packages](https://github.com/ipsimple/platform/pkgs/container/ipsimple-app/versions) page will list all the available versions, please refer to the version ${{ needs.determine-version.outputs.version }} for this release - + + The Docker image for this release is available on [GitHub Packages](https://github.com/ipsimple/platform/pkgs/container/ipsimple-app/versions). You can pull this image using: + + ```bash + docker pull ghcr.io/ipsimple/ipsimple-app:${{ needs.determine-version.outputs.version }} + ``` env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml new file mode 100644 index 0000000..86ab3a5 --- /dev/null +++ b/.github/workflows/pr-checks.yml @@ -0,0 +1,87 @@ +name: PR Validation + +on: + pull_request: + branches: + - main + +jobs: + setup-dotnet: + runs-on: ubuntu-latest + outputs: + dotnet-installed: ${{ steps.setup_dotnet.outputs.success }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup .NET + id: setup_dotnet + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + + codeql-scan: + runs-on: ubuntu-latest + needs: setup-dotnet + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: 'csharp' + + - name: Build the code + run: dotnet build src/IpSimple.Platform.sln --configuration Release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + + build: + runs-on: ubuntu-latest + needs: codeql-scan + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Build solution + run: dotnet build src/IpSimple.Platform.sln --configuration Release --output src/IpSimple.Platform/bin/Release + + test: + runs-on: ubuntu-latest + needs: build + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Find and run all test projects + run: | + for test_project in $(find . -name "*.Tests.csproj"); do + dotnet test "$test_project" --configuration Release --logger "trx;LogFileName=test_results.trx" --results-directory "TestResults" + done + + - name: Publish Test Results + uses: actions/upload-artifact@v4 + with: + name: ipsimple-unit-test-results + path: TestResults/ + if: ${{ always() }} + + build-docker: + runs-on: ubuntu-latest + needs: test + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to GitHub Docker registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build Docker image (validation only) + run: | + docker build -f src/IpSimple.PublicIp.Api/Dockerfile -t ghcr.io/ipsimple/ipsimple-app-pr-validation src/