1+ # SPDX-License-Identifier: Apache-2.0
2+ # Licensed to the Ed-Fi Alliance under one or more agreements.
3+ # The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
4+ # See the LICENSE and NOTICES files in the project root for more information.
5+
6+ name : On Pre-Release
7+ on :
8+ release :
9+ types :
10+ - prereleased
11+ workflow_dispatch :
12+
13+ permissions : read-all
14+
15+ env :
16+ ARTIFACTS_API_KEY : ${{ secrets.AZURE_ARTIFACTS_PERSONAL_ACCESS_TOKEN }}
17+ ARTIFACTS_FEED_URL : " https://pkgs.dev.azure.com/ed-fi-alliance/Ed-Fi-Alliance-OSS/_packaging/EdFi/nuget/v3/index.json"
18+ VSS_NUGET_EXTERNAL_FEED_ENDPOINTS : ' {"endpointCredentials": [{"endpoint": "https://pkgs.dev.azure.com/ed-fi-alliance/Ed-Fi-Alliance-OSS/_packaging/EdFi/nuget/v3/index.json","password": "${{ secrets.AZURE_ARTIFACTS_PERSONAL_ACCESS_TOKEN }}"}]}'
19+ DOCKER_HUB_TOKEN : ${{ secrets.DOCKER_HUB_TOKEN }}
20+ DOCKER_USERNAME : ${{ vars.DOCKER_USERNAME }}
21+ MANIFEST_FILE : " _manifest/spdx_2.2/manifest.spdx.json"
22+ PACKAGE_NAME : " AdminConsole.InstanceManagementWorker"
23+ REF : ${{ github.ref_name }}
24+ IMAGE_NAME : ${{ vars.IMAGE_NAME }}
25+
26+ jobs :
27+ pack :
28+ name : Build and Pack
29+ runs-on : ubuntu-22.04
30+ defaults :
31+ run :
32+ shell : pwsh
33+ outputs :
34+ hash-code : ${{ steps.hash-code.outputs.hash-code }}
35+ instance-management-version : ${{ steps.versions.outputs.instance-management }}
36+
37+ steps :
38+ - uses : actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
39+ with :
40+ fetch-depth : 0
41+
42+ - name : Set Version Numbers
43+ id : versions
44+ run : |
45+ $prefix = "v"
46+ # Install the MinVer CLI tool
47+ &dotnet tool install --global minver-cli
48+ $appVersion = $(minver -t $prefix)
49+ # Full release name
50+ "instance-management=$appVersion" >> $env:GITHUB_OUTPUT
51+ # SemVer
52+ "instance-management-semver=$($appVersion -Replace $prefix)" >> $env:GITHUB_OUTPUT
53+
54+ - name : Setup .NET
55+ uses : actions/setup-dotnet@607fce577a46308457984d59e4954e075820f10a # v3.0.3
56+ with :
57+ dotnet-version : 8.0.x
58+
59+ - name : Publish .NET Assemblies
60+ run : |
61+ $appVersion = "${{ steps.versions.outputs.instance-management-semver }}"
62+ ./build.ps1 -Command BuildAndPublish `
63+ -Configuration Release `
64+ -Version $appVersion
65+
66+ - name : Setup Nuget.exe
67+ uses : nuget/setup-nuget@fd9fffd6ca4541cf4152a9565835ca1a88a6eb37 # v1.1.1
68+
69+ - name : Create NuGet Packages
70+ if : success()
71+ run : |
72+ $appVersion = "${{ steps.versions.outputs.instance-management-semver }}"
73+ "Building ${{ env.PACKAGE_NAME }} NuGet Package" | Write-Output
74+ # installer and Transform load to single package
75+ ./build.ps1 -Command Package `
76+ -Version $appVersion `
77+ -Configuration Release
78+
79+ - name : Generate hash for NuGet package
80+ id : hash-code
81+ shell : bash
82+ run : |
83+ echo "hash-code=$(sha256sum *.nupkg | base64 -w0)" >> $GITHUB_OUTPUT
84+
85+ - name : Upload Packages as Artifacts
86+ if : success()
87+ uses : actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
88+ with :
89+ name : " ${{ env.PACKAGE_NAME }}-NuGet"
90+ path : ./*.nupkg
91+ if-no-files-found : error
92+ retention-days : 30
93+
94+ docker-analysis :
95+ runs-on : ubuntu-latest
96+ permissions :
97+ security-events : write
98+ pull-requests : write
99+ strategy :
100+ fail-fast : false
101+ matrix :
102+ dockerfile :
103+ [ { name : " development" , path: "docker/Dockerfile", type: "local" } ]
104+ steps :
105+ - name : Checkout code
106+ uses : actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
107+
108+ - name : Log in to Docker Hub
109+ uses : docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
110+ with :
111+ username : ${{ env.DOCKER_USERNAME }}
112+ password : ${{ env.DOCKER_HUB_TOKEN }}
113+
114+ - name : Build
115+ run : |
116+ dockerfile=$(echo ${{matrix.dockerfile.path}})
117+
118+ docker build -f $dockerfile -t ${{ matrix.dockerfile.name }} --build-arg="pre" .
119+
120+ - name : Analyze
121+ uses : docker/scout-action@b23590dc1e4d09febc00cfcbc51e9e8c0f7ee9f3 # v1.16.1
122+ with :
123+ command : cves
124+ image : local://${{ matrix.dockerfile.name }}
125+ sarif-file : sarif-${{ matrix.dockerfile.name }}.output.json
126+ summary : true
127+
128+ - name : Upload SARIF result
129+ id : upload-sarif
130+ if : ${{ github.event_name != 'pull_request_target' }}
131+ uses : github/codeql-action/upload-sarif@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # codeql-bundle-v3.28.0
132+ with :
133+ sarif_file : sarif-${{ matrix.dockerfile.name }}.output.json
134+
135+ docker-publish :
136+ name : Publish to Docker Hub
137+ permissions :
138+ actions : read
139+ contents : write
140+ runs-on : ubuntu-latest
141+ needs :
142+ - pack
143+ - docker-analysis
144+ steps :
145+ - name : Wait 20s
146+ # Give Azure Artifacts caching a moment to catch up
147+ run : sleep 20
148+
149+ - name : Prepare Tags
150+ id : prepare-tags
151+ run : |
152+ BASE="${{ env.IMAGE_NAME }}"
153+ REF="${{ env.REF }}"
154+ if [[ $REF =~ "pre" ]]
155+ then
156+ # Pre-releases get the version and the tag "pre"
157+ TAGS="${{ env.IMAGE_NAME }}:${REF},${{ env.IMAGE_NAME }}:pre"
158+ else
159+ # Releases get the version, plus shortened form for minor release.
160+ # We are not using shortened form for major or using "latest"
161+ # because they are too imprecise.
162+ MINOR=`echo ${REF} | awk -F"." '{print $1"."$2}'`
163+ TAGS="${{ env.IMAGE_NAME }}:${REF},${{ env.IMAGE_NAME }}:${MINOR}"
164+ fi
165+ echo "TAGS=$TAGS" >> $GITHUB_OUTPUT
166+
167+ - name : Set up Docker Buildx
168+ uses : docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
169+
170+ - name : Log in to Docker Hub
171+ uses : docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
172+ with :
173+ username : ${{ env.DOCKER_USERNAME }}
174+ password : ${{ env.DOCKER_HUB_TOKEN }}
175+
176+ - name : Extract metadata (tags, labels) for Docker
177+ id : meta
178+ uses : docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
179+ with :
180+ images : ${{ env.IMAGE_NAME }}
181+
182+ - name : Build and push
183+ uses : docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0
184+ with :
185+ context : " {{defaultContext}}:/"
186+ cache-from : type=registry,ref=${{ env.IMAGE_NAME }}:pre
187+ cache-to : type=inline
188+ build-args : ML_VERSION=${{ steps.prepare-tags.outputs.NPM_VERSION }} # Ask Jesus which version to use
189+ file : docker/Dockerfile
190+ tags : ${{ steps.prepare-tags.outputs.TAGS }}
191+ labels : ${{ steps.meta.outputs.labels }}
192+ push : true
193+
194+ sbom-create :
195+ name : Create SBOM
196+ runs-on : ubuntu-latest
197+ needs : pack
198+ permissions :
199+ actions : read
200+ contents : write
201+ outputs :
202+ sbom-hash-code : ${{ steps.sbom-hash-code.outputs.sbom-hash-code }}
203+ steps :
204+ - uses : actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
205+
206+ - name : Get Artifacts
207+ uses : actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
208+ with :
209+ name : ${{ env.PACKAGE_NAME }}-NuGet
210+
211+ - name : Generate Software Bill of Materials (SBOM) - API
212+ shell : pwsh
213+ run : |
214+ $packageName = "${{ env.PACKAGE_NAME }}"
215+ $version = "${{ needs.pack.outputs.instance-management-version }}"
216+
217+ Get-ChildItem -Include "$packageName.*.nupkg" -Recurse | ForEach-Object { $_.FullName } > buildfilelist.txt
218+
219+ dotnet tool install --global Microsoft.Sbom.DotNetTool
220+
221+ sbom-tool generate `
222+ -b ./ `
223+ -bl ./buildfilelist.txt `
224+ -bc "./" `
225+ -pn "$packageName" `
226+ -pv $version `
227+ -nsb https://ed-fi.org `
228+ -m ./ `
229+ -ps "Ed-Fi Alliance"
230+
231+ - name : Upload SBOM
232+ if : success()
233+ uses : actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
234+ with :
235+ name : ${{ env.PACKAGE_NAME }}-SBOM
236+ path : ${{ env.MANIFEST_FILE }}
237+ if-no-files-found : error
238+ retention-days : 30
239+
240+ - name : Generate hash code for SBOM
241+ id : sbom-hash-code
242+ shell : bash
243+ run : |
244+ # sha256sum returns "<hashcode> <name of file". Split that and return only the <hashcode>.
245+ sbom_hash=$(sha256sum ./${{ env.MANIFEST_FILE }} | awk '{split($0,a); print a[1]}')
246+ echo "sbom-hash-code=$sbom_hash" >> $GITHUB_OUTPUT
247+
248+ sbom-attach :
249+ name : Attach SBOM file
250+ runs-on : ubuntu-latest
251+ needs :
252+ - sbom-create
253+ - pack
254+ permissions :
255+ actions : read
256+ contents : write
257+ steps :
258+ - name : Download the SBOM
259+ uses : Ed-Fi-Alliance-OSS/slsa-github-generator/.github/actions/secure-download-artifact@main
260+ with :
261+ name : " ${{ env.PACKAGE_NAME }}-SBOM"
262+ path : ${{ env.MANIFEST_FILE }}
263+ sha256 : " ${{ needs.sbom-create.outputs.sbom-hash-code }}"
264+
265+ - name : Attach to release
266+ shell : pwsh
267+ run : |
268+ $release = "${{ github.ref_name }}"
269+ $repo = "${{ github.repository }}"
270+ $token = "${{ secrets.GITHUB_TOKEN }}"
271+ $file = "${{ env.MANIFEST_FILE }}"
272+ $uploadName = "${{ env.PACKAGE_NAME }}-SBOM.zip"
273+ $url = "https://api.github.com/repos/$repo/releases/tags/$release"
274+ $gh_headers = @{
275+ "Accept" = "application/vnd.github+json"
276+ "Authorization" = "Bearer $token"
277+ }
278+ $response = Invoke-RestMethod -Uri $url -Headers $gh_headers
279+ $releaseId = $response.id
280+ $url = "https://uploads.github.com/repos/$repo/releases/$releaseId/assets"
281+ Compress-Archive $file -DestinationPath $uploadName
282+ $gh_headers["Content-Type"] = "application/octet"
283+ Invoke-RestMethod -Method POST `
284+ -Uri "$($url)?name=$($uploadName)" `
285+ -Headers $gh_headers `
286+ -InFile $uploadName
287+
288+ provenance-create :
289+ name : Create Provenance
290+ needs : pack
291+ permissions :
292+ actions : read
293+ id-token : write
294+ contents : write
295+ uses : Ed-Fi-Alliance-OSS/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@main
296+ with :
297+ base64-subjects : ${{ needs.pack.outputs.hash-code }}
298+ attestation-name : InstanceManagement.intoto.jsonl
299+ upload-assets : true
300+ # TODO: remove this after this issue is resolved: https://github.com/slsa-framework/slsa-github-generator/issues/876
301+ compile-generator : true
302+
303+ publish-package :
304+ name : Publish NuGet Package
305+ needs : pack
306+ runs-on : ubuntu-latest
307+ defaults :
308+ run :
309+ shell : pwsh
310+ steps :
311+ - uses : actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
312+
313+ - name : Get Artifact
314+ uses : actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
315+ with :
316+ name : ${{ env.PACKAGE_NAME }}-NuGet
317+
318+ - name : Install-credential-handler
319+ run : iex "& { $(irm https://aka.ms/install-artifacts-credprovider.ps1) } -AddNetfx"
320+
321+ - name : Push Package to Azure Artifacts
322+ run : |
323+ $artifact = (Get-ChildItem -Path $_ -Name -Include *.nupkg)
324+ $arguments = @{
325+ EdFiNuGetFeed = "${{ env.ARTIFACTS_FEED_URL }}"
326+ NuGetApiKey = "${{ env.ARTIFACTS_API_KEY }}"
327+ }
328+ $artifact | ForEach-Object {
329+ $arguments.PackageFile = $_
330+ ./build.ps1 Push @arguments
331+ }
0 commit comments