Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: multiplatform sbom and vulnscan #160

Merged
merged 18 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
.task/*
sbom.*.json
vulns.*.json
seiso_goat:*.tar

# Created by https://www.toptal.com/developers/gitignore/api/vim,emacs,vs,python,node,macos
# Edit at https://www.toptal.com/developers/gitignore?templates=vim,emacs,vs,python,node,macos
Expand Down
109 changes: 89 additions & 20 deletions Task/Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ set:
- pipefail

vars:
# Inspired by https://github.com/containerd/containerd/blob/e0912c068b131b33798ae45fd447a1624a6faf0a/platforms/database.go#L76
LOCAL_PLATFORM:
sh: |
os="linux"
Expand Down Expand Up @@ -91,7 +92,6 @@ tasks:
VERSION: '{{.VERSION}}'
PLATFORM: '{{if eq .PLATFORM "all"}}{{.SUPPORTED_PLATFORMS}}{{else if .PLATFORM}}{{.PLATFORM}}{{else}}{{.LOCAL_PLATFORM}}{{end}}'
PUBLISH: '{{.PUBLISH | default "false"}}'
DOCKER_BUILDX_CUSTOM_ARGS: '{{.DOCKER_BUILDX_CUSTOM_ARGS | default ""}}'
TAG_COMMIT_HASH:
sh: git rev-list -1 "v{{.VERSION}}"
COMMIT_HASH:
Expand All @@ -116,25 +116,30 @@ tasks:
else:
build_version = f"{{.VERSION}}-{{.COMMIT_HASH_SHORT}}"
print(build_version)'
OUTPUT_FILE: '{{.IMAGE_NAME | replace "/" "_"}}:{{.BUILD_VERSION}}_{{.PLATFORM | replace "/" "_"}}.tar'
DOCKER_BUILDX_CUSTOM_ARGS: '{{.DOCKER_BUILDX_CUSTOM_ARGS | default ""}}'
DOCKER_BUILDX_DOCKERFILE: '{{.DOCKER_BUILDX_DOCKERFILE | default "."}}'
DOCKER_BUILDX_BUILDARGS: '{{.DOCKER_BUILDX_BUILDARGS | default "--build-arg VERSION=\"{{.BUILD_VERSION}}\" --build-arg COMMIT_HASH=\"{{.COMMIT_HASH}}\""}}'
DOCKER_BUILDX_TAGS: '{{.DOCKER_BUILDX_TAGS | default "--tag \"{{.IMAGE_NAME}}:latest\" --tag \"{{.IMAGE_NAME}}:{{.BUILD_VERSION}}\""}}'
cmds:
# We only load when the provided platform equals the detected local platform. This is for two reasons:
# 1. We assume you don't want to load a cross-platform build
# 2. Currently (2023-07-30) you cannot --load if you are building multiple platforms
#
# Also, we make load and push mutually exclusive because docker says "ERROR: push and load may not be set together at the moment"
#
# Finally, we combine this all together in one `docker buildx build` with `--push` when {{.PUBLISH}} is true so that it handles the multi-platform
# manifest creation for us. Otherwise we'd need to push per-platform tags and artisanally craft the manifest with `crane`, `docker manifest`, or similar
# If we aren't loading or pushing, we dump an OCI-formatted artifact out to disk
#
# We leverage `docker buildx build` with `--push` to make a multi-platform manifest when {{.PUBLISH}} is true. Otherwise we'd need to push per-platform
# tags and artisanally craft the multi-platform manifest with a tool like `crane`, `docker manifest`, or similar
- |
docker buildx build --platform="{{.PLATFORM}}" \
{{if eq .PUBLISH "true"}}--push{{else if eq .PLATFORM .LOCAL_PLATFORM}}--load{{end}} \
{{if eq .PUBLISH "true"}}--push{{else if eq .PLATFORM .LOCAL_PLATFORM}}--load{{else}}-o type=oci,dest="{{.OUTPUT_FILE}}"{{end}} \
JonZeolla marked this conversation as resolved.
Show resolved Hide resolved
{{if .DOCKER_BUILDX_CUSTOM_ARGS}}{{.DOCKER_BUILDX_CUSTOM_ARGS}}{{end}} \
--build-arg VERSION="{{.BUILD_VERSION}}" \
JonZeolla marked this conversation as resolved.
Show resolved Hide resolved
--build-arg COMMIT_HASH="{{.COMMIT_HASH}}" \
--tag {{.IMAGE_NAME}}:latest \
--tag {{.IMAGE_NAME}}:{{.BUILD_VERSION}} \
"${PWD}/."
- '{{if ne .PLATFORM .LOCAL_PLATFORM}}{{if ne .PUBLISH "true"}}echo "WARNING: Avoided loading {{.IMAGE_NAME}}:latest and {{.IMAGE_NAME}}:{{.BUILD_VERSION}} into your docker daemon because you built a cross-platform image of {{.PLATFORM}}"{{end}}{{end}}'
{{.DOCKER_BUILDX_BUILDARGS}} \
{{.DOCKER_BUILDX_TAGS}} \
"{{.DOCKER_BUILDX_DOCKERFILE}}"
- '{{if ne .PLATFORM .LOCAL_PLATFORM}}{{if ne .PUBLISH "true"}}echo "WARNING: Avoided loading {{.IMAGE_NAME}}:latest and {{.IMAGE_NAME}}:{{.BUILD_VERSION}} into your docker daemon because you built a cross-platform image of {{.PLATFORM}}.{{if ne .PUBLISH "true"}} See {{.OUTPUT_FILE}} for the OCI artifact.{{end}}"{{end}}{{end}}'
JonZeolla marked this conversation as resolved.
Show resolved Hide resolved

release:
desc: Cut a project release
Expand Down Expand Up @@ -241,6 +246,7 @@ tasks:
- find {{.ROOT_DIR}} -type d -name '.task' -exec rm -rf {} +
- find {{.ROOT_DIR}} -type f -name 'sbom.*.json' -delete
- find {{.ROOT_DIR}} -type f -name 'vulns.*.json' -delete
- find {{.ROOT_DIR}} -type f -name 'seiso_*:*.tar' -delete
JonZeolla marked this conversation as resolved.
Show resolved Hide resolved

sbom:
desc: Generate project SBOMs
Expand All @@ -249,25 +255,88 @@ tasks:
- sh: which syft
msg: "Syft must be installed and reasonably current"
vars:
IMAGE_AND_TAG: '{{.IMAGE_NAME}}:{{.VERSION}}'
PLATFORM: '{{if eq .PLATFORM "all"}}{{.SUPPORTED_PLATFORMS}}{{else if .PLATFORM}}{{.PLATFORM}}{{else}}{{.LOCAL_PLATFORM}}{{end}}'
# This duplicates some build logic; consider centralizing
JonZeolla marked this conversation as resolved.
Show resolved Hide resolved
TAG_COMMIT_HASH:
sh: git rev-list -1 "v{{.VERSION}}"
COMMIT_HASH:
sh: git rev-parse HEAD
COMMIT_HASH_SHORT:
sh: git rev-parse --short HEAD
REPO_TAGS:
sh: git tag -l
BUILD_VERSION:
sh: |
pipenv run python -c '
version_string = "v{{.VERSION}}"
repo_tags = []
{{range $tag := .REPO_TAGS | splitLines -}}
repo_tags.append("{{$tag}}")
{{end}}
if (
version_string in repo_tags
and "{{.TAG_COMMIT_HASH}}" == "{{.COMMIT_HASH}}"
):
build_version = "{{.VERSION}}"
else:
build_version = f"{{.VERSION}}-{{.COMMIT_HASH_SHORT}}"
print(build_version)'
IMAGE_AND_TAG: '{{.IMAGE_NAME}}:{{.BUILD_VERSION}}'
SANITIZED_IMAGE_AND_TAG: '{{.IMAGE_AND_TAG | replace "/" "_"}}'
cmds:
- for:
var: PLATFORM
split: ','
as: platform
task: build
vars:
PLATFORM: '{{.platform}}'
DOCKER_BUILDX_TAGS: '--tag {{.IMAGE_AND_TAG}}-{{.platform | replace "/" "_"}}'
- for:
var: PLATFORM
split: ','
as: platform
cmd: |
export sanitized_platform=$(echo "{{.platform}}" | sed "s%/%_%g") \
&& syft docker:{{.IMAGE_AND_TAG}} --platform {{.platform}} \
-o json=sbom.{{.PROJECT_SLUG}}.{{.VERSION}}.${sanitized_platform}.json \
-o spdx-json=sbom.{{.PROJECT_SLUG}}.{{.VERSION}}.${sanitized_platform}.spdx.json \
-o cyclonedx-json=sbom.{{.PROJECT_SLUG}}.{{.VERSION}}.${sanitized_platform}.cyclonedx.json
export base_name='{{.SANITIZED_IMAGE_AND_TAG}}_{{.platform | replace "/" "_" }}' \
&& export syft_command="{{if ne .platform .LOCAL_PLATFORM}}oci-archive:${base_name}.tar{{else}}docker:{{.IMAGE_AND_TAG}}{{end}}" \
&& syft "${syft_command}" {{if eq .PLATFORM .LOCAL_PLATFORM}}--platform {{.platform}}{{end}} \
-o json=sbom.${base_name}.syft.json \
-o spdx-json=sbom.${base_name}.spdx.json \
-o cyclonedx-json=sbom.${base_name}.cyclonedx.json


vulnscan:
desc: Vuln scan the SBOM
dir: ../../..
vars:
PLATFORM: '{{if eq .PLATFORM "all"}}{{.SUPPORTED_PLATFORMS}}{{else if .PLATFORM}}{{.PLATFORM}}{{else}}{{.LOCAL_PLATFORM}}{{end}}'
# This duplicates some build logic; consider centralizing
TAG_COMMIT_HASH:
sh: git rev-list -1 "v{{.VERSION}}"
COMMIT_HASH:
sh: git rev-parse HEAD
COMMIT_HASH_SHORT:
sh: git rev-parse --short HEAD
REPO_TAGS:
sh: git tag -l
BUILD_VERSION:
sh: |
pipenv run python -c '
version_string = "v{{.VERSION}}"
repo_tags = []
{{range $tag := .REPO_TAGS | splitLines -}}
repo_tags.append("{{$tag}}")
{{end}}
if (
version_string in repo_tags
and "{{.TAG_COMMIT_HASH}}" == "{{.COMMIT_HASH}}"
):
build_version = "{{.VERSION}}"
else:
build_version = f"{{.VERSION}}-{{.COMMIT_HASH_SHORT}}"
print(build_version)'
IMAGE_AND_TAG: '{{.IMAGE_NAME}}:{{.BUILD_VERSION}}'
SANITIZED_IMAGE_AND_TAG: '{{.IMAGE_AND_TAG | replace "/" "_"}}'
preconditions:
- sh: which grype
msg: "Grype must be installed and reasonably current"
Expand All @@ -277,7 +346,7 @@ tasks:
split: ','
as: platform
cmd: |
export sanitized_platform=$(echo "{{.platform}}" | sed "s%/%_%g") \
&& grype sbom:sbom.{{.PROJECT_SLUG}}.{{.VERSION}}.${sanitized_platform}.json \
--output json \
--file vulns.{{.PROJECT_SLUG}}.{{.VERSION}}.${sanitized_platform}.json
export base_name='{{.SANITIZED_IMAGE_AND_TAG}}_{{.platform | replace "/" "_" }}' \
&& grype "sbom:sbom.${base_name}.syft.json" \
--output json \
--file "vulns.${base_name}.json"
Loading