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

Stacks - receipt.sh script - multi arch support #992

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
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
113 changes: 91 additions & 22 deletions stack/scripts/receipts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ set -o pipefail
readonly PROG_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly STACK_DIR="$(cd "${PROG_DIR}/.." && pwd)"
readonly BIN_DIR="${STACK_DIR}/.bin"
readonly BUILD_DIR="${STACK_DIR}/build"
readonly DEFAULT_BUILD_DIR="${STACK_DIR}/build"

# shellcheck source=SCRIPTDIR/.util/tools.sh
source "${PROG_DIR}/.util/tools.sh"
Expand All @@ -15,11 +15,13 @@ source "${PROG_DIR}/.util/tools.sh"
source "${PROG_DIR}/.util/print.sh"

function main() {
local build run buildReceipt runReceipt
build="${BUILD_DIR}/build.oci"
run="${BUILD_DIR}/run.oci"
buildReceipt="${BUILD_DIR}/build-receipt.cyclonedx.json"
runReceipt="${BUILD_DIR}/run-receipt.cyclonedx.json"
local build run receiptFilename buildReceipt runReceipt receipts
build="${DEFAULT_BUILD_DIR}/build.oci"
run="${DEFAULT_BUILD_DIR}/run.oci"
receiptFilename="receipt.cyclonedx.json"
buildReceipt="${DEFAULT_BUILD_DIR}/build-${receiptFilename}"
runReceipt="${DEFAULT_BUILD_DIR}/run-${receiptFilename}"
build_image_specified=false

while [[ "${#}" != 0 ]]; do
case "${1}" in
Expand All @@ -31,6 +33,7 @@ function main() {

--build-image|-b)
build="${2}"
build_image_specified=true
shift 2
;;

Expand Down Expand Up @@ -61,10 +64,18 @@ function main() {

tools::install

receipts::generate "${build}" "${buildReceipt}"
receipts::generate "${run}" "${runReceipt}"
# If the build image is specified, then the build directory
# is differenet from the default
if [ $build_image_specified = true ]; then
build_dir=$(dirname "${build}")
else
build_dir="${DEFAULT_BUILD_DIR}"
fi

util::print::success "Success! Receipts are:\n ${buildReceipt}\n ${runReceipt}\n"
# We are generating receipts for all platforms
receiptFilenames=$(receipts::generate::multi::arch "${build}" "${run}" "${buildReceipt}" "${runReceipt}" "${build_dir}")

util::print::success "Success! Receipts are:\n${receiptFilenames}"
}

function usage() {
Expand All @@ -77,31 +88,89 @@ stack.
OPTIONS
--help -h prints the command usage
--build-image -b path to OCI image of build image. Defaults to
${BUILD_DIR}/build.oci
${DEFAULT_BUILD_DIR}/build.oci
--run-image -r path to OCI image of build image
${BUILD_DIR}/run.oci
${DEFAULT_BUILD_DIR}/run.oci
--build-receipt -B path to output build image package receipt. Defaults to
${BUILD_DIR}/build-receipt.txt
${DEFAULT_BUILD_DIR}/build-receipt.cyclonedx.json
--run-receipt -R path to output run image package receipt. Defaults to
${BUILD_DIR}/run-receipt.txt
${DEFAULT_BUILD_DIR}/run-receipt.cyclonedx.json
USAGE
}

function tools::install() {
util::tools::crane::install \
--directory "${BIN_DIR}"
util::tools::jam::install \
--directory "${BIN_DIR}"
util::tools::syft::install \
--directory "${BIN_DIR}"
}

function receipts::generate() {
local image output

image="${1}"
output="${2}"

util::print::title "Generating package SBOM for ${image}"
# Generates syft receipts for each architecture for given oci archives
function receipts::generate::multi::arch() {
local buildArchive runArchive
local registryPort registryPid localRegistry
local imageType archiveName imageReceipt receiptFilenames

receiptFilenames=""
buildArchive="${1}"
runArchive="${2}"
buildOutput="${3}"
runOutput="${4}"
build_dir="${5}"

registryPort=$(get::random::port)
registryPid=$(local::registry::start $registryPort)
localRegistry="127.0.0.1:$registryPort"

# Push the oci archives to the local registry
jam publish-stack \
--build-ref "$localRegistry/build" \
--build-archive $buildArchive \
--run-ref "$localRegistry/run" \
--run-archive $runArchive >/dev/null

# Ensure we can write to the build_dir
if [ $(stat -c %u $build_dir) = "0" ]; then
sudo chown -R "$(id -u):$(id -g)" "$build_dir"
fi

for archivePath in "${buildArchive}" "${runArchive}" ; do
archiveName=$(basename "${archivePath}") # either 'build.oci' or 'run.oci'
imageType=$(basename -s .oci "${archivePath}") # either 'build' or 'run'

util::print::title "Generating package SBOM for ${archiveName}"

for imageArch in $(crane manifest "$localRegistry/$imageType" | jq -r '.manifests[].platform.architecture'); do

if [[ "$imageType" = "build" ]]; then
dir=$(dirname ${buildOutput})
fileName=$(basename ${buildOutput})
elif [[ "$imageType" = "run" ]]; then
dir=$(dirname ${runOutput})
fileName=$(basename ${runOutput})
fi

if [ $imageArch = "amd64" ]; then
imageReceipt="${dir}/${fileName}"
else
imageReceipt="${dir}/${imageArch}-${fileName}"
fi

util::print::info "Generating CycloneDX package SBOM using syft for $archiveName on platform linux/$imageArch saved as $imageReceipt"

# Generate the architecture-specific SBOM from image in the local registry
syft scan "registry:$localRegistry/$imageType" \
--output cyclonedx-json="$imageReceipt" \
--platform "linux/$imageArch"

receiptFilenames+="$imageReceipt\n"
done
done

util::print::info "Generating CycloneDX package SBOM using syft"
syft packages "${image}" --output cyclonedx-json --file "${output}"
kill $registryPid
echo $receiptFilenames
}

main "${@:-}"
Loading