xref: /aosp_15_r20/external/bazelbuild-rules_python/python/private/auth.bzl (revision 60517a1edbc8ecf509223e9af94a7adec7d736b8)
1# Copyright 2022 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#    http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Helpers copied from http_file source to be reused here.
16
17The implementation below is copied directly from Bazel's implementation of `http_archive`.
18Accordingly, the return value of this function should be used identically as the `auth` parameter of `http_archive`.
19Reference: https://github.com/bazelbuild/bazel/blob/6.3.2/tools/build_defs/repo/http.bzl#L109
20
21The helpers were further modified to support module_ctx.
22"""
23
24load("@bazel_tools//tools/build_defs/repo:utils.bzl", "read_netrc", "read_user_netrc", "use_netrc")
25
26# Copied from https://sourcegraph.com/github.com/bazelbuild/bazel@26c6add3f9809611ad3795bce1e5c0fb37902902/-/blob/tools/build_defs/repo/http.bzl
27_AUTH_PATTERN_DOC = """An optional dict mapping host names to custom authorization patterns.
28
29If a URL's host name is present in this dict the value will be used as a pattern when
30generating the authorization header for the http request. This enables the use of custom
31authorization schemes used in a lot of common cloud storage providers.
32
33The pattern currently supports 2 tokens: <code>&lt;login&gt;</code> and
34<code>&lt;password&gt;</code>, which are replaced with their equivalent value
35in the netrc file for the same host name. After formatting, the result is set
36as the value for the <code>Authorization</code> field of the HTTP request.
37
38Example attribute and netrc for a http download to an oauth2 enabled API using a bearer token:
39
40<pre>
41auth_patterns = {
42    "storage.cloudprovider.com": "Bearer &lt;password&gt;"
43}
44</pre>
45
46netrc:
47
48<pre>
49machine storage.cloudprovider.com
50        password RANDOM-TOKEN
51</pre>
52
53The final HTTP request would have the following header:
54
55<pre>
56Authorization: Bearer RANDOM-TOKEN
57</pre>
58"""
59
60# AUTH_ATTRS are used within whl_library and pip bzlmod extension.
61AUTH_ATTRS = {
62    "auth_patterns": attr.string_dict(
63        doc = _AUTH_PATTERN_DOC,
64    ),
65    "netrc": attr.string(
66        doc = "Location of the .netrc file to use for authentication",
67    ),
68}
69
70def get_auth(ctx, urls, ctx_attr = None):
71    """Utility for retrieving netrc-based authentication parameters for repository download rules used in python_repository.
72
73    Args:
74        ctx(repository_ctx or module_ctx): The extension module_ctx or
75            repository rule's repository_ctx object.
76        urls: A list of URLs from which assets will be downloaded.
77        ctx_attr(struct): The attributes to get the netrc from. When ctx is
78            repository_ctx, then we will attempt to use repository_ctx.attr
79            if this is not specified, otherwise we will use the specified
80            field. The module_ctx attributes are located in the tag classes
81            so it cannot be retrieved from the context.
82
83    Returns:
84        dict: A map of authentication parameters by URL.
85    """
86
87    # module_ctx does not have attributes, as they are stored in tag classes. Whilst
88    # the correct behaviour should be to pass the `attr` to the
89    ctx_attr = ctx_attr or getattr(ctx, "attr", None)
90    ctx_attr = struct(
91        netrc = getattr(ctx_attr, "netrc", None),
92        auth_patterns = getattr(ctx_attr, "auth_patterns", ""),
93    )
94
95    if ctx_attr.netrc:
96        netrc = read_netrc(ctx, ctx_attr.netrc)
97    elif "NETRC" in ctx.os.environ:
98        # This can be used on newer bazel versions
99        if hasattr(ctx, "getenv"):
100            netrc = read_netrc(ctx, ctx.getenv("NETRC"))
101        else:
102            netrc = read_netrc(ctx, ctx.os.environ["NETRC"])
103    else:
104        netrc = read_user_netrc(ctx)
105
106    return use_netrc(netrc, urls, ctx_attr.auth_patterns)
107