Skip to content

Commit 5dbf583

Browse files
committed
add syft and grype
1 parent 8c2f0a0 commit 5dbf583

6 files changed

Lines changed: 170 additions & 31 deletions

File tree

.github/workflows/build_multi_arch_image.yml

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,12 @@ jobs:
6767
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f
6868
with:
6969
node-version: '24.14.0'
70-
70+
- name: setup syft and grype
71+
run: |
72+
mkdir -p "$RUNNER_TEMP/bin"
73+
docker build --output="$RUNNER_TEMP/bin" -f "src/base/.devcontainer/Dockerfile.syft" src/base/.devcontainer/
74+
docker build --output="$RUNNER_TEMP/bin" -f "src/base/.devcontainer/Dockerfile.grype" src/base/.devcontainer/
75+
echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH"
7176
- name: make install
7277
run: |
7378
make install-node
@@ -92,32 +97,28 @@ jobs:
9297
CONTAINER_NAME: '${{ inputs.container_name }}'
9398
BASE_FOLDER: "${{ inputs.base_folder }}"
9499
IMAGE_TAG: "${{ inputs.docker_tag }}-${{ matrix.arch }}"
95-
EXIT_CODE: 0
96-
EXTRA_COMMON: "${{ inputs.extra_common }}"
97-
# - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
98-
# name: Upload scan results
99-
# with:
100-
# name: "scan_results_docker_${{ inputs.container_name }}_${{ matrix.arch }}.json"
101-
# path: .out/scan_results_docker.json
102-
# - name: Check docker vulnerabilities - table output
103-
# run: |
104-
# make scan-image
105-
# env:
106-
# CONTAINER_NAME: '${{ inputs.container_name }}'
107-
# BASE_FOLDER: "${{ inputs.base_folder }}"
108-
# IMAGE_TAG: "${{ inputs.docker_tag }}-${{ matrix.arch }}"
109-
# EXIT_CODE: "1"
110-
# EXTRA_COMMON: "${{ inputs.extra_common }}"
111-
# - name: Show docker vulnerability output
112-
# if: always()
113-
# run: |
114-
# echo "Scan output for ghcr.io/nhsdigital/eps-devcontainers/base:${DOCKER_TAG}-${ARCHITECTURE}"
115-
# if [ -f .out/scan_results_docker.txt ]; then
116-
# cat .out/scan_results_docker.txt
117-
# fi
118-
# env:
119-
# ARCHITECTURE: '${{ matrix.arch }}'
120-
# DOCKER_TAG: '${{ inputs.docker_tag }}'
100+
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
101+
name: Upload scan results
102+
with:
103+
name: "grype_${{ inputs.container_name }}_${{ matrix.arch }}.json"
104+
path: .grype_out/grype_${{ inputs.container_name }}_${{ matrix.arch }}.json
105+
- name: Check docker vulnerabilities - text output
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+
- name: Show docker vulnerability output
113+
if: always()
114+
run: |
115+
echo "Scan output for ghcr.io/nhsdigital/eps-devcontainers/base:${DOCKER_TAG}-${ARCHITECTURE}"
116+
if [ -f .out/scan_results_docker.txt ]; then
117+
cat .out/scan_results_docker.txt
118+
fi
119+
env:
120+
ARCHITECTURE: '${{ matrix.arch }}'
121+
DOCKER_TAG: '${{ inputs.docker_tag }}'
121122
- name: Push tagged image and rebuild for github actions
122123
run: |
123124
echo "Pushing image..."

Makefile

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,12 @@ build-all: build-base-image build-node-24-image build-node-24-python-3-10-image
6464
build-eps-storage-terraform-image build-eps-data-extract-image build-fhir-facade-image build-node-24-python-3-14-golang-1-24-image build-node-24-python-3-14-java-24-image \
6565
build-regression-tests-image
6666

67-
build-image: guard-CONTAINER_NAME guard-BASE_VERSION_TAG guard-BASE_FOLDER guard-IMAGE_TAG
67+
build-syft:
68+
docker build -f src/base/.devcontainer/Dockerfile.syft --tag local_syft src/base/.devcontainer/
69+
build-grype:
70+
docker build -f src/base/.devcontainer/Dockerfile.grype --tag local_grype src/base/.devcontainer/
71+
72+
build-image: build-syft build-grype guard-CONTAINER_NAME guard-BASE_VERSION_TAG guard-BASE_FOLDER guard-IMAGE_TAG
6873
npx devcontainer build \
6974
--workspace-folder ./src/$${BASE_FOLDER}/$${CONTAINER_NAME} \
7075
$(NO_CACHE_FLAG) \
@@ -83,11 +88,17 @@ build-githubactions-image: guard-BASE_IMAGE_NAME guard-BASE_IMAGE_TAG guard-IMAG
8388
-t "${CONTAINER_PREFIX}$${BASE_IMAGE_NAME}:githubactions-$${IMAGE_TAG}" \
8489
.
8590

