Skip to content

New: [AEA-0000] - add syft and grype#69

Open
anthony-nhs wants to merge 9 commits intomainfrom
syft_grype
Open

New: [AEA-0000] - add syft and grype#69
anthony-nhs wants to merge 9 commits intomainfrom
syft_grype

Conversation

@anthony-nhs
Copy link
Copy Markdown
Contributor

Summary

  • Routine Change

Details

  • add syft
  • add grype

Copilot AI review requested due to automatic review settings March 26, 2026 14:58
@github-actions
Copy link
Copy Markdown
Contributor

This PR is linked to a ticket in an NHS Digital JIRA Project. Here's a handy link to the ticket:

AEA-0000

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Replaces the Trivy-based image scanning and ignore-file workflow with Anchore tooling (Syft/Grype), updates CI to install/run the new scanners, and removes Trivy ignore/config artifacts across images.

Changes:

  • Remove Trivy config/ignore files and Trivy helper tooling/docs; disable Trivy make targets.
  • Add verified install flow for Anchore tools (Syft/Grype) and wire them into the base devcontainer + CI workflow.
  • Add zizmor (and cfn-lint for some images) via per-image requirements-user.txt, and expose a make zizmor target.

Reviewed changes

Copilot reviewed 49 out of 49 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
trivy.yaml Removes repository-level Trivy ignorefile config.
src/projects/regression_tests/trivy.yaml Removes project Trivy ignorefile config.
src/projects/regression_tests/.trivyignore.yaml Removes project Trivy ignore list.
src/projects/node_24_python_3_14_java_24/trivy.yaml Removes project Trivy ignorefile config.
src/projects/node_24_python_3_14_java_24/.trivyignore.yaml Removes project Trivy ignore list.
src/projects/node_24_python_3_14_golang_1_24/trivy.yaml Removes project Trivy ignorefile config.
src/projects/node_24_python_3_14_golang_1_24/.trivyignore.yaml Removes project Trivy ignore list.
src/projects/fhir_facade_api/trivy.yaml Removes project Trivy ignorefile config.
src/projects/fhir_facade_api/.trivyignore.yaml Removes project Trivy ignore list.
src/projects/fhir_facade_api/.devcontainer/.tool-versions Pins Java to a specific patch version.
src/projects/eps-storage-terraform/trivy.yaml Removes project Trivy ignorefile config.
src/projects/eps-storage-terraform/.trivyignore.yaml Removes project Trivy ignore list.
src/languages/node_24_python_3_14/trivy.yaml Removes language image Trivy ignorefile config.
src/languages/node_24_python_3_14/.trivyignore.yaml Removes language image Trivy ignore list.
src/languages/node_24_python_3_14/.devcontainer/scripts/vscode_install.sh Switches to installing user pip tools from a requirements file.
src/languages/node_24_python_3_14/.devcontainer/scripts/requirements-user.txt Adds pinned zizmor and cfn-lint.
src/languages/node_24_python_3_13/trivy.yaml Removes language image Trivy ignorefile config.
src/languages/node_24_python_3_13/.trivyignore.yaml Removes language image Trivy ignore list marker.
src/languages/node_24_python_3_13/.devcontainer/scripts/vscode_install.sh Switches to installing user pip tools from a requirements file.
src/languages/node_24_python_3_13/.devcontainer/scripts/requirements-user.txt Adds pinned zizmor and cfn-lint.
src/languages/node_24_python_3_12/trivy.yaml Removes language image Trivy ignorefile config.
src/languages/node_24_python_3_12/.trivyignore.yaml Removes language image Trivy ignore list marker.
src/languages/node_24_python_3_12/.devcontainer/scripts/vscode_install.sh Switches to installing user pip tools from a requirements file.
src/languages/node_24_python_3_12/.devcontainer/scripts/requirements-user.txt Adds pinned zizmor and cfn-lint.
src/languages/node_24_python_3_10/trivy.yaml Removes language image Trivy ignorefile config.
src/languages/node_24_python_3_10/.trivyignore.yaml Removes language image Trivy ignore list.
src/languages/node_24_python_3_10/.devcontainer/scripts/vscode_install.sh Adds requirements-based pip installs.
src/languages/node_24_python_3_10/.devcontainer/scripts/requirements-user.txt Adds pinned zizmor.
src/common_node_24/Dockerfile Attempts to copy requirements-user.txt into images built from this common Dockerfile.
src/common/.trivyignore.yaml Removes common/base Trivy ignore list.
src/base_node/node_24/trivy.yaml Removes base-node Trivy ignorefile config.
src/base/trivy.yaml Removes base image Trivy ignorefile config.
src/base/.trivyignore.yaml Removes base image Trivy ignore list marker.
src/base/.devcontainer/scripts/vscode_install.sh Removes ASDF Trivy plugin installation.
src/base/.devcontainer/scripts/install_trivy.sh Removes Trivy install script.
src/base/.devcontainer/scripts/install_anchore_tool.sh Adds Syft/Grype installer with signature/checksum verification.
src/base/.devcontainer/Mk/trivy.mk Strips out old commented Trivy target implementations (keeps “Not implemented”).
src/base/.devcontainer/Mk/check.mk Adds zizmor make target.
src/base/.devcontainer/Dockerfile.trivy.arm64 Removes Trivy tool image definition.
src/base/.devcontainer/Dockerfile.trivy.amd64 Removes Trivy tool image definition.
src/base/.devcontainer/Dockerfile.syft Adds Syft tool image definition.
src/base/.devcontainer/Dockerfile.grype Adds Grype tool image definition.
src/base/.devcontainer/Dockerfile Injects Syft/Grype binaries into the base devcontainer image; updates PATH.
scripts/trivy_to_trivyignore.py Removes helper for generating .trivyignore from Trivy JSON output.
README.md Removes Trivy docs; documents zizmor; notes Trivy targets will be removed later.
Makefile Adds build steps for Syft/Grype tool images; replaces Trivy scan targets with Grype scan targets.
.trivyignore.yaml Removes repository-level Trivy ignore list.
.github/workflows/build_multi_arch_image.yml Replaces Trivy setup/scan with Syft/Grype setup + Grype scan + artifact upload.
.devcontainer/Dockerfile.bootstrap Removes Trivy bootstrap installation steps.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +24 to +25
# use glob pattern to copy requirements-user.txt if it exists, to avoid build failure if it doesn't
COPY scripts/requirements-user.tx[t] ${SCRIPTS_DIR}/${CONTAINER_NAME}/requirements-user.txt
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COPY scripts/requirements-user.tx[t] ... does not make the copy optional: Docker expands source globs and the build fails if the pattern matches no files. If the intent is “copy if present”, either ensure scripts/requirements-user.txt always exists in the build context (possibly empty), or handle optional install in vscode_install.sh by checking for the file before running pip install -r.

