Skip to content

Commit f11bcca

Browse files
authored
Merge branch 'main' into cb_windows
2 parents 0948fc9 + 55f7e9d commit f11bcca

20 files changed

+310
-34
lines changed

cosign/private/attest.bzl

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,25 @@ cosign_attest(
3131
```
3232
3333
via `bazel run :attest_spdx -- --repository=index.docker.io/org/test`
34+
35+
You can also omit the `repository` attribute and provide it at runtime.
36+
```starlark
37+
cosign_attest(
38+
name = "attest_no_repo",
39+
image = ":image",
40+
predicate = "image.sbom.spdx.json",
41+
type = "spdx",
42+
)
43+
```
44+
Then run `bazel run :attest_no_repo -- --repository=index.docker.io/org/test`
3445
"""
3546

3647
_attrs = {
3748
"image": attr.label(allow_single_file = True, mandatory = True, doc = "Label to an oci_image"),
3849
"type": attr.string(values = ["slsaprovenance", "link", "spdx", "vuln", "custom"], mandatory = True, doc = "Type of predicate. Acceptable values are (slsaprovenance|link|spdx|vuln|custom)"),
3950
"predicate": attr.label(allow_single_file = True, mandatory = True, doc = "Label to the predicate file. Only files are allowed. eg: sbom.spdx, in-toto.json"),
40-
"repository": attr.string(mandatory = True, doc = """\
41-
Repository URL where the image will be signed at, e.g.: `index.docker.io/<user>/image`.
42-
Digests and tags are not allowed.
51+
"repository": attr.string(doc = """ Repository URL where the image will be signed at, e.g.: `index.docker.io/<user>/image`.
52+
Digests and tags are not allowed. If this attribute is not set, the repository must be passed at runtime via the `--repository` flag.
4353
"""),
4454
"_attest_sh_tpl": attr.label(default = "attest.sh.tpl", allow_single_file = True),
4555
}
@@ -48,17 +58,17 @@ def _cosign_attest_impl(ctx):
4858
cosign = ctx.toolchains["@rules_oci//cosign:toolchain_type"]
4959
jq = ctx.toolchains["@aspect_bazel_lib//lib:jq_toolchain_type"]
5060

51-
if ctx.attr.repository.find(":") != -1 or ctx.attr.repository.find("@") != -1:
61+
if ctx.attr.repository and (ctx.attr.repository.find(":") != -1 or ctx.attr.repository.find("@") != -1):
5262
fail("repository attribute should not contain digest or tag.")
5363

5464
fixed_args = [
55-
"--repository",
56-
ctx.attr.repository,
5765
"--predicate",
5866
ctx.file.predicate.short_path,
5967
"--type",
6068
ctx.attr.type,
6169
]
70+
if ctx.attr.repository:
71+
fixed_args.extend(["--repository", ctx.attr.repository])
6272

6373
executable = ctx.actions.declare_file("cosign_attest_{}.sh".format(ctx.label.name))
6474
ctx.actions.expand_template(

cosign/private/attest.sh.tpl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ readonly IMAGE_DIR="{{image_dir}}"
77
readonly DIGEST=$("${JQ}" -r '.manifests[].digest' "${IMAGE_DIR}/index.json")
88
readonly FIXED_ARGS=({{fixed_args}})
99

10-
1110
# set $@ to be FIXED_ARGS+$@
12-
ARGS=(${FIXED_ARGS[@]} $@)
13-
set -- ${ARGS[@]}
11+
ALL_ARGS=(${FIXED_ARGS[@]+"${FIXED_ARGS[@]}"} "$@")
12+
if [[ ${#ALL_ARGS[@]} -gt 0 ]]; then
13+
set -- "${ALL_ARGS[@]}"
14+
fi
1415

1516
REPOSITORY=""
1617
ARGS=()
@@ -23,5 +24,10 @@ while (( $# > 0 )); do
2324
esac
2425
done
2526

27+
if [[ -z "${REPOSITORY}" ]]; then
28+
echo "ERROR: repository not set. Please pass --repository flag or set the 'repository' attribute in the rule." >&2
29+
exit 1
30+
fi
31+
2632
exec "${COSIGN}" attest "${REPOSITORY}@${DIGEST}" ${ARGS[@]+"${ARGS[@]}"}
2733

cosign/private/sign.bzl

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,21 @@ cosign_sign(
3131
```
3232
3333
run `bazel run :sign -- --repository=index.docker.io/org/test`
34+
35+
You can also omit the `repository` attribute and provide it at runtime.
36+
```starlark
37+
cosign_sign(
38+
name = "sign_no_repo",
39+
image = ":image",
40+
)
41+
```
42+
Then run `bazel run :sign_no_repo -- --repository=index.docker.io/org/test`
3443
"""
3544

3645
_attrs = {
3746
"image": attr.label(allow_single_file = True, mandatory = True, doc = "Label to an oci_image"),
38-
"repository": attr.string(mandatory = True, doc = """\
39-
Repository URL where the image will be signed at, e.g.: `index.docker.io/<user>/image`.
40-
Digests and tags are not allowed.
47+
"repository": attr.string(doc = """ Repository URL where the image will be signed at, e.g.: `index.docker.io/<user>/image`.
48+
Digests and tags are not allowed. If this attribute is not set, the repository must be passed at runtime via the `--repository` flag.
4149
"""),
4250
"_sign_sh_tpl": attr.label(default = "sign.sh.tpl", allow_single_file = True),
4351
}
@@ -46,10 +54,15 @@ def _cosign_sign_impl(ctx):
4654
cosign = ctx.toolchains["@rules_oci//cosign:toolchain_type"]
4755
jq = ctx.toolchains["@aspect_bazel_lib//lib:jq_toolchain_type"]
4856

