diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java index bac7c5d829f92c..63e28754fc904c 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java @@ -80,7 +80,6 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.ArrayList; -import java.util.Base64; import java.util.List; import java.util.Map; @@ -965,7 +964,9 @@ public void enforceLabelAttributes() throws EvalException, InterruptedException } /** - * From an authentication dict extract a map of headers. + * From an authentication dict extract a map of headers. Due to + * https://github.com/bazelbuild/bazel/issues/9327, this fucntion does the validation of the + * auth map, but always returns an empty set of headers. * *

Given a dict as provided as "auth" argument, compute a map specifying for each URI provided * which additional headers (as usual, represented as a map from Strings to Strings) should @@ -976,7 +977,6 @@ public void enforceLabelAttributes() throws EvalException, InterruptedException private static Map> getAuthHeaders( SkylarkDict> auth) throws RepositoryFunctionException, EvalException { - ImmutableMap.Builder> headers = new ImmutableMap.Builder<>(); for (Map.Entry> entry : auth.entrySet()) { try { URL url = new URL(entry.getKey()); @@ -990,14 +990,7 @@ private static Map> getAuthHeaders( + entry.getKey() + " without 'login' and 'password' being provided."); } - String credentials = authMap.get("login") + ":" + authMap.get("password"); - headers.put( - url.toURI(), - ImmutableMap.of( - "Authorization", - "Basic " - + Base64.getEncoder() - .encodeToString(credentials.getBytes(StandardCharsets.UTF_8)))); + url.toURI(); // for URL validation. } } } catch (MalformedURLException e) { @@ -1006,6 +999,7 @@ private static Map> getAuthHeaders( throw new EvalException(null, e.getMessage()); } } - return headers.build(); + // TODO(https://github.com/bazelbuild/bazel/issues/9327) + return ImmutableMap.of(); } } diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/repository/SkylarkRepositoryContextApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/repository/SkylarkRepositoryContextApi.java index 2fe7a7a3a9f651..7faa55e9e4a9d7 100644 --- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/repository/SkylarkRepositoryContextApi.java +++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/repository/SkylarkRepositoryContextApi.java @@ -405,7 +405,7 @@ public void patch(Object patchFile, Integer strip, Location location) type = SkylarkDict.class, defaultValue = "{}", named = true, - doc = "An optional dict specifying authentication information for some of the URLs."), + doc = "Has no effect; do not use."), @Param( name = "integrity", type = String.class, @@ -560,7 +560,7 @@ public void extract(Object archive, Object output, String stripPrefix, Location type = SkylarkDict.class, defaultValue = "{}", named = true, - doc = "An optional dict specifying authentication information for some of the URLs."), + doc = "Has no effect; do not use."), @Param( name = "integrity", type = String.class, diff --git a/src/test/shell/bazel/skylark_repository_test.sh b/src/test/shell/bazel/skylark_repository_test.sh index 3b753e42abbc78..ceba818bf907c4 100755 --- a/src/test/shell/bazel/skylark_repository_test.sh +++ b/src/test/shell/bazel/skylark_repository_test.sh @@ -1551,226 +1551,6 @@ EOF expect_log "//:b.bzl" } -function test_auth_provided() { - mkdir x - echo 'exports_files(["file.txt"])' > x/BUILD - echo 'Hello World' > x/file.txt - tar cvf x.tar x - sha256="$(sha256sum x.tar | head -c 64)" - serve_file_auth x.tar - cat >> $(create_workspace_with_default_repos WORKSPACE) < auth.bzl <<'EOF' -def _impl(ctx): - ctx.download_and_extract( - url = ctx.attr.url, - sha256 = ctx.attr.sha256, - # Use the username/password pair hard-coded - # in the testing server. - auth = {ctx.attr.url : { "type": "basic", - "login" : "foo", - "password" : "bar"}} - ) - -with_auth = repository_rule( - implementation = _impl, - attrs = { "url" : attr.string(), "sha256" : attr.string() } -) -EOF - cat > BUILD <<'EOF' -genrule( - name = "it", - srcs = ["@ext//x:file.txt"], - outs = ["it.txt"], - cmd = "cp $< $@", -) -EOF - bazel build //:it \ - || fail "Expected success despite needing a file behind basic auth" -} - -function test_netrc_reading() { - # Write a badly formated, but correct, .netrc file - cat > .netrc <<'EOF' -machine ftp.example.com -macdef init -cd pub -mget * -quit - -machine example.com login -myusername password mysecret default -login anonymous password myusername@example.com -EOF - # We expect that `read_netrc` can parse this file... - cat > def.bzl <<'EOF' -load("@bazel_tools//tools/build_defs/repo:utils.bzl", "read_netrc") -def _impl(ctx): - rc = read_netrc(ctx, ctx.attr.path) - ctx.file("data.bzl", "netrc = %s" % (rc,)) - ctx.file("BUILD", "") - ctx.file("WORKSPACE", "") - -netrcrepo = repository_rule( - implementation = _impl, - attrs = {"path": attr.string()}, -) -EOF - cat >> $(create_workspace_with_default_repos WORKSPACE) < BUILD <<'EOF' -load("@netrc//:data.bzl", "netrc") - -[genrule( - name = name, - outs = [ "%s.txt" % (name,)], - cmd = "echo %s > $@" % (netrc["example.com"][name],), -) for name in ["login", "password"]] -EOF - bazel build //:login //:password - grep 'myusername' `bazel info bazel-genfiles`/login.txt \ - || fail "Username not parsed correctly" - grep 'mysecret' `bazel info bazel-genfiles`/password.txt \ - || fail "Password not parsed correctly" - - # Also check the precise value of parsed file - cat > expected.bzl <<'EOF' -expected = { - "ftp.example.com" : { "macdef init" : "cd pub\nmget *\nquit\n" }, - "example.com" : { "login" : "myusername", - "password" : "mysecret", - }, - "" : { "login": "anonymous", - "password" : "myusername@example.com" }, -} -EOF - cat > verify.bzl <<'EOF' -load("@netrc//:data.bzl", "netrc") -load("//:expected.bzl", "expected") - -def check_equal_expected(): - print("Parsed value: %s" % (netrc,)) - print("Expected value: %s" % (expected,)) - if netrc == 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 "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 >> $(create_workspace_with_default_repos WORKSPACE) < 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 test_disallow_unverified_http() { mkdir x echo 'exports_files(["file.txt"])' > x/BUILD @@ -1819,74 +1599,4 @@ function tear_down() { true } -function test_http_archive_netrc() { - mkdir x - echo 'exports_files(["file.txt"])' > x/BUILD - echo 'Hello World' > x/file.txt - tar cvf x.tar x - sha256=$(sha256sum x.tar | head -c 64) - serve_file_auth x.tar - cat > WORKSPACE < .netrc <<'EOF' -machine 127.0.0.1 -login foo -password bar -EOF - cat > BUILD <<'EOF' -genrule( - name = "it", - srcs = ["@ext//x:file.txt"], - outs = ["it.txt"], - cmd = "cp $< $@", -) -EOF - bazel build //:it \ - || fail "Expected success despite needing a file behind basic auth" -} - -function test_implicit_netrc() { - mkdir x - echo 'exports_files(["file.txt"])' > x/BUILD - echo 'Hello World' > x/file.txt - tar cvf x.tar x - sha256=$(sha256sum x.tar | head -c 64) - serve_file_auth x.tar - - export HOME=`pwd` - cat > .netrc <<'EOF' -machine 127.0.0.1 -login foo -password bar -EOF - - mkdir main - cd main - cat > WORKSPACE < BUILD <<'EOF' -genrule( - name = "it", - srcs = ["@ext//x:file.txt"], - outs = ["it.txt"], - cmd = "cp $< $@", -) -EOF - bazel build //:it \ - || fail "Expected success despite needing a file behind basic auth" -} - run_suite "local repository tests" diff --git a/tools/build_defs/repo/http.bzl b/tools/build_defs/repo/http.bzl index da4bf88b67dbff..180e078f61efd1 100644 --- a/tools/build_defs/repo/http.bzl +++ b/tools/build_defs/repo/http.bzl @@ -26,36 +26,15 @@ load( ) ``` -These rules are improved versions of the native http rules and will eventually -replace the native rules. """ load( ":utils.bzl", "patch", - "read_netrc", "update_attrs", - "use_netrc", "workspace_and_buildfile", ) -def _get_auth(ctx, urls): - """Given the list of URLs obtain the correct auth dict.""" - if ctx.attr.netrc: - netrc = read_netrc(ctx, ctx.attr.netrc) - return use_netrc(netrc, urls) - - if "HOME" in ctx.os.environ: - if not ctx.os.name.startswith("windows"): - netrcfile = "%s/.netrc" % (ctx.os.environ["HOME"],) - if ctx.execute(["test", "-f", netrcfile]).return_code == 0: - netrc = read_netrc(ctx, netrcfile) - return use_netrc(netrc, urls) - - # TODO: Search at a similarly canonical place for Windows as well - - return {} - def _http_archive_impl(ctx): """Implementation of the http_archive rule.""" if not ctx.attr.url and not ctx.attr.urls: @@ -69,8 +48,6 @@ def _http_archive_impl(ctx): if ctx.attr.url: all_urls = [ctx.attr.url] + all_urls - auth = _get_auth(ctx, all_urls) - download_info = ctx.download_and_extract( all_urls, "", @@ -78,7 +55,6 @@ def _http_archive_impl(ctx): ctx.attr.type, ctx.attr.strip_prefix, canonical_id = ctx.attr.canonical_id, - auth = auth, ) patch(ctx) workspace_and_buildfile(ctx) @@ -109,13 +85,11 @@ def _http_file_impl(ctx): download_path = ctx.path("file/" + downloaded_file_path) if download_path in forbidden_files or not str(download_path).startswith(str(repo_root)): fail("'%s' cannot be used as downloaded_file_path in http_file" % ctx.attr.downloaded_file_path) - auth = _get_auth(ctx, ctx.attr.urls) download_info = ctx.download( ctx.attr.urls, "file/" + downloaded_file_path, ctx.attr.sha256, ctx.attr.executable, - auth = auth, ) ctx.file("WORKSPACE", "workspace(name = \"{name}\")".format(name = ctx.name)) ctx.file("file/BUILD", _HTTP_FILE_BUILD.format(downloaded_file_path)) @@ -146,12 +120,10 @@ def _http_jar_impl(ctx): all_urls = ctx.attr.urls if ctx.attr.url: all_urls = [ctx.attr.url] + all_urls - auth = _get_auth(ctx, all_urls) download_info = ctx.download( all_urls, "jar/downloaded.jar", ctx.attr.sha256, - auth = auth, ) ctx.file("WORKSPACE", "workspace(name = \"{name}\")".format(name = ctx.name)) ctx.file("jar/BUILD", _HTTP_JAR_BUILD) @@ -185,9 +157,7 @@ to omit the SHA-256 as remote files can change._ At best omitting this field will make your build non-hermetic. It is optional to make development easier but should be set before shipping.""", ), - "netrc": attr.string( - doc = "Location of the .netrc file to use for authentication", - ), + "netrc": attr.string(), "canonical_id": attr.string( doc = """A canonical id of the archive downloaded @@ -364,9 +334,7 @@ easier but should be set before shipping.""", Each entry must be a file, http or https URL. Redirections are followed. Authentication is not supported.""", ), - "netrc": attr.string( - doc = "Location of the .netrc file to use for authentication", - ), + "netrc": attr.string(), } http_file = repository_rule( @@ -408,9 +376,7 @@ _http_jar_attrs = { "A list of URLS the jar can be fetched from. They have to end " + "in `.jar`.", ), - "netrc": attr.string( - doc = "Location of the .netrc file to use for authentication", - ), + "netrc": attr.string(), } http_jar = repository_rule( diff --git a/tools/build_defs/repo/utils.bzl b/tools/build_defs/repo/utils.bzl index 039af452778ea6..9b680f9be75293 100644 --- a/tools/build_defs/repo/utils.bzl +++ b/tools/build_defs/repo/utils.bzl @@ -167,124 +167,3 @@ def maybe(repo_rule, name, **kwargs): """ if not native.existing_rule(name): repo_rule(name = name, **kwargs) - -def read_netrc(ctx, filename): - """Utility function to parse at least a basic .netrc file. - - Args: - ctx: The repository context of the repository rule calling this utility - function. - filename: the name of the .netrc file to read - - Returns: - dict mapping a machine names to a dict with the information provided - about them - """ - contents = ctx.read(filename) - - # Parse the file. This is mainly a token-based update of a simple state - # machine, but we need to keep the line structure to correctly determine - # the end of a `macdef` command. - netrc = {} - currentmachinename = None - currentmachine = {} - macdef = None - currentmacro = "" - cmd = None - for line in contents.splitlines(): - if macdef: - # as we're in a macro, just determine if we reached the end. - if line: - currentmacro += line + "\n" - else: - # reached end of macro, add it - currentmachine[macdef] = currentmacro - macdef = None - currentmacro = "" - else: - # Essentially line.split(None) which starlark does not support. - tokens = [ - w.strip() - for w in line.split(" ") - if len(w.strip()) > 0 - ] - for token in tokens: - if cmd: - # we have a command that expects another argument - if cmd == "machine": - # a new machine definition was provided, so save the - # old one, if present - if not currentmachinename == None: - netrc[currentmachinename] = currentmachine - currentmachine = {} - currentmachinename = token - elif cmd == "macdef": - macdef = "macdef %s" % (token,) - # a new macro definition; the documentation says - # "its contents begin with the next .netrc line [...]", - # so should there really be tokens left in the current - # line, they're not part of the macro. - - else: - currentmachine[cmd] = token - cmd = None - elif token in [ - "machine", - "login", - "password", - "account", - "macdef", - ]: - # command takes one argument - cmd = token - elif token == "default": - # defines the default machine; again, store old machine - if not currentmachinename == None: - netrc[currentmachinename] = currentmachine - - # We use the empty string for the default machine, as that - # can never be a valid hostname ("default" could be, in the - # default search domain). - currentmachinename = "" - currentmachine = {} - else: - fail("Unexpected token '%s' while reading %s" % - (token, 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