Suggested change
# use glob pattern to copy requirements-user.txt if it exists, to avoid build failure if it doesn't
COPY scripts/requirements-user.tx[t] ${SCRIPTS_DIR}/${CONTAINER_NAME}/requirements-user.txt
# copy requirements-user.txt into the container; ensure this file exists in the build context (it may be empty)
COPY scripts/requirements-user.txt ${SCRIPTS_DIR}/${CONTAINER_NAME}/requirements-user.txt

Copilot uses AI. Check for mistakes.
Comment on lines +97 to +101
grype "${CONTAINER_PREFIX}$${CONTAINER_NAME}:$${IMAGE_TAG}" \
--scope all-layers \
--output json \
--file ".grype_out/grype_${CONTAINER_NAME}_${IMAGE_TAG}.json" \
--sort-by severity
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scan-image-json writes to .grype_out/... but the target doesn’t create the .grype_out directory, so this will fail on a clean checkout. Add a mkdir -p .grype_out before invoking grype (and consider also writing a text/table output to a file for later inspection in CI).

Copilot uses AI. Check for mistakes.
Comment on lines +103 to +104
name: "grype_${{ inputs.container_name }}_${{ matrix.arch }}.json"
path: .grype_out/grype_${{ inputs.container_name }}_${{ matrix.arch }}.json
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filename produced by scan-image-json is ./.grype_out/grype_${CONTAINER_NAME}_${IMAGE_TAG}.json, but the workflow later uploads .grype_out/grype_${container_name}_${matrix.arch}.json. With IMAGE_TAG set to ${docker_tag}-${arch}, these paths won’t match, so the upload step will fail. Align the Makefile output name with the workflow expectation (or update the workflow to use the Makefile naming).

Suggested change
name: "grype_${{ inputs.container_name }}_${{ matrix.arch }}.json"
path: .grype_out/grype_${{ inputs.container_name }}_${{ matrix.arch }}.json
name: "grype_${{ inputs.container_name }}_${{ inputs.docker_tag }}-${{ matrix.arch }}.json"
path: .grype_out/grype_${{ inputs.container_name }}_${{ inputs.docker_tag }}-${{ matrix.arch }}.json

Copilot uses AI. Check for mistakes.
Comment on lines +112 to +121
- name: Show docker vulnerability output
if: always()
run: |
echo "Scan output for ghcr.io/nhsdigital/eps-devcontainers/base:${DOCKER_TAG}-${ARCHITECTURE}"
if [ -f .out/scan_results_docker.txt ]; then
cat .out/scan_results_docker.txt
fi
env:
ARCHITECTURE: '${{ matrix.arch }}'
DOCKER_TAG: '${{ inputs.docker_tag }}'
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “Show docker vulnerability output” step still checks for .out/scan_results_docker.txt, but make scan-image no longer writes anything to .out/. As written, this step will always print nothing even if the scan finds issues. Either capture grype output to a file (e.g., under .grype_out/) and update this step to cat that file, or remove the step.

Suggested change
- name: Show docker vulnerability output
if: always()
run: |
echo "Scan output for ghcr.io/nhsdigital/eps-devcontainers/base:${DOCKER_TAG}-${ARCHITECTURE}"
if [ -f .out/scan_results_docker.txt ]; then
cat .out/scan_results_docker.txt
fi
env:
ARCHITECTURE: '${{ matrix.arch }}'
DOCKER_TAG: '${{ inputs.docker_tag }}'

