Skip to content

Commit

Permalink
Add a starlark function computing auth dict from netrc data
Browse files Browse the repository at this point in the history
Add a Starlark function combining the data from a netrc file with
a list of URLs to obtain a suitable auth dict for the download function
of a repository context. This will be used by the http_archive rule, but
is also a useful building block for repository-rule authors.

Change-Id: Ie61c648323fa9c2f954d773a9a726eb3c90c259f
PiperOrigin-RevId: 254717280
  • Loading branch information
aehlig authored and copybara-github committed Jun 24, 2019
1 parent a79a4b6 commit 38cfc18
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 0 deletions.
91 changes: 91 additions & 0 deletions src/test/shell/bazel/skylark_repository_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1562,6 +1562,97 @@ EOF
|| fail "Parsed dict not equal to expected value"
}

function test_use_netrc() {
# Test the starlark utility function use_netrc.
cat > .netrc <<'EOF'
machine foo.example.org
login foousername
password foopass
machine bar.example.org
login barusername
password passbar
EOF
# Read a given .netrc file and combine it with a list of URL,
# and write the obtained authentication dicionary to disk; this
# is not the intended way of using, but makes testing easy.
cat > def.bzl <<'EOF'
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "read_netrc", "use_netrc")
def _impl(ctx):
rc = read_netrc(ctx, ctx.attr.path)
auth = use_netrc(rc, ctx.attr.urls)
ctx.file("data.bzl", "auth = %s" % (auth,))
ctx.file("BUILD", "")
ctx.file("WORKSPACE", "")
authrepo = repository_rule(
implementation = _impl,
attrs = {"path": attr.string(),
"urls": attr.string_list()
},
)
EOF
cat > WORKSPACE <<EOF
load("//:def.bzl", "authrepo")
authrepo(
name = "auth",
path="$(pwd)/.netrc",
urls = [
"http://example.org/public/null.tar",
"https://foo.example.org/file1.tar",
"https://foo.example.org:8080/file2.tar",
"https://bar.example.org/file3.tar",
"https://evil.com/bar.example.org/file4.tar",
],
)
EOF
# Here dicts give us the correct notion of equality, so we can simply
# compare against the expected value.
cat > expected.bzl <<'EOF'
expected = {
"https://foo.example.org/file1.tar" : {
"type" : "basic",
"login": "foousername",
"password" : "foopass",
},
"https://foo.example.org:8080/file2.tar" : {
"type" : "basic",
"login": "foousername",
"password" : "foopass",
},
"https://bar.example.org/file3.tar" : {
"type" : "basic",
"login": "barusername",
"password" : "passbar",
},
}
EOF
cat > verify.bzl <<'EOF'
load("@auth//:data.bzl", "auth")
load("//:expected.bzl", "expected")
def check_equal_expected():
print("Computed value: %s" % (auth,))
print("Expected value: %s" % (expected,))
if auth == expected:
return "OK"
else:
return "BAD"
EOF
cat > BUILD <<'EOF'
load ("//:verify.bzl", "check_equal_expected")
genrule(
name = "check_expected",
outs = ["check_expected.txt"],
cmd = "echo %s > $@" % (check_equal_expected(),)
)
EOF
bazel build //:check_expected
grep 'OK' `bazel info bazel-genfiles`/check_expected.txt \
|| fail "Authentication merged incorrectly"
}

function tear_down() {
shutdown_server
if [ -d "${TEST_TMPDIR}/server_dir" ]; then
Expand Down
35 changes: 35 additions & 0 deletions tools/build_defs/repo/utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,38 @@ def read_netrc(ctx, filename):
if not currentmachinename == None:
netrc[currentmachinename] = currentmachine
return netrc

def use_netrc(netrc, urls):
"""compute an auth dict from a parsed netrc file and a list of URLs
Args:
netrc: a netrc file already parsed to a dict, e.g., as obtained from
read_netrc
urls: a list of URLs.
Returns:
dict suitable as auth argument for ctx.download; more precisely, the dict
will map all URLs where the netrc file provides login and password to a
dict containing the corresponding login and passwored, as well as the
mapping of "type" to "basic"
"""
auth = {}
for url in urls:
schemerest = url.split("://", 1)
if len(schemerest) < 2:
continue
if not (schemerest[0] in ["http", "https"]):
# For other protocols, bazel currently does not support
# authentication. So ignore them.
continue
host = schemerest[1].split("/")[0].split(":")[0]
if not host in netrc:
continue
authforhost = netrc[host]
if "login" in authforhost and "password" in authforhost:
auth[url] = {
"type": "basic",
"login": authforhost["login"],
"password": authforhost["password"],
}
return auth

0 comments on commit 38cfc18

Please sign in to comment.