49-
if ctx.attr.repository.find(":") != -1 or ctx.attr.repository.find("@") != -1:
57+
if ctx.attr.repository and (ctx.attr.repository.find(":") != -1 or ctx.attr.repository.find("@") != -1):
5058
fail("repository attribute should not contain digest or tag.")
5159

5260
executable = ctx.actions.declare_file("cosign_sign_{}.sh".format(ctx.label.name))
61+
62+
fixed_args = []
63+
if ctx.attr.repository:
64+
fixed_args.extend(["--repository", ctx.attr.repository])
65+
5366
ctx.actions.expand_template(
5467
template = ctx.file._sign_sh_tpl,
5568
output = executable,
@@ -58,7 +71,7 @@ def _cosign_sign_impl(ctx):
5871
"{{cosign_path}}": cosign.cosign_info.binary.short_path,
5972
"{{jq_path}}": jq.jqinfo.bin.short_path,
6073
"{{image_dir}}": ctx.file.image.short_path,
61-
"{{fixed_args}}": " ".join(["--repository", ctx.attr.repository]),
74+
"{{fixed_args}}": " ".join(fixed_args),
6275
},
6376
)
6477

cosign/private/sign.sh.tpl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ readonly DIGEST=$("${JQ}" -r '.manifests[].digest' "${IMAGE_DIR}/index.json")
88
readonly FIXED_ARGS=({{fixed_args}})
99

