diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 0e7ee62..345a5a0 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,3 +1,15 @@ +FROM alpine:3.23.3 AS build +ARG TARGETARCH +RUN apk add --no-cache cosign bash curl jq +COPY src/base/.devcontainer/scripts/install_trivy.sh /tmp/install_trivy.sh +RUN case "${TARGETARCH}" in \ + x86_64|amd64) TRIVY_ARCH=64bit ;; \ + aarch64|arm64) TRIVY_ARCH=ARM64 ;; \ + *) echo "Unsupported TARGETARCH: ${TARGETARCH}" && exit 1 ;; \ + esac \ + && INSTALL_DIR=/tmp/trivy/ ARCH="${TRIVY_ARCH}" /tmp/install_trivy.sh + + FROM mcr.microsoft.com/devcontainers/base:ubuntu-22.04 ARG TARGETARCH ENV TARGETARCH=${TARGETARCH} @@ -64,11 +76,13 @@ RUN git clone https://github.com/awslabs/git-secrets.git /tmp/git-secrets && \ chmod 755 /usr/share/secrets-scanner && \ curl -L https://raw.githubusercontent.com/NHSDigital/software-engineering-quality-framework/main/tools/nhsd-git-secrets/nhsd-rules-deny.txt -o /usr/share/secrets-scanner/nhsd-rules-deny.txt +COPY --from=build /tmp/trivy/trivy /usr/local/bin/trivy + USER vscode -ENV PATH="/home/vscode/.asdf/shims/:$PATH:/workspaces/eps-devcontainers/node_modules/.bin" +ENV PATH="/home/vscode/.asdf/shims:/home/vscode/.local/bin:$PATH:/workspaces/eps-devcontainers/node_modules/.bin" RUN \ - echo 'PATH="/home/vscode/.asdf/shims/:$PATH:/workspaces/eps-devcontainers/node_modules/.bin"' >> ~/.bashrc; \ + echo 'PATH="/home/vscode/.asdf/shims:/home/vscode/.local/bin:$PATH:/workspaces/eps-devcontainers/node_modules/.bin"' >> ~/.bashrc; \ echo '. <(asdf completion bash)' >> ~/.bashrc; \ echo '# Install Ruby Gems to ~/gems' >> ~/.bashrc; \ echo 'export GEM_HOME="$HOME/gems"' >> ~/.bashrc; \ @@ -82,9 +96,7 @@ RUN asdf plugin add python; \ asdf plugin add direnv; \ asdf plugin add actionlint; \ asdf plugin add ruby https://github.com/asdf-vm/asdf-ruby.git; \ - asdf plugin add trivy https://github.com/zufardhiyaulhaq/asdf-trivy.git; \ - asdf plugin add yq https://github.com/sudermanjr/asdf-yq.git - + asdf plugin add yq https://github.com/sudermanjr/asdf-yq.git; WORKDIR /workspaces/eps-devcontainers COPY .tool-versions /workspaces/eps-devcontainers/.tool-versions diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b08221a..645e5c2 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -12,7 +12,8 @@ "source=${env:HOME}${env:USERPROFILE}/.aws,target=/home/vscode/.aws,type=bind", "source=${env:HOME}${env:USERPROFILE}/.ssh,target=/home/vscode/.ssh,type=bind", "source=${env:HOME}${env:USERPROFILE}/.gnupg,target=/home/vscode/.gnupg,type=bind", - "source=${env:HOME}${env:USERPROFILE}/.npmrc,target=/home/vscode/.npmrc,type=bind" + "source=${env:HOME}${env:USERPROFILE}/.npmrc,target=/home/vscode/.npmrc,type=bind", + "source=${env:HOME}${env:USERPROFILE}/.gitconfig,target=/home/vscode/.gitconfig,type=bind" ], "runArgs": [ "--network=host" diff --git a/.github/workflows/build_all_images.yml b/.github/workflows/build_all_images.yml index 111abf8..fe3279a 100644 --- a/.github/workflows/build_all_images.yml +++ b/.github/workflows/build_all_images.yml @@ -33,6 +33,7 @@ jobs: echo "node_24_languages=$node_24_language_folders" echo "projects=$project_folders" } >> "$GITHUB_OUTPUT" + package_base_docker_image: uses: ./.github/workflows/build_multi_arch_image.yml with: diff --git a/.github/workflows/build_multi_arch_image.yml b/.github/workflows/build_multi_arch_image.yml index b9d5334..c3d5862 100644 --- a/.github/workflows/build_multi_arch_image.yml +++ b/.github/workflows/build_multi_arch_image.yml @@ -64,9 +64,12 @@ jobs: with: fetch-depth: 0 - name: setup trivy - uses: aquasecurity/setup-trivy@3fb12ec12f41e471780db15c232d5dd185dcb514 - with: - version: v0.69.3 + run: | + mkdir -p "$RUNNER_TEMP/bin" + docker build --output="$RUNNER_TEMP/bin" -f "src/base/.devcontainer/Dockerfile.trivy.${ARCH}" . + echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH" + env: + ARCH: '${{ matrix.arch }}' - name: setup node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f with: diff --git a/.gitignore b/.gitignore index 35bc1fd..7c362b6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ src/base/.devcontainer/language_versions/ .trivyignore_combined.yaml .out/ .envrc +.trivy_out/ diff --git a/.tool-versions b/.tool-versions index 1aed182..2500101 100644 --- a/.tool-versions +++ b/.tool-versions @@ -5,5 +5,4 @@ shellcheck 0.11.0 direnv 2.37.1 actionlint 1.7.10 ruby 3.3.0 -trivy 0.69.3 yq 4.52.2 diff --git a/Makefile b/Makefile index 8b40ad8..697df53 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,9 @@ guard-%: exit 1; \ fi +.PHONY: install install-python install-node install-hooks build-base-image build-node-24-image build-node-24-python-3-10-image build-node-24-python-3-12-image build-node-24-python-3-13-image build-node-24-python-3-14-image \ + build-eps-storage-terraform-image build-fhir-facade-image build-node-24-python-3-14-golang-1-24-image build-node-24-python-3-14-java-24-image \ + build-regression-tests-image build-all build-image build-githubactions-image scan-image scan-image-json shell-image lint test lint-githubactions lint-githubaction-scripts clean install: install-python install-node install-hooks install-python: @@ -129,13 +132,9 @@ test: lint-githubactions: actionlint -github-login: - gh auth login --scopes read:packages - lint-githubaction-scripts: shellcheck .github/scripts/*.sh clean: rm -rf .out find . -type f -name '.trivyignore_combined.yaml' -delete - diff --git a/src/base/.devcontainer/.tool-versions b/src/base/.devcontainer/.tool-versions index bac5b7b..7aaf5f8 100644 --- a/src/base/.devcontainer/.tool-versions +++ b/src/base/.devcontainer/.tool-versions @@ -2,5 +2,4 @@ shellcheck 0.11.0 direnv 2.37.1 actionlint 1.7.11 ruby 3.3.0 -trivy 0.69.3 yq 4.52.4 diff --git a/src/base/.devcontainer/Dockerfile b/src/base/.devcontainer/Dockerfile index 1d39021..0ccee69 100644 --- a/src/base/.devcontainer/Dockerfile +++ b/src/base/.devcontainer/Dockerfile @@ -1,3 +1,14 @@ +FROM alpine:3.23.3 AS build +ARG TARGETARCH +RUN apk add --no-cache cosign bash curl jq +COPY --chmod=755 scripts/install_trivy.sh /tmp/install_trivy.sh +RUN case "${TARGETARCH}" in \ + x86_64|amd64) TRIVY_ARCH=64bit ;; \ + aarch64|arm64) TRIVY_ARCH=ARM64 ;; \ + *) echo "Unsupported TARGETARCH: ${TARGETARCH}" && exit 1 ;; \ + esac \ + && INSTALL_DIR=/tmp/trivy/ ARCH="${TRIVY_ARCH}" /tmp/install_trivy.sh + FROM mcr.microsoft.com/devcontainers/base:ubuntu-22.04 ARG SCRIPTS_DIR=/usr/local/share/eps @@ -16,6 +27,8 @@ COPY --chmod=755 Mk ${SCRIPTS_DIR}/Mk WORKDIR ${SCRIPTS_DIR}/${CONTAINER_NAME} RUN ./root_install.sh +COPY --from=build /tmp/trivy/trivy /usr/local/bin/trivy + COPY --chmod=755 scripts/vscode_install.sh ${SCRIPTS_DIR}/${CONTAINER_NAME}/vscode_install.sh USER vscode COPY --chown=vscode:vscode .tool-versions.asdf /home/vscode/.tool-versions.asdf diff --git a/src/base/.devcontainer/Dockerfile.trivy.amd64 b/src/base/.devcontainer/Dockerfile.trivy.amd64 new file mode 100644 index 0000000..4a719ad --- /dev/null +++ b/src/base/.devcontainer/Dockerfile.trivy.amd64 @@ -0,0 +1,8 @@ +FROM alpine:3.23.3 AS build +RUN apk add --no-cache cosign bash curl jq +COPY --chmod=755 src/base/.devcontainer/scripts/install_trivy.sh /tmp/install_trivy.sh +RUN INSTALL_DIR=/tmp/trivy/ ARCH=64bit /tmp/install_trivy.sh + +FROM scratch +COPY --from=build /tmp/trivy/trivy / +ENTRYPOINT ["/trivy"] diff --git a/src/base/.devcontainer/Dockerfile.trivy.arm64 b/src/base/.devcontainer/Dockerfile.trivy.arm64 new file mode 100644 index 0000000..899ea76 --- /dev/null +++ b/src/base/.devcontainer/Dockerfile.trivy.arm64 @@ -0,0 +1,8 @@ +FROM alpine:3.23.3 AS build +RUN apk add --no-cache cosign bash curl jq +COPY --chmod=755 src/base/.devcontainer/scripts/install_trivy.sh /tmp/install_trivy.sh +RUN INSTALL_DIR=/tmp/trivy/ ARCH=ARM64 /tmp/install_trivy.sh + +FROM scratch +COPY --from=build /tmp/trivy/trivy / +ENTRYPOINT ["/trivy"] diff --git a/src/base/.devcontainer/scripts/install_trivy.sh b/src/base/.devcontainer/scripts/install_trivy.sh new file mode 100755 index 0000000..c49ab97 --- /dev/null +++ b/src/base/.devcontainer/scripts/install_trivy.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +set -euo pipefail + +DEFAULT_INSTALL_DIR="/usr/local/bin" +INSTALL_DIR="${INSTALL_DIR:-$DEFAULT_INSTALL_DIR}" +VERSION="${VERSION:-v0.69.3}" +DEFAULT_ARCH="64bit" +ARCH="${ARCH:-$DEFAULT_ARCH}" +RELEASE_NUMBER="${VERSION#v}" +BASE_URL="https://github.com/aquasecurity/trivy/releases/download/${VERSION}" +ARCHIVE="trivy_${RELEASE_NUMBER}_Linux-${ARCH}.tar.gz" +BUNDLE="${ARCHIVE}.sigstore.json" +CERT_IDENTITY="https://github.com/aquasecurity/trivy/.github/workflows/reusable-release.yaml@refs/tags/${VERSION}" + +usage() { + cat <<'EOF' +Usage: install_trivy.sh + +Downloads the Trivy archive and its sigstore bundle to a temporary directory, +verifies the sigstore bundle following +https://github.com/aquasecurity/trivy/blob/main/docs/getting-started/signature-verification.md, +and installs the trivy binary into INSTALL_DIR (default: /usr/local/bin). + +Environment variables: + INSTALL_DIR Directory to install the trivy binary into (default: /usr/local/bin) + VERSION Trivy version tag to install (default: v0.69.3) + ARCH Architecture suffix used in the download (default: 64bit) +EOF +} + +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage + exit 0 +fi + +for cmd in curl cosign; do + if ! command -v "$cmd" >/dev/null 2>&1; then + echo "Error: $cmd is required but not found in PATH" >&2 + exit 1 + fi +done + +TMP_DIR="$(mktemp -d)" +trap 'rm -rf "$TMP_DIR"' EXIT + +download() { + local url="${1}" dest="${2}" + echo "Downloading ${dest} ..." + curl -fsSL "${url}" -o "${dest}" +} +ARCHIVE_PATH="${TMP_DIR}/${ARCHIVE}" +BUNDLE_PATH="${TMP_DIR}/${BUNDLE}" +download "${BASE_URL}/${ARCHIVE}" "${ARCHIVE_PATH}" +download "${BASE_URL}/${BUNDLE}" "${BUNDLE_PATH}" + + +cosign verify-blob-attestation "${ARCHIVE_PATH}" \ + --bundle "${BUNDLE_PATH}" \ + --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \ + --certificate-identity "${CERT_IDENTITY}" + +echo "Sigstore verification passed" +tar -xzf "${ARCHIVE_PATH}" -C "${TMP_DIR}" + +mkdir -p "$INSTALL_DIR" +install -m 0755 "$TMP_DIR/trivy" "${INSTALL_DIR}/trivy" + +echo "trivy ${VERSION} installed to ${INSTALL_DIR}" diff --git a/src/projects/regression_tests/.devcontainer/scripts/root_install.sh b/src/projects/regression_tests/.devcontainer/scripts/root_install.sh index 97d3b80..1795cbe 100755 --- a/src/projects/regression_tests/.devcontainer/scripts/root_install.sh +++ b/src/projects/regression_tests/.devcontainer/scripts/root_install.sh @@ -4,7 +4,7 @@ set -euo pipefail # install chrome mkdir -p /etc/apt/keyrings -wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo tee /etc/apt/keyrings/google.asc >/dev/null +wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | tee /etc/apt/keyrings/google.asc >/dev/null sh -c 'echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/google.asc] https://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list' apt-get update apt-get install -y google-chrome-stable