Skip to content

Commit 88fbdfd

Browse files
authored
Merge pull request #6 from NGWPC/pena-pipeline-updates
updated cicd file
2 parents 81b1843 + 9a17fab commit 88fbdfd

2 files changed

Lines changed: 203 additions & 129 deletions

File tree

.github/workflows/ci-cd.yml

Lines changed: 179 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,27 @@ name: CI/CD Pipeline
22

33
on:
44
pull_request:
5-
branches: [ngwpc-candidate, ngwpc-release, main, nwm-main, development, release-candidate]
5+
branches:
6+
- ngwpc-candidate
7+
- ngwpc-release
8+
- main
9+
- nwm-main
10+
- development
11+
- release-candidate
612
push:
7-
branches: [ngwpc-candidate, ngwpc-release, main, nwm-main, development, release-candidate]
8-
release:
9-
types: [published]
13+
branches:
14+
- ngwpc-candidate
15+
- ngwpc-release
16+
- main
17+
- nwm-main
18+
- development
19+
- release-candidate
20+
workflow_dispatch:
21+
inputs:
22+
NGEN_IMAGE_TAG:
23+
description: 'NGEN_IMAGE_TAG'
24+
required: false
25+
type: string
1026

1127
permissions:
1228
contents: read
@@ -18,47 +34,122 @@ env:
1834
PYTHON_VERSION: '3.11'
1935

2036
jobs:
37+
# set variables for use in other jobs
2138
setup:
39+
name: setup
2240
runs-on: ubuntu-latest
2341
outputs:
42+
org: ${{ steps.vars.outputs.org }}
2443
image_base: ${{ steps.vars.outputs.image_base }}
2544
pr_tag: ${{ steps.vars.outputs.pr_tag }}
2645
commit_sha: ${{ steps.vars.outputs.commit_sha }}
2746
commit_sha_short: ${{ steps.vars.outputs.commit_sha_short }}
2847
test_image_tag: ${{ steps.vars.outputs.test_image_tag }}
48+
alias_tag: ${{ steps.vars.outputs.alias_tag }}
49+
build_date: ${{ steps.vars.outputs.build_date }}
50+
clean_ref: ${{ steps.vars.outputs.clean_ref }}
2951
steps:
3052
- name: Compute image vars
3153
id: vars
3254
shell: bash
3355
run: |
3456
set -euo pipefail
57+
58+
# set variables to use with Docker images
3559
ORG="$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')"
3660
REPO="$(basename "${GITHUB_REPOSITORY}")"
3761
IMAGE_BASE="${REGISTRY}/${ORG}/${REPO}"
38-
echo "image_base=${IMAGE_BASE}" >> "$GITHUB_OUTPUT"
3962
40-
if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then
41-
PR_NUM="${{ github.event.pull_request.number }}"
42-
PR_TAG="pr-${PR_NUM}-build"
43-
echo "pr_tag=${PR_TAG}" >> "$GITHUB_OUTPUT"
44-
echo "test_image_tag=${PR_TAG}" >> "$GITHUB_OUTPUT"
63+
# one datetime for all time variables
64+
NOW=$(date -u +'%Y-%m-%d %H:%M:%S')
65+
66+
# for OCI labels
67+
BUILD_DATE=$(date -u -d "$NOW" +'%Y-%m-%dT%H:%M:%SZ')
68+
69+
# for Docker image tags
70+
TIMESTAMP=$(date -u -d "$NOW" +'%Y%m%d%H%M%SZ')
71+
72+
# logic to get the real branch name and commit SHA on pull requests
73+
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
74+
REAL_REF="${{ github.head_ref }}"
75+
REAL_SHA="${{ github.event.pull_request.head.sha }}"
76+
else
77+
REAL_REF="${{ github.ref_name }}"
78+
REAL_SHA="${GITHUB_SHA}"
4579
fi
4680
47-
if [ "${GITHUB_EVENT_NAME}" = "push" ]; then
48-
COMMIT_SHA="${GITHUB_SHA}"
49-
SHORT_SHA="${COMMIT_SHA:0:12}"
50-
echo "commit_sha=${COMMIT_SHA}" >> "$GITHUB_OUTPUT"
51-
echo "commit_sha_short=${SHORT_SHA}" >> "$GITHUB_OUTPUT"
52-
echo "test_image_tag=${SHORT_SHA}" >> "$GITHUB_OUTPUT"
81+
# clean ref name and short commit sha
82+
CLEAN_REF=$(echo "$REAL_REF" | tr '[:upper:]' '[:lower:]' | sed 's/\//-/g')
83+
SHORT_SHA="${REAL_SHA:0:7}"
84+
85+
# logic for the tags:
86+
# test_image_tag (commit short sha): used for the initial build and test
87+
# alias_tag: used for final tagging on successful tests
88+
89+
# test tag is always commit short sha
90+
TEST_TAG="${SHORT_SHA}"
91+
92+
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
93+
# for pull requests, use pr-<pr number>-build
94+
ALIAS="pr-${{ github.event.pull_request.number }}-build"
95+
elif [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ] && [ "${{ github.ref_type }}" = "tag" ]; then
96+
# for manual workflow dispatch on tags, use the git tag
97+
ALIAS="${CLEAN_REF}"
98+
else
99+
# for pushes to branches, use timestamp-branchname
100+
ALIAS="${TIMESTAMP}-${CLEAN_REF}"
53101
fi
54102
103+
# save outputs
104+
echo "org=${ORG}" >> "$GITHUB_OUTPUT"
105+
echo "image_base=${IMAGE_BASE}" >> "$GITHUB_OUTPUT"
106+
echo "build_date=${BUILD_DATE}" >> "$GITHUB_OUTPUT"
107+
echo "test_image_tag=${TEST_TAG}" >> "$GITHUB_OUTPUT"
108+
echo "alias_tag=${ALIAS}" >> "$GITHUB_OUTPUT"
109+
echo "commit_sha=${REAL_SHA}" >> "$GITHUB_OUTPUT"
110+
echo "commit_sha_short=${SHORT_SHA}" >> "$GITHUB_OUTPUT"
111+
echo "clean_ref=${CLEAN_REF}" >> "$GITHUB_OUTPUT"
112+
113+
# CodeQL scan
114+
codeql-scan:
115+
name: codeql-scan
116+
if: |
117+
(github.event_name == 'pull_request') ||
118+
(github.event_name == 'push') ||
119+
(github.event_name == 'workflow_dispatch')
120+
runs-on: ubuntu-latest
121+
needs: setup
122+
permissions:
123+
actions: read
124+
contents: read
125+
security-events: write
126+
steps:
127+
- uses: actions/checkout@v6
128+
- name: Set up Python
129+
uses: actions/setup-python@v6
130+
with:
131+
python-version: ${{ env.PYTHON_VERSION }}
132+
- name: Initialize CodeQL
133+
uses: github/codeql-action/init@v4
134+
with:
135+
languages: python
136+
- name: Install dependencies
137+
run: |
138+
python -m pip install --upgrade pip
139+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
140+
- name: Perform CodeQL Analysis
141+
uses: github/codeql-action/analyze@v4
142+
55143
build:
56144
name: build
57-
if: github.event_name == 'pull_request' || github.event_name == 'push'
145+
if: |
146+
(github.event_name == 'pull_request') ||
147+
(github.event_name == 'push') ||
148+
(github.event_name == 'workflow_dispatch')
58149
runs-on: ubuntu-latest
59150
needs: setup
60151
steps:
61-
- uses: actions/checkout@v4
152+
- uses: actions/checkout@v6
62153