86-
scan-image: guard-CONTAINER_NAME guard-BASE_FOLDER
87-
echo "Not implemented"
91+
scan-image: guard-CONTAINER_NAME guard-BASE_FOLDER guard-IMAGE_TAG
92+
grype "${CONTAINER_PREFIX}$${CONTAINER_NAME}:$${IMAGE_TAG}" \
93+
--scope all-layers \
94+
--sort-by severity
8895

8996
scan-image-json: guard-CONTAINER_NAME guard-BASE_FOLDER guard-IMAGE_TAG
90-
echo "Not implemented"
97+
grype "${CONTAINER_PREFIX}$${CONTAINER_NAME}:$${IMAGE_TAG}" \
98+
--scope all-layers \
99+
--output json \
100+
--file ".grype_out/grype_${CONTAINER_NAME}_${IMAGE_TAG}.json" \
101+
--sort-by severity
91102

92103
shell-image: guard-CONTAINER_NAME guard-IMAGE_TAG
93104
docker run -it \

src/base/.devcontainer/Dockerfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
FROM local_syft AS syft-build
2+
FROM local_grype AS grype-build
13
FROM mcr.microsoft.com/devcontainers/base:ubuntu-22.04
24

35
ARG SCRIPTS_DIR=/usr/local/share/eps
@@ -16,6 +18,9 @@ COPY --chmod=755 Mk ${SCRIPTS_DIR}/Mk
1618
WORKDIR ${SCRIPTS_DIR}/${CONTAINER_NAME}
1719
RUN ./root_install.sh
1820

