1+ name : Docker Build and Publish
2+
3+ on :
4+ push :
5+ branches : [main]
6+ tags : ['v*']
7+ pull_request :
8+ branches : [main]
9+ workflow_dispatch :
10+ inputs :
11+ publish :
12+ description : ' Publish to registry'
13+ required : false
14+ default : ' false'
15+ type : boolean
16+
17+ env :
18+ REGISTRY : ghcr.io
19+ IMAGE_NAME : ${{ github.repository }}
20+
21+ jobs :
22+ build-and-test :
23+ runs-on : ubuntu-latest
24+ outputs :
25+ image-digest : ${{ steps.build.outputs.digest }}
26+ image-tag : ${{ steps.meta.outputs.tags }}
27+ should-publish : ${{ steps.should-publish.outputs.result }}
28+
29+ steps :
30+ - name : Checkout repository
31+ uses : actions/checkout@v4
32+
33+ - name : Set up Docker Buildx
34+ uses : docker/setup-buildx-action@v3
35+
36+ - name : Extract metadata
37+ id : meta
38+ uses : docker/metadata-action@v5
39+ with :
40+ images : ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
41+ tags : |
42+ type=ref,event=branch
43+ type=ref,event=pr
44+ type=semver,pattern={{version}}
45+ type=semver,pattern={{major}}.{{minor}}
46+ type=semver,pattern={{major}}
47+ type=raw,value=latest,enable={{is_default_branch}}
48+
49+ - name : Determine if should publish
50+ id : should-publish
51+ run : |
52+ if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/main" ]] || \
53+ [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == refs/tags/* ]] || \
54+ [[ "${{ github.event.inputs.publish }}" == "true" ]]; then
55+ echo "result=true" >> $GITHUB_OUTPUT
56+ else
57+ echo "result=false" >> $GITHUB_OUTPUT
58+ fi
59+
60+ - name : Build Docker image
61+ id : build
62+ uses : docker/build-push-action@v5
63+ with :
64+ context : .
65+ platforms : linux/amd64,linux/arm64
66+ push : false
67+ load : false
68+ tags : ${{ steps.meta.outputs.tags }}
69+ labels : ${{ steps.meta.outputs.labels }}
70+ cache-from : type=gha
71+ cache-to : type=gha,mode=max
72+ outputs : type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push=false
73+
74+ publish :
75+ runs-on : ubuntu-latest
76+ needs : build-and-test
77+ if : needs.build-and-test.outputs.should-publish == 'true'
78+ environment : production
79+
80+ steps :
81+ - name : Checkout repository
82+ uses : actions/checkout@v4
83+
84+ - name : Set up Docker Buildx
85+ uses : docker/setup-buildx-action@v3
86+
87+ - name : Log in to Container Registry
88+ uses : docker/login-action@v3
89+ with :
90+ registry : ${{ env.REGISTRY }}
91+ username : ${{ github.actor }}
92+ password : ${{ secrets.GITHUB_TOKEN }}
93+
94+ - name : Extract metadata
95+ id : meta
96+ uses : docker/metadata-action@v5
97+ with :
98+ images : ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
99+ tags : |
100+ type=ref,event=branch
101+ type=semver,pattern={{version}}
102+ type=semver,pattern={{major}}.{{minor}}
103+ type=semver,pattern={{major}}
104+ type=raw,value=latest,enable={{is_default_branch}}
105+
106+ - name : Build and push Docker image
107+ uses : docker/build-push-action@v5
108+ with :
109+ context : .
110+ platforms : linux/amd64,linux/arm64
111+ push : true
112+ tags : ${{ steps.meta.outputs.tags }}
113+ labels : ${{ steps.meta.outputs.labels }}
114+ cache-from : type=gha
115+ cache-to : type=gha,mode=max
116+
117+ - name : Generate SBOM
118+ uses : anchore/sbom-action@v0
119+ if : github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
120+ with :
121+ image : ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
122+ format : spdx-json
123+ output-file : sbom.spdx.json
124+
125+ - name : Upload SBOM
126+ uses : actions/upload-artifact@v4
127+ if : github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
128+ with :
129+ name : sbom
130+ path : sbom.spdx.json
131+
132+ publish-private-registry :
133+ runs-on : ubuntu-latest
134+ needs : build-and-test
135+ if : needs.build-and-test.outputs.should-publish == 'true' && secrets.PRIVATE_REGISTRY_URL != ''
136+ environment : production
137+
138+ steps :
139+ - name : Checkout repository
140+ uses : actions/checkout@v4
141+
142+ - name : Set up Docker Buildx
143+ uses : docker/setup-buildx-action@v3
144+
145+ - name : Log in to Private Registry
146+ uses : docker/login-action@v3
147+ with :
148+ registry : ${{ secrets.PRIVATE_REGISTRY_URL }}
149+ username : ${{ secrets.PRIVATE_REGISTRY_USERNAME }}
150+ password : ${{ secrets.PRIVATE_REGISTRY_PASSWORD }}
151+
152+ - name : Extract metadata for private registry
153+ id : meta-private
154+ uses : docker/metadata-action@v5
155+ with :
156+ images : ${{ secrets.PRIVATE_REGISTRY_URL }}/${{ secrets.PRIVATE_REGISTRY_IMAGE_NAME || github.repository }}
157+ tags : |
158+ type=ref,event=branch
159+ type=semver,pattern={{version}}
160+ type=semver,pattern={{major}}.{{minor}}
161+ type=semver,pattern={{major}}
162+ type=raw,value=latest,enable={{is_default_branch}}
163+
164+ - name : Build and push to Private Registry
165+ uses : docker/build-push-action@v5
166+ with :
167+ context : .
168+ platforms : linux/amd64,linux/arm64
169+ push : true
170+ tags : ${{ steps.meta-private.outputs.tags }}
171+ labels : ${{ steps.meta-private.outputs.labels }}
172+ cache-from : type=gha
173+ cache-to : type=gha,mode=max
174+
175+ security-scan :
176+ runs-on : ubuntu-latest
177+ needs : [build-and-test, publish]
178+ if : needs.build-and-test.outputs.should-publish == 'true'
179+ environment : production
180+
181+ steps :
182+ - name : Run Trivy vulnerability scanner
183+ uses : aquasecurity/trivy-action@master
184+ with :
185+ image-ref : ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build-and-test.outputs.image-digest }}
186+ format : ' sarif'
187+ output : ' trivy-results.sarif'
188+
189+ - name : Upload Trivy scan results to GitHub Security tab
190+ uses : github/codeql-action/upload-sarif@v3
191+ if : always()
192+ with :
193+ sarif_file : ' trivy-results.sarif'
0 commit comments