From aea061004c741f35aebcf537c06980f6d60cadb8 Mon Sep 17 00:00:00 2001 From: Tiago Quelhas Date: Tue, 16 May 2023 07:40:25 -0700 Subject: [PATCH] [6.3.0] Wire credential helper to repository fetching. After this change, credential helpers will be used when available to obtain credentials for repository fetching, taking precedence over the `auth` parameter to rctx.download and rctx.download_and_extract. Tests that need a credential helper are skipped on Windows for now, as otherwise the credential helper would have to be reimplemented in Batch or Powershell. Also improve the documentation for credential helper related flags. Fixes https://github.com/bazelbuild/bazel/issues/15013. Closes #18173. PiperOrigin-RevId: 532454935 Change-Id: Ia3be8c21e001a36160f3d1df858593f8fb846055 --- .../lib/authandtls/AuthAndTLSOptions.java | 28 +-- .../build/lib/authandtls/GoogleAuthUtils.java | 1 - .../lib/authandtls/credentialhelper/BUILD | 1 + .../credentialhelper/CredentialModule.java | 6 + .../com/google/devtools/build/lib/bazel/BUILD | 4 + .../lib/bazel/BazelRepositoryModule.java | 48 +++++ .../downloader/DownloadManager.java | 14 +- src/main/protobuf/failure_details.proto | 1 + .../devtools/build/lib/buildtool/util/BUILD | 1 + .../util/BuildIntegrationTestCase.java | 4 +- src/test/shell/bazel/remote_helpers.sh | 3 +- .../shell/bazel/starlark_repository_test.sh | 186 ++++++++++++++++-- src/test/shell/bazel/testing_server.py | 4 +- 13 files changed, 265 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/google/devtools/build/lib/authandtls/AuthAndTLSOptions.java b/src/main/java/com/google/devtools/build/lib/authandtls/AuthAndTLSOptions.java index 7423b555a13e9c..ae592aafac8981 100644 --- a/src/main/java/com/google/devtools/build/lib/authandtls/AuthAndTLSOptions.java +++ b/src/main/java/com/google/devtools/build/lib/authandtls/AuthAndTLSOptions.java @@ -148,11 +148,13 @@ public class AuthAndTLSOptions extends OptionsBase { documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.UNKNOWN}, help = - "Configures Credential Helpers to use for retrieving credentials for the provided scope" - + " (domain).\n\n" - + "Credentials from Credential Helpers take precedence over credentials from" - + " --google_default_credentials, `--google_credentials`, or" - + " .netrc.\n\n" + "Configures a credential helper to use for retrieving authorization credentials for " + + " repository fetching, remote caching and execution, and the build event" + + " service.\n\n" + + "Credentials supplied by a helper take precedence over credentials supplied by" + + " --google_default_credentials, --google_credentials, a .netrc file, or the auth" + + " parameter to repository_ctx.download and repository_ctx.download_and_extract.\n\n" + + "May be specified multiple times to set up multiple helpers.\n\n" + "See https://github.com/bazelbuild/proposals/blob/main/designs/2022-06-07-bazel-credential-helpers.md" + " for details.") public List credentialHelpers; @@ -164,8 +166,8 @@ public class AuthAndTLSOptions extends OptionsBase { documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.UNKNOWN}, help = - "Configures the timeout for the Credential Helper.\n\n" - + "Credential Helpers failing to respond within this timeout will fail the" + "Configures the timeout for a credential helper.\n\n" + + "Credential helpers failing to respond within this timeout will fail the" + " invocation.") public Duration credentialHelperTimeout; @@ -176,13 +178,13 @@ public class AuthAndTLSOptions extends OptionsBase { documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, effectTags = {OptionEffectTag.UNKNOWN}, help = - "Configures the duration for which credentials from Credential Helpers are cached.\n\n" + "The duration for which credentials supplied by a credential helper are cached.\n\n" + "Invoking with a different value will adjust the lifetime of preexisting entries;" + " pass zero to clear the cache. A clean command always clears the cache, regardless" + " of this flag.") public Duration credentialHelperCacheTimeout; - /** One of the values of the `--credential_helper` flag. */ + /** One of the values of the `--experimental_credential_helper` flag. */ @AutoValue public abstract static class UnresolvedScopedCredentialHelper { /** Returns the scope of the credential helper (if any). */ @@ -192,7 +194,7 @@ public abstract static class UnresolvedScopedCredentialHelper { public abstract String getPath(); } - /** A {@link Converter} for the `--credential_helper` flag. */ + /** A {@link Converter} for the `--experimental_credential_helper` flag. */ public static final class UnresolvedScopedCredentialHelperConverter extends Converter.Contextless { public static final UnresolvedScopedCredentialHelperConverter INSTANCE = @@ -200,7 +202,11 @@ public static final class UnresolvedScopedCredentialHelperConverter @Override public String getTypeDescription() { - return "An (unresolved) path to a credential helper for a scope."; + return "Path to a credential helper. It may be absolute, relative to the PATH environment" + + " variable, or %workspace%-relative. The path be optionally prefixed by a scope " + + " followed by an '='. The scope is a domain name, optionally with a single leading '*'" + + " wildcard component. A helper applies to URIs matching its scope, with more specific" + + " scopes preferred. If a helper has no scope, it applies to every URI."; } @Override diff --git a/src/main/java/com/google/devtools/build/lib/authandtls/GoogleAuthUtils.java b/src/main/java/com/google/devtools/build/lib/authandtls/GoogleAuthUtils.java index e226e6b069db20..409263929c7cdc 100644 --- a/src/main/java/com/google/devtools/build/lib/authandtls/GoogleAuthUtils.java +++ b/src/main/java/com/google/devtools/build/lib/authandtls/GoogleAuthUtils.java @@ -372,7 +372,6 @@ static Optional newCredentialsFromNetrc( } } - @VisibleForTesting public static CredentialHelperProvider newCredentialHelperProvider( CredentialHelperEnvironment environment, CommandLinePathFactory pathFactory, diff --git a/src/main/java/com/google/devtools/build/lib/authandtls/credentialhelper/BUILD b/src/main/java/com/google/devtools/build/lib/authandtls/credentialhelper/BUILD index 275c159b60087c..6a571986e57eea 100644 --- a/src/main/java/com/google/devtools/build/lib/authandtls/credentialhelper/BUILD +++ b/src/main/java/com/google/devtools/build/lib/authandtls/credentialhelper/BUILD @@ -14,6 +14,7 @@ java_library( deps = [ "//src/main/java/com/google/devtools/build/lib:runtime", "//src/main/java/com/google/devtools/build/lib/authandtls", + "//src/main/java/com/google/devtools/common/options", "//third_party:caffeine", "//third_party:guava", ], diff --git a/src/main/java/com/google/devtools/build/lib/authandtls/credentialhelper/CredentialModule.java b/src/main/java/com/google/devtools/build/lib/authandtls/credentialhelper/CredentialModule.java index 95af2af5fcced0..610c82452d66c5 100644 --- a/src/main/java/com/google/devtools/build/lib/authandtls/credentialhelper/CredentialModule.java +++ b/src/main/java/com/google/devtools/build/lib/authandtls/credentialhelper/CredentialModule.java @@ -21,6 +21,7 @@ import com.google.devtools.build.lib.authandtls.AuthAndTLSOptions; import com.google.devtools.build.lib.runtime.BlazeModule; import com.google.devtools.build.lib.runtime.CommandEnvironment; +import com.google.devtools.common.options.OptionsBase; import java.net.URI; import java.time.Duration; @@ -34,6 +35,11 @@ public Cache>> getCredentialCach return credentialCache; } + @Override + public Iterable> getCommonCommandOptions() { + return ImmutableList.of(AuthAndTLSOptions.class); + } + @Override public void beforeCommand(CommandEnvironment env) { // Update the cache expiration policy according to the command options. diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BUILD b/src/main/java/com/google/devtools/build/lib/bazel/BUILD index 22c366230dbd89..3c29ea712d2909 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/BUILD +++ b/src/main/java/com/google/devtools/build/lib/bazel/BUILD @@ -26,6 +26,9 @@ java_library( "//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster", "//src/main/java/com/google/devtools/build/lib/analysis:blaze_directories", "//src/main/java/com/google/devtools/build/lib/analysis:config/build_configuration", + "//src/main/java/com/google/devtools/build/lib/authandtls", + "//src/main/java/com/google/devtools/build/lib/authandtls/credentialhelper", + "//src/main/java/com/google/devtools/build/lib/authandtls/credentialhelper:credential_module", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:common", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:inspection", "//src/main/java/com/google/devtools/build/lib/bazel/bzlmod:inspection_impl", @@ -59,6 +62,7 @@ java_library( "//src/main/java/com/google/devtools/common/options", "//src/main/protobuf:failure_details_java_proto", "//third_party:guava", + "//third_party:jsr305", ], ) diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java index 26d05bbbef501f..5e87645a450f50 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java @@ -15,6 +15,7 @@ package com.google.devtools.build.lib.bazel; +import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; @@ -25,6 +26,13 @@ import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.RuleDefinition; import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; +import com.google.devtools.build.lib.authandtls.AuthAndTLSOptions; +import com.google.devtools.build.lib.authandtls.GoogleAuthUtils; +import com.google.devtools.build.lib.authandtls.StaticCredentials; +import com.google.devtools.build.lib.authandtls.credentialhelper.CredentialHelperCredentials; +import com.google.devtools.build.lib.authandtls.credentialhelper.CredentialHelperEnvironment; +import com.google.devtools.build.lib.authandtls.credentialhelper.CredentialHelperProvider; +import com.google.devtools.build.lib.authandtls.credentialhelper.CredentialModule; import com.google.devtools.build.lib.bazel.bzlmod.AttributeValues; import com.google.devtools.build.lib.bazel.bzlmod.BazelDepGraphFunction; import com.google.devtools.build.lib.bazel.bzlmod.BazelLockFileFunction; @@ -110,6 +118,7 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; +import javax.annotation.Nullable; /** Adds support for fetching external code. */ public class BazelRepositoryModule extends BlazeModule { @@ -146,6 +155,8 @@ public class BazelRepositoryModule extends BlazeModule { private List allowedYankedVersions = ImmutableList.of(); private SingleExtensionEvalFunction singleExtensionEvalFunction; + @Nullable private CredentialModule credentialModule; + public BazelRepositoryModule() { this.starlarkRepositoryFunction = new StarlarkRepositoryFunction(downloadManager); this.repositoryHandlers = repositoryRules(); @@ -263,6 +274,8 @@ SkyFunctions.BAZEL_LOCK_FILE, new BazelLockFileFunction(directories.getWorkspace .addSkyFunction(SkyFunctions.SINGLE_EXTENSION_EVAL, singleExtensionEvalFunction) .addSkyFunction(SkyFunctions.SINGLE_EXTENSION_USAGES, new SingleExtensionUsagesFunction()); filesystem = runtime.getFileSystem(); + + credentialModule = Preconditions.checkNotNull(runtime.getBlazeModule(CredentialModule.class)); } @Override @@ -373,6 +386,41 @@ public void beforeCommand(CommandEnvironment env) throws AbruptExitException { Code.BAD_DOWNLOADER_CONFIG)); } + try { + AuthAndTLSOptions authAndTlsOptions = env.getOptions().getOptions(AuthAndTLSOptions.class); + var credentialHelperEnvironment = + CredentialHelperEnvironment.newBuilder() + .setEventReporter(env.getReporter()) + .setWorkspacePath(env.getWorkspace()) + .setClientEnvironment(env.getClientEnv()) + .setHelperExecutionTimeout(authAndTlsOptions.credentialHelperTimeout) + .build(); + CredentialHelperProvider credentialHelperProvider = + GoogleAuthUtils.newCredentialHelperProvider( + credentialHelperEnvironment, + env.getCommandLinePathFactory(), + authAndTlsOptions.credentialHelpers); + + downloadManager.setCredentialFactory( + headers -> { + Preconditions.checkNotNull(headers); + + return new CredentialHelperCredentials( + credentialHelperProvider, + credentialHelperEnvironment, + credentialModule.getCredentialCache(), + Optional.of(new StaticCredentials(headers))); + }); + } catch (IOException e) { + env.getReporter().handle(Event.error(e.getMessage())); + env.getBlazeModuleEnvironment() + .exit( + new AbruptExitException( + detailedExitCode( + "Error initializing credential helper", Code.CREDENTIALS_INIT_FAILURE))); + return; + } + if (repoOptions.experimentalDistdir != null) { downloadManager.setDistdir( repoOptions.experimentalDistdir.stream() diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/DownloadManager.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/DownloadManager.java index 05250dc08608a1..f8c88defa99f73 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/DownloadManager.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/DownloadManager.java @@ -61,6 +61,12 @@ public class DownloadManager { private int retries = 0; private boolean urlsAsDefaultCanonicalId; @Nullable private Credentials netrcCreds; + private CredentialFactory credentialFactory = StaticCredentials::new; + + /** Creates {@code Credentials} from a map of per-{@code URI} authentication headers. */ + public interface CredentialFactory { + Credentials create(Map>> authHeaders); + } public DownloadManager(RepositoryCache repositoryCache, Downloader downloader) { this.repositoryCache = repositoryCache; @@ -92,6 +98,10 @@ public void setNetrcCreds(Credentials netrcCreds) { this.netrcCreds = netrcCreds; } + public void setCredentialFactory(CredentialFactory credentialFactory) { + this.credentialFactory = credentialFactory; + } + /** * Downloads file to disk and returns path. * @@ -257,7 +267,7 @@ public Path download( try { downloader.download( rewrittenUrls, - new StaticCredentials(rewrittenAuthHeaders), + credentialFactory.create(rewrittenAuthHeaders), checksum, canonicalId, destination, @@ -338,7 +348,7 @@ public byte[] downloadAndReadOneUrl( for (int attempt = 0; attempt <= retries; ++attempt) { try { return httpDownloader.downloadAndReadOneUrl( - rewrittenUrls.get(0), new StaticCredentials(authHeaders), eventHandler, clientEnv); + rewrittenUrls.get(0), credentialFactory.create(authHeaders), eventHandler, clientEnv); } catch (ContentLengthMismatchException e) { if (attempt == retries) { throw e; diff --git a/src/main/protobuf/failure_details.proto b/src/main/protobuf/failure_details.proto index 99c919d2e4cdf4..2bced000af26af 100644 --- a/src/main/protobuf/failure_details.proto +++ b/src/main/protobuf/failure_details.proto @@ -249,6 +249,7 @@ message ExternalRepository { OVERRIDE_DISALLOWED_MANAGED_DIRECTORIES = 1 [(metadata) = { exit_code: 2 }]; BAD_DOWNLOADER_CONFIG = 2 [(metadata) = { exit_code: 2 }]; REPOSITORY_MAPPING_RESOLUTION_FAILED = 3 [(metadata) = { exit_code: 37 }]; + CREDENTIALS_INIT_FAILURE = 4 [(metadata) = { exit_code: 2 }]; } Code code = 1; // Additional data could include external repository names. diff --git a/src/test/java/com/google/devtools/build/lib/buildtool/util/BUILD b/src/test/java/com/google/devtools/build/lib/buildtool/util/BUILD index 09ba9771ffbd1f..bd188c69f5740e 100644 --- a/src/test/java/com/google/devtools/build/lib/buildtool/util/BUILD +++ b/src/test/java/com/google/devtools/build/lib/buildtool/util/BUILD @@ -50,6 +50,7 @@ java_library( "//src/main/java/com/google/devtools/build/lib/analysis:top_level_artifact_context", "//src/main/java/com/google/devtools/build/lib/analysis:transitive_info_collection", "//src/main/java/com/google/devtools/build/lib/analysis:workspace_status_action", + "//src/main/java/com/google/devtools/build/lib/authandtls/credentialhelper:credential_module", "//src/main/java/com/google/devtools/build/lib/bazel:main", "//src/main/java/com/google/devtools/build/lib/bazel:repository_module", "//src/main/java/com/google/devtools/build/lib/bugreport", diff --git a/src/test/java/com/google/devtools/build/lib/buildtool/util/BuildIntegrationTestCase.java b/src/test/java/com/google/devtools/build/lib/buildtool/util/BuildIntegrationTestCase.java index 1d4cea1c13df02..2ba922485a8942 100644 --- a/src/test/java/com/google/devtools/build/lib/buildtool/util/BuildIntegrationTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/buildtool/util/BuildIntegrationTestCase.java @@ -53,6 +53,7 @@ import com.google.devtools.build.lib.analysis.util.AnalysisMock; import com.google.devtools.build.lib.analysis.util.AnalysisTestUtil; import com.google.devtools.build.lib.analysis.util.AnalysisTestUtil.DummyWorkspaceStatusActionContext; +import com.google.devtools.build.lib.authandtls.credentialhelper.CredentialModule; import com.google.devtools.build.lib.bazel.BazelRepositoryModule; import com.google.devtools.build.lib.bugreport.BugReport; import com.google.devtools.build.lib.bugreport.BugReporter; @@ -530,7 +531,8 @@ protected BlazeRuntime.Builder getRuntimeBuilder() throws Exception { .addBlazeModule(new BuildIntegrationTestCommandsModule()) .addBlazeModule(new OutputFilteringModule()) .addBlazeModule(connectivityModule) - .addBlazeModule(getMockBazelRepositoryModule()); + .addBlazeModule(getMockBazelRepositoryModule()) + .addBlazeModule(new CredentialModule()); getSpawnModules().forEach(builder::addBlazeModule); builder .addBlazeModule(getBuildInfoModule()) diff --git a/src/test/shell/bazel/remote_helpers.sh b/src/test/shell/bazel/remote_helpers.sh index 52078d1065a534..bf406364fcadf4 100755 --- a/src/test/shell/bazel/remote_helpers.sh +++ b/src/test/shell/bazel/remote_helpers.sh @@ -38,8 +38,7 @@ function serve_file() { cd - } -# Serves $1 as a file on localhost:$nc_port insisting on authentication (but -# accepting any credentials. +# Serves $1 as a file on localhost:$nc_port expecting authentication. # * nc_port - the port nc is listening on. # * nc_log - the path to nc's log. # * nc_pid - the PID of nc. diff --git a/src/test/shell/bazel/starlark_repository_test.sh b/src/test/shell/bazel/starlark_repository_test.sh index 1f526efcbdeb4c..84f933fb1b6011 100755 --- a/src/test/shell/bazel/starlark_repository_test.sh +++ b/src/test/shell/bazel/starlark_repository_test.sh @@ -1713,38 +1713,64 @@ EOF expect_log "//:b.bzl" } -function test_auth_provided() { - mkdir x +# Common setup logic for test_auth_*. +# Receives as arguments the username and password for basic authentication. +# If no arguments are provided, no authentication is used. +function setup_auth() { + if [[ $# -ne 0 && $# -ne 2 ]]; then + fail "setup_auth expects exactly zero or two arguments" + fi + + mkdir -p 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_attrs.bzl < auth_attrs.bzl <<'EOF' +AUTH_ATTRS = None EOF + fi + cat > auth.bzl <<'EOF' +load("//:auth_attrs.bzl", "AUTH_ATTRS") 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"}} + auth = { ctx.attr.url: AUTH_ATTRS } if AUTH_ATTRS else {}, ) -with_auth = repository_rule( +maybe_with_auth = repository_rule( implementation = _impl, - attrs = { "url" : attr.string(), "sha256" : attr.string() } + attrs = { + "url" : attr.string(), + "sha256" : attr.string(), + } ) EOF + + cat >> $(create_workspace_with_default_repos WORKSPACE) < BUILD <<'EOF' genrule( name = "it", @@ -1753,8 +1779,51 @@ genrule( cmd = "cp $< $@", ) EOF +} + +function test_auth_from_starlark() { + setup_auth foo bar + bazel build //:it \ - || fail "Expected success despite needing a file behind basic auth" + || fail "Expected success when downloading repo with basic auth" +} + +function test_auth_from_credential_helper() { + if "$is_windows"; then + # Skip on Windows: credential helper is a Python script. + return + fi + + setup_credential_helper + + setup_auth # no auth + + bazel build //:it \ + && fail "Expected failure when downloading repo without credential helper" + + bazel build --experimental_credential_helper="${TEST_TMPDIR}/credhelper" //:it \ + || fail "Expected success when downloading repo with credential helper" + + expect_credential_helper_calls 1 + + bazel build --experimental_credential_helper="${TEST_TMPDIR}/credhelper" //:it \ + || fail "Expected success when downloading repo with credential helper" + + expect_credential_helper_calls 1 # expect credentials to have been cached +} + +function test_auth_from_credential_helper_overrides_starlark() { + if "$is_windows"; then + # Skip on Windows: credential helper is a Python script. + return + fi + + setup_credential_helper + + setup_auth baduser badpass + + bazel build --experimental_credential_helper="${TEST_TMPDIR}/credhelper" //:it \ + || fail "Expected success when downloading repo with credential helper overriding basic auth" } function test_netrc_reading() { @@ -2078,7 +2147,7 @@ EOF || fail "Expected success despite needing a file behind bearer auth" } -function test_implicit_netrc() { +function test_http_archive_implicit_netrc() { mkdir x echo 'exports_files(["file.txt"])' > x/BUILD echo 'Hello World' > x/file.txt @@ -2118,6 +2187,87 @@ EOF || fail "Expected success despite needing a file behind basic auth" } +function test_http_archive_credential_helper() { + if "$is_windows"; then + # Skip on Windows: credential helper is a Python script. + return + fi + + setup_credential_helper + + 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 < BUILD <<'EOF' +genrule( + name = "it", + srcs = ["@ext//x:file.txt"], + outs = ["it.txt"], + cmd = "cp $< $@", +) +EOF + bazel build --experimental_credential_helper="${TEST_TMPDIR}/credhelper" //:it \ + || fail "Expected success despite needing a file behind credential helper" +} + +function test_http_archive_credential_helper_overrides_netrc() { + if "$is_windows"; then + # Skip on Windows: credential helper is a Python script. + return + fi + + setup_credential_helper + + 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` + if "$is_windows"; then + export USERPROFILE="$(cygpath -m ${HOME})" + fi + cat > .netrc <<'EOF' +machine 127.0.0.1 +login badusername +password badpassword +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 --experimental_credential_helper="${TEST_TMPDIR}/credhelper" //:it \ + || fail "Expected success despite needing a file behind credential helper" +} + function test_disable_download_should_prevent_downloading() { mkdir x echo 'exports_files(["file.txt"])' > x/BUILD diff --git a/src/test/shell/bazel/testing_server.py b/src/test/shell/bazel/testing_server.py index 9d6cd23a57ee88..00c714792d2d95 100644 --- a/src/test/shell/bazel/testing_server.py +++ b/src/test/shell/bazel/testing_server.py @@ -94,7 +94,9 @@ def do_GET(self): # pylint: disable=invalid-name self.serve_file() else: self.do_AUTHHEAD() - self.wfile.write(b'Login required.' + str(auth_header)) + self.wfile.write( + 'Bad authorization header: {}'.format(auth_header).encode('ascii') + ) def serve_file(self): path_to_serve = self.path[1:]