63154
- name: Log in to registry
64155
uses: docker/login-action@v3
@@ -74,145 +165,106 @@ jobs:
74165
push: true
75166
tags: ${{ needs.setup.outputs.image_base }}:${{ needs.setup.outputs.test_image_tag }}
76167
build-args: |
77-
NGEN_IMAGE_TAG=${{ env.NGEN_IMAGE_TAG || 'latest' }}
78-
CI_COMMIT_REF_NAME=${{ github.ref_name }}
168+
ORG=${{ needs.setup.outputs.org }}
169+
NGEN_IMAGE_TAG=${{ inputs.NGEN_IMAGE_TAG || 'latest' }}
170+
IMAGE_SOURCE=https://github.com/${{ github.repository }}
171+
IMAGE_VENDOR=${{ github.repository_owner }}
172+
IMAGE_VERSION=${{ needs.setup.outputs.clean_ref }}
173+
IMAGE_REVISION=${{ needs.setup.outputs.commit_sha }}
174+
IMAGE_CREATED=${{ needs.setup.outputs.build_date }}
175+
CI_COMMIT_REF_NAME=${{ needs.setup.outputs.clean_ref }}
79176
80177
unit-test:
81178
name: unit-test
82-
if: github.event_name == 'pull_request' || github.event_name == 'push'
179+
if: |
180+
(github.event_name == 'pull_request') ||
181+
(github.event_name == 'push') ||
182+
(github.event_name == 'workflow_dispatch')
83183
runs-on: ubuntu-latest
84-
needs: [setup, build]
184+
needs:
185+
- setup
186+
- build
85187
container:
86188
image: ${{ needs.setup.outputs.image_base }}:${{ needs.setup.outputs.test_image_tag }}
87189
steps:
88190
- name: Run unit tests
89191
run: |
90192
echo "TODO: add unit tests here"
91193
92-
codeql-scan:
93-
if: github.event_name == 'pull_request' || github.event_name == 'push'
94-
runs-on: ubuntu-latest
95-
needs: [setup, build]
96-
permissions:
97-
actions: read
98-
contents: read
99-
security-events: write
100-
steps:
101-
- uses: actions/checkout@v4
102-
- name: Set up Python
103-
uses: actions/setup-python@v5
104-
with:
105-
python-version: ${{ env.PYTHON_VERSION }}
106-
- name: Initialize CodeQL
107-
uses: github/codeql-action/init@v3
108-
with:
109-
languages: python
110-
- name: Install dependencies
111-
run: |
112-
python -m pip install --upgrade pip
113-
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
114-
- name: Perform CodeQL Analysis
115-
uses: github/codeql-action/analyze@v3
116-
194+
# run container security scan using Trivy
117195
container-scanning:
118-
if: github.event_name == 'pull_request' || github.event_name == 'push'
196+
if: |
197+
(github.event_name == 'pull_request') ||
198+
(github.event_name == 'push') ||
199+
(github.event_name == 'workflow_dispatch')
119200
runs-on: ubuntu-latest
120-
needs: [setup, build]
201+
needs:
202+
- setup
203+
- build
121204
steps:
122-
- name: Scan container with Trivy
123-
uses: aquasecurity/trivy-action@0.20.0
124-
with:
125-
image-ref: ${{ needs.setup.outputs.image_base }}:${{ needs.setup.outputs.test_image_tag }}
126-
format: 'template'
127-
template: '@/contrib/sarif.tpl'
128-
output: 'trivy-results.sarif'
129-
severity: 'CRITICAL,HIGH'
130-
- name: Upload Trivy SARIF
131-
uses: github/codeql-action/upload-sarif@v3
205+
- name: Install Trivy
206+
uses: aquasecurity/setup-trivy@v0.2.2
132207
with:
133-
sarif_file: 'trivy-results.sarif'
208+
cache: true
209+
version: v0.68.2
134210

