Skip to content

Commit 469314c

Browse files
authored
Fix: [AEA-0000] - Base node image (#21)
## Summary - Routine Change ### Details - use base node image - use local trivy for scanning in ci
1 parent a68181c commit 469314c

File tree

34 files changed

+233
-160
lines changed

34 files changed

+233
-160
lines changed

.github/workflows/build_all_images.yml

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,22 @@ jobs:
1717
discover_folders:
1818
runs-on: ubuntu-latest
1919
outputs:
20-
language_folders: ${{ steps.find-folders.outputs.languages }}
20+
base_node_folders: ${{ steps.find-folders.outputs.base_node }}
21+
node_24_language_folders: ${{ steps.find-folders.outputs.node_24_languages }}
2122
project_folders: ${{ steps.find-folders.outputs.projects }}
2223
steps:
2324
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
2425

2526
- id: find-folders
2627
run: |
27-
language_folders=$(find src/languages -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | jq -R -s -c 'split("\n")[:-1]')
28+
base_node_folders=$(find src/base_node -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | jq -R -s -c 'split("\n")[:-1]')
29+
node_24_language_folders=$(find src/languages -mindepth 1 -maxdepth 1 -type d -name 'node_24*' -printf '%f\n' | jq -R -s -c 'split("\n")[:-1]')
2830
project_folders=$(find src/projects -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | jq -R -s -c 'split("\n")[:-1]')
29-
echo "languages=$language_folders" >> "$GITHUB_OUTPUT"
30-
echo "projects=$project_folders" >> "$GITHUB_OUTPUT"
31+
{
32+
echo "base_node=$base_node_folders"
33+
echo "node_24_languages=$node_24_language_folders"
34+
echo "projects=$project_folders"
35+
} >> "$GITHUB_OUTPUT"
3136
package_base_docker_image:
3237
uses: ./.github/workflows/build_multi_arch_image.yml
3338
with:
@@ -36,25 +41,42 @@ jobs:
3641
container_name: base
3742
base_folder: "."
3843
NO_CACHE: ${{ inputs.NO_CACHE }}
39-
package_language_docker_images:
44+
package_base_node_images:
4045
needs:
4146
- package_base_docker_image
4247
- discover_folders
4348
strategy:
4449
fail-fast: false
4550
matrix:
46-
container_name: ${{ fromJson(needs.discover_folders.outputs.language_folders) }}
51+
container_name: ${{ fromJson(needs.discover_folders.outputs.base_node_folders) }}
52+
uses: ./.github/workflows/build_multi_arch_image.yml
53+
with:
54+
tag_latest: ${{ inputs.tag_latest }}
55+
docker_tag: ${{ inputs.docker_tag }}
56+
container_name: ${{ matrix.container_name }}
57+
base_folder: "base_node"
58+
NO_CACHE: ${{ inputs.NO_CACHE }}
59+
EXTRA_COMMON: "common_node_24"
60+
package_node_24_language_docker_images:
61+
needs:
62+
- package_base_docker_image
63+
- package_base_node_images
64+
- discover_folders
65+
strategy:
66+
fail-fast: false
67+
matrix:
68+
container_name: ${{ fromJson(needs.discover_folders.outputs.node_24_language_folders) }}
4769
uses: ./.github/workflows/build_multi_arch_image.yml
4870
with:
4971
tag_latest: ${{ inputs.tag_latest }}
5072
docker_tag: ${{ inputs.docker_tag }}
5173
container_name: ${{ matrix.container_name }}
5274
base_folder: "languages"
5375
NO_CACHE: ${{ inputs.NO_CACHE }}
76+
EXTRA_COMMON: "common_node_24"
5477
package_project_docker_images:
5578
needs:
56-
- package_language_docker_images
57-
79+
- package_node_24_language_docker_images
5880
- discover_folders
5981
strategy:
6082
fail-fast: false
@@ -67,3 +89,4 @@ jobs:
6789
container_name: ${{ matrix.container_name }}
6890
base_folder: "projects"
6991
NO_CACHE: ${{ inputs.NO_CACHE }}
92+
EXTRA_COMMON: "common_node_24"

.github/workflows/build_multi_arch_image.yml

Lines changed: 27 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ name: Build and push docker image
1717
NO_CACHE:
1818
required: true
1919
type: boolean
20+
EXTRA_COMMON:
21+
required: false
22+
type: string
2023

2124
jobs:
2225
build_and_push_image:
@@ -27,6 +30,7 @@ jobs:
2730
attestations: write
2831
id-token: write
2932
runs-on: '${{ matrix.runner }}'
33+
3034
strategy:
3135
fail-fast: false
3236
matrix:
@@ -59,6 +63,10 @@ jobs:
5963
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
6064
with:
6165
fetch-depth: 0
66+
- name: setup trivy
67+
uses: aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514
68+
with:
69+
version: v0.69.1
6270
- name: setup node
6371
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238
6472
with:
@@ -72,17 +80,6 @@ jobs:
7280
run: |
7381
echo "Building image..."
7482
make build-image
75-
76-
echo "Creating combined trivy ignore file"
77-
# create combined trivy ignore file for use in trivy scan, combining common and specific ignore files if they exist
78-
combined="src/${BASE_FOLDER}/${CONTAINER_NAME}/.trivyignore_combined.yaml"
79-
common="src/common/.trivyignore.yaml"
80-
specific="src/${BASE_FOLDER}/${CONTAINER_NAME}/.trivyignore.yaml"
81-
echo "vulnerabilities:" > "$combined"
82-
if [ -f "$common" ]; then sed -n '2,$p' "$common" >> "$combined"; fi
83-
if [ -f "$specific" ]; then sed -n '2,$p' "$specific" >> "$combined"; fi
84-
echo "Combined trivy ignore file created at $combined"
85-
8683
env:
8784
ARCHITECTURE: '${{ matrix.arch }}'
8885
CONTAINER_NAME: '${{ inputs.container_name }}'
@@ -92,41 +89,34 @@ jobs:
9289
BASE_FOLDER: "${{ inputs.base_folder }}"
9390
NO_CACHE: '${{ inputs.NO_CACHE }}'
9491
- name: Check docker vulnerabilities - json output
95-
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284
96-
with:
97-
scan-type: "image"
98-
image-ref: "ghcr.io/nhsdigital/eps-devcontainers/${{ inputs.container_name }}:${{ inputs.docker_tag }}-${{ matrix.arch }}"
99-
severity: "CRITICAL,HIGH"
100-
scanners: "vuln"
101-
vuln-type: "os,library"
102-
format: "json"
103-
output: "scan_results_docker.json"
104-
exit-code: "0"
105-
trivy-config: src/${{ inputs.base_folder }}/${{ inputs.container_name }}/trivy.yaml
92+
run: |
93+
make scan-image-json
94+
env:
95+
CONTAINER_NAME: '${{ inputs.container_name }}'
96+
BASE_FOLDER: "${{ inputs.base_folder }}"
97+
IMAGE_TAG: "${{ inputs.docker_tag }}-${{ matrix.arch }}"
98+
EXIT_CODE: 0
99+
EXTRA_COMMON: "${{ inputs.extra_common }}"
106100
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
107101
name: Upload scan results
108102
with:
109103
name: "scan_results_docker_${{ inputs.container_name }}_${{ matrix.arch }}.json"
110-
path: scan_results_docker.json
104+
path: .out/scan_results_docker.json
111105
- name: Check docker vulnerabilities - table output
112-
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284
113-
with:
114-
scan-type: "image"
115-
image-ref: "ghcr.io/nhsdigital/eps-devcontainers/${{ inputs.container_name }}:${{ inputs.docker_tag }}-${{ matrix.arch }}"
116-
severity: "CRITICAL,HIGH"
117-
scanners: "vuln"
118-
vuln-type: "os,library"
119-
format: "table"
120-
output: "scan_results_docker.txt"
121-
exit-code: "1"
122-
trivy-config: src/${{ inputs.base_folder }}/${{ inputs.container_name }}/trivy.yaml
123-
106+
run: |
107+
make scan-image
108+
env:
109+
CONTAINER_NAME: '${{ inputs.container_name }}'
110+
BASE_FOLDER: "${{ inputs.base_folder }}"
111+
IMAGE_TAG: "${{ inputs.docker_tag }}-${{ matrix.arch }}"
112+
EXIT_CODE: "1"
113+
EXTRA_COMMON: "${{ inputs.extra_common }}"
124114
- name: Show docker vulnerability output
125115
if: always()
126116
run: |
127117
echo "Scan output for ghcr.io/nhsdigital/eps-devcontainers/base:${DOCKER_TAG}-${ARCHITECTURE}"
128-
if [ -f scan_results_docker.txt ]; then
129-
cat scan_results_docker.txt
118+
if [ -f .out/scan_results_docker.txt ]; then
119+
cat .out/scan_results_docker.txt
130120
fi
131121
env:
132122
ARCHITECTURE: '${{ matrix.arch }}'

.github/workflows/ci.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ jobs:
4040
tag_format: ${{ needs.get_asdf_version.outputs.tag_format }}
4141
secrets: inherit
4242
build_all_images:
43-
needs: tag_release
43+
needs:
44+
- tag_release
4445
uses: ./.github/workflows/build_all_images.yml
4546
with:
4647
docker_tag: 'ci-${{ needs.tag_release.outputs.version_tag }}'

.github/workflows/release.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ jobs:
4141
tag_format: ${{ needs.get_asdf_version.outputs.tag_format }}
4242
secrets: inherit
4343
build_all_images:
44-
needs: tag_release
44+
needs:
45+
- tag_release
4546
uses: ./.github/workflows/build_all_images.yml
4647
with:
4748
docker_tag: '${{ needs.tag_release.outputs.version_tag }}'

Makefile

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,32 +41,40 @@ build-githubactions-image: guard-BASE_IMAGE_NAME guard-BASE_IMAGE_TAG guard-IMAG
4141
.
4242

4343
scan-image: guard-CONTAINER_NAME guard-BASE_FOLDER
44+
mkdir -p .out
4445
@combined="src/$${BASE_FOLDER}/$${CONTAINER_NAME}/.trivyignore_combined.yaml"; \
4546
common="src/common/.trivyignore.yaml"; \
47+
extra_common="src/$${EXTRA_COMMON}/.trivyignore.yaml"; \
4648
specific="src/$${BASE_FOLDER}/$${CONTAINER_NAME}/.trivyignore.yaml"; \
49+
exit_code="$${EXIT_CODE:-1}"; \
4750
echo "vulnerabilities:" > "$$combined"; \
4851
if [ -f "$$common" ]; then sed -n '2,$$p' "$$common" >> "$$combined"; fi; \
49-
if [ -f "$$specific" ]; then sed -n '2,$$p' "$$specific" >> "$$combined"; fi
52+
if [ -f "$$extra_common" ]; then sed -n '2,$$p' "$$extra_common" >> "$$combined"; fi; \
53+
if [ -f "$$specific" ]; then sed -n '2,$$p' "$$specific" >> "$$combined"; fi; \
5054
trivy image \
5155
--severity HIGH,CRITICAL \
5256
--config src/${BASE_FOLDER}/${CONTAINER_NAME}/trivy.yaml \
5357
--scanners vuln \
54-
--exit-code 1 \
55-
--format table "${CONTAINER_PREFIX}$${CONTAINER_NAME}:$${IMAGE_TAG}"
58+
--exit-code $$exit_code \
59+
--format table \
60+
--output .out/scan_results_docker.txt "${CONTAINER_PREFIX}$${CONTAINER_NAME}:$${IMAGE_TAG}"
5661

5762
scan-image-json: guard-CONTAINER_NAME guard-BASE_FOLDER guard-IMAGE_TAG
63+
mkdir -p .out
5864
@combined="src/$${BASE_FOLDER}/$${CONTAINER_NAME}/.trivyignore_combined.yaml"; \
5965
common="src/common/.trivyignore.yaml"; \
66+
extra_common="src/$${EXTRA_COMMON}/.trivyignore.yaml"; \
6067
specific="src/$${BASE_FOLDER}/$${CONTAINER_NAME}/.trivyignore.yaml"; \
68+
exit_code="$${EXIT_CODE:-1}"; \
6169
echo "vulnerabilities:" > "$$combined"; \
6270
if [ -f "$$common" ]; then sed -n '2,$$p' "$$common" >> "$$combined"; fi; \
63-
if [ -f "$$specific" ]; then sed -n '2,$$p' "$$specific" >> "$$combined"; fi
64-
mkdir -p .out
71+
if [ -f "$$extra_common" ]; then sed -n '2,$$p' "$$extra_common" >> "$$combined"; fi; \
72+
if [ -f "$$specific" ]; then sed -n '2,$$p' "$$specific" >> "$$combined"; fi; \
6573
trivy image \
6674
--severity HIGH,CRITICAL \
6775
--config src/${BASE_FOLDER}/${CONTAINER_NAME}/trivy.yaml \
6876
--scanners vuln \
69-
--exit-code 1 \
77+
--exit-code "$$exit_code" \
7078
--format json \
7179
--output .out/scan_results_docker.json "${CONTAINER_PREFIX}$${CONTAINER_NAME}:$${IMAGE_TAG}"
7280

@@ -89,3 +97,8 @@ github-login:
8997

9098
lint-githubaction-scripts:
9199
shellcheck .github/scripts/*.sh
100+
101+
clean:
102+
rm -rf .out
103+
find . -type f -name '.trivyignore_combined.yaml' -delete
104+

README.md

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -130,18 +130,24 @@ It is important that
130130
- there is `options: --user 1001:1001 --group-add 128` below image to ensure it uses the correct user id and is added to the docker group
131131
- the default shell is set to be bash
132132
- the first step copies .tool-versions from /home/vscode to $HOME/.tool-versions
133+
## Using local or pull request images in visual studio code
134+
You can use local or pull request images by changing IMAGE_VERSION in devcontainer.json.
135+
For an image built locally following instructions below, you should put the IMAGE_VERSION=local-build.
136+
For an image built from a pull request, you should put the IMAGE_VERSION=<tag of image as show in pull request job>.
137+
You can only use images built from a pull request for testing changes in github actions.
133138

134139
# Project structure
135-
We have 4 types of dev container. These are defined under src
140+
We have 5 types of dev container. These are defined under src
136141

137142
`base` - this is the base image that all others are based on.
138-
`languages` - this installs specific versions of node and python.
143+
`base_node` - images that install node - most language projects rely on one of these
144+
`languages` - this installs specific versions of python - normally based off a node image
139145
`projects` - this is used for projects where more customization is needed than just a base language image.
140146
`githubactions` - this just takes an existing image and remaps vscode user to be 1001 so it can be used by github actions.
141147

142148
Each image to be built contains a .devcontainer folder that defines how the devcontainer should be built. At a minimum, this should contain a devcontainer.json file. See https://containers.dev/implementors/json_reference/ for options for this
143149

144-
Images under languages should point to a dockerfile under src/common that is based off the base image. This also runs `.devcontainer/scripts/root_install.sh` and `.devcontainer/scripts/vscode_install.sh` as vscode user as part of the build. These files should be in the language specific folder.
150+
Images under languages should point to a dockerfile under src/common or src/common_node_24 that is based off the base or node image. This also runs `.devcontainer/scripts/root_install.sh` and `.devcontainer/scripts/vscode_install.sh` as vscode user as part of the build. These files should be in the language specific folder.
145151

146152
We use trivy to scan for vulnerabilities in the built docker images. Known vulnerabilities in the base image are in `src/common/.trivyignore.yaml`. Vulnerabilities in specific images are in `.trivyignore.yaml` file in each images folder. These are combined before running a scan to exclude all known vulnerabilities
147153

@@ -180,6 +186,14 @@ CONTAINER_NAME=base \
180186
IMAGE_TAG=local-build \
181187
make build-image
182188
```
189+
Base node 24 image
190+
```
191+
CONTAINER_NAME=node_24 \
192+
BASE_VERSION_TAG=local-build \
193+
BASE_FOLDER=base_node \
194+
IMAGE_TAG=local-build \
195+
make build-image
196+
```
183197
Language images
184198
```
185199
CONTAINER_NAME=node_24_python_3_14 \
@@ -212,11 +226,20 @@ CONTAINER_NAME=base \
212226
IMAGE_TAG=local-build \
213227
make scan-image
214228
```
229+
Base node 24 image
230+
```
231+
CONTAINER_NAME=node_24 \
232+
BASE_FOLDER=base_node \
233+
IMAGE_TAG=local-build \
234+
EXTRA_COMMON=common_node_24 \
235+
make scan-image
236+
```
215237
Language images
216238
```
217-
CONTAINER_NAME=node_24_python_3_12 \
239+
CONTAINER_NAME=node_24_python_3_14 \
218240
BASE_FOLDER=languages \
219241
IMAGE_TAG=local-build \
242+
EXTRA_COMMON=common_node_24 \
220243
make scan-image
221244
```
222245
Project images
@@ -254,12 +277,6 @@ CONTAINER_NAME=base \
254277
make shell-image
255278
```
256279

257-
## Using local or pull request images in visual studio code
258-
You can use local or pull request images by changing IMAGE_VERSION in devcontainer.json.
259-
For an image built locally, you should put the IMAGE_VERSION=local-build.
260-
For an image built from a pull request, you should put the IMAGE_VERSION=<tag of image as show in pull request job>.
261-
You can only use images built from a pull request for testing changes in github actions.
262-
263280
## Generating a .trivyignore file
264281
You can generate a .trivyignore file for known vulnerabilities by either downloading the json scan output generated by the build, or by generating it locally using the scanning images commands above with a make target of scan-image-json
265282

src/base/.devcontainer/Mk/check.mk

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ shellcheck:
1616
fi
1717

1818
cfn-lint:
19-
cfn-lint -I "cloudformation/**/*.y*ml" 2>&1 | awk '/Run scan/ { print } /^[EW][0-9]/ { print; getline; print }'
20-
cfn-lint -I "SAMtemplates/**/*.y*ml" 2>&1 | awk '/Run scan/ { print } /^[EW][0-9]/ { print; getline; print }'
19+
@if find cloudformation -type f \( -name "*.yaml" -o -name "*.yml" \) 2>/dev/null | grep -q .; then \
20+
cfn-lint -I "cloudformation/**/*.y*ml" 2>&1 | awk '/Run scan/ { print } /^[EW][0-9]/ { print; getline; print; found=1 } END { exit found }'; \
21+
fi
22+
@if find SAMtemplates -type f \( -name "*.yaml" -o -name "*.yml" \) 2>/dev/null | grep -q .; then \
23+
cfn-lint -I "SAMtemplates/**/*.y*ml" 2>&1 | awk '/Run scan/ { print } /^[EW][0-9]/ { print; getline; print; found=1 } END { exit found }'; \
24+
fi
2125

2226
cdk-synth:
2327
echo "Not implemented"

src/base/.devcontainer/scripts/root_install.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ apt-get -y install --no-install-recommends htop vim curl git build-essential \
2727
libffi-dev libssl-dev libxml2-dev libxslt1-dev libjpeg8-dev libbz2-dev \
2828
zlib1g-dev unixodbc unixodbc-dev libsecret-1-0 libsecret-1-dev libsqlite3-dev \
2929
jq apt-transport-https ca-certificates gnupg-agent \
30-
software-properties-common bash-completion make \
30+
software-properties-common bash-completion make parallel \
3131
libreadline-dev wget llvm libncurses5-dev libncursesw5-dev \
3232
xz-utils tk-dev liblzma-dev netcat-traditional libyaml-dev uuid-runtime xxd unzip
3333

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nodejs 24.13.0

src/languages/python_3_10/.devcontainer/devcontainer.json renamed to src/base_node/node_24/.devcontainer/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
22
// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
33
{
4-
"name": "EPS Devcontainer node_24 python_3.10",
4+
"name": "EPS Devcontainer node_24",
55
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
66
"build": {
77
"dockerfile": "../../../common/Dockerfile",

0 commit comments

Comments
 (0)