Skip to content

Commit 3ffee56

Browse files
committed
refactor: remove curl fallback (#568)
1 parent f730436 commit 3ffee56

File tree

6 files changed

+69
-171
lines changed

6 files changed

+69
-171
lines changed

.bazelrc

+5-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ test --test_env=DOCKER_HOST
99
# Disable bzlmod lockfile
1010
common --lockfile_mode=off
1111

12-
# TODO(2.0): enable once we drop support for Bazel 5.
13-
# common --credential_helper=public.ecr.aws=%workspace%/examples/credential_helper/auth.sh
12+
# On bazel 6.4.0 these are needed to successfully fetch images.
13+
common:needs_credential_helpers --credential_helper=public.ecr.aws=%workspace%/examples/credential_helper/auth.sh
14+
common:needs_credential_helpers --credential_helper=index.docker.io=%workspace%/examples/credential_helper/auth.sh
15+
common:needs_credential_helpers --credential_helper=docker.elastic.co=%workspace%/examples/credential_helper/auth.sh
16+
common:needs_credential_helpers --credential_helper_cache_duration=0
1417

1518
# Load any settings specific to the current user.
1619
# .bazelrc.user should appear in .gitignore so that settings are not shared with team members

.github/workflows/ci.yaml

+20-1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,19 @@ jobs:
103103
if: matrix.bzlmodEnabled
104104
run: echo "bzlmod_flag=--enable_bzlmod" >> $GITHUB_OUTPUT
105105

106+
- name: Set credential helpers flag
107+
# Add --config needs_credential_helpers to add additional credential helpers
108+
# to fetch from registries with HTTP headers set by credential helpers.
109+
id: set_credential_helper_flag
110+
if: matrix.bazelversion == '6.4.0' && matrix.folder == '.'
111+
run: echo "credential_helper_flag=--config=needs_credential_helpers" >> $GITHUB_OUTPUT
112+
113+
- name: Setup crane for credential helpers to use
114+
uses: imjasonh/[email protected]
115+
if: matrix.bazelversion == '6.4.0' && matrix.folder == '.'
116+
with:
117+
version: "v0.19.1"
118+
106119
- name: Configure Bazel version
107120
working-directory: ${{ matrix.folder }}
108121
run: echo "${{ matrix.bazelversion }}" > .bazelversion
@@ -153,4 +166,10 @@ jobs:
153166
env:
154167
# Bazelisk will download bazel to here, ensure it is cached between runs.
155168
XDG_CACHE_HOME: ~/.cache/bazel-repo
156-
run: bazel --bazelrc=$GITHUB_WORKSPACE/.github/workflows/ci.bazelrc --bazelrc=.bazelrc test ${{ steps.set_bzlmod_flag.outputs.bzlmod_flag }} //...
169+
run: |
170+
bazel \
171+
--bazelrc=$GITHUB_WORKSPACE/.github/workflows/ci.bazelrc \
172+
--bazelrc=.bazelrc \
173+
test //... \
174+
${{ steps.set_bzlmod_flag.outputs.bzlmod_flag }} \
175+
${{ steps.set_credential_helper_flag.outputs.credential_helper_flag }}

examples/credential_helper/auth.sh

+28-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
#!/usr/bin/env bash
22

33
# Requirements
4-
# - curl
4+
# - crane
55
# - jq
66
# - awk
77
#
88
# ./examples/credential_helper/auth.sh <<< '{"uri":"https://public.ecr.aws/token/?scope\u003drepository:lambda/python:pull\u0026service\u003dpublic.ecr.aws"}'
99
# ./examples/credential_helper/auth.sh <<< '{"uri":"https://public.ecr.aws/v2/lambda/python/manifests/3.11.2024.01.25.10"}'
10+
1011
function log () {
11-
echo "$1" >> /tmp/oci_auth.log
12+
echo $@ >> "/tmp/oci_auth.log"
1213
}
1314

1415
log ""
@@ -20,18 +21,39 @@ log "Payload: $input"
2021
uri=$(jq -r ".uri" <<< $input)
2122
log "URI: $uri"
2223

23-
host="$(echo $uri | awk -F[/:] '{print $4}')"
24+
host="$(awk -F[/:] '{print $4}' <<< $uri)"
2425
log "Host: $host"
2526

27+
2628
if [[ $input == *"/token"* ]]; then
2729
log "Auth: None"
2830
echo "{}"
29-
exit 0
31+
exit 1
3032
fi
3133

34+
repository=$(awk -F'^https?://|v2/|/manifests|/blobs' '{print $2 $3}' <<< "$uri")
35+
log "Repository: $repository"
36+
37+
38+
ACCEPTED_MEDIA_TYPES='[
39+
"application/vnd.docker.distribution.manifest.v2+json",
40+
"application/vnd.docker.distribution.manifest.list.v2+json",
41+
"application/vnd.oci.image.manifest.v1+json",
42+
"application/vnd.oci.image.index.v1+json"
43+
]'
44+
45+
3246
# This will write the response to stdout in a format that Bazels credential helper protocol understands.
3347
# Since this is called by Bazel, users won't bee seeing output of this.
34-
curl -fsSL https://$host/token | jq '{headers:{"Authorization": [("Bearer " + .token)]}}'
48+
crane auth token "$repository" |
49+
jq --argjson accept "$ACCEPTED_MEDIA_TYPES" \
50+
'{headers: {Authorization: [("Bearer " + .token)], Accept: [($accept | join(", "))], "Docker-Distribution-API-Version": ["registry/2.0"] }}'
51+
52+
if [[ $? != 0 ]]; then
53+
log "Auth: Failed"
54+
exit 1
55+
fi
3556
log "Auth: Complete"
3657

