From f7f4cdb9f4af8bca0d27d7ae50edac452a7687ee Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Wed, 4 Feb 2026 14:27:23 +0100 Subject: [PATCH 01/14] Add content validate reusable workflow --- .github/workflows/ci.yml | 30 ++---------- .../workflows/reusable-content-validate.yaml | 46 +++++++++++++++++++ .../workflows/reusable-terraform-apply.yml | 21 +++++++-- .../workflows/reusable-terraform-validate.yml | 11 +++-- README.md | 2 + .../docker}/build-push/action.yml | 0 .../docker}/build-scan/action.yml | 0 .../dotnet}/build-lint-test/action.yml | 0 {mongodb => actions/mongodb}/start/action.yml | 0 9 files changed, 76 insertions(+), 34 deletions(-) create mode 100644 .github/workflows/reusable-content-validate.yaml rename {docker => actions/docker}/build-push/action.yml (100%) rename {docker => actions/docker}/build-scan/action.yml (100%) rename {dotnet => actions/dotnet}/build-lint-test/action.yml (100%) rename {mongodb => actions/mongodb}/start/action.yml (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e204047..bdd9531 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,34 +2,12 @@ name: CI on: push: - branches: - - main + branches: [main] pull_request: - branches: - - main + branches: [main] workflow_dispatch: {} -env: - python_version: "3.13" - jobs: build: - runs-on: ubuntu-latest - steps: - - name: Checks-out the repository - uses: actions/checkout@v4 - - name: Lints Markdown files - uses: DavidAnson/markdownlint-cli2-action@v20 - with: - globs: "**/*.md" - - name: Set up Python ${{ env.python_version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ env.python_version }} - - name: Installs Python packages - run: | - python -m pip install --upgrade pip - pip install yamllint - - name: Lint YAML files - run: | - yamllint . + name: Content + uses: ./.github/workflows/reusable-content-validate.yaml diff --git a/.github/workflows/reusable-content-validate.yaml b/.github/workflows/reusable-content-validate.yaml new file mode 100644 index 0000000..b1b15d0 --- /dev/null +++ b/.github/workflows/reusable-content-validate.yaml @@ -0,0 +1,46 @@ +name: Reusable - Content validate + +on: + workflow_call: + inputs: + job-name: + description: "Job name" + type: string + required: false + default: "Validate" + working-directory: + description: "Working directory" + type: string + required: false + default: "." + operating-system: + description: "Operating system executing the runner" + type: string + required: false + default: "ubuntu-latest" + python-version: + description: "Python version" + type: string + required: false + default: "3.14" + +jobs: + content-validate: + name: ${{ inputs.job-name }} + runs-on: ${{ inputs.operating-system }} + steps: + - name: Check out repository + uses: actions/checkout@v6 + - name: Lint Markdown files + uses: DavidAnson/markdownlint-cli2-action@v22 + with: + globs: "**/*.md" + - name: Install Python ${{ inputs.python-version }} + uses: actions/setup-python@v6 + with: + python-version: ${{ inputs.python-version }} + - name: Lint YAML files + run: | + python -m pip install --upgrade pip + pip install yamllint + yamllint . diff --git a/.github/workflows/reusable-terraform-apply.yml b/.github/workflows/reusable-terraform-apply.yml index 0e1ea69..44e1b12 100644 --- a/.github/workflows/reusable-terraform-apply.yml +++ b/.github/workflows/reusable-terraform-apply.yml @@ -3,13 +3,24 @@ on: workflow_call: inputs: - environment: - description: "GitHub environment" + job-name: + description: "Job name" type: string - required: true + required: false + default: "Deploy" working-directory: description: "Working directory" type: string + required: false + default: "." + operating-system: + description: "Operating system executing the runner" + type: string + required: false + default: "ubuntu-latest" + environment: + description: "GitHub environment" + type: string required: true tfbackend-project: description: "Terraform backend project" @@ -61,8 +72,8 @@ on: jobs: deploy: - name: Deploy - runs-on: ubuntu-latest + name: ${{ inputs.job-name }} + runs-on: ${{ inputs.operating-system }} environment: ${{ inputs.environment }} defaults: run: diff --git a/.github/workflows/reusable-terraform-validate.yml b/.github/workflows/reusable-terraform-validate.yml index 7ada9b2..89918f6 100644 --- a/.github/workflows/reusable-terraform-validate.yml +++ b/.github/workflows/reusable-terraform-validate.yml @@ -5,19 +5,24 @@ on: inputs: job-name: description: "Job name" - required: false type: string + required: false default: "Validate" working-directory: description: "Working directory" - required: false type: string + required: false default: "." + operating-system: + description: "Operating system executing the runner" + type: string + required: false + default: "ubuntu-latest" jobs: terraform-validate: name: ${{ inputs.job-name }} - runs-on: ubuntu-latest + runs-on: ${{ inputs.operating-system }} defaults: run: working-directory: ${{ inputs.working-directory }} diff --git a/README.md b/README.md index 009280d..4ffda7e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # GitHub workflow parts +[![CI](https://github.com/devpro/github-workflow-parts/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/devpro/github-workflow-parts/actions/workflows/ci.yml) + Repository of workflow parts to be used in GitHub Actions. ## Actions diff --git a/docker/build-push/action.yml b/actions/docker/build-push/action.yml similarity index 100% rename from docker/build-push/action.yml rename to actions/docker/build-push/action.yml diff --git a/docker/build-scan/action.yml b/actions/docker/build-scan/action.yml similarity index 100% rename from docker/build-scan/action.yml rename to actions/docker/build-scan/action.yml diff --git a/dotnet/build-lint-test/action.yml b/actions/dotnet/build-lint-test/action.yml similarity index 100% rename from dotnet/build-lint-test/action.yml rename to actions/dotnet/build-lint-test/action.yml diff --git a/mongodb/start/action.yml b/actions/mongodb/start/action.yml similarity index 100% rename from mongodb/start/action.yml rename to actions/mongodb/start/action.yml From ccb77bff3eed31e0b526f658a8deead6932e94f5 Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Wed, 4 Feb 2026 17:33:13 +0100 Subject: [PATCH 02/14] Initiate reusable dotnet validate workflow --- .github/workflows/ci.yml | 2 +- .../workflows/reusable-dotnet-validate.yml | 154 ++++++++++++++++++ README.md | 8 +- .../action.yml | 66 +------- actions/dotnet/build-test/action.yml | 33 ++++ .../dotnet/install-lint-restore/action.yml | 31 ++++ 6 files changed, 228 insertions(+), 66 deletions(-) create mode 100644 .github/workflows/reusable-dotnet-validate.yml rename actions/dotnet/{build-lint-test => build-test-sonar}/action.yml (56%) create mode 100644 actions/dotnet/build-test/action.yml create mode 100644 actions/dotnet/install-lint-restore/action.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bdd9531..82f10d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,6 @@ on: workflow_dispatch: {} jobs: - build: + content-validate: name: Content uses: ./.github/workflows/reusable-content-validate.yaml diff --git a/.github/workflows/reusable-dotnet-validate.yml b/.github/workflows/reusable-dotnet-validate.yml new file mode 100644 index 0000000..dd2b51d --- /dev/null +++ b/.github/workflows/reusable-dotnet-validate.yml @@ -0,0 +1,154 @@ +name: Reusable - .NET validate + +on: + workflow_call: + inputs: + job-name: + description: Job name + type: string + required: false + default: Validate + working-directory: + description: Working directory + type: string + required: false + default: "." + operating-system: + description: Operating system executing the runner + type: string + required: false + default: ubuntu-latest + workflow-parts-version: + description: GitHub workflow parts version (branch/tag/SHA) + type: string + required: false + default: main + dotnet-version: + description: .NET version + type: string + default: "10.0" + extra-vars: + description: "Additional environment variables at the start of the pipeline" + type: string + required: false + default: "" + mongodb-enabled: + description: Start MongoDB for integration tests? + type: boolean + required: false + default: false + sonar-enabled: + description: Enable check done by Sonar (SonarQube or SonarCloud) + type: boolean + required: false + default: false + sonar_host_url: + description: Sonar host URL + type: string + required: false + default: "https://sonarcloud.io" + sonar_organization: + description: Sonar organization + type: string + required: false + default: "" + sonar_project_name: + description: Sonar project name + type: string + required: false + default: "" + sonar_project_key: + description: Sonar project key + type: string + required: false + default: "" + sonar_token: + description: Sonar token for login + type: string + required: false + default: "" + fossa-enabled: + description: Enable license compliance with FOSSA + type: boolean + required: false + default: false + fossa-api-key: + description: FOSSA API KEY + type: string + required: false + default: "" + +jobs: + dotnet-validate: + name: ${{ inputs.job-name }} + runs-on: ${{ inputs.operating-system }} + defaults: + run: + working-directory: ${{ inputs.working-directory }} + steps: + - name: Set additional variables + run: | + if [[ -z "${{ secrets.extra-vars }}" ]]; then + echo "No extra-vars provided - skipping" + else + echo "${{ secrets.extra-vars }}" >> "$GITHUB_ENV" + fi + - name: Clone repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Checkout workflow parts + uses: actions/checkout@v6 + with: + repository: devpro/github-workflow-parts + ref: ${{ inputs.workflow-parts-version }} + path: workflow-parts + - name: Install & lint .NET + uses: ./workflow-parts/dotnet/install-lint-restore + with: + dotnet-version: ${{ dotnet-version }} + - name: Start MongoDB + if: ${{ inputs.mongodb-enabled }} + uses: ./workflow-parts/mongodb/start + - name: Build & test .NET + if: ${{ ! inputs.sonar-enabled }} + uses: ./workflow-parts/dotnet/build-test + - name: Build, lint & test + if: ${{ inputs.sonar-enabled }} + uses: ./workflow-parts/dotnet/build-test-sonar + with: + sonar_organization: ${{ inputs.sonar_organization }} + sonar_host_url: ${{ inputs.sonar_host_url }} + sonar_project_name: ${{ inputs.sonar_project_name }} + sonar_project_key: ${{ inputs.sonar_project_key }} + sonar_token: ${{ inputs.sonar_token }} + - name: License Compliance with FOSSA + if: ${{ inputs.fossa-enabled }} + uses: fossas/fossa-action@v1 + with: + api-key: "${{ inputs.fossa-api-key }}" + run-tests: false + - name: Generate SBOM with Syft + uses: anchore/sbom-action@v0 + # with: + # path: . # Or Dockerfile path + # format: spdx-json # Or cyclonedx-json + # output-file: sbom.json + # upload-artifact: true # Auto-upload to workflow artifacts + - name: Archive test results + uses: actions/upload-artifact@v4 + with: + name: dotnet-test-results + path: | + ./**/*test-result.xml + ./test/*/TestResults/*/coverage.cobertura.xml + ./**/SonarQube.xml + ./**/Summary.txt + +# GITHUB_TOKEN: secrets.GITHUB_TOKEN +# secrets.FOSSA_API_KEY +# Application__IsHttpsRedirectionEnabled: "false" +# sonar_organization: vars.SONAR_ORG +# sonar_project_name: Todo Blazor +# sonar_project_key: vars.SONAR_PROJECT_KEY +# sonar_token: secrets.SONAR_TOKEN diff --git a/README.md b/README.md index 4ffda7e..32be3aa 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ Repository of workflow parts to be used in GitHub Actions. -## Actions +## Composite actions + + Technology | Role | Action | Detail -----------|----------|---------------------------------------------------------|---------------------------------------------------------------------------- @@ -12,3 +14,7 @@ Docker | CD | [Build & Push](docker/build-push/action.yml) Docker | CI | [Build & Scan](docker/build-scan/action.yml) | Build a new container image with Docker, and scan it .NET | CI | [Build, lint & test](dotnet/build-lint-test/action.yml) | Build .NET code, check the code with linter and Sonar, and run tests MongoDB | Services | [Start](mongodb/start/action.yml) | Start a local MongoDB database + +## Reusable workflows + +TODO diff --git a/actions/dotnet/build-lint-test/action.yml b/actions/dotnet/build-test-sonar/action.yml similarity index 56% rename from actions/dotnet/build-lint-test/action.yml rename to actions/dotnet/build-test-sonar/action.yml index 2fe7b85..71fbd02 100644 --- a/actions/dotnet/build-lint-test/action.yml +++ b/actions/dotnet/build-test-sonar/action.yml @@ -5,11 +5,7 @@ inputs: dotnet_version: description: .NET SDK version to be used required: false - default: "10.0.x" - sonar_enabled: - description: Enable code scan by Sonar - required: false - default: "false" + default: "10.0" sonar_organization: description: Sonar organization required: false @@ -34,52 +30,22 @@ inputs: description: Folder where report files will be generated required: false default: report - fossa_enabled: - description: Enable license compliance with FOSSA - required: false - default: "false" - fossa_api_key: - description: FOSSA API KEY - required: false - default: "" runs: using: "composite" steps: - - name: Install .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: ${{ inputs.dotnet_version }} - name: Set up JDK for Sonar - if: ${{ inputs.sonar_enabled == 'true' }} uses: actions/setup-java@v4 with: java-version: 21 distribution: "zulu" - - name: Install .NET linters - if: ${{ inputs.dotnet_version == '7.0.x' }} - run: dotnet tool install -g dotnet-format --version "7.*" --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json - shell: bash - - name: Install .NET tools - run: | - dotnet tool install --global dotnet-reportgenerator-globaltool - export PATH="$PATH:/root/.dotnet/tools" - shell: bash - - name: Restore .NET packages - run: dotnet restore - shell: bash - - name: Lint .NET code - run: dotnet format --verify-no-changes --severity warn --verbosity:diagnostic - shell: bash - name: Cache Sonar packages - if: ${{ inputs.sonar_enabled == 'true' }} uses: actions/cache@v4 with: path: ~/sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Cache Sonar scanner - if: ${{ inputs.sonar_enabled == 'true' }} id: cache-sonar-scanner uses: actions/cache@v4 with: @@ -87,13 +53,12 @@ runs: key: ${{ runner.os }}-sonar-scanner restore-keys: ${{ runner.os }}-sonar-scanner - name: Install Sonar scanner - if: ${{ inputs.sonar_enabled == 'true' && steps.cache-sonar-scanner.outputs.cache-hit != 'true' }} + if: ${{ steps.cache-sonar-scanner.outputs.cache-hit != 'true' }} run: | mkdir -p ./.sonar/scanner dotnet tool update dotnet-sonarscanner --tool-path ./.sonar/scanner shell: bash - name: Start code analysis - if: ${{ inputs.sonar_enabled == 'true' }} run: | ./.sonar/scanner/dotnet-sonarscanner begin /k:"${{ inputs.sonar_project_key }}" /o:"${{ inputs.sonar_organization }}" \ /n:"${{ inputs.sonar_project_name }}" /d:sonar.token="${{ inputs.sonar_token}}" /d:sonar.host.url="${{inputs.sonar_host_url}}" \ @@ -111,7 +76,6 @@ runs: shell: bash env: ASPNETCORE_ENVIRONMENT: Development - Application__IsHttpsRedirectionEnabled: "false" - name: Generate test report run: | reportgenerator "-reports:./test/*/TestResults/*/coverage.cobertura.xml" \ @@ -119,31 +83,5 @@ runs: "-reporttypes:Cobertura;Html;TextSummary;SonarQube" shell: bash - name: Complete code analysis - if: ${{ inputs.sonar_enabled == 'true' }} run: ./.sonar/scanner/dotnet-sonarscanner end /d:sonar.token="${{inputs.sonar_token}}" shell: bash - - - name: License Compliance with FOSSA - if: ${{ inputs.fossa_enabled == 'true' }} - uses: fossas/fossa-action@v1 - with: - api-key: "${{ inputs.fossa_api_key }}" - run-tests: false - - - name: Generate SBOM with Syft - uses: anchore/sbom-action@v0 - # with: - # path: . # Or Dockerfile path - # format: spdx-json # Or cyclonedx-json - # output-file: sbom.json - # upload-artifact: true # Auto-upload to workflow artifacts - - - name: Archive test results - uses: actions/upload-artifact@v4 - with: - name: dotnet-test-results - path: | - ./**/*test-result.xml - ./test/*/TestResults/*/coverage.cobertura.xml - ./**/SonarQube.xml - ./**/Summary.txt diff --git a/actions/dotnet/build-test/action.yml b/actions/dotnet/build-test/action.yml new file mode 100644 index 0000000..1778c24 --- /dev/null +++ b/actions/dotnet/build-test/action.yml @@ -0,0 +1,33 @@ +name: Build & Test +description: Builds and runs tests on a .NET codebase + +inputs: + dotnet_version: + description: .NET SDK version to be used + required: false + default: "10.0" + report_folder: + description: Folder where report files will be generated + required: false + default: report + +runs: + using: "composite" + steps: + - name: Build .NET code + run: dotnet build --no-restore + shell: bash + - name: Run .NET tests + run: | + dotnet test --no-build --verbosity normal --configuration Debug \ + --logger:"junit;LogFilePath=..\..\artifacts\{assembly}-test-result.xml;MethodFormat=Class;FailureBodyFormat=Verbose" \ + --collect:"XPlat Code Coverage" + shell: bash + env: + ASPNETCORE_ENVIRONMENT: Development + - name: Generate test report + run: | + reportgenerator "-reports:./test/*/TestResults/*/coverage.cobertura.xml" \ + "-targetdir:${{inputs.report_folder}}" \ + "-reporttypes:Cobertura;Html;TextSummary" + shell: bash diff --git a/actions/dotnet/install-lint-restore/action.yml b/actions/dotnet/install-lint-restore/action.yml new file mode 100644 index 0000000..87679a8 --- /dev/null +++ b/actions/dotnet/install-lint-restore/action.yml @@ -0,0 +1,31 @@ +name: Install & Lint +description: Installs .NET SDK, lints and restores .NET code + +inputs: + dotnet-version: + description: .NET SDK version to be used + required: false + default: "10.0" + +runs: + using: "composite" + steps: + - name: Install .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: ${{ inputs.dotnet-version }} + - name: Install .NET linters + if: ${{ startsWith(inputs.dotnet-version, '7') }} + run: dotnet tool install -g dotnet-format --version "7.*" --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json + shell: bash + - name: Install .NET tools + run: | + dotnet tool install --global dotnet-reportgenerator-globaltool + export PATH="$PATH:/root/.dotnet/tools" + shell: bash + - name: Lint .NET code + run: dotnet format --verify-no-changes --severity warn --verbosity:diagnostic + shell: bash + - name: Restore .NET packages + run: dotnet restore + shell: bash From 47de2d7ad002d52d30dcb7a04df488c06ba061c2 Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Wed, 4 Feb 2026 20:54:55 +0100 Subject: [PATCH 03/14] Improve naming --- .../workflows/reusable-dotnet-validate.yml | 94 +++++++++---------- actions/dotnet/build-test-sonar/action.yml | 48 +++++----- actions/dotnet/build-test/action.yml | 8 +- 3 files changed, 69 insertions(+), 81 deletions(-) diff --git a/.github/workflows/reusable-dotnet-validate.yml b/.github/workflows/reusable-dotnet-validate.yml index dd2b51d..35d701c 100644 --- a/.github/workflows/reusable-dotnet-validate.yml +++ b/.github/workflows/reusable-dotnet-validate.yml @@ -3,26 +3,6 @@ name: Reusable - .NET validate on: workflow_call: inputs: - job-name: - description: Job name - type: string - required: false - default: Validate - working-directory: - description: Working directory - type: string - required: false - default: "." - operating-system: - description: Operating system executing the runner - type: string - required: false - default: ubuntu-latest - workflow-parts-version: - description: GitHub workflow parts version (branch/tag/SHA) - type: string - required: false - default: main dotnet-version: description: .NET version type: string @@ -32,51 +12,68 @@ on: type: string required: false default: "" + fossa-enabled: + description: Enable license compliance with FOSSA + type: boolean + required: false + default: false + job-name: + description: Job name + type: string + required: false + default: Validate mongodb-enabled: - description: Start MongoDB for integration tests? + description: "Start MongoDB for integration tests?" type: boolean required: false default: false + operating-system: + description: Operating system executing the runner + type: string + required: false + default: ubuntu-latest sonar-enabled: description: Enable check done by Sonar (SonarQube or SonarCloud) type: boolean required: false default: false - sonar_host_url: + sonar-host-url: description: Sonar host URL type: string required: false default: "https://sonarcloud.io" - sonar_organization: + sonar-organization: description: Sonar organization type: string required: false default: "" - sonar_project_name: - description: Sonar project name + sonar-project-key: + description: Sonar project key type: string required: false default: "" - sonar_project_key: - description: Sonar project key + sonar-project-name: + description: Sonar project name type: string required: false default: "" - sonar_token: - description: Sonar token for login + workflow-parts-version: + description: GitHub workflow parts version (branch/tag/SHA) type: string required: false - default: "" - fossa-enabled: - description: Enable license compliance with FOSSA - type: boolean + default: main + working-directory: + description: Working directory + type: string required: false - default: false + default: "." + secrets: fossa-api-key: description: FOSSA API KEY - type: string required: false - default: "" + sonar-token: + description: Sonar token for login + required: false jobs: dotnet-validate: @@ -106,7 +103,7 @@ jobs: - name: Install & lint .NET uses: ./workflow-parts/dotnet/install-lint-restore with: - dotnet-version: ${{ dotnet-version }} + dotnet-version: ${{ inputs.dotnet-version }} - name: Start MongoDB if: ${{ inputs.mongodb-enabled }} uses: ./workflow-parts/mongodb/start @@ -117,16 +114,16 @@ jobs: if: ${{ inputs.sonar-enabled }} uses: ./workflow-parts/dotnet/build-test-sonar with: - sonar_organization: ${{ inputs.sonar_organization }} - sonar_host_url: ${{ inputs.sonar_host_url }} - sonar_project_name: ${{ inputs.sonar_project_name }} - sonar_project_key: ${{ inputs.sonar_project_key }} - sonar_token: ${{ inputs.sonar_token }} + sonar-organization: ${{ inputs.sonar-organization }} + sonar-host-url: ${{ inputs.sonar-host-url }} + sonar-project-name: ${{ inputs.sonar-project-name }} + sonar-project-key: ${{ inputs.sonar-project-key }} + sonar-token: ${{ secrets.sonar-token }} - name: License Compliance with FOSSA if: ${{ inputs.fossa-enabled }} uses: fossas/fossa-action@v1 with: - api-key: "${{ inputs.fossa-api-key }}" + api-key: "${{ secrets.fossa-api-key }}" run-tests: false - name: Generate SBOM with Syft uses: anchore/sbom-action@v0 @@ -144,11 +141,6 @@ jobs: ./test/*/TestResults/*/coverage.cobertura.xml ./**/SonarQube.xml ./**/Summary.txt - -# GITHUB_TOKEN: secrets.GITHUB_TOKEN -# secrets.FOSSA_API_KEY -# Application__IsHttpsRedirectionEnabled: "false" -# sonar_organization: vars.SONAR_ORG -# sonar_project_name: Todo Blazor -# sonar_project_key: vars.SONAR_PROJECT_KEY -# sonar_token: secrets.SONAR_TOKEN + env: + # https://docs.github.com/en/actions/reference/workflows-and-actions/contexts + GITHUB_TOKEN: ${{ github.token }} diff --git a/actions/dotnet/build-test-sonar/action.yml b/actions/dotnet/build-test-sonar/action.yml index 71fbd02..89f873e 100644 --- a/actions/dotnet/build-test-sonar/action.yml +++ b/actions/dotnet/build-test-sonar/action.yml @@ -1,35 +1,35 @@ -name: Build, lint and test .NET -description: Builds, checks and runs tests on a .NET codebase +name: Build, Test & Analyze +description: Builds, runs tests on a .NET codebase and run analysis with Sonar inputs: - dotnet_version: - description: .NET SDK version to be used + java-version: + description: Java version that will be installed (for Sonar CLI) required: false - default: "10.0" - sonar_organization: - description: Sonar organization + default: "21" + report-folder: + description: Folder where report files will be generated required: false - default: "" - sonar_host_url: + default: report + sonar-host-url: description: Sonar host URL required: false default: "" - sonar_project_name: - description: Sonar project name + sonar-organization: + description: Sonar organization required: false default: "" - sonar_project_key: + sonar-project-key: description: Sonar project key required: false default: "" - sonar_token: - description: Sonar token for login + sonar-project-name: + description: Sonar project name required: false default: "" - report_folder: - description: Folder where report files will be generated + sonar-token: + description: Sonar token for login required: false - default: report + default: "" runs: using: "composite" @@ -37,7 +37,7 @@ runs: - name: Set up JDK for Sonar uses: actions/setup-java@v4 with: - java-version: 21 + java-version: ${{ inputs.java-version }} distribution: "zulu" - name: Cache Sonar packages uses: actions/cache@v4 @@ -60,10 +60,10 @@ runs: shell: bash - name: Start code analysis run: | - ./.sonar/scanner/dotnet-sonarscanner begin /k:"${{ inputs.sonar_project_key }}" /o:"${{ inputs.sonar_organization }}" \ - /n:"${{ inputs.sonar_project_name }}" /d:sonar.token="${{ inputs.sonar_token}}" /d:sonar.host.url="${{inputs.sonar_host_url}}" \ - /d:sonar.cpd.exclusions="**/*Generated*.cs,${{ inputs.report_folder }}/**" /d:sonar.exclusions="${{ inputs.report_folder }}/**/*" \ - /d:sonar.coverageReportPaths="${{ inputs.report_folder }}/SonarQube.xml" + ./.sonar/scanner/dotnet-sonarscanner begin /k:"${{ inputs.sonar-project-key }}" /o:"${{ inputs.sonar-organization }}" \ + /n:"${{ inputs.sonar-project-name }}" /d:sonar.token="${{ inputs.sonar-token}}" /d:sonar.host.url="${{ inputs.sonar-host-url }}" \ + /d:sonar.cpd.exclusions="**/*Generated*.cs,${{ inputs.report-folder }}/**" /d:sonar.exclusions="${{ inputs.report-folder }}/**/*" \ + /d:sonar.coverageReportPaths="${{ inputs.report-folder }}/SonarQube.xml" shell: bash - name: Build .NET solution run: dotnet build --no-restore @@ -79,9 +79,9 @@ runs: - name: Generate test report run: | reportgenerator "-reports:./test/*/TestResults/*/coverage.cobertura.xml" \ - "-targetdir:${{inputs.report_folder}}" \ + "-targetdir:${{ inputs.report-folder }}" \ "-reporttypes:Cobertura;Html;TextSummary;SonarQube" shell: bash - name: Complete code analysis - run: ./.sonar/scanner/dotnet-sonarscanner end /d:sonar.token="${{inputs.sonar_token}}" + run: ./.sonar/scanner/dotnet-sonarscanner end /d:sonar.token="${{ inputs.sonar-token }}" shell: bash diff --git a/actions/dotnet/build-test/action.yml b/actions/dotnet/build-test/action.yml index 1778c24..c1afcdc 100644 --- a/actions/dotnet/build-test/action.yml +++ b/actions/dotnet/build-test/action.yml @@ -2,11 +2,7 @@ name: Build & Test description: Builds and runs tests on a .NET codebase inputs: - dotnet_version: - description: .NET SDK version to be used - required: false - default: "10.0" - report_folder: + report-folder: description: Folder where report files will be generated required: false default: report @@ -28,6 +24,6 @@ runs: - name: Generate test report run: | reportgenerator "-reports:./test/*/TestResults/*/coverage.cobertura.xml" \ - "-targetdir:${{inputs.report_folder}}" \ + "-targetdir:${{ inputs.report-folder }}" \ "-reporttypes:Cobertura;Html;TextSummary" shell: bash From ae3aab10bbfab4dd51cec2ed9f3bdb7248364872 Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Wed, 4 Feb 2026 20:58:49 +0100 Subject: [PATCH 04/14] Changed extension --- ...usable-content-validate.yaml => reusable-content-validate.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{reusable-content-validate.yaml => reusable-content-validate.yml} (100%) diff --git a/.github/workflows/reusable-content-validate.yaml b/.github/workflows/reusable-content-validate.yml similarity index 100% rename from .github/workflows/reusable-content-validate.yaml rename to .github/workflows/reusable-content-validate.yml From bb76195591d51538a8ad6e42161e814a4090c408 Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Wed, 4 Feb 2026 21:30:48 +0100 Subject: [PATCH 05/14] Fix missing folder --- .github/workflows/reusable-dotnet-validate.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/reusable-dotnet-validate.yml b/.github/workflows/reusable-dotnet-validate.yml index 35d701c..d8becb3 100644 --- a/.github/workflows/reusable-dotnet-validate.yml +++ b/.github/workflows/reusable-dotnet-validate.yml @@ -101,18 +101,18 @@ jobs: ref: ${{ inputs.workflow-parts-version }} path: workflow-parts - name: Install & lint .NET - uses: ./workflow-parts/dotnet/install-lint-restore + uses: ./workflow-parts/actions/dotnet/install-lint-restore with: dotnet-version: ${{ inputs.dotnet-version }} - name: Start MongoDB if: ${{ inputs.mongodb-enabled }} - uses: ./workflow-parts/mongodb/start + uses: ./workflow-parts/actions/mongodb/start - name: Build & test .NET if: ${{ ! inputs.sonar-enabled }} - uses: ./workflow-parts/dotnet/build-test + uses: ./workflow-parts/actions/dotnet/build-test - name: Build, lint & test if: ${{ inputs.sonar-enabled }} - uses: ./workflow-parts/dotnet/build-test-sonar + uses: ./workflow-parts/actions/dotnet/build-test-sonar with: sonar-organization: ${{ inputs.sonar-organization }} sonar-host-url: ${{ inputs.sonar-host-url }} From 3abe5ffe9a533dc6a25dd3eb05e0ea3322023d9b Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Wed, 4 Feb 2026 22:45:56 +0100 Subject: [PATCH 06/14] Add reusable-container-scan.yml --- .github/workflows/reusable-container-scan.yml | 92 +++++++++++++++++++ ...lidate.yml => reusable-dotnet-quality.yml} | 14 +-- ...-validate.yml => reusable-markup-lint.yml} | 6 +- .../workflows/reusable-terraform-apply.yml | 2 +- 4 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/reusable-container-scan.yml rename .github/workflows/{reusable-dotnet-validate.yml => reusable-dotnet-quality.yml} (95%) rename .github/workflows/{reusable-content-validate.yml => reusable-markup-lint.yml} (93%) diff --git a/.github/workflows/reusable-container-scan.yml b/.github/workflows/reusable-container-scan.yml new file mode 100644 index 0000000..df0e92e --- /dev/null +++ b/.github/workflows/reusable-container-scan.yml @@ -0,0 +1,92 @@ +name: Reusable - Container scan + +on: + workflow_call: + inputs: + image-definition: + description: Path to the container definition file (Dockerfile, Containerfile) + type: string + required: true + image-name: + description: Image name + type: string + required: true + image-path: + description: Image path + type: string + required: true + image-tag: + description: Image tag + type: string + required: true + job-name: + description: Job name + type: string + required: false + default: Scan + max-high-cves: + description: Maximum number of high CVEs authorized + type: number + required: false + default: 0 + max-medium-cves: + description: Maximum number of medium CVEs authorized + type: number + required: false + default: 0 + neuvector-enabled: + description: "Use NeuVector to scan the image?" + type: string + required: false + default: false + operating-system: + description: Operating system executing the runner + type: string + required: false + default: ubuntu-latest + trivy-enabled: + description: "Use Trivy to scan the image?" + type: boolean + required: false + default: true + working-directory: + description: Working directory + type: string + required: false + default: "." + secrets: + +jobs: + container-scan: + name: ${{ inputs.job-name }} + runs-on: ${{ inputs.operating-system }} + defaults: + run: + working-directory: ${{ inputs.working-directory }} + steps: + - name: Clone repository + uses: actions/checkout@v6 + - name: Build container image + run: docker build . --file ${{ inputs.image-definition }} --tag ${{ env.IMAGE_REF }} + shell: bash + - name: Scan container image with NeuVector + if: ${{ inputs.neuvector-enabled }} + uses: neuvector/scan-action@main + with: + image-repository: ${{ inputs.image-path }}/${{ inputs.image-name }} + image-tag: ${{ inputs.image-tag }} + min-high-cves-to-fail: '${{ inputs.max-high-cves }}' + min-medium-cves-to-fail: '${{ inputs.max-medium-cves }}' + - name: Scan container image with Trivy + if: ${{ inputs.trivy-enabled }} + uses: aquasecurity/trivy-action@master + with: + image-ref: ${{ env.IMAGE_REF }} + format: 'table' + exit-code: '1' + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' + env: + IMAGE_REF: ${{ inputs.image-path }}/${{ inputs.image-name }}:${{ inputs.image-tag }} + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/reusable-dotnet-validate.yml b/.github/workflows/reusable-dotnet-quality.yml similarity index 95% rename from .github/workflows/reusable-dotnet-validate.yml rename to .github/workflows/reusable-dotnet-quality.yml index d8becb3..ce6a604 100644 --- a/.github/workflows/reusable-dotnet-validate.yml +++ b/.github/workflows/reusable-dotnet-quality.yml @@ -1,4 +1,4 @@ -name: Reusable - .NET validate +name: Reusable - .NET quality on: workflow_call: @@ -21,7 +21,7 @@ on: description: Job name type: string required: false - default: Validate + default: Quality mongodb-enabled: description: "Start MongoDB for integration tests?" type: boolean @@ -76,7 +76,7 @@ on: required: false jobs: - dotnet-validate: + dotnet-quality: name: ${{ inputs.job-name }} runs-on: ${{ inputs.operating-system }} defaults: @@ -100,17 +100,17 @@ jobs: repository: devpro/github-workflow-parts ref: ${{ inputs.workflow-parts-version }} path: workflow-parts - - name: Install & lint .NET + - name: Install .NET & lint uses: ./workflow-parts/actions/dotnet/install-lint-restore with: dotnet-version: ${{ inputs.dotnet-version }} - name: Start MongoDB if: ${{ inputs.mongodb-enabled }} uses: ./workflow-parts/actions/mongodb/start - - name: Build & test .NET + - name: Build & test if: ${{ ! inputs.sonar-enabled }} uses: ./workflow-parts/actions/dotnet/build-test - - name: Build, lint & test + - name: Build, test & analyze if: ${{ inputs.sonar-enabled }} uses: ./workflow-parts/actions/dotnet/build-test-sonar with: @@ -119,7 +119,7 @@ jobs: sonar-project-name: ${{ inputs.sonar-project-name }} sonar-project-key: ${{ inputs.sonar-project-key }} sonar-token: ${{ secrets.sonar-token }} - - name: License Compliance with FOSSA + - name: Check license compliance with FOSSA if: ${{ inputs.fossa-enabled }} uses: fossas/fossa-action@v1 with: diff --git a/.github/workflows/reusable-content-validate.yml b/.github/workflows/reusable-markup-lint.yml similarity index 93% rename from .github/workflows/reusable-content-validate.yml rename to .github/workflows/reusable-markup-lint.yml index b1b15d0..8d131ff 100644 --- a/.github/workflows/reusable-content-validate.yml +++ b/.github/workflows/reusable-markup-lint.yml @@ -1,4 +1,4 @@ -name: Reusable - Content validate +name: Reusable - Markup Lint on: workflow_call: @@ -7,7 +7,7 @@ on: description: "Job name" type: string required: false - default: "Validate" + default: "Lint" working-directory: description: "Working directory" type: string @@ -25,7 +25,7 @@ on: default: "3.14" jobs: - content-validate: + markup-lint: name: ${{ inputs.job-name }} runs-on: ${{ inputs.operating-system }} steps: diff --git a/.github/workflows/reusable-terraform-apply.yml b/.github/workflows/reusable-terraform-apply.yml index 44e1b12..7b6fe40 100644 --- a/.github/workflows/reusable-terraform-apply.yml +++ b/.github/workflows/reusable-terraform-apply.yml @@ -71,7 +71,7 @@ on: required: false jobs: - deploy: + terraform-apply: name: ${{ inputs.job-name }} runs-on: ${{ inputs.operating-system }} environment: ${{ inputs.environment }} From 92a8fd2bff68370484d94ac0105fb5865b989818 Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Wed, 4 Feb 2026 22:47:05 +0100 Subject: [PATCH 07/14] Delete empty field --- .github/workflows/reusable-container-scan.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/reusable-container-scan.yml b/.github/workflows/reusable-container-scan.yml index df0e92e..541de61 100644 --- a/.github/workflows/reusable-container-scan.yml +++ b/.github/workflows/reusable-container-scan.yml @@ -54,7 +54,6 @@ on: type: string required: false default: "." - secrets: jobs: container-scan: From 54660d8bb4e4c87fa640584fa5edd15afc94bd17 Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Wed, 4 Feb 2026 22:48:25 +0100 Subject: [PATCH 08/14] Fix ci --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82f10d3..2a36b0e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,6 @@ on: workflow_dispatch: {} jobs: - content-validate: - name: Content - uses: ./.github/workflows/reusable-content-validate.yaml + markup-lint: + name: Markup + uses: ./.github/workflows/reusable-markup-lint.yml From 9efb68fe0e2af09ccaad444d9a79087cd50a65a1 Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Wed, 4 Feb 2026 23:20:56 +0100 Subject: [PATCH 09/14] Add Cosign --- .../reusable-container-publication.yml | 123 ++++++++++++++++++ actions/cosign/sign/action.yml | 39 ++++++ 2 files changed, 162 insertions(+) create mode 100644 .github/workflows/reusable-container-publication.yml create mode 100644 actions/cosign/sign/action.yml diff --git a/.github/workflows/reusable-container-publication.yml b/.github/workflows/reusable-container-publication.yml new file mode 100644 index 0000000..073069f --- /dev/null +++ b/.github/workflows/reusable-container-publication.yml @@ -0,0 +1,123 @@ +name: Reusable - Container publication +# description: | +# Builds a new container image with Docker and pushes it to a registry +# Make sure to add (needed by cosign): +# ``` +# permissions: +# id-token: write +# contents: read +# ``` + +on: + workflow_call: + inputs: + container-registry: + description: Container registry + type: string + required: false + default: "docker.io" + create-latest: + description: "Create latest tag?" + type: boolean + required: false + default: false + extra-build-arguments: + description: Container build additional arguments + type: string + required: false + default: "" + image-definition: + description: Path to the container definition file (Dockerfile, Containerfile) + type: string + required: true + image-name: + description: Image name + type: string + required: true + image-path: + description: Image path + type: string + required: true + image-tag: + description: Image tag + type: string + required: true + job-name: + description: Job name + type: string + required: false + default: Publication + operating-system: + description: Operating system executing the runner + type: string + required: false + default: ubuntu-latest + workflow-parts-version: + description: GitHub workflow parts version (branch/tag/SHA) + type: string + required: false + default: main + working-directory: + description: Working directory + type: string + required: false + default: "." + secrets: + container-registry-username: + description: Container registry username + required: true + container-registry-password: + description: Container registry password + required: true + +jobs: + container-publication: + name: ${{ inputs.job-name }} + runs-on: ${{ inputs.operating-system }} + defaults: + run: + working-directory: ${{ inputs.working-directory }} + steps: + - name: Clone repository + uses: actions/checkout@v6 + - name: Checkout workflow parts + uses: actions/checkout@v6 + with: + repository: devpro/github-workflow-parts + ref: ${{ inputs.workflow-parts-version }} + path: workflow-parts + - name: Login to container registry + uses: docker/login-action@v3 + with: + registry: ${{ inputs.container-registry }} + username: ${{ inputs.container-registry-username }} + password: ${{ inputs.container-registry-password }} + - name: Build container image + run: docker build . --file ${{ inputs.image-definition }} --tag ${{ env.IMAGE_REF }} ${{ inputs.extra-build-arguments }} + shell: bash + - name: Generate SBOM with Syft + uses: anchore/sbom-action@v0 + continue-on-error: true + with: + image: ${{ env.IMAGE_REF }} + # format: spdx-json # Or cyclonedx-json + # output-file: sbom.json + # upload-artifact: true # Auto-upload to workflow artifacts + - name: Push image to container registry + run: docker push ${{ env.IMAGE_REF }} + shell: bash + - name: Push latest tag to container registry + if: ${{ inputs.create_latest }} + run: | + docker tag ${{ env.IMAGE_REF }} ${{ env.IMAGE_REF_LATEST }} + docker push ${{ env.IMAGE_REF_LATEST }} + shell: bash + - name: Sign container image with Cosign + uses: ./workflow-parts/actions/cosign/sign + with: + image-name: ${{ inputs.image-name }} + image-path: ${{ inputs.image-path }} + image-tag: ${{ inputs.image-tag }} + env: + IMAGE_REF: ${{ inputs.image-path }}/${{ inputs.image-name }}:${{ inputs.image-tag }} + IMAGE_REF_LATEST: ${{ inputs.image-path }}/${{ inputs.image-name }}:latest diff --git a/actions/cosign/sign/action.yml b/actions/cosign/sign/action.yml new file mode 100644 index 0000000..85611c7 --- /dev/null +++ b/actions/cosign/sign/action.yml @@ -0,0 +1,39 @@ +name: Sign a container image +description: | + Make sure to add (needed by cosign): + ``` + permissions: + id-token: write + contents: read + ``` + +inputs: + image-name: + description: Image name + required: true + image-path: + description: Image path + required: true + image-tag: + description: Image tag + required: true + +runs: + using: "composite" + steps: + - name: Install Cosign + uses: sigstore/cosign-installer@v4.0.0 + with: + cosign-release: 'v3.0.3' + - name: Get image digest + id: digest + run: | + DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' ${{ inputs.image-path }}/${{ inputs.image-name }}:${{ inputs.image-tag }} | cut -d'@' -f2) + echo "DIGEST=$DIGEST" >> $GITHUB_OUTPUT + shell: bash + - name: Sign image with Cosign + env: + COSIGN_EXPERIMENTAL: 1 + run: | + cosign sign --yes ${{ inputs.image-path }}/${{ inputs.image-name }}@${{ steps.digest.outputs.DIGEST }} + shell: bash From dcfc2c2b3159fc859898c10e13c9590a9aafec9c Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Wed, 4 Feb 2026 23:24:46 +0100 Subject: [PATCH 10/14] Move to secrets --- .github/workflows/reusable-container-publication.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/reusable-container-publication.yml b/.github/workflows/reusable-container-publication.yml index 073069f..fff8f79 100644 --- a/.github/workflows/reusable-container-publication.yml +++ b/.github/workflows/reusable-container-publication.yml @@ -21,11 +21,6 @@ on: type: boolean required: false default: false - extra-build-arguments: - description: Container build additional arguments - type: string - required: false - default: "" image-definition: description: Path to the container definition file (Dockerfile, Containerfile) type: string @@ -69,6 +64,9 @@ on: container-registry-password: description: Container registry password required: true + extra-build-arguments: + description: Container build additional arguments + required: false jobs: container-publication: @@ -93,7 +91,7 @@ jobs: username: ${{ inputs.container-registry-username }} password: ${{ inputs.container-registry-password }} - name: Build container image - run: docker build . --file ${{ inputs.image-definition }} --tag ${{ env.IMAGE_REF }} ${{ inputs.extra-build-arguments }} + run: docker build . --file ${{ inputs.image-definition }} --tag ${{ env.IMAGE_REF }} ${{ secrets.extra-build-arguments }} shell: bash - name: Generate SBOM with Syft uses: anchore/sbom-action@v0 From cbf23a991e2e17aaad78a4d21975058fd946fdec Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Thu, 5 Feb 2026 12:44:13 +0100 Subject: [PATCH 11/14] Fix secret for docker build --- .../reusable-container-publication.yml | 21 +++++++++++++++++-- ....yml => reusable-terraform-deployment.yml} | 0 ...ate.yml => reusable-terraform-quality.yml} | 0 3 files changed, 19 insertions(+), 2 deletions(-) rename .github/workflows/{reusable-terraform-apply.yml => reusable-terraform-deployment.yml} (100%) rename .github/workflows/{reusable-terraform-validate.yml => reusable-terraform-quality.yml} (100%) diff --git a/.github/workflows/reusable-container-publication.yml b/.github/workflows/reusable-container-publication.yml index fff8f79..ddae896 100644 --- a/.github/workflows/reusable-container-publication.yml +++ b/.github/workflows/reusable-container-publication.yml @@ -21,6 +21,11 @@ on: type: boolean required: false default: false + extra-build-arguments: + description: Container build additional arguments + type: string + required: false + default: "" image-definition: description: Path to the container definition file (Dockerfile, Containerfile) type: string @@ -64,8 +69,8 @@ on: container-registry-password: description: Container registry password required: true - extra-build-arguments: - description: Container build additional arguments + extra-vars: + description: "Additional environment variables" required: false jobs: @@ -76,6 +81,18 @@ jobs: run: working-directory: ${{ inputs.working-directory }} steps: + - name: Set additional variables + run: | + if [[ -z "${{ secrets.extra-vars }}" ]]; then + echo "No additional-vars bundle provided - skipping." + else + echo "${{ secrets.extra-vars }}" | while IFS='=' read -r key val; do + if [[ -n "$val" ]]; then + echo "::add-mask::$val" + fi + done + echo "${{ secrets.extra-vars }}" >> "$GITHUB_ENV" + fi - name: Clone repository uses: actions/checkout@v6 - name: Checkout workflow parts diff --git a/.github/workflows/reusable-terraform-apply.yml b/.github/workflows/reusable-terraform-deployment.yml similarity index 100% rename from .github/workflows/reusable-terraform-apply.yml rename to .github/workflows/reusable-terraform-deployment.yml diff --git a/.github/workflows/reusable-terraform-validate.yml b/.github/workflows/reusable-terraform-quality.yml similarity index 100% rename from .github/workflows/reusable-terraform-validate.yml rename to .github/workflows/reusable-terraform-quality.yml From 2728478887cef5c78caa0583c06aa01181aa9dd1 Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Thu, 5 Feb 2026 12:52:41 +0100 Subject: [PATCH 12/14] Update --- .github/workflows/reusable-container-publication.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-container-publication.yml b/.github/workflows/reusable-container-publication.yml index ddae896..df268c8 100644 --- a/.github/workflows/reusable-container-publication.yml +++ b/.github/workflows/reusable-container-publication.yml @@ -84,7 +84,7 @@ jobs: - name: Set additional variables run: | if [[ -z "${{ secrets.extra-vars }}" ]]; then - echo "No additional-vars bundle provided - skipping." + echo "No extra-vars bundle provided - skipping." else echo "${{ secrets.extra-vars }}" | while IFS='=' read -r key val; do if [[ -n "$val" ]]; then From 784ac4797130feb47d0e568bc7c3600c11b7ed36 Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Thu, 5 Feb 2026 12:55:17 +0100 Subject: [PATCH 13/14] Fix invalid ref --- .github/workflows/reusable-container-publication.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-container-publication.yml b/.github/workflows/reusable-container-publication.yml index df268c8..e2160c6 100644 --- a/.github/workflows/reusable-container-publication.yml +++ b/.github/workflows/reusable-container-publication.yml @@ -105,8 +105,8 @@ jobs: uses: docker/login-action@v3 with: registry: ${{ inputs.container-registry }} - username: ${{ inputs.container-registry-username }} - password: ${{ inputs.container-registry-password }} + username: ${{ secrets.container-registry-username }} + password: ${{ secrets.container-registry-password }} - name: Build container image run: docker build . --file ${{ inputs.image-definition }} --tag ${{ env.IMAGE_REF }} ${{ secrets.extra-build-arguments }} shell: bash From b2fe1b08a39870371728d546f02847ba694bac57 Mon Sep 17 00:00:00 2001 From: Bertrand THOMAS Date: Thu, 5 Feb 2026 13:12:15 +0100 Subject: [PATCH 14/14] Update README --- README.md | 47 +++++++++++--- actions/docker/build-push/action.yml | 93 ---------------------------- actions/docker/build-scan/action.yml | 57 ----------------- 3 files changed, 37 insertions(+), 160 deletions(-) delete mode 100644 actions/docker/build-push/action.yml delete mode 100644 actions/docker/build-scan/action.yml diff --git a/README.md b/README.md index 32be3aa..d4efd66 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,46 @@ [![CI](https://github.com/devpro/github-workflow-parts/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/devpro/github-workflow-parts/actions/workflows/ci.yml) -Repository of workflow parts to be used in GitHub Actions. +GitHub workflow components you can trust for your repositories. +Keep your pipelines DRY! (Don't Repeat Yourself) + +## Reusable workflows + +> Rather than copying and pasting from one workflow to another, you can make workflows reusable ([Reusing workflow configurations](https://docs.github.com/en/actions/concepts/workflows-and-actions/reusing-workflow-configurations)) + +Containers: + +- [Publish your image](.github/workflows/reusable-container-publication.yml) +- [Scan your image](.github/workflows/reusable-container-scan.yml) + +.NET: + +- [Ensure the quality of your code](.github/workflows/reusable-dotnet-quality.yml) + +Markup (Markdown, YAML): + +- [Ensure the quality of your content](.github/workflows/reusable-markup-lint.yml) + +Terraform: + +- [Deploy your environment](.github/workflows/reusable-terraform-deployment.yml) +- [Ensure the quality of your infrastructure code](.github/workflows/reusable-terraform-quality.yml) ## Composite actions - +> Composite actions allow you to collect a series of workflow job steps into a single action which you can then run as a single job step in multiple workflows ([Creating a composite action](https://docs.github.com/en/actions/tutorials/create-actions/create-a-composite-action)) -Technology | Role | Action | Detail ------------|----------|---------------------------------------------------------|---------------------------------------------------------------------------- -Docker | CD | [Build & Push](docker/build-push/action.yml) | Build a new container image with Docker, and push it to a container registry -Docker | CI | [Build & Scan](docker/build-scan/action.yml) | Build a new container image with Docker, and scan it -.NET | CI | [Build, lint & test](dotnet/build-lint-test/action.yml) | Build .NET code, check the code with linter and Sonar, and run tests -MongoDB | Services | [Start](mongodb/start/action.yml) | Start a local MongoDB database +Containers: -## Reusable workflows +- [Sign your image with Cosign](actions/cosign/sign/action.yml) + +.NET: + +- [Build, test your code and analyze it with Sonar](actions/dotnet/build-test-sonar/action.yml) +- [Build and test your code](actions/dotnet/build-test/action.yml) +- [Install the SDK, lint the code and restore NuGet packages](actions/dotnet/install-lint-restore/) + +MongoDB: -TODO +- [Add your runner IP address to Atlas access list](actions/mongodb-atlas/add-runner-ip/action.yml) +- [Start a server in your pipeline](actions/mongodb/start/action.yml) diff --git a/actions/docker/build-push/action.yml b/actions/docker/build-push/action.yml deleted file mode 100644 index 48a5005..0000000 --- a/actions/docker/build-push/action.yml +++ /dev/null @@ -1,93 +0,0 @@ -name: Build and push a container image -description: | - Builds a new container image with Docker and pushes it to a registry - Make sure to add (needed by cosign): - ``` - permissions: - id-token: write - contents: read - ``` - -inputs: - container_registry: - description: Container registry - required: true - container_registry_username: - description: Container registry username - required: true - container_registry_password: - description: Container registry password - required: true - docker_file: - description: Path to the Dockerfile - required: true - image_path: - description: Image tag - required: true - image_name: - description: Image name - required: true - image_tag: - description: Image tag - required: true - create_latest: - description: Create latest tag? - required: false - default: 'false' - build_arguments: - description: Container build arguments - required: false - default: '' - -runs: - using: "composite" - steps: - - name: Login to container registry - uses: docker/login-action@v3 - with: - registry: ${{ inputs.container_registry }} - username: ${{ inputs.container_registry_username }} - password: ${{ inputs.container_registry_password }} - - - name: Build container image - run: docker build . --file ${{ inputs.docker_file }} --tag ${{ inputs.image_path }}/${{ inputs.image_name }}:${{ inputs.image_tag }}${{ inputs.build_arguments }} - shell: bash - - - name: Generate SBOM with Syft - uses: anchore/sbom-action@v0 - continue-on-error: true - with: - image: ${{ inputs.image_path }}/${{ inputs.image_name }}:${{ inputs.image_tag }} - # format: spdx-json # Or cyclonedx-json - # output-file: sbom.json - # upload-artifact: true # Auto-upload to workflow artifacts - - - name: Push image to container registry - run: docker push ${{ inputs.image_path }}/${{ inputs.image_name }}:${{ inputs.image_tag }} - shell: bash - - - name: Push latest tag to container registry - if: ${{ inputs.create_latest == 'true' }} - run: | - docker tag ${{ inputs.image_path }}/${{ inputs.image_name }}:${{ inputs.image_tag }} ${{ inputs.image_path }}/${{ inputs.image_name }}:latest - docker push ${{ inputs.image_path }}/${{ inputs.image_name }}:latest - shell: bash - - - name: Install Cosign - uses: sigstore/cosign-installer@v4.0.0 - with: - cosign-release: 'v3.0.3' - - - name: Get image digest - id: digest - run: | - DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' ${{ inputs.image_path }}/${{ inputs.image_name }}:${{ inputs.image_tag }} | cut -d'@' -f2) - echo "DIGEST=$DIGEST" >> $GITHUB_OUTPUT - shell: bash - - - name: Sign image with Cosign - env: - COSIGN_EXPERIMENTAL: 1 - run: | - cosign sign --yes ${{ inputs.image_path }}/${{ inputs.image_name }}@${{ steps.digest.outputs.DIGEST }} - shell: bash diff --git a/actions/docker/build-scan/action.yml b/actions/docker/build-scan/action.yml deleted file mode 100644 index fbc1a5d..0000000 --- a/actions/docker/build-scan/action.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Scan container image -description: Builds a new container image with Docker and scans it - -inputs: - docker_file: - description: Path to the Dockerfile - required: true - image_tag: - description: Image tag - required: true - image_path: - description: Image tag - required: true - image_name: - description: Image name - required: true - neuvector_enabled: - description: Use NeuVector to scan the image? - required: false - default: 'true' - trivy_enabled: - description: Use Trivy to scan the image? - required: false - default: 'true' - max_high_cves: - description: Maximum number of high CVE authorized - required: false - default: '1' - max_medium_cves: - description: Maximum number of medium CVE authorized - required: false - default: '1' - -runs: - using: "composite" - steps: - - name: Build container image - run: docker build . --file ${{inputs.docker_file}} --tag ${{inputs.image_path}}/${{inputs.image_name}}:${{inputs.image_tag}} - shell: bash - - name: Scan container image with NeuVector - if: ${{ inputs.neuvector_enabled == 'true' }} - uses: neuvector/scan-action@main - with: - image-repository: ${{inputs.image_path}}/${{inputs.image_name}} - image-tag: ${{inputs.image_tag}} - min-high-cves-to-fail: '${{inputs.max_high_cves}}' - min-medium-cves-to-fail: '${{inputs.max_medium_cves}}' - - name: Scan container image with Trivy - if: ${{ inputs.trivy_enabled == 'true' }} - uses: aquasecurity/trivy-action@master - with: - image-ref: '${{inputs.image_path}}/${{inputs.image_name}}:${{inputs.image_tag}}' - format: 'table' - exit-code: '1' - ignore-unfixed: true - vuln-type: 'os,library' - severity: 'CRITICAL,HIGH'