11# This workflow will build, test, sign and pack the release branches for EPPlus.
2- # It will also generate and publish an SBOM
2+ # It will also generate and publish an SBOM per target framework.
33# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
44
55name : Build Release Branches
2020 uses : actions/setup-dotnet@v4
2121 with :
2222 dotnet-version : ' 9.0.x'
23+
24+ # --- Read version and TFMs from csproj ---
25+ - name : Read version and target frameworks from csproj
26+ id : read_csproj
27+ run : |
28+ $xml = [xml](Get-Content ./src/EPPlus/EPPlus.csproj)
29+ $version = $xml.Project.PropertyGroup.Version | Where-Object { $_ } | Select-Object -First 1
30+ $tfms = $xml.Project.PropertyGroup.TargetFrameworks | Where-Object { $_ } | Select-Object -First 1
31+ echo "VERSION=$version" >> $env:GITHUB_ENV
32+ echo "TFMS=$tfms" >> $env:GITHUB_ENV
33+ shell : pwsh
34+
2335 - name : Restore dependencies
2436 run : dotnet restore ./src/EPPlus.sln
2537
4759 - name : Test
4860 run : dotnet test ./src/EPPlus.sln --no-build --verbosity normal --configuration Release
4961 - name : Install AzureSignTool
50- run : dotnet tool install --global AzureSignTool --version 6.0.0
62+ run : dotnet tool install --global AzureSignTool --version 6.0.0
5163 - name : Install NuGetKeyVaultSignTool
5264 run : dotnet tool install --global NuGetKeyVaultSignTool
5365
@@ -57,66 +69,93 @@ jobs:
5769 uses : Azure/login@v2
5870 with :
5971 creds : ' {"clientId":"${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }}","clientSecret":"${{ secrets.EPPLUS_CODE_SIGNING_SECRET }}","subscriptionId":"${{ secrets.EPPLUS_CODE_SIGNING_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }}"}'
72+
73+ # --- Sign DLLs ---
6074 - name : Sign EPPlus.dll with AzureSignTool
6175 run : |
62- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus\bin\Release\net9.0\EPPlus.dll"
63- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus\bin\Release\net8.0\EPPlus.dll"
64- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus\bin\Release\netstandard2.1\EPPlus.dll"
65- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus\bin\Release\netstandard2.0\EPPlus.dll"
66- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus\bin\Release\net462\EPPlus.dll"
67- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus\bin\Release\net35\EPPlus.dll"
68- - name : Sign EPPlus.Interface.dll with AzureSignTool
76+ $tfms = "${{ env.TFMS }}" -split ";"
77+ foreach ($tfm in $tfms) {
78+ $tfm = $tfm.Trim()
79+ if ([string]::IsNullOrEmpty($tfm)) { continue }
80+ $dll = ".\src\EPPlus\bin\Release\$tfm\EPPlus.dll"
81+ Write-Host "Signing $dll"
82+ azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL }} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 "$dll"
83+ }
84+ shell : pwsh
85+ - name : Sign EPPlus.Interfaces.dll with AzureSignTool
6986 run : |
70- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus.Interfaces\bin\Release\net9.0\EPPlus.Interfaces.dll"
71- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus.Interfaces\bin\Release\net8.0\EPPlus.Interfaces.dll"
72- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus.Interfaces\bin\Release\netstandard2.1\EPPlus.Interfaces.dll"
73- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus.Interfaces\bin\Release\netstandard2.0\EPPlus.Interfaces.dll"
74- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus.Interfaces\bin\Release\net462\EPPlus.Interfaces.dll"
75- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus.Interfaces\bin\Release\net35\EPPlus.Interfaces.dll"
87+ $tfms = "${{ env.TFMS }}" -split ";"
88+ foreach ($tfm in $tfms) {
89+ $tfm = $tfm.Trim()
90+ if ([string]::IsNullOrEmpty($tfm)) { continue }
91+ $dll = ".\src\EPPlus.Interfaces\bin\Release\$tfm\EPPlus.Interfaces.dll"
92+ Write-Host "Signing $dll"
93+ azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL }} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 "$dll"
94+ }
95+ shell : pwsh
7696 - name : Sign EPPlus.System.Drawing.dll with AzureSignTool
7797 run : |
78- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus.System.Drawing\bin\Release\net9.0\EPPlus.System.Drawing.dll"
79- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus.System.Drawing\bin\Release\net8.0\EPPlus.System.Drawing.dll"
80- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus.System.Drawing\bin\Release\netstandard2.1\EPPlus.System.Drawing.dll"
81- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus.System.Drawing\bin\Release\netstandard2.0\EPPlus.System.Drawing.dll"
82- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus.System.Drawing\bin\Release\net462\EPPlus.System.Drawing.dll"
83- azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 ".\src\EPPlus.System.Drawing\bin\Release\net35\EPPlus.System.Drawing.dll"
98+ $tfms = "${{ env.TFMS }}" -split ";"
99+ foreach ($tfm in $tfms) {
100+ $tfm = $tfm.Trim()
101+ if ([string]::IsNullOrEmpty($tfm)) { continue }
102+ $dll = ".\src\EPPlus.System.Drawing\bin\Release\$tfm\EPPlus.System.Drawing.dll"
103+ Write-Host "Signing $dll"
104+ azuresigntool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL }} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -tr http://timestamp.globalsign.com/tsa/advanced -td sha256 "$dll"
105+ }
106+ shell : pwsh
107+ # --- Sign DLLs ---
108+
84109 - name : Pack NuGet package
85110 run : dotnet pack ./src/EPPlus.sln --configuration Release --output ./output
86111 - name : Sign NuGet package
87112 run : |
88- NuGetKeyVaultSignTool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL}} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -tr http://timestamp.globalsign.com/tsa/advanced -fd sha256 -td sha256 -own EPPlusSoftware ".\output\*.nupkg"
113+ NuGetKeyVaultSignTool.exe sign -kvu ${{ secrets.EPPLUS_CODE_SIGNING_KEY_VAULT_URL }} -kvc ${{ secrets.EPPLUS_CODE_SIGNING_CERTIFICATE_NAME }} -kvi ${{ secrets.EPPLUS_CODE_SIGNING_APPLICATION_ID }} -kvs ${{ secrets.EPPLUS_CODE_SIGNING_SECRET }} -kvt ${{ secrets.EPPLUS_CODE_SIGNING_TENENT_ID }} -tr http://timestamp.globalsign.com/tsa/advanced -fd sha256 -td sha256 -own EPPlusSoftware ".\output\*.nupkg"
89114 - name : Upload NuGet package as artifact
90115 uses : actions/upload-artifact@v4
91116 with :
92- name : signed-nuget-package
93- path : ./output/*.nupkg
94- # --- SBOM ---
95- - name : Upload SBOM to Azure Blob Storage
117+ name : signed-nuget-package
118+ path : ./output/*.nupkg
119+
120+ # --- SBOM (after build to avoid CycloneDX overwriting project.assets.json) ---
121+ - name : Install CycloneDX
122+ run : dotnet tool install --global CycloneDX
123+ - name : Generate combined SBOM
124+ run : dotnet CycloneDX ./src/EPPlus/EPPlus.csproj -o ./sbom -F Json -st Library -sv ${{ env.VERSION }} -fn epplus-${{ env.VERSION }}.sbom.json -imp ./src/EPPlus/sbom-metadata-template.xml --spec-version 1.6
125+ - name : Generate per-TFM SBOMs
126+ run : |
127+ $tfms = "${{ env.TFMS }}" -split ";"
128+ foreach ($tfm in $tfms) {
129+ $tfm = $tfm.Trim()
130+ if ([string]::IsNullOrEmpty($tfm)) { continue }
131+ Write-Host "Generating SBOM for $tfm"
132+ dotnet CycloneDX ./src/EPPlus/EPPlus.csproj -o ./sbom -F Json -st Library -sv ${{ env.VERSION }} -fn "epplus-${{ env.VERSION }}.$tfm.sbom.json" -imp ./src/EPPlus/sbom-metadata-template.xml --framework $tfm --spec-version 1.6
133+ }
134+ shell : pwsh
135+ - name : Generate SHA-256 checksums for all SBOMs
96136 run : |
97- az storage blob upload `
98- --account-name eppluswebprod `
99- --container-name sbom `
100- --name epplus-${{ env.VERSION }}.sbom.json `
101- --file ./sbom/epplus-${{ env.VERSION }}.sbom.json `
102- --auth-mode login `
103- --overwrite
137+ Get-ChildItem -Path "./sbom" -Filter "*.sbom.json" | ForEach-Object {
138+ $hash = (Get-FileHash -Path $_.FullName -Algorithm SHA256).Hash.ToLower()
139+ "$hash $($_.Name)" | Out-File -FilePath "$($_.FullName).sha256" -Encoding utf8NoBOM
140+ Write-Host "Checksum generated for $($_.Name): $hash"
141+ }
104142 shell : pwsh
105- - name : Upload SBOM checksum to Azure Blob Storage
143+ - name : Upload all SBOMs to Azure Blob Storage
106144 run : |
107- az storage blob upload `
108- --account-name eppluswebprod `
109- --container-name sbom `
110- --name epplus-${{ env.VERSION }}.sbom.json.sha256 `
111- --file ./sbom/epplus-${{ env.VERSION }}.sbom.json.sha256 `
112- --auth-mode login `
113- --overwrite
145+ Get-ChildItem -Path "./sbom" | ForEach-Object {
146+ Write-Host "Uploading $($_.Name)"
147+ az storage blob upload `
148+ --account-name eppluswebprod `
149+ --container-name sbom `
150+ --name $_.Name `
151+ --file $_.FullName `
152+ --auth-mode login `
153+ --overwrite
154+ }
114155 shell : pwsh
115- - name : Upload SBOM as artifact
156+ - name : Upload all SBOMs as artifact
116157 uses : actions/upload-artifact@v4
117158 with :
118- name : sbom
119- path : |
120- ./sbom/epplus-${{ env.VERSION }}.sbom.json
121- ./sbom/epplus-${{ env.VERSION }}.sbom.json.sha256
159+ name : sbom
160+ path : ./sbom/
122161 # --- SBOM ---
0 commit comments