135-
deploy-latest-on-development:
136-
name: deploy-latest-on-development
137-
if: github.event_name == 'push' && github.ref_name == 'development'
138-
runs-on: ubuntu-latest
139-
needs: [setup, build, unit-test, codeql-scan, container-scanning]
140-
steps:
141-
- name: Tag image with 'latest'
142-
shell: bash
211+
- name: Trivy scan
212+
env:
213+
TMPDIR: /mnt/trivy-temp
143214
run: |
144-
set -euo pipefail
145-
IMAGE_BASE="${{ needs.setup.outputs.image_base }}"
146-
SHORT_SHA="${{ needs.setup.outputs.commit_sha_short }}"
215+
sudo mkdir -p $TMPDIR
216+
sudo chown -R $USER:$USER $TMPDIR
147217
148-
# ensure skopeo is available
149-
if ! command -v skopeo >/dev/null 2>&1; then
150-
sudo apt-get update -y
151-
sudo apt-get install -y --no-install-recommends skopeo
152-
fi
153-
154-
skopeo copy \
155-
--src-creds "${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}" \
156-
--dest-creds "${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}" \
157-
docker://"${IMAGE_BASE}:${SHORT_SHA}" docker://"${IMAGE_BASE}:latest"
218+
trivy image \
219+
--format sarif \
220+
--output trivy-results.sarif \
221+
--severity CRITICAL,HIGH \
222+
--scanners vuln \
223+
--ignore-unfixed \
224+
--timeout 45m \
225+
${{ needs.setup.outputs.image_base }}:${{ needs.setup.outputs.test_image_tag }}
158226
159-
release:
160-
name: release
161-
if: github.event_name == 'release' && github.event.action == 'published'
227+
# promote Docker image tags after successful tests
228+
promote-tags:
229+
name: Promote Tags
230+
if: |
231+
(github.event_name == 'pull_request') ||
232+
(github.event_name == 'push') ||
233+
(github.event_name == 'workflow_dispatch')
162234
runs-on: ubuntu-latest
163-
needs: setup
235+
needs:
236+
- setup
237+
- codeql-scan
238+
- build
239+
- container-scanning
164240
steps:
165-
- name: Get commit sha for the tag
166-
id: rev
167-
shell: bash
168-
env:
169-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
170-
run: |
171-
set -euo pipefail
172-
TAG="${{ github.event.release.tag_name }}"
173-
REPO="${{ github.repository }}"
174-
175-
# ensure jq is available
176-
if ! command -v jq >/dev/null 2>&1; then
177-
sudo apt-get update -y
178-
sudo apt-get install -y --no-install-recommends jq
179-
fi
180-
181-
# ensure gh cli is available
182-
if ! command -v gh >/dev/null 2>&1; then
183-
sudo apt-get update -y
184-
sudo apt-get install -y --no-install-recommends gh
185-
fi
186-
187-
REF_JSON="$(gh api "repos/${REPO}/git/refs/tags/${TAG}")"
188-
OBJ_SHA="$(jq -r '.object.sha' <<<"$REF_JSON")"
189-
OBJ_TYPE="$(jq -r '.object.type' <<<"$REF_JSON")"
190-
191-
if [ "$OBJ_TYPE" = "tag" ]; then
192-
TAG_OBJ="$(gh api "repos/${REPO}/git/tags/${OBJ_SHA}")"
193-
COMMIT_SHA="$(jq -r '.object.sha' <<<"$TAG_OBJ")"
194-
else
195-
COMMIT_SHA="$OBJ_SHA"
196-
fi
197-
198-
SHORT_SHA="${COMMIT_SHA:0:12}"
199-
echo "short_sha=${SHORT_SHA}" >> "$GITHUB_OUTPUT"
200-
201-
- name: Tag image with release tag
241+
- name: Tag image with alias and latest
202242
shell: bash
203243
run: |
204244
set -euo pipefail
205-
IMAGE_BASE="${{ needs.setup.outputs.image_base }}"
206-
SHORT_SHA="${{ steps.rev.outputs.short_sha }}"
207-
RELEASE_TAG="${{ github.event.release.tag_name }}"
208245
209-
# ensure skopeo is available
246+
# ensure skopeo is available for promotion
210247
if ! command -v skopeo >/dev/null 2>&1; then
211248
sudo apt-get update -y
212249
sudo apt-get install -y --no-install-recommends skopeo
213250
fi
214251
252+
IMAGE_BASE="${{ needs.setup.outputs.image_base }}"
253+
TEST_TAG="${{ needs.setup.outputs.test_image_tag }}"
254+
ALIAS_TAG="${{ needs.setup.outputs.alias_tag }}"
255+
256+
# apply the primary alias (pr tag or timestamp-branch)
215257
skopeo copy \
216258
--src-creds "${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}" \
217259
--dest-creds "${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}" \
218-
docker://"${IMAGE_BASE}:${SHORT_SHA}" docker://"${IMAGE_BASE}:${RELEASE_TAG}"
260+
--all \
261+
"docker://${IMAGE_BASE}:${TEST_TAG}" "docker://${IMAGE_BASE}:${ALIAS_TAG}"
262+
263+
# tag with 'latest' on development branch push
264+
if [ "$GITHUB_EVENT_NAME" = "push" ] && [ "$GITHUB_REF_NAME" = "development" ]; then
265+
skopeo copy \
266+
--src-creds "${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}" \
267+
--dest-creds "${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}" \
268+
--all \
269+
"docker://${IMAGE_BASE}:${TEST_TAG}" "docker://${IMAGE_BASE}:latest"
270+
fi

0 commit comments

Comments
 (0)