21+
COPY --from=syft-build /syft /usr/local/bin/syft
22+
COPY --from=grype-build /grype /usr/local/bin/grype
23+
1924
COPY --chmod=755 scripts/vscode_install.sh ${SCRIPTS_DIR}/${CONTAINER_NAME}/vscode_install.sh
2025
USER vscode
2126
COPY --chown=vscode:vscode .tool-versions.asdf /home/vscode/.tool-versions.asdf
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
FROM alpine:3.23.3 AS build
2+
ARG TARGETARCH
3+
ARG GRYPE_VERSION="0.110.0"
4+
ENV GRYPE_VERSION=${GRYPE_VERSION}
5+
RUN apk add --no-cache cosign bash curl jq
6+
COPY --chmod=755 scripts/install_anchore_tool.sh /tmp/install_anchore_tool.sh
7+
RUN case "${TARGETARCH}" in \
8+
x86_64|amd64) ANCHORE_ARCH=amd64 ;; \
9+
aarch64|arm64) ANCHORE_ARCH=arm64 ;; \
10+
*) echo "Unsupported TARGETARCH: ${TARGETARCH}" && exit 1 ;; \
11+
esac \
12+
&& INSTALL_DIR=/tmp/anchore/ TOOL=grype ARCH="${ANCHORE_ARCH}" VERSION="${GRYPE_VERSION}" /tmp/install_anchore_tool.sh
13+
14+
FROM scratch
15+
COPY --from=build /tmp/anchore/grype /grype
16+
ENTRYPOINT ["/grype"]
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
FROM alpine:3.23.3 AS build
2+
ARG TARGETARCH
3+
ARG SYFT_VERSION="1.42.3"
4+
ENV SYFT_VERSION=${SYFT_VERSION}
5+
RUN apk add --no-cache cosign bash curl jq
6+
COPY --chmod=755 scripts/install_anchore_tool.sh /tmp/install_anchore_tool.sh
7+
RUN case "${TARGETARCH}" in \
8+
x86_64|amd64) ANCHORE_ARCH=amd64 ;; \
9+
aarch64|arm64) ANCHORE_ARCH=arm64 ;; \
10+
*) echo "Unsupported TARGETARCH: ${TARGETARCH}" && exit 1 ;; \
11+
esac \
12+
&& INSTALL_DIR=/tmp/anchore/ TOOL=syft ARCH="${ANCHORE_ARCH}" VERSION="${SYFT_VERSION}" /tmp/install_anchore_tool.sh
13+
14+
FROM scratch
15+
COPY --from=build /tmp/anchore/syft /syft
16+
ENTRYPOINT ["/syft"]
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
DEFAULT_INSTALL_DIR="/usr/local/bin"
5+
INSTALL_DIR="${INSTALL_DIR:-$DEFAULT_INSTALL_DIR}"
6+
BASE_URL="https://github.com/anchore/${TOOL}/releases/download/v${VERSION}"
7+
ARCHIVE="${TOOL}_${VERSION}_linux_${ARCH}.tar.gz"
8+
CHECKSUMS="${TOOL}_${VERSION}_checksums.txt"
9+
CHECKSUMS_PEM="${TOOL}_${VERSION}_checksums.txt.pem"
10+
CHECKSUMS_SIG="${TOOL}_${VERSION}_checksums.txt.sig"
11+
12+
if [ -z "$TOOL" ]
13+
then
14+
echo "\$TOOL is NULL"
15+
fi
16+
if [ -z "$ARCH" ]
17+
then
18+
echo "\$ARCH is NULL"
19+
fi
20+
if [ -z "$VERSION" ]
21+
then
22+
echo "\$VERSION is NULL"
23+
fi
24+
25+
usage() {
26+
cat <<'EOF'
27+
Usage: install_anchore_tool.sh
28+
29+
Downloads an Anchore tool (syft or grype) archive and its sigstore bundle to a temporary directory,
30+
verifies the sigstore bundle following
31+
https://oss.anchore.com/docs/installation/verification/,
32+
and installs the Anchore tool binary into INSTALL_DIR (default: /usr/local/bin).
33+
34+
Environment variables:
35+
INSTALL_DIR Directory to install the Anchore tool binary into (default: /usr/local/bin)
36+
VERSION Anchore tool version tag to install
37+
ARCH Architecture suffix used in the download
38+
TOOL Anchore tool name, either "syft" or "grype"
39+
EOF
40+
}
41+
42+
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
43+
usage
44+
exit 0
45+
fi
46+
47+
for cmd in curl cosign; do
48+
if ! command -v "$cmd" >/dev/null 2>&1; then
49+
echo "Error: $cmd is required but not found in PATH" >&2
50+
exit 1
51+
fi
52+
done
53+
54+
TMP_DIR="$(mktemp -d)"
55+
trap 'rm -rf "$TMP_DIR"' EXIT
56+
57+
download() {
58+
local url="${1}" dest="${2}"
59+
echo "Downloading ${dest} from ${url} ..."
60+
curl -fsSL "${url}" -o "${dest}"
61+
}
62+
ARCHIVE_PATH="${TMP_DIR}/${ARCHIVE}"
63+
ALL_CHECKSUMS_PATH="${TMP_DIR}/${CHECKSUMS}"
64+
CHECKSUM_PATH="${TMP_DIR}/${ARCHIVE}.sha256sum"
65+
CHECKSUMS_PEM_PATH="${TMP_DIR}/${CHECKSUMS_PEM}"
66+
CHECKSUMS_SIG_PATH="${TMP_DIR}/${CHECKSUMS_SIG}"
67+
download "${BASE_URL}/${ARCHIVE}" "${ARCHIVE_PATH}"
68+
download "${BASE_URL}/${CHECKSUMS}" "${ALL_CHECKSUMS_PATH}"
69+
download "${BASE_URL}/${CHECKSUMS_PEM}" "${CHECKSUMS_PEM_PATH}"
70+
download "${BASE_URL}/${CHECKSUMS_SIG}" "${CHECKSUMS_SIG_PATH}"
71+
72+
cosign verify-blob "${ALL_CHECKSUMS_PATH}" \
73+
--certificate "${CHECKSUMS_PEM_PATH}" \
74+
--signature "${CHECKSUMS_SIG_PATH}" \
75+
--certificate-identity-regexp "https://github\.com/anchore/${TOOL}/\.github/workflows/.+" \
76+
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
77+
78+
echo "Sigstore verification passed"
79+
80+
grep "${ARCHIVE}" "${ALL_CHECKSUMS_PATH}" > "${CHECKSUM_PATH}"
81+
82+
cd "${TMP_DIR}"
83+
sha256sum -c "${CHECKSUM_PATH}"
84+
echo "Checksum verification passed"
85+
tar -xzf "${ARCHIVE_PATH}" -C "${TMP_DIR}"
86+
87+
mkdir -p "$INSTALL_DIR"
88+
install -m 0755 "$TMP_DIR/${TOOL}" "${INSTALL_DIR}/${TOOL}"
89+
90+
echo "${TOOL} ${VERSION} installed to ${INSTALL_DIR}"

0 commit comments

Comments
 (0)