@@ -319,9 +319,52 @@ def build_command:
319319
320320 # TODO consider / check what "crane validate" does and if it would be appropriate here
321321
322- # TODO generate SBOM? ... somehow
323-
324- empty
322+ if build_should_sbom then
323+ # we'll trick BuildKit into generating an SBOM for us, then inject it into our OCI layout
324+ "# SBOM" ,
325+ "originalImageManifest=\" $(jq -r '.manifests[0].digest' temp/index.json)\" " ,
326+ (
327+ [
328+ @sh "SOURCE_DATE_EPOCH=\( .source.entry.SOURCE_DATE_EPOCH ) " ,
329+ "docker buildx build --progress=plain" ,
330+ "--load=false" , "--provenance=false" , # explicitly disable a few features we want to avoid
331+ "--build-arg BUILDKIT_DOCKERFILE_CHECK=skip=all" , # disable linting (https://github.com/moby/buildkit/pull/4962)
332+ "--sbom=generator=\" $BASHBREW_BUILDKIT_SBOM_GENERATOR\" " ,
333+ "--output 'type=oci,tar=false,dest=sbom'" ,
334+ # TODO also add appropriate "--tag" lines (which would give us a mostly correct "subject" block in the generated SBOM, but we'd then need to replace instances of ${sbomImageManifest#*:} with ${originalImageManifest#*:} for their values to be correct)
335+ @sh "--platform \( .source.arches [.build.arch ].platformString ) " ,
336+ "--build-context \" fake=oci-layout://$PWD/temp@$originalImageManifest\" " ,
337+ "- <<<'FROM fake'" , # note: "<<<" is a bashism (so this output must be invoked via bash)
338+ empty
339+ ] | join (" \\\n\t " )
340+ ),
341+ "sbomIndex=\" $(jq -r '.manifests[0].digest' sbom/index.json)\" " ,
342+ @sh "shell=\" $(jq -r --arg originalImageManifest \" $originalImageManifest\" \( "
343+ # https://docs.docker.com/build/attestations/attestation-storage/
344+ first(
345+ .manifests[]
346+ | select(.annotations[\" vnd.docker.reference.type\" ] == \" attestation-manifest\" )
347+ ) as $attDesc
348+ | @sh \" sbomManifest=\\ ($attDesc.digest)\" ,
349+ @sh \" sbomManifestDesc=\\ (
350+ $attDesc
351+ | .annotations[\" vnd.docker.reference.digest\" ] = $originalImageManifest
352+ | tojson
353+ )\"
354+ " | unindent_and_decomment_jq (4 )) \" sbom/blobs/${sbomIndex/://}\" )\" " ,
355+ "eval \" $shell\" " ,
356+ @sh "shell=\" $(jq -r \( "
357+ \" copyBlobs=( \\ ([ .config.digest, .layers[].digest | @sh ] | join(\" \" )) )\"
358+ " | unindent_and_decomment_jq (4 )) \" sbom/blobs/${sbomManifest/://}\" )\" " ,
359+ "eval \" $shell\" " ,
360+ "copyBlobs+=( \" $sbomManifest\" )" ,
361+ "for blob in \" ${copyBlobs[@]}\" ; do" ,
362+ "\t cp \" sbom/blobs/${blob/://}\" \" temp/blobs/${blob/://}\" " ,
363+ "done" ,
364+ "jq -r --argjson sbomManifestDesc \" $sbomManifestDesc\" '.manifests += [ $sbomManifestDesc ]' temp/index.json > temp/index.json.new" ,
365+ "mv temp/index.json.new temp/index.json" ,
366+ empty
367+ else empty end
325368 ] | join ("\n " )
326369 else
327370 error ("unknown/unimplemented Builder: \( $builder ) " )
0 commit comments