1010
# set $@ to be FIXED_ARGS+$@
11-
ARGS=(${FIXED_ARGS[@]} $@)
12-
set -- ${ARGS[@]}
11+
ALL_ARGS=(${FIXED_ARGS[@]+"${FIXED_ARGS[@]}"} "$@")
12+
if [[ ${#ALL_ARGS[@]} -gt 0 ]]; then
13+
set -- "${ALL_ARGS[@]}"
14+
fi
1315

1416
REPOSITORY=""
1517
ARGS=()
@@ -22,5 +24,10 @@ while (( $# > 0 )); do
2224
esac
2325
done
2426

27+
if [[ -z "${REPOSITORY}" ]]; then
28+
echo "ERROR: repository not set. Please pass --repository flag or set the 'repository' attribute in the rule." >&2
29+
exit 1
30+
fi
31+
2532
exec "${COSIGN}" sign "${REPOSITORY}@${DIGEST}" ${ARGS[@]+"${ARGS[@]}"}
2633

docs/push.md

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/attest/BUILD.bazel

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,43 @@ sh_test(
4848
"@jq_toolchains//:resolved_toolchain",
4949
],
5050
)
51+
52+
cosign_attest(
53+
name = "attest_no_repo",
54+
image = ":image",
55+
predicate = ":sbom_generated.spdx",
56+
type = "spdx",
57+
)
58+
59+
sh_test(
60+
name = "test_attest_no_repo_fails",
61+
srcs = ["test_attest_no_repo_fails.bash"],
62+
args = ["$(location :attest_no_repo)"],
63+
data = [":attest_no_repo"],
64+
)
65+
66+
sh_test(
67+
name = "test_attest_no_repo_passes",
68+
srcs = ["test_attest_no_repo_passes.bash"],
69+
args = [
70+
"$(JQ_BIN)",
71+
"$(COSIGN_BIN)",
72+
"$(CRANE_BIN)",
73+
"$(location :attest_no_repo)",
74+
"$(location :image)",
75+
"$(location sbom.spdx)",
76+
],
77+
data = [
78+
"sbom.spdx",
79+
":attest_no_repo",
80+
":image",
81+
"@jq_toolchains//:resolved_toolchain",
82+
"@oci_cosign_toolchains//:current_toolchain",
83+
"@oci_crane_toolchains//:current_toolchain",
84+
],
85+
toolchains = [
86+
"@oci_cosign_toolchains//:current_toolchain",
87+
"@oci_crane_toolchains//:current_toolchain",
88+
"@jq_toolchains//:resolved_toolchain",
89+
],
90+
)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env bash
2+
3+
set -o pipefail -o errexit -o nounset
4+
5+
readonly IMAGE_ATTESTER="$1"
6+
7+
# Run the cosign_attest target and check that it fails with the expected error message.
8+
if ! "$IMAGE_ATTESTER" &> output.txt; then
9+
cat output.txt
10+
grep "ERROR: repository not set. Please pass --repository flag or set the 'repository' attribute in the rule." output.txt
11+
else
12+
echo "Expected cosign_attest to fail, but it succeeded."
13+
exit 1
14+
fi
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/env bash
2+
set -o pipefail -o errexit -o nounset
3+
4+
readonly JQ="${1/external\//../}"
5+
readonly COSIGN="${2/external\//../}"
6+
readonly CRANE="${3/external\//../}"
7+
readonly ATTACHER_NO_REPO="$4"
8+
readonly IMAGE_PATH="$5"
9+
readonly SBOM_PATH="$6"
10+
11+
# start a registry
12+
output=$(mktemp)
13+
$CRANE registry serve --address=localhost:0 >> "$output" 2>&1 &
14+
timeout=$((SECONDS+10))
15+
while [ "${SECONDS}" -lt "${timeout}" ]; do
16+
port="$(sed -nr 's/.+serving on port ([0-9]+)/\1/p' < "$output")"
17+
[ -n "${port}" ] && break
18+
done
19+
20+
readonly REPOSITORY="localhost:$port/local"
21+
22+
# generate key
23+
COSIGN_PASSWORD=123 "${COSIGN}" generate-key-pair
24+
25+
REF=$("${CRANE}" push "${IMAGE_PATH}" "${REPOSITORY}")
26+
27+
# attach the sbom
28+
COSIGN_PASSWORD=123 "${ATTACHER_NO_REPO}" --repository "${REPOSITORY}" --key=cosign.key -y
29+
30+
# download the sbom
31+
"${COSIGN}" verify-attestation "$REF" --key=cosign.pub --type spdx | "${JQ}" -r '.payload' | base64 --decode | "${JQ}" -r '.predicate' > "$TEST_TMPDIR/download.sbom"
32+
33+
diff -u --ignore-space-change --strip-trailing-cr "$SBOM_PATH" "$TEST_TMPDIR/download.sbom" || (echo "FAIL: downloaded SBOM does not match the original" && exit 1)

examples/push/BUILD.bazel

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ oci_push(
2929
repository = "index.docker.io/<ORG>/image",
3030
)
3131

32+
oci_push(
33+
name = "push_image_wo_repository",
34+
image = ":image",
35+
remote_tags = ["latest"],
36+
)
37+
3238
oci_image_index(
3339
name = "image_index",
3440
images = [
@@ -87,15 +93,26 @@ sh_test(
8793
"$(location :push_image_index)",
8894
"$(location :push_image_repository_file)",
8995
"$(location :push_image_wo_tags)",
96+
"$(location :push_image_wo_repository)",
9097
],
9198
data = [
9299
":push_image",
93100
":push_image_index",
94101
":push_image_repository_file",
95102
":push_image_wo_tags",
103+
":push_image_wo_repository",
96104
"@oci_crane_toolchains//:current_toolchain",
97105
],
98106
toolchains = [
99107
"@oci_crane_toolchains//:current_toolchain",
100108
],
101109
)
110+
111+
sh_test(
112+
name = "test_push_image_wo_repository_fails",
113+
srcs = ["test_push_image_wo_repository_fails.bash"],
114+
args = ["$(location :push_image_wo_repository)"],
115+
data = [
116+
":push_image_wo_repository",
117+
],
118+
)

examples/push/test.bash

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ readonly PUSH_IMAGE="$2"
66
readonly PUSH_IMAGE_INDEX="$3"
77
readonly PUSH_IMAGE_REPOSITORY_FILE="$4"
88
readonly PUSH_IMAGE_WO_TAGS="$5"
9+
readonly PUSH_IMAGE_WO_REPOSITORY="$6"
910

1011
# start a registry
1112
output=$(mktemp)
@@ -54,4 +55,9 @@ if [ "${TAGS}" != "custom" ]; then
5455
echo "image is supposed to have custom tag but got"
5556
echo "${TAGS}"
5657
exit 1
57-
fi
58+
fi
59+
60+
# should push image without repository with default tags
61+
REPOSITORY="${REGISTRY}/local-wo-repository"
62+
"${PUSH_IMAGE_WO_REPOSITORY}" --repository "${REPOSITORY}"
63+
"${CRANE}" digest "$REPOSITORY:latest"

0 commit comments

Comments
 (0)