diff --git a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/profile.bashrc b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/profile.bashrc index 4364514f5b..559985a71e 100644 --- a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/profile.bashrc +++ b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/profile.bashrc @@ -94,6 +94,9 @@ cros_pre_pkg_setup_sysroot_build_bin_dir() { PATH+=":${CROS_BUILD_BOARD_BIN}" } +# Source hooks for SLSA build provenance report generation +source "${BASH_SOURCE[0]}.slsa-provenance" + # Insert our sysroot wrappers into the path SYSROOT_WRAPPERS_BIN="/usr/lib64/sysroot-wrappers/bin" if [[ "$PATH" != *"$SYSROOT_WRAPPERS_BIN"* ]]; then diff --git a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/profile.bashrc.slsa-provenance b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/profile.bashrc.slsa-provenance new file mode 100644 index 0000000000..f6eb9ad981 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/base/profile.bashrc.slsa-provenance @@ -0,0 +1,194 @@ +# Build provenance hooks +# ====================== +# The functions below hook into every ebuild's execution and generate provenance files +# to meet the SLSA provenance requirements (https://slsa.dev/spec/v0.1/requirements#available). +# All input files (source tarball / git commit hash) plus added patches / files, +# and all resulting installation binaries and files are captured. +# The information is emitted in SLSA provenance 0.2 format (see https://slsa.dev/provenance/v0.2) + + +# We only record provenance when a package is actually being built. +# See profiles/coreos/base/profile.bashrc for cros_... +cros_post_src_configure_enable_slsa_provenance_report() { + if [ "${GENERATE_SLSA_PROVENANCE:-}" != "true" ] ; then + einfo "Provenance generation not requested by build; skipping." + return 0 + fi + export generate_slsa_provenance_report="yes" +} +# -- + +# Generate SLSA provenance 0.2 Subject information. +# The information will cover all installation files shipped with a package. +__slsa_provenance_subject() { + local parallel="$(nproc)" + local comma="" + + einfo " Provenance: recording subject (output)" + + echo ' "subject": [' + + ( + cd "$D" + find . -type f -print | sed 's:^./::' | xargs -P "$parallel" -L 1 sha512sum | sort -k2 + ) | while read checksum filepath; do + echo -en "${comma} {\"name\":\"/$filepath\", \"digest\":{\"sha512\":\"$checksum\"}}" + if [ -z "$comma" ] ; then + comma=',\n' + fi + done + echo -en "\n ]" +} +# -- + +__slsa_provenance_materials() { + local csum="" uri="" repo="" ebuild="" ebuildcsum="" + + local ebuild="${CATEGORY}/${PN}/${PF}.ebuild" + local repopath="$(portageq get_repo_path ${ROOT:-/} coreos)" + if [ -f "${repopath}/${ebuild}" ] ; then + repo="coreos-overlay" + ebuildcsum=$(sha1sum - < "${repopath}/${ebuild}") + else + repopath="$(portageq get_repo_path ${ROOT:-/} portage-stable)" + if [ -f "${repopath}/${ebuild}" ] ; then + repo="portage-stable" + ebuildcsum=$(sha1sum - < "${repopath}/${ebuild}") + fi + fi + if [ -z "${repo}" ]; then + die "SLSA provenance: Unable to detect ebuild repository for package '${ebuild}'" + fi + ebuildcsum=${ebuildcsum%% *} + + einfo " Provenance: recording ebuild material (input) '${repo}/${ebuild}'" + echo ' "materials": [' + + # The ebuild. Since "configSource" in "invocation" cannot have more than one (top/level) entry + # we add the ebuild and git repo checksum here, as a material. + csum="$(cat "/mnt/host/source/src/scripts/.git/modules/sdk_container/src/third_party/${repo}/HEAD")" + uri="git+https://github.com/flatcar-linux/${repo}.git@${csum}#${ebuild}" + echo -e " { \"uri\": \"${uri}\"," + echo -n " \"digest\": {\"sha1\":\"${ebuildcsum}\"} }" + + # The main sources + if [ -n "${A}" ] ; then + # Package is built from downloaded source tarball(s) + # There can be multiple, and can be used conditionally based on use flags, + # and even replaced with different local names ("http://... -> othername.tgz"). So + # we go through what's actually used ($A), then find the corresponding source URI. + local src="" prev_uri="" rename="false" orig_name="" + for src in ${A}; do + local found="false" + for uri in ${SRC_URI}; do + if [ "${uri}" = "->" ] ; then + rename="true" + continue + fi + if [ "${src}" = "$(basename "${uri}")" ] ; then + orig_name="${src}" + if [ "${rename}" = "true" ] ; then + uri="${prev_uri}" + orig_name="$(basename "${uri}")" + fi + einfo " Provenance: recording tarball material (input) '${src}' ('${orig_name}')" + csum="$(sha512sum "${DISTDIR}/${src}" | cut -d' ' -f1)" + echo -e ",\n { \"uri\": \"${uri}\"," + echo -n " \"digest\": {\"sha512\":\"${csum}\"} }" + found="true" + fi + rename="false" + prev_uri="${uri}" + done + if [ "${found}" != "true" ] ; then + die "No SRC_URI found for source '${src}', unable to record provenance!" + fi + done + elif [ -n "${EGIT_REPO_URI:-}" ] ; then + # package is built from repo checkout (git) + einfo " Provenance: recording GIT material (input) '${EGIT_REPO_URI}'" + csum="${EGIT_COMMIT}" + uri="${EGIT_REPO_URI}" + echo -e ",\n { \"uri\": \"${uri}\"," + echo -n " \"digest\": {\"sha1\":\"$csum\"} }" + fi + + # Patches / files shipped with the ebuild (if any) + csum="$(cat "/mnt/host/source/src/scripts/.git/modules/sdk_container/src/third_party/${repo}/HEAD")" + uri="git+https://github.com/flatcar-linux/${repo}.git@${csum}#${CATEGORY}/${PN}/files" + if [ -d "${FILESDIR}" ] ; then + for file in $(cd "$FILESDIR" && find . -type f | sed 's:^./::') ; do + csum="$(sha1sum - <"${FILESDIR}/${file}")" + csum="${csum%% *}" + einfo " Provenance: recording ebuild material (input) '${file}'" + echo -e ",\n { \"uri\": \"${uri}/${file}\"," + echo -n " \"digest\": {\"sha1\":\"$csum\"} }" + done + fi + + echo -ne '\n ]' +} +# -- + +__slsa_provenance_report() { + local scripts_hash="$(cat "/mnt/host/source/src/scripts/.git/HEAD")" + local buildcmd="emerge" + # extract board from e.g. '/build/amd64-usr/build'. Empty if no board is set (SDK build). + local board="$(echo "${CROS_BUILD_BOARD_TREE:-}" | sed -n 's:^/build/\([^/]\+\)/.*:\1:p')" + if [ -n "$board" ] ; then + buildcmd="emerge-${board}" + fi + if [[ "${scripts_hash}" == "ref:"* ]]; then + scripts_hash="$(cat /mnt/host/source/src/scripts/.git/${scripts_hash#ref: })" + fi + + # FIXME: Supply SDK image ID and sha256 digest along with the version tag + local sdk_version="$(source /mnt/host/source/.repo/manifests/version.txt; echo ${FLATCAR_SDK_VERSION})" + + # FIXME: add builder ID +cat < "${T}/${report_file}" + + mkdir -p "${dest_dir}" + mv "${T}/${report_file}" "${dest_dir}" +}