11"rules for signing, attesting and pushing images"
22
33load ("@bazel_skylib//rules:write_file.bzl" , "write_file" )
4- load ("@rules_oci//cosign:defs.bzl" , "cosign_attest" , "cosign_sign" )
5- load ("@rules_oci//oci:defs.bzl" , "oci_push" )
64load ("//private/pkg:oci_image_spdx.bzl" , "oci_image_spdx" )
5+ load (":digest.bzl" , "digest" )
76
87PUSH_AND_SIGN_CMD = """\
8+ # Push {IMAGE}
99repository="$(stamp "{REPOSITORY}")"
10- tag="$(stamp "{TAG}")"
11-
12- [[ -n $EXPORT ]] && echo "$repository:$tag" >> $EXPORT
13-
14- # Push the image by its digest
15- "$(realpath {PUSH_CMD})" --repository "$repository"
16-
17- # Attest the sbom
18- GOOGLE_SERVICE_ACCOUNT_NAME="$KEYLESS" "$(realpath {ATTEST_CMD})" --repository "$repository" --yes
19-
20- # Sign keyless by using an identity
21- GOOGLE_SERVICE_ACCOUNT_NAME="$KEYLESS" "$(realpath {SIGN_CMD})" --repository "$repository" --yes
10+ digest="$(cat {DIGEST})"
11+ echo "Pushing $repository@$digest"
12+ {CRANE} push {IMAGE} "$repository@$digest"
13+ {COSIGN} attest "$repository@$digest" --predicate "{SBOM}" --type "spdx" --yes
14+ {COSIGN} sign "$repository@$digest" --yes
15+ """
2216
23- # Tag the image
24- "$(realpath {PUSH_CMD})" --repository "$repository" --tag "$tag"
17+ TAG_CMD = """\
18+ # Tag {IMAGE}
19+ from="$(stamp "{FROM}")"
20+ to="$(stamp "{TO}")"
21+ {CRANE} copy "$from" "$to"
2522"""
2623
2724def _sign_and_push_impl (ctx ):
2825 cmds = []
29- runfiles = ctx .runfiles (files = ctx .files .targets + [ctx .version_file ])
3026
31- for (target , url ) in ctx .attr .targets .items ():
27+ runfiles = ctx .runfiles (files = ctx .files .targets + [ctx .version_file , ctx .file ._crane , ctx .file ._cosign ])
28+
29+ for (image , target ) in ctx .attr .targets .items ():
3230 files = target [DefaultInfo ].files .to_list ()
33- runfiles = runfiles .merge (target [DefaultInfo ].default_runfiles )
34- repository_and_tag = url .split (":" )
31+
32+ all_refs = ctx .attr .refs [image ]
33+ first_ref = all_refs [0 ]
34+ repository_and_tag = first_ref .split (":" )
3535 cmds .append (
3636 PUSH_AND_SIGN_CMD .format (
37- ATTEST_CMD = files [0 ].short_path ,
38- SIGN_CMD = files [1 ].short_path ,
39- PUSH_CMD = files [2 ].short_path ,
37+ IMAGE = files [0 ].short_path ,
38+ SBOM = files [1 ].short_path ,
39+ DIGEST = files [2 ].short_path ,
40+ CRANE = ctx .file ._crane .short_path ,
41+ COSIGN = ctx .file ._cosign .short_path ,
4042 REPOSITORY = repository_and_tag [0 ],
4143 TAG = repository_and_tag [1 ],
4244 ),
4345 )
4446
47+ for ref in all_refs [1 :]:
48+ cmds .append (
49+ TAG_CMD .format (
50+ IMAGE = image ,
51+ FROM = first_ref ,
52+ TO = ref ,
53+ CRANE = ctx .file ._crane .short_path ,
54+ ),
55+ )
56+
4557 executable = ctx .actions .declare_file ("{}_sign_and_push.sh" .format (ctx .label .name ))
4658 ctx .actions .expand_template (
4759 template = ctx .file ._push_tpl ,
@@ -58,8 +70,11 @@ def _sign_and_push_impl(ctx):
5870sign_and_push = rule (
5971 implementation = _sign_and_push_impl ,
6072 attrs = {
61- "targets" : attr .label_keyed_string_dict (mandatory = True , cfg = "exec" ),
73+ "refs" : attr .string_list_dict (mandatory = True ),
74+ "targets" : attr .string_keyed_label_dict (mandatory = True , cfg = "exec" ),
6275 "_push_tpl" : attr .label (default = "sign_and_push.sh.tpl" , allow_single_file = True ),
76+ "_crane" : attr .label (allow_single_file = True , cfg = "exec" , default = "@oci_crane_toolchains//:current_toolchain" ),
77+ "_cosign" : attr .label (allow_single_file = True , cfg = "exec" , default = "@oci_cosign_toolchains//:current_toolchain" ),
6378 },
6479 executable = True ,
6580)
@@ -69,59 +84,53 @@ def sign_and_push_all(name, images):
6984
7085 Args:
7186 name: name of the target
72- images: a dict where keys are fully qualified image url and values are image labels
87+ images: a dict where keys are fully qualified image reference and values are image label
7388 """
74- image_dict = dict ()
75- query_dict = dict ()
76- for (idx , (url , image )) in enumerate (images .items ()):
77- oci_push (
78- name = "{}_{}_push" .format (name , idx ),
79- image = image ,
80- repository = "repository.default.local" ,
81- )
89+
90+ dedup_image_dict = dict ()
91+ dedup_push_dict = dict ()
92+
93+ for (idx , (ref , image )) in enumerate (images .items ()):
94+ if image in dedup_image_dict :
95+ dedup_image_dict [image ].append (ref )
96+ else :
97+ dedup_image_dict [image ] = [ref ]
98+
99+ for (idx , (image , ref )) in enumerate (dedup_image_dict .items ()):
82100 oci_image_spdx (
83101 name = "{}_{}_sbom" .format (name , idx ),
84102 image = image ,
85103 )
86- cosign_attest (
87- name = "{}_{}_attest" .format (name , idx ),
88- image = image ,
89- type = "spdx" ,
90- predicate = "{}_{}_sbom" .format (name , idx ),
91- repository = "repository.default.local" ,
92- )
93- cosign_sign (
94- name = "{}_{}_sign" .format (name , idx ),
104+ digest (
105+ name = "{}_{}_digest" .format (name , idx ),
95106 image = image ,
96- repository = "repository.default.local" ,
97107 )
108+
98109 native .filegroup (
99110 name = "{}_{}" .format (name , idx ),
100111 srcs = [
101- ":{}_{}_attest" . format ( name , idx ) ,
102- ":{}_{}_sign " .format (name , idx ),
103- ":{}_{}_push " .format (name , idx ),
112+ image ,
113+ ":{}_{}_sbom " .format (name , idx ),
114+ ":{}_{}_digest " .format (name , idx ),
104115 ],
105116 )
106117
107- image_dict [":{}_{}" .format (name , idx )] = url
108- query_dict [image ] = url .split (":" ) + [":{}_{}_push" .format (name , idx )]
118+ dedup_push_dict [image ] = "{}_{}" .format (name , idx )
109119
110120 write_file (
111121 name = name + ".query" ,
112122 content = [
113- "{repo} {tag} {push_label} {image_label}" .format (
114- repo = ref [0 ],
115- tag = ref [1 ],
116- push_label = ref [2 ],
117- image_label = image ,
123+ "{repo} {image}" .format (
124+ repo = refs [0 ],
125+ image = image ,
118126 )
119- for (image , ref ) in query_dict .items ()
127+ for (image , refs ) in dedup_image_dict .items ()
120128 ],
121129 out = name + "_query" ,
122130 )
123131
124132 sign_and_push (
125133 name = name ,
126- targets = image_dict ,
134+ targets = dedup_push_dict ,
135+ refs = dedup_image_dict ,
127136 )
0 commit comments