37-
# Alternatively you can call an external program such as `docker-credential-ecr-login` to perform the token exchange.
58+
59+
# Alternatively you can call an external program such as `docker-credential-ecr-login` to perform the token exchange.

oci/private/BUILD.bazel

-8
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ bzl_library(
5151
],
5252
deps = [
5353
"//oci/private:authn",
54-
"//oci/private:download",
5554
"//oci/private:util",
5655
"@bazel_skylib//lib:dicts",
5756
],
@@ -84,13 +83,6 @@ bzl_library(
8483
visibility = ["//oci:__subpackages__"],
8584
)
8685

87-
bzl_library(
88-
name = "download",
89-
srcs = ["download.bzl"],
90-
visibility = ["//oci:__subpackages__"],
91-
deps = ["@bazel_skylib//lib:versions"],
92-
)
93-
9486
bzl_library(
9587
name = "authn",
9688
srcs = ["authn.bzl"],

oci/private/download.bzl

-125
This file was deleted.

oci/private/pull.bzl

+16-29
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"Implementation details for oci_pull repository rules"
22

33
load("@bazel_skylib//lib:dicts.bzl", "dicts")
4+
load("@bazel_skylib//lib:versions.bzl", "versions")
45
load("//oci/private:authn.bzl", "authn")
5-
load("//oci/private:download.bzl", "download")
66
load("//oci/private:util.bzl", "util")
77

88
# attributes that are specific to image reference url. shared between multiple targets
@@ -38,15 +38,16 @@ _IMAGE_REFERENCE_ATTRS = {
3838
SCHEMA1_ERROR = """\
3939
The registry sent a manifest with schemaVersion=1.
4040
This commonly occurs when fetching from a registry that needs the Docker-Distribution-API-Version header to be set.
41+
See: https://github.com/bazel-contrib/rules_oci/blob/main/docs/pull.md#authentication-using-credential-helpers
4142
"""
4243

4344
OCI_MEDIA_TYPE_OR_AUTHN_ERROR = """\
44-
Unable to retrieve the manifest. This could be due to authentication problems or an attempt to fetch an image with OCI image media types.
45+
Unable to retrieve the image manifest. This could be due to authentication problems or an attempt to fetch an image with OCI image media types.
46+
See: https://github.com/bazel-contrib/rules_oci/blob/main/docs/pull.md#authentication-using-credential-helpers
4547
"""
4648

47-
CURL_FALLBACK_WARNING = """\
48-
The use of Curl fallback is deprecated and is set to be removed in version 2.0.
49-
For more details, refer to: https://github.com/bazel-contrib/rules_oci/issues/456
49+
OCI_MEDIA_TYPE_OR_AUTHN_ERROR_BAZEL7 = """\
50+
Unable to retrieve the image manifest. This could be due to authentication problems.
5051
"""
5152

5253
# Supported media types
@@ -85,7 +86,7 @@ def _digest_into_blob_path(digest):
8586
digest_path = digest.replace(":", "/", 1)
8687
return "blobs/{}".format(digest_path)
8788

88-
def _download(rctx, authn, identifier, output, resource, download_fn = download.bazel, headers = {}, allow_fail = False):
89+
def _download(rctx, authn, identifier, output, resource, headers = {}, allow_fail = False):
8990
"Use the Bazel Downloader to fetch from the remote registry"
9091

9192
if resource != "blobs" and resource != "manifests":
@@ -108,17 +109,19 @@ def _download(rctx, authn, identifier, output, resource, download_fn = download.
108109
if identifier.startswith("sha256:"):
109110
sha256 = identifier[len("sha256:"):]
110111
else:
111-
util.warning(rctx, "Fetching from {}@{} without an integrity hash. The result will not be cached.".format(rctx.attr.repository, identifier))
112+
util.warning(rctx, "Fetching from {}@{} without an integrity hash, result will not be cached.".format(rctx.attr.repository, identifier))
112113

113-
return download_fn(
114-
rctx,
114+
kwargs = dict(
115115
output = output,
116116
sha256 = sha256,
117117
url = registry_url,
118118
auth = {registry_url: auth},
119-
headers = headers,
120119
allow_fail = allow_fail,
121120
)
121+
if versions.is_at_least("7.1.0", versions.get()):
122+
return rctx.download(headers = headers, **kwargs)
123+
else:
124+
return rctx.download(**kwargs)
122125

123126
def _download_manifest(rctx, authn, identifier, output):
124127
bytes = None
@@ -135,35 +138,19 @@ def _download_manifest(rctx, authn, identifier, output):
135138
headers = _DOWNLOAD_HEADERS,
136139
)
137140

138-
fallback_to_curl = False
139141
if result.success:
140142
bytes = rctx.read(output)
141143
manifest = json.decode(bytes)
142144
digest = "sha256:{}".format(result.sha256)
143145
if manifest["schemaVersion"] == 1:
144-
fallback_to_curl = True
145-
util.warning(rctx, SCHEMA1_ERROR)
146+
fail(SCHEMA1_ERROR)
146147
else:
147-
fallback_to_curl = True
148-
util.warning(rctx, OCI_MEDIA_TYPE_OR_AUTHN_ERROR)
149148
explanation = authn.explain()
150149
if explanation:
151150
util.warning(rctx, explanation)
152-
153-
if fallback_to_curl:
154-
util.warning(rctx, CURL_FALLBACK_WARNING)
155-
_download(
156-
rctx,
157-
authn,
158-
identifier,
159-
output,
160-
"manifests",
161-
download.curl,
162-
headers = _DOWNLOAD_HEADERS,
151+
fail(
152+
OCI_MEDIA_TYPE_OR_AUTHN_ERROR_BAZEL7 if versions.is_at_least("7.1.0", versions.get()) else OCI_MEDIA_TYPE_OR_AUTHN_ERROR,
163153
)
164-
bytes = rctx.read(output)
165-
manifest = json.decode(bytes)
166-
digest = "sha256:{}".format(util.sha256(rctx, output))
167154

168155
return manifest, len(bytes), digest
169156

0 commit comments

Comments
 (0)