From 2f631fd2c655c7c20320e433077297d7d6b66c1b Mon Sep 17 00:00:00 2001 From: Jamie Taylor <1607732+GaProgMan@users.noreply.github.com> Date: Mon, 23 Dec 2024 23:02:41 +0000 Subject: [PATCH] Add Attestations to build and release workflow (#148) * Attempt at creating a step to build attestations in Actions * [docs] Added Attestations page; altered numbering of root-level pages. * [pr build action] Added sha for attestations action * Added Attestation generation to Release build * Added mentions of Attestation generation to readmes * Added mention of the Attestation stuff to the changelog * Minor version bump --- .github/workflows/dotnet.yml | 7 ++ .github/workflows/release.yml | 7 ++ README-NuGet.md | 6 ++ README.md | 6 ++ changelog.md | 6 +- docs/Code-of-Conduct.md | 2 +- docs/Contributing.md | 2 +- docs/Minimal-Code-Sample.md | 2 +- docs/assets/images/attestations/artifacts.jpg | Bin 0 -> 14360 bytes docs/assets/images/attestations/created.jpg | Bin 0 -> 28670 bytes docs/attestations.md | 83 ++++++++++++++++++ docs/changelog.md | 6 +- docs/configuration/index.md | 2 +- src/OwaspHeaders.Core.csproj | 2 +- 14 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 docs/assets/images/attestations/artifacts.jpg create mode 100644 docs/assets/images/attestations/created.jpg create mode 100644 docs/attestations.md diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index ae6b29b..48dd0a6 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -12,6 +12,8 @@ on: permissions: contents: read + id-token: write + attestations: write jobs: @@ -149,6 +151,11 @@ jobs: - name: Build NuGet Package run: dotnet pack src/OwaspHeaders.Core.csproj --configuration Release + - name: Generate Attestations + uses: actions/attest-build-provenance@963f8a02f24ac90336362e63ca6730cf69ad102e # v2.1.0 + with: + subject-path: ${{ github.workspace }}/**/*.nupkg + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 if: ${{ success() }} with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bbb2d62..627cb26 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,6 +14,8 @@ on: permissions: contents: read + id-token: write + attestations: write jobs: @@ -98,6 +100,11 @@ jobs: - name: Build NuGet package run: dotnet pack src/OwaspHeaders.Core.csproj --configuration Release + - name: Generate Attestations + uses: actions/attest-build-provenance@963f8a02f24ac90336362e63ca6730cf69ad102e # v2.1.0 + with: + subject-path: ${{ github.workspace }}/**/*.nupkg + - name: Push NuGet package run: dotnet nuget push **\*.nupkg --source 'https://api.nuget.org/v3/index.json' --api-key ${{secrets.NUGET_API_KEY}} env: diff --git a/README-NuGet.md b/README-NuGet.md index 49e905b..fd01411 100644 --- a/README-NuGet.md +++ b/README-NuGet.md @@ -52,6 +52,12 @@ The source code for this NuGet package can be found at: [https://github.com/GaPr The documentation for this NuGet package can be found at: [https://gaprogman.github.io/OwaspHeaders.Core/](https://gaprogman.github.io/OwaspHeaders.Core/). +### Attestations + +As of [PR 148](https://github.com/GaProgMan/OwaspHeaders.Core/pull/148), OwaspHeaders.Core uses the GitHub provided process for creating attestations per build. This document talks through how to verify those attestations using the [gh CLI](https://cli.github.com/). + +See the [Attestations](https://gaprogman.github.io/OwaspHeaders.Core/attestations) page of the documentation to read about how you can verify the attestations for builds from 9.5.0 onward. + ## Issues and Bugs Please raise any issues and bugs at the above mentioned source code repo. diff --git a/README.md b/README.md index 4f2892d..b047fd1 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,12 @@ That's it. The latest documentation for OwaspHeaders.Core can be found at [https://gaprogman.github.io/OwaspHeaders.Core/](https://gaprogman.github.io/OwaspHeaders.Core/). +### Attestations + +As of [PR 148](https://github.com/GaProgMan/OwaspHeaders.Core/pull/148), OwaspHeaders.Core uses the GitHub provided process for creating attestations per build. This document talks through how to verify those attestations using the [gh CLI](https://cli.github.com/). + +See the [Attestations](https://gaprogman.github.io/OwaspHeaders.Core/attestations) page of the documentation to read about how you can verify the attestations for builds from 9.5.0 onward. + ## Pull Requests [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/GaProgMan/OwaspHeaders.Core/pulls) diff --git a/changelog.md b/changelog.md index c334c00..ca8bf1b 100644 --- a/changelog.md +++ b/changelog.md @@ -22,11 +22,15 @@ This version dropped support for .NET 6 and .NET 7, as they are no longer suppor All projects in the [GitHub repo](https://github.com/GaProgMan/OwaspHeaders.Core) now build and run with either .NET 8 or .NET 9, whichever is present (deferring to the highest version number if both are present). As of November 19th, 2024 there are no new features in Version 9, so if you still need to use the NuGet package with .NET 6 or 7 please use Version 8 of the package. +#### Version 9.5.x + +This version saw the addition of attestation generation on both a per PR-build and Release basis. See the [Attestations](https://gaprogman.github.io/OwaspHeaders.Core/attestations) page of the documentation to read about how you can verify the attestations per build or release. + #### Version 9.2.x A number of small optimisations for generating HTTP header values have been made. There are also new Guard clauses in place to protect from a number of null or null/whitespace issues. All using statements have been cleaned up, with a large number placed in relevant global usings files. -**BREAKING CHANGE**: Removal of the X-Powered-By header has been completely removed in this version. The reason for this is that the X-Powered-By header is included by the reverse proxy, which ASP .NET Core has no control over. See the section in the Readme labelled "Server Header: A Warning" for details on how to remove this header. +**BREAKING CHANGE**: Removal of the X-Powered-By header has been completely removed in this version. The reason for this is that the X-Powered-By header is included by the reverse proxy, which ASP .NET Core has no control over. See the section in the Readme labelled "Server Header: A Warning" for details on how to remove this header. #### Version 9.1.x diff --git a/docs/Code-of-Conduct.md b/docs/Code-of-Conduct.md index feeb994..482c9db 100644 --- a/docs/Code-of-Conduct.md +++ b/docs/Code-of-Conduct.md @@ -1,7 +1,7 @@ --- title: Code of Conduct layout: page -nav_order: 4 +nav_order: 5 --- # Contributor Covenant Code of Conduct diff --git a/docs/Contributing.md b/docs/Contributing.md index dcd4183..65b0bd2 100644 --- a/docs/Contributing.md +++ b/docs/Contributing.md @@ -1,7 +1,7 @@ --- title: Contributing layout: page -nav_order: 3 +nav_order: 4 --- # Contributing to OwaspHeaders.Core diff --git a/docs/Minimal-Code-Sample.md b/docs/Minimal-Code-Sample.md index 4d79225..2c1dbda 100644 --- a/docs/Minimal-Code-Sample.md +++ b/docs/Minimal-Code-Sample.md @@ -1,7 +1,7 @@ --- title: Minimal Code Sample layout: page -nav_order: 5 +nav_order: 10 --- # Tips For Creating A Minimal Code Sample diff --git a/docs/assets/images/attestations/artifacts.jpg b/docs/assets/images/attestations/artifacts.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c3dfc28c4eadfe7b64b9cce8732ae5248e67a394 GIT binary patch literal 14360 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 literal 0 HcmV?d00001 diff --git a/docs/assets/images/attestations/created.jpg b/docs/assets/images/attestations/created.jpg new file mode 100644 index 0000000000000000000000000000000000000000..459ca6658550f667096b742452c4ec515ebd94c7 GIT binary patch literal 28670 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 DjYiPC literal 0 HcmV?d00001 diff --git a/docs/attestations.md b/docs/attestations.md new file mode 100644 index 0000000..6e9ce6c --- /dev/null +++ b/docs/attestations.md @@ -0,0 +1,83 @@ +--- +title: Attestations +nav_order: 2 +layout: page +--- + +As of [PR 148](https://github.com/GaProgMan/OwaspHeaders.Core/pull/148), OwaspHeaders.Core uses the GitHub provided process for creating attestations per build. This document talks through how to verify those attestations using the [gh CLI](https://cli.github.com/). + +## PR Build + +All PRs are built using the [dotnet.yml](https://github.com/GaProgMan/OwaspHeaders.Core/blob/main/.github/workflows/dotnet.yml) file found in the .github/Workflows directory in the GitHub repo. Attestations for these builds are created in the step labelled "Generate Attestations": + +```yml +# The following yml is correct as of Dec 23rd, 2024 +# For the latest version, please see: +# https://github.com/GaProgMan/OwaspHeaders.Core/blob/main/.github/workflows/dotnet.yml +- name: Generate Attestations + uses: actions/attest-build-provenance@963f8a02f24ac90336362e63ca6730cf69ad102e # v2.1.0 + with: + subject-path: ${{ github.workspace }}/**/*.nupkg +``` + +This step will provide an attestation for the commit which caused the PR build to run. + +### Slightly Less Manual Verification + +When the build workflow completes, there will be a section in the job summary called "Create the NuGet package for PR-level user testing summary" (see: [this link](https://github.com/GaProgMan/OwaspHeaders.Core/actions/runs/12473647282#summary-34814538093) or the following screenshot for an example) + +![](./assets/images/attestations/created.jpg) + +Clicking the link under "Attestation created" will take you to the attestation for the particular build of OwaspHeaders.Core. + +In the above screenshot, the Attestation link is [https://github.com/GaProgMan/OwaspHeaders.Core/attestations/4097094](https://github.com/GaProgMan/OwaspHeaders.Core/attestations/4097094). + +### Manual Verification + +In order to manually verify the nupkg file, you will need to download the generated artifact for a given workflow run and follow the steps below. + +- Open a workflow run + - For example: https://github.com/GaProgMan/OwaspHeaders.Core/actions/runs/12473647282 +- Scroll to the bottom of the workflow run and download the generated artifact + - The file will be called "OwaspHeaders.Core" + - See the following screenshot: + +![](./assets/images/attestations/artifacts.jpg) + +- Extract the zip file + - You can using your favourite unarchiver + - Or you can open the zip file and drag the nupkg file out +- Open a terminal where you have extracted the nupkg file +- Run `gh attestation verify --owner GaProgMan OwaspHeaders.Core.x.y.z.nupkg` + - Replacing `x.y.z` with the version number of the nupkg file + +You should receive output which matches the following: + +```bash +Loaded digest sha256:5e657fed02f84c8072a33a8791e01d6bd45c67863f83ec8542154af08171ed04 for file://OwaspHeaders.Core.9.4.3.nupkg +Loaded 1 attestation from GitHub API + +The following policy criteria will be enforced: +- OIDC Issuer must match:................... https://token.actions.githubusercontent.com +- Source Repository Owner URI must match:... https://github.com/GaProgMan +- Predicate type must match:................ https://slsa.dev/provenance/v1 +- Subject Alternative Name must match regex: (?i)^https://github.com/GaProgMan/ + +✓ Verification succeeded! + +sha256:5e657fed02f84c8072a33a8791e01d6bd45c67863f83ec8542154af08171ed04 was attested by: +REPO PREDICATE_TYPE WORKFLOW +GaProgMan/OwaspHeaders.Core https://slsa.dev/provenance/v1 .github/workflows/dotnet.yml@refs/pull/148/merge +``` + +> [!NOTE] NOTE +> The above output is specific to the version of OwaspHeaders.Core built using the first workflow run for [PR 148](https://github.com/GaProgMan/OwaspHeaders.Core/pull/148). The output you receive will differ slightly. + +## Releases + +TBC + +## Resources + +- [Artifact Attestations is generally available](https://github.blog/changelog/2024-06-25-artifact-attestations-is-generally-available/) +- [gh CLI](https://cli.github.com/) \ No newline at end of file diff --git a/docs/changelog.md b/docs/changelog.md index 98673d7..1f40d29 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,7 +1,7 @@ --- title: Changelog layout: page -nav_order: 10 +nav_order: 7 --- # Changelog @@ -28,6 +28,10 @@ This version dropped support for .NET 6 and .NET 7, as they are no longer suppor All projects in the [GitHub repo](https://github.com/GaProgMan/OwaspHeaders.Core) now build and run with either .NET 8 or .NET 9, whichever is present (deferring to the highest version number if both are present). As of November 19th, 2024 there are no new features in Version 9, so if you still need to use the NuGet package with .NET 6 or 7 please use Version 8 of the package. +#### Version 9.5.x + +This version saw the addition of attestation generation on both a per PR-build and Release basis. See the [Attestations](https://gaprogman.github.io/OwaspHeaders.Core/attestations) page of the documentation to read about how you can verify the attestations per build or release. + #### Version 9.2.x A number of small optimisations for generating HTTP header values have been made. There are also new Guard clauses in place to protect from a number of null or null/whitespace issues. All using statements have been cleaned up, with a large number placed in relevant global usings files. diff --git a/docs/configuration/index.md b/docs/configuration/index.md index 760a6a7..db83ed1 100644 --- a/docs/configuration/index.md +++ b/docs/configuration/index.md @@ -1,6 +1,6 @@ --- title: Configuration -nav_order: 2 +nav_order: 3 layout: page --- diff --git a/src/OwaspHeaders.Core.csproj b/src/OwaspHeaders.Core.csproj index d6150bb..f91b1aa 100644 --- a/src/OwaspHeaders.Core.csproj +++ b/src/OwaspHeaders.Core.csproj @@ -8,7 +8,7 @@ OwaspHeaders.Core - 9.4.3 + 9.5.0 Jamie Taylor RJJ Software Ltd MIT