Copilot uses AI. Check for mistakes.
Comment on lines +91 to +94
scan-image: guard-CONTAINER_NAME guard-BASE_FOLDER guard-IMAGE_TAG
grype "${CONTAINER_PREFIX}$${CONTAINER_NAME}:$${IMAGE_TAG}" \
--scope all-layers \
--sort-by severity
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scan-image currently runs grype without any explicit failure threshold/severity policy (previous Trivy command gated on HIGH/CRITICAL with --exit-code 1). If this target is meant to enforce vulnerability gating in CI, add the appropriate Grype options (e.g., --fail-on / severity configuration) so the build fails when policy is violated.

Copilot uses AI. Check for mistakes.
@@ -142,7 +119,6 @@ lint-githubaction-scripts:

clean:
rm -rf .out
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clean removes .out but the new scan artifacts are written under .grype_out. Update clean to remove .grype_out as well, otherwise local runs will accumulate stale Grype outputs and CI reruns may upload outdated files if names collide.

Suggested change
rm -rf .out
rm -rf .out .grype_out

Copilot uses AI. Check for mistakes.
Comment on lines +6 to +24
BASE_URL="https://github.com/anchore/${TOOL}/releases/download/v${VERSION}"
ARCHIVE="${TOOL}_${VERSION}_linux_${ARCH}.tar.gz"
CHECKSUMS="${TOOL}_${VERSION}_checksums.txt"
CHECKSUMS_PEM="${TOOL}_${VERSION}_checksums.txt.pem"
CHECKSUMS_SIG="${TOOL}_${VERSION}_checksums.txt.sig"

if [ -z "$TOOL" ]
then
echo "\$TOOL is NULL"
fi
if [ -z "$ARCH" ]
then
echo "\$ARCH is NULL"
fi
if [ -z "$VERSION" ]
then
echo "\$VERSION is NULL"
fi

Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set -euo pipefail means referencing an unset variable aborts the script, but BASE_URL, ARCHIVE, etc. are constructed using ${TOOL}, ${VERSION}, ${ARCH} before you validate them. This will fail with an “unbound variable” error when any are missing, and the later -z checks won’t run. Move validation to the top using ${TOOL:?}, ${VERSION:?}, ${ARCH:?} (or use ${TOOL:-} in checks) and exit non-zero with a clear message when required vars are not set.

Suggested change
BASE_URL="https://github.com/anchore/${TOOL}/releases/download/v${VERSION}"
ARCHIVE="${TOOL}_${VERSION}_linux_${ARCH}.tar.gz"
CHECKSUMS="${TOOL}_${VERSION}_checksums.txt"
CHECKSUMS_PEM="${TOOL}_${VERSION}_checksums.txt.pem"
CHECKSUMS_SIG="${TOOL}_${VERSION}_checksums.txt.sig"
if [ -z "$TOOL" ]
then
echo "\$TOOL is NULL"
fi
if [ -z "$ARCH" ]
then
echo "\$ARCH is NULL"
fi
if [ -z "$VERSION" ]
then
echo "\$VERSION is NULL"
fi
# Validate required environment variables before first use.
: "${TOOL:?Environment variable TOOL must be set (e.g., 'syft' or 'grype')}"
: "${VERSION:?Environment variable VERSION must be set (e.g., '1.0.0')}"
: "${ARCH:?Environment variable ARCH must be set (e.g., 'amd64')}"
BASE_URL="https://github.com/anchore/${TOOL}/releases/download/v${VERSION}"
ARCHIVE="${TOOL}_${VERSION}_linux_${ARCH}.tar.gz"
CHECKSUMS="${TOOL}_${VERSION}_checksums.txt"
CHECKSUMS_PEM="${TOOL}_${VERSION}_checksums.txt.pem"
CHECKSUMS_SIG="${TOOL}_${VERSION}_checksums.txt.sig"

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +23
if [ -z "$TOOL" ]
then
echo "\$TOOL is NULL"
fi
if [ -z "$ARCH" ]
then
echo "\$ARCH is NULL"
fi
if [ -z "$VERSION" ]
then
echo "\$VERSION is NULL"
fi
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if [ -z "$TOOL" ] ... echo ... fi blocks don’t stop execution, so the script will continue (and later curl/cosign/tar/install) even when required inputs are missing. After validating inputs, exit 1 on missing/invalid values (and ideally restrict TOOL to syft|grype to avoid unexpected downloads).

Copilot uses AI. Check for mistakes.
fi

zizmor:
zizmor .
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new zizmor target assumes zizmor is installed in every devcontainer, but the base image’s vscode_install.sh doesn’t install it (and only the Node+Python language images add it via pip install --user). Either install zizmor in the base image so the target works everywhere, or make the target conditional with a clear error message when zizmor isn’t available.

Suggested change
zizmor .
@ if command -v zizmor >/dev/null 2>&1; then \
zizmor .; \
else \
echo "Error: 'zizmor' is not installed in this devcontainer. Install zizmor or use a language image that provides it." >&2; \
exit 1; \
fi

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants