| #!/bin/bash |
| # |
| # Copyright 2015 The Bazel Authors. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| # Test sandboxing spawn strategy |
| # |
| |
| # Load test environment |
| # Load the test setup defined in the parent directory |
| CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
| source "${CURRENT_DIR}/../integration_test_setup.sh" \ |
| || { echo "integration_test_setup.sh not found!" >&2; exit 1; } |
| source ${CURRENT_DIR}/../sandboxing_test_utils.sh \ |
| || { echo "sandboxing_test_utils.sh not found!" >&2; exit 1; } |
| function set_up { |
| add_to_bazelrc "build --spawn_strategy=sandboxed" |
| add_to_bazelrc "build --genrule_strategy=sandboxed" |
| |
| # Enabled in testenv.sh.tmpl, but not in Bazel by default. |
| sed -i.bak '/sandbox_tmpfs_path/d' "$bazelrc" |
| } |
| |
| function assert_not_exists() { |
| path="$1" |
| [ ! -f "$path" ] && return 0 |
| |
| fail "Expected file '$path' to not exist, but it did" |
| return 1 |
| } |
| |
| function test_sandboxed_tooldir() { |
| mkdir -p examples/genrule |
| |
| cat << 'EOF' > examples/genrule/BUILD |
| genrule( |
| name = "tooldir", |
| srcs = [], |
| outs = ["tooldir.txt"], |
| cmd = "ls -l external/bazel_tools/tools/genrule | tee $@ >&2; " + |
| "cat external/bazel_tools/tools/genrule/genrule-setup.sh >&2", |
| ) |
| EOF |
| |
| bazel build examples/genrule:tooldir &> $TEST_log \ |
| || fail "Hermetic genrule failed: examples/genrule:tooldir" |
| [ -f "bazel-genfiles/examples/genrule/tooldir.txt" ] \ |
| || fail "Genrule did not produce output: examples/genrule:works" |
| cat "bazel-genfiles/examples/genrule/tooldir.txt" > $TEST_log |
| expect_log "genrule-setup.sh" |
| } |
| |
| function test_sandbox_block_filesystem() { |
| # The point of this test is to attempt to read something from the filesystem |
| # that is blocked via --sandbox_block_path= and thus shouldn't be accessible. |
| # |
| # /var/log is an arbitrary choice of directory that should exist on all |
| # Unix-like systems. |
| local block_path |
| case "$(uname -s)" in |
| Darwin) |
| # TODO(jmmv): sandbox-exec does not resolve symlinks, so attempting |
| # to block /var/log does not work. Unsure if we should make this work |
| # by resolving symlinks or documenting the expected behavior. |
| block_path=/private/var/log |
| ;; |
| *) |
| block_path=/var/log |
| ;; |
| esac |
| |
| mkdir pkg |
| cat >pkg/BUILD <<EOF |
| genrule( |
| name = "breaks", |
| srcs = [ "a.txt" ], |
| outs = [ "breaks.txt" ], |
| cmd = "ls ${block_path} &> \$@", |
| ) |
| EOF |
| touch pkg/a.txt |
| |
| local output_file="bazel-genfiles/pkg/breaks.txt" |
| |
| bazel build --sandbox_block_path="${block_path}" \ |
| --sandbox_block_path=/doesnotexist pkg:breaks \ |
| &> $TEST_log \ |
| && fail "Non-hermetic genrule succeeded: examples/genrule:breaks" || true |
| |
| [ -f "$output_file" ] || |
| fail "Action did not produce output: $output_file" |
| cat "${output_file}" >$TEST_log |
| |
| if [ "$(wc -l $output_file | awk '{print $1}')" -gt 1 ]; then |
| fail "Output contained more than one line: $output_file" |
| fi |
| |
| grep -E "(Operation not permitted|Permission denied)" $output_file || |
| fail "Output did not contain expected error message: $output_file" |
| } |
| |
| # TODO(philwo) - this doesn't work on Ubuntu 14.04 due to "unshare" being too |
| # old and not understanding the --user flag. |
| function DISABLED_test_sandbox_different_nobody_uid() { |
| cat /etc/passwd | sed 's/\(^nobody:[^:]*:\)[0-9]*:[0-9]*/\15000:16000/g' > \ |
| "${TEST_TMPDIR}/passwd" |
| unshare --user --mount --map-root-user -- bash - \ |
| << EOF || fail "Hermetic genrule with different UID for nobody failed" \ |
| set -e |
| set -u |
| |
| mount --bind ${TEST_TMPDIR}/passwd /etc/passwd |
| bazel build examples/genrule:works &> ${TEST_log} |
| EOF |
| } |
| |
| # Tests that a pseudoterminal can be opened in linux when --sandbox_explicit_pseudoterminal is active |
| function test_can_enable_pseudoterminals() { |
| if [[ "$(uname -s)" != Linux ]]; then |
| echo "Skipping test: flag intended for linux systems" |
| return 0 |
| fi |
| |
| cat > test.py <<'EOF' |
| import pty |
| pty.openpty() |
| EOF |
| cat > BUILD <<'EOF' |
| py_test( |
| name = "test", |
| srcs = ["test.py"], |
| ) |
| EOF |
| bazel test --sandbox_explicit_pseudoterminal --verbose_failures --sandbox_debug :test || fail "test did not pass" |
| } |
| |
| function test_sandbox_debug() { |
| if [[ "$PLATFORM" == "darwin" ]]; then |
| # The process wrapper sandbox used in MacOS doesn't emit debug output. |
| return 0 |
| fi |
| |
| cat > BUILD <<'EOF' |
| genrule( |
| name = "broken", |
| outs = ["bla.txt"], |
| cmd = "exit 1", |
| ) |
| EOF |
| bazel build --verbose_failures :broken &> $TEST_log \ |
| && fail "build should have failed" || true |
| expect_log "Use --sandbox_debug to see verbose messages from the sandbox and retain the sandbox build root for debugging" |
| expect_log "Executing genrule //:broken failed" |
| |
| bazel build --verbose_failures --sandbox_debug :broken &> $TEST_log \ |
| && fail "build should have failed" || true |
| expect_log "Executing genrule //:broken failed" |
| expect_not_log "Use --sandbox_debug to see verbose messages from the sandbox and retain the sandbox build root for debugging" |
| expect_log "child exited normally with code 1" |
| |
| bazel build --verbose_failures --sandbox_debug --experimental_use_hermetic_linux_sandbox :broken &> $TEST_log \ |
| && fail "build should have failed with hermetic sandbox" || true |
| expect_log "child exited normally with code 1" |
| |
| bazel build --verbose_failures --sandbox_debug --incompatible_sandbox_hermetic_tmp :broken &> $TEST_log \ |
| && fail "build should have failed with hermetic sandbox /tmp" || true |
| expect_log "child exited normally with code 1" |
| } |
| |
| function test_sandbox_expands_tree_artifacts_in_runfiles_tree() { |
| create_workspace_with_default_repos WORKSPACE |
| |
| cat > def.bzl <<'EOF' |
| def _mkdata_impl(ctx): |
| out = ctx.actions.declare_directory(ctx.label.name + ".d") |
| script = "mkdir -p {out}; touch {out}/file; ln -s file {out}/link".format(out = out.path) |
| ctx.actions.run_shell( |
| outputs = [out], |
| command = script, |
| ) |
| runfiles = ctx.runfiles(files = [out]) |
| return [DefaultInfo( |
| files = depset([out]), |
| runfiles = runfiles, |
| )] |
| |
| mkdata = rule( |
| _mkdata_impl, |
| ) |
| EOF |
| |
| cat > mkdata_test.sh <<'EOF' |
| #!/bin/bash |
| |
| set -euo pipefail |
| |
| test_dir="$1" |
| cd "$test_dir" |
| ls -l | cut -f1,9 -d' ' >&2 |
| |
| if [ ! -f file -o -L file ]; then |
| echo "'file' is not a regular file" >&2 |
| exit 1 |
| fi |
| EOF |
| chmod +x mkdata_test.sh |
| |
| cat > BUILD <<'EOF' |
| load("//:def.bzl", "mkdata") |
| |
| mkdata(name = "mkdata") |
| |
| sh_test( |
| name = "mkdata_test", |
| srcs = ["mkdata_test.sh"], |
| args = ["$(location :mkdata)"], |
| data = [":mkdata"], |
| ) |
| EOF |
| |
| bazel test --test_output=streamed //:mkdata_test &>$TEST_log && fail "expected test to fail" || true |
| expect_log "'file' is not a regular file" |
| } |
| |
| # Regression test for https://github.com/bazelbuild/bazel/issues/6262. |
| function test_create_tree_artifact_outputs() { |
| create_workspace_with_default_repos WORKSPACE |
| |
| cat > def.bzl <<'EOF' |
| def _r(ctx): |
| d = ctx.actions.declare_directory("%s_dir" % ctx.label.name) |
| ctx.actions.run_shell( |
| outputs = [d], |
| command = "cd %s && pwd" % d.path, |
| ) |
| return [DefaultInfo(files = depset([d]))] |
| |
| r = rule(implementation = _r) |
| EOF |
| |
| cat > BUILD <<'EOF' |
| load(":def.bzl", "r") |
| |
| r(name = "a") |
| EOF |
| |
| bazel build --test_output=streamed :a &>$TEST_log || fail "expected build to succeed" |
| } |
| |
| # Regression test for https://github.com/bazelbuild/bazel/issues/20032 and |
| # https://github.com/bazelbuild/bazel/issues/22260. |
| function test_permissionless_tree_artifact() { |
| create_workspace_with_default_repos WORKSPACE |
| |
| cat > def.bzl <<'EOF' |
| def _r(ctx): |
| d = ctx.actions.declare_directory(ctx.label.name) |
| ctx.actions.run_shell( |
| outputs = [d], |
| command = "touch $1/file.txt && chmod 000 $1", |
| arguments = [d.path], |
| ) |
| return DefaultInfo(files = depset([d])) |
| |
| r = rule(_r) |
| EOF |
| |
| cat > BUILD <<'EOF' |
| load(":def.bzl", "r") |
| |
| r(name = "a") |
| EOF |
| |
| bazel build --test_output=streamed :a &>$TEST_log || fail "expected build to succeed" |
| } |
| |
| function test_empty_tree_artifact_as_inputs() { |
| # Test that when an empty tree artifact is the input, an empty directory is |
| # created in the sandbox for action to read. |
| create_workspace_with_default_repos WORKSPACE |
| |
| mkdir -p pkg |
| |
| cat > pkg/def.bzl <<'EOF' |
| def _r(ctx): |
| empty_d = ctx.actions.declare_directory("%s/empty_dir" % ctx.label.name) |
| ctx.actions.run_shell( |
| outputs = [empty_d], |
| command = "mkdir -p %s" % empty_d.path, |
| ) |
| f = ctx.actions.declare_file("%s/file" % ctx.label.name) |
| ctx.actions.run_shell( |
| inputs = [empty_d], |
| outputs = [f], |
| command = "touch %s && cd %s && pwd" % (f.path, empty_d.path), |
| ) |
| return [DefaultInfo(files = depset([f]))] |
| |
| r = rule(implementation = _r) |
| EOF |
| |
| cat > pkg/BUILD <<'EOF' |
| load(":def.bzl", "r") |
| |
| r(name = "a") |
| EOF |
| |
| bazel build //pkg:a &>$TEST_log || fail "expected build to succeed" |
| } |
| |
| # Sets up targets under //test that, when building //test:all, verify that the |
| # sandbox setup ensures that /tmp contents written by one action are not visible |
| # to another action. |
| # |
| # Arguments: |
| # - The path to a unique temporary directory under /tmp that a |
| # file named "bazel_was_here" is written to in actions. |
| function setup_tmp_hermeticity_check() { |
| local -r tmpdir=$1 |
| |
| mkdir -p test |
| cat > test/BUILD <<'EOF' |
| cc_binary( |
| name = "create_file", |
| srcs = ["create_file.cc"], |
| ) |
| |
| [ |
| genrule( |
| name = "gen" + str(i), |
| outs = ["gen{}.txt".format(i)], |
| tools = [":create_file"], |
| cmd = """ |
| path=$$($(location :create_file)) |
| cp "$$path" $@ |
| """, |
| ) |
| for i in range(1, 3) |
| ] |
| EOF |
| cat > test/create_file.cc <<EOF |
| // Create a file in a fixed location only if it doesn't exist. |
| // Then write its path to stdout. |
| #include <fcntl.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| int main() { |
| if (mkdir("$tmpdir", 0755) < 0) { |
| perror("mkdir"); |
| return 1; |
| } |
| int fd = open("$tmpdir/bazel_was_here", O_CREAT | O_EXCL | O_WRONLY, 0600); |
| if (fd < 0) { |
| perror("open"); |
| return 1; |
| } |
| if (write(fd, "HERMETIC\n", 9) != 9) { |
| perror("write"); |
| return 1; |
| } |
| close(fd); |
| printf("$tmpdir/bazel_was_here\n"); |
| return 0; |
| } |
| EOF |
| } |
| |
| function test_add_mount_pair_tmp_source() { |
| if [[ "$PLATFORM" == "darwin" ]]; then |
| # Tests Linux-specific functionality |
| return 0 |
| fi |
| |
| create_workspace_with_default_repos WORKSPACE |
| |
| local mounted=$(mktemp -d "/tmp/bazel_mounted.XXXXXXXX") |
| trap "rm -fr $mounted" EXIT |
| echo GOOD > "$mounted/data.txt" |
| |
| local tmp_dir=$(mktemp -d "/tmp/bazel_mounted.XXXXXXXX") |
| trap "rm -fr $tmp_dir" EXIT |
| setup_tmp_hermeticity_check "$tmp_dir" |
| |
| mkdir -p pkg |
| cat > pkg/BUILD <<'EOF' |
| genrule( |
| name = "gen", |
| outs = ["gen.txt"], |
| cmd = "cp /etc/data.txt $@", |
| ) |
| EOF |
| |
| # This assumes the existence of /etc on the host system |
| bazel build --sandbox_add_mount_pair="$mounted:/etc" \ |
| //pkg:gen //test:all || fail "build failed" |
| assert_equals GOOD "$(cat bazel-bin/pkg/gen.txt)" |
| assert_equals HERMETIC "$(cat bazel-bin/test/gen1.txt)" |
| assert_equals HERMETIC "$(cat bazel-bin/test/gen2.txt)" |
| assert_not_exists "$tmp_dir/bazel_was_here" |
| } |
| |
| function test_add_mount_pair_tmp_target() { |
| if [[ "$PLATFORM" == "darwin" ]]; then |
| # Tests Linux-specific functionality |
| return 0 |
| fi |
| |
| create_workspace_with_default_repos WORKSPACE |
| |
| local source_dir=$(mktemp -d "/tmp/bazel_mounted.XXXXXXXX") |
| trap "rm -fr $source_dir" EXIT |
| echo BAD > "$source_dir/data.txt" |
| |
| local tmp_dir=$(mktemp -d "/tmp/bazel_mounted.XXXXXXXX") |
| trap "rm -fr $tmp_dir" EXIT |
| setup_tmp_hermeticity_check "$tmp_dir" |
| |
| mkdir -p pkg |
| cat > pkg/BUILD <<EOF |
| genrule( |
| name = "gen", |
| outs = ["gen.txt"], |
| cmd = """ls "$source_dir" > \$@""", |
| ) |
| EOF |
| |
| |
| # This assumes the existence of /etc on the host system |
| bazel build --sandbox_add_mount_pair="/etc:$source_dir" \ |
| //pkg:gen //test:all || fail "build failed" |
| assert_contains passwd bazel-bin/pkg/gen.txt |
| assert_not_contains data.txt bazel-bin/pkg/gen.txt |
| assert_equals HERMETIC "$(cat bazel-bin/test/gen1.txt)" |
| assert_equals HERMETIC "$(cat bazel-bin/test/gen2.txt)" |
| assert_not_exists "$tmp_dir/bazel_was_here" |
| } |
| |
| function test_add_mount_pair_tmp_target_and_source() { |
| if [[ "$PLATFORM" == "darwin" ]]; then |
| # Tests Linux-specific functionality |
| return 0 |
| fi |
| |
| create_workspace_with_default_repos WORKSPACE |
| |
| local mounted=$(mktemp -d "/tmp/bazel_mounted.XXXXXXXX") |
| trap "rm -fr $mounted" EXIT |
| echo GOOD > "$mounted/data.txt" |
| |
| local tmp_dir=$(mktemp -d "/tmp/bazel_mounted.XXXXXXXX") |
| trap "rm -fr $tmp_dir" EXIT |
| setup_tmp_hermeticity_check "$tmp_dir" |
| |
| mkdir -p pkg |
| cat > pkg/BUILD <<EOF |
| genrule( |
| name = "gen", |
| outs = ["gen.txt"], |
| cmd = """cp "$mounted/data.txt" \$@""", |
| ) |
| EOF |
| |
| bazel build --sandbox_add_mount_pair="$mounted" \ |
| //pkg:gen //test:all || fail "build failed" |
| assert_equals GOOD "$(cat bazel-bin/pkg/gen.txt)" |
| assert_equals HERMETIC "$(cat bazel-bin/test/gen1.txt)" |
| assert_equals HERMETIC "$(cat bazel-bin/test/gen2.txt)" |
| assert_not_exists "$tmp_dir/bazel_was_here" |
| } |
| |
| function test_symlink_with_output_base_under_tmp() { |
| if [[ "$PLATFORM" == "darwin" ]]; then |
| # Tests Linux-specific functionality |
| return 0 |
| fi |
| |
| local repo=$(mktemp -d "/tmp/bazel_mounted.XXXXXXXX") |
| trap "rm -fr $repo" EXIT |
| |
| touch WORKSPACE |
| |
| mkdir -p $repo/pkg |
| touch $repo/WORKSPACE |
| cat > $repo/pkg/es1 <<'EOF' |
| EXTERNAL_SOURCE_CONTENT |
| EOF |
| cat > $repo/pkg/BUILD <<'EOF' |
| exports_files(["es1"]) |
| genrule( |
| name="er1", |
| srcs=[], |
| outs=[":er1"], |
| cmd="echo EXTERNAL_GEN_CONTENT > $@", |
| visibility=["//visibility:public"], |
| ) |
| EOF |
| |
| mkdir -p $repo/examples |
| cd $repo/examples || fail "cd $repo/examples failed" |
| |
| cat > WORKSPACE <<EOF |
| local_repository( |
| name = "repo", |
| path = "$repo", |
| ) |
| EOF |
| |
| mkdir -p pkg |
| cat > pkg/s1 <<'EOF' |
| SOURCE_CONTENT |
| EOF |
| cat > pkg/BUILD <<'EOF' |
| load(":r.bzl", "symlink_rule") |
| |
| genrule(name="r1", srcs=[], outs=[":r1"], cmd="echo GEN_CONTENT > $@") |
| symlink_rule(name="r2", input=":r1") |
| genrule(name="r3", srcs=[":r2"], outs=[":r3"], cmd="cp $< $@") |
| symlink_rule(name="s2", input=":s1") |
| genrule(name="s3", srcs=[":s2"], outs=[":s3"], cmd="cp $< $@") |
| symlink_rule(name="er2", input="@repo//pkg:er1") |
| genrule(name="er3", srcs=[":er2"], outs=[":er3"], cmd="cp $< $@") |
| symlink_rule(name="es2", input="@repo//pkg:es1") |
| genrule(name="es3", srcs=[":es2"], outs=[":es3"], cmd="cp $< $@") |
| EOF |
| |
| cat > pkg/r.bzl <<'EOF' |
| def _symlink_impl(ctx): |
| output = ctx.actions.declare_file(ctx.label.name) |
| ctx.actions.symlink(output = output, target_file = ctx.file.input) |
| return [DefaultInfo(files = depset([output]))] |
| |
| symlink_rule = rule( |
| implementation = _symlink_impl, |
| attrs = {"input": attr.label(allow_single_file=True)}) |
| EOF |
| |
| local tmp_output_base=$(mktemp -d "/tmp/bazel_output_base.XXXXXXXX") |
| trap "chmod -R u+w $tmp_output_base && rm -fr $tmp_output_base" EXIT |
| |
| bazel --output_base="$tmp_output_base" build //pkg:{er,es,r,s}3 --sandbox_debug |
| assert_contains EXTERNAL_GEN_CONTENT bazel-bin/pkg/er3 |
| assert_contains EXTERNAL_SOURCE_CONTENT bazel-bin/pkg/es3 |
| assert_contains GEN_CONTENT bazel-bin/pkg/r3 |
| assert_contains SOURCE_CONTENT bazel-bin/pkg/s3 |
| bazel --output_base="$tmp_output_base" shutdown |
| } |
| |
| function test_symlink_to_directory_absolute_path() { |
| if [[ "$PLATFORM" == "darwin" ]]; then |
| # Tests Linux-specific functionality |
| return 0 |
| fi |
| |
| create_workspace_with_default_repos WORKSPACE |
| |
| mkdir -p /tmp/tree/{a,b} |
| touch /tmp/tree/{a,b}/file |
| |
| mkdir -p pkg |
| cat > pkg/BUILD <<'EOF' |
| load(":r.bzl", "symlink_rule", "tree_rule") |
| |
| symlink_rule(name="s", input=":t") |
| tree_rule(name="t") |
| EOF |
| |
| |
| cat > pkg/r.bzl <<'EOF' |
| def _symlink_impl(ctx): |
| output = ctx.actions.declare_directory(ctx.label.name) |
| ctx.actions.symlink(output = output, target_file = ctx.file.input) |
| return [DefaultInfo(files = depset([output]))] |
| |
| symlink_rule = rule( |
| implementation = _symlink_impl, |
| attrs = {"input": attr.label(allow_single_file=True)}) |
| |
| def _tree_impl(ctx): |
| output = ctx.actions.declare_directory(ctx.label.name) |
| ctx.actions.run_shell( |
| outputs = [output], |
| # Make the tree artifact itself a symlink to /tmp/tree |
| command = "export TREE=%s && rmdir $TREE && ln -s /tmp/tree $TREE" % output.path) |
| return [DefaultInfo(files = depset([output]))] |
| |
| tree_rule = rule( |
| implementation = _tree_impl, |
| attrs = {}) |
| EOF |
| |
| # /tmp/tree in the action sandbox must be the same as outside of it |
| bazel build --sandbox_add_mount_pair=/tmp/tree //pkg:s || fail "build failed" |
| } |
| |
| function test_symlink_to_directory_with_output_base_under_tmp() { |
| if [[ "$PLATFORM" == "darwin" ]]; then |
| # Tests Linux-specific functionality |
| return 0 |
| fi |
| |
| create_workspace_with_default_repos WORKSPACE |
| |
| mkdir -p pkg |
| cat > pkg/BUILD <<'EOF' |
| load(":r.bzl", "symlink_rule", "tree_rule") |
| |
| tree_rule(name="t1") |
| symlink_rule(name="t2", input=":t1") |
| genrule(name="t3", srcs=[":t2"], outs=[":t3"], cmd=";\n".join( |
| ["cat $(location :t2)/{a/a,b/b} > $@"])) |
| EOF |
| |
| cat > pkg/r.bzl <<'EOF' |
| def _symlink_impl(ctx): |
| output = ctx.actions.declare_directory(ctx.label.name) |
| ctx.actions.symlink(output = output, target_file = ctx.file.input) |
| return [DefaultInfo(files = depset([output]))] |
| |
| symlink_rule = rule( |
| implementation = _symlink_impl, |
| attrs = {"input": attr.label(allow_single_file=True)}) |
| |
| def _tree_impl(ctx): |
| output = ctx.actions.declare_directory(ctx.label.name) |
| ctx.actions.run_shell( |
| outputs = [output], |
| command = "export TREE=%s && mkdir $TREE/a $TREE/b && echo -n A > $TREE/a/a && echo -n B > $TREE/b/b" % output.path) |
| return [DefaultInfo(files = depset([output]))] |
| |
| tree_rule = rule( |
| implementation = _tree_impl, |
| attrs = {}) |
| |
| EOF |
| |
| local tmp_output_base=$(mktemp -d "/tmp/bazel_output_base.XXXXXXXX") |
| trap "chmod -R u+w $tmp_output_base && rm -fr $tmp_output_base" EXIT |
| |
| bazel --output_base="$tmp_output_base" build //pkg:t3 |
| assert_contains AB bazel-bin/pkg/t3 |
| bazel --output_base="$tmp_output_base" shutdown |
| } |
| |
| function test_tmpfs_path_under_tmp() { |
| if [[ "$PLATFORM" == "darwin" ]]; then |
| # Tests Linux-specific functionality |
| return 0 |
| fi |
| |
| create_workspace_with_default_repos WORKSPACE |
| |
| local tmpfs=$(mktemp -d "/tmp/bazel_tmpfs.XXXXXXXX") |
| trap "rm -fr $tmpfs" EXIT |
| echo BAD > "$tmpfs/data.txt" |
| |
| local tmp_dir=$(mktemp -d "/tmp/bazel_mounted.XXXXXXXX") |
| trap "rm -fr $tmp_dir" EXIT |
| setup_tmp_hermeticity_check "$tmp_dir" |
| |
| mkdir -p pkg |
| cat > pkg/BUILD <<EOF |
| genrule( |
| name = "gen", |
| outs = ["gen.txt"], |
| cmd = """ |
| # Verify that the tmpfs under /tmp exists and is empty. |
| [[ -d "$tmpfs" ]] |
| [[ ! -e "$tmpfs/data.txt" ]] |
| # Verify that the tmpfs on /etc exists and is empty. |
| [[ -d /etc ]] |
| [[ -z "\$\$(ls -A /etc)" ]] |
| touch \$@ |
| """, |
| ) |
| EOF |
| |
| # This assumes the existence of /etc on the host system |
| bazel build --sandbox_tmpfs_path="$tmpfs" --sandbox_tmpfs_path=/etc \ |
| //pkg:gen //test:all || fail "build failed" |
| assert_equals HERMETIC "$(cat bazel-bin/test/gen1.txt)" |
| assert_equals HERMETIC "$(cat bazel-bin/test/gen2.txt)" |
| assert_not_exists "$tmp_dir/bazel_was_here" |
| } |
| |
| function test_hermetic_tmp_under_tmp { |
| if [[ "$(uname -s)" != Linux ]]; then |
| echo "Skipping test: --incompatible_sandbox_hermetic_tmp is only supported in Linux" 1>&2 |
| return 0 |
| fi |
| |
| temp_dir=$(mktemp -d /tmp/test.XXXXXX) |
| trap 'rm -rf ${temp_dir}' EXIT |
| |
| mkdir -p "${temp_dir}/workspace/a" |
| mkdir -p "${temp_dir}/package-path/b" |
| mkdir -p "${temp_dir}/repo/c" |
| mkdir -p "${temp_dir}/output-base" |
| |
| cd "${temp_dir}/workspace" |
| cat > WORKSPACE <<EOF |
| local_repository(name="repo", path="${temp_dir}/repo") |
| EOF |
| |
| cat > a/BUILD <<'EOF' |
| genrule( |
| name = "g", |
| outs = ["go"], |
| srcs = [], |
| cmd = "echo GO > $@", |
| ) |
| sh_binary( |
| name = "bin", |
| srcs = ["bin.sh"], |
| data = [":s", ":go", "//b:s", "//b:go", "@repo//c:s", "@repo//c:go"], |
| ) |
| genrule( |
| name = "t", |
| tools = [":bin"], |
| srcs = [":s", ":go", "//b:s", "//b:go", "@repo//c:s", "@repo//c:go"], |
| outs = ["to"], |
| cmd = "\n".join([ |
| "RUNFILES=$(location :bin).runfiles/_main", |
| "S=$(location :s); GO=$(location :go)", |
| "BS=$(location //b:s); BGO=$(location //b:go)", |
| "RS=$(location @repo//c:s); RGO=$(location @repo//c:go)", |
| "for i in $$S $$GO $$BS $$BGO $$RS $$RGO; do", |
| " echo reading $$i", |
| " cat $$i >> $@", |
| "done", |
| "for i in a/s a/go b/s b/go ../repo/c/s ../repo/c/go; do", |
| " echo reading $$RUNFILES/$$i", |
| " cat $$RUNFILES/$$i >> $@", |
| "done", |
| ]), |
| ) |
| EOF |
| |
| touch a/bin.sh |
| chmod +x a/bin.sh |
| |
| touch ../repo/WORKSPACE |
| cat > ../repo/c/BUILD <<'EOF' |
| exports_files(["s"]) |
| genrule( |
| name = "g", |
| outs = ["go"], |
| srcs = [], |
| cmd = "echo GO > $@", |
| visibility = ["//visibility:public"], |
| ) |
| EOF |
| |
| cat > ../package-path/b/BUILD <<'EOF' |
| exports_files(["s"]) |
| genrule( |
| name = "g", |
| outs = ["go"], |
| srcs = [], |
| cmd = "echo GO > $@", |
| visibility = ["//visibility:public"], |
| ) |
| EOF |
| |
| touch "a/s" "../package-path/b/s" "../repo/c/s" |
| |
| cat WORKSPACE |
| bazel \ |
| --output_base="${temp_dir}/output-base" \ |
| build \ |
| --incompatible_sandbox_hermetic_tmp \ |
| --package_path="%workspace%:${temp_dir}/package-path" \ |
| //a:t || fail "build failed" |
| } |
| |
| # Regression test for https://github.com/bazelbuild/bazel/issues/21215 |
| function test_copy_input_symlinks() { |
| create_workspace_with_default_repos WORKSPACE |
| |
| cat > MODULE.bazel <<'EOF' |
| repo = use_repo_rule("//pkg:repo.bzl", "repo") |
| repo(name = "some_repo") |
| EOF |
| |
| mkdir -p pkg |
| cat > pkg/BUILD <<'EOF' |
| genrule( |
| name = "copy_files", |
| srcs = [ |
| "@some_repo//:files", |
| ], |
| outs = [ |
| "some_file1.json", |
| "some_file2.json", |
| ], |
| cmd = "cp -r $(locations @some_repo//:files) $(RULEDIR)", |
| ) |
| EOF |
| cat > pkg/repo.bzl <<'EOF' |
| def _impl(rctx): |
| rctx.file("some_file1.json", "hello") |
| rctx.file("some_file2.json", "world") |
| rctx.file("BUILD", """filegroup( |
| name = "files", |
| srcs = ["some_file1.json", "some_file2.json"], |
| visibility = ["//visibility:public"], |
| )""") |
| |
| repo = repository_rule(_impl) |
| EOF |
| |
| bazel build //pkg:copy_files || fail "build failed" |
| assert_equals hello "$(cat bazel-bin/pkg/some_file1.json)" |
| assert_equals world "$(cat bazel-bin/pkg/some_file2.json)" |
| } |
| |
| # The test shouldn't fail if the environment doesn't support running it. |
| check_sandbox_allowed || exit 0 |
| |
| run_suite "sandbox" |