From b4c49261f083210ddeb9cfc85b17a7f64f943f0f Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Thu, 10 Mar 2022 10:22:37 -0500 Subject: [PATCH] integration tests: learn to start a dummy registry When a test needs to talk to a registry server, launch one as part of the test rather than depending on it having been started by someone else. Use run_buildah where we used to use 'run buildah' without checking the return code, and in a few cases where we did check it. In the "from with non buildah container" test, use "podman create" with host networking, in an attempt to avoid messing with networking in cases where we're running on a system with a version of podman that will create a bridge with CNI that we'll also create with netavark. We're not sharing storage between the two invocations, so the logic that tries to detect this problem won't detect it. Signed-off-by: Nalin Dahyabhai --- Makefile | 2 +- cmd/buildah/passwd.go | 34 +++ internal/parse/parse.go | 2 +- tests/authenticate.bats | 92 +++--- tests/bud.bats | 41 ++- tests/bud/from-encrypted-image/Dockerfile | 1 - tests/commit.bats | 13 +- tests/containers.bats | 7 +- tests/containers_conf.bats | 91 +++--- tests/copy.bats | 22 +- tests/from.bats | 33 ++- tests/helpers.bash | 131 ++++++++- tests/pull.bats | 40 +-- tests/push.bats | 28 +- tests/registries.conf | 4 +- tests/source.bats | 6 +- vendor/golang.org/x/crypto/bcrypt/base64.go | 35 +++ vendor/golang.org/x/crypto/bcrypt/bcrypt.go | 295 ++++++++++++++++++++ vendor/modules.txt | 1 + 19 files changed, 693 insertions(+), 185 deletions(-) create mode 100644 cmd/buildah/passwd.go delete mode 100644 tests/bud/from-encrypted-image/Dockerfile create mode 100644 vendor/golang.org/x/crypto/bcrypt/base64.go create mode 100644 vendor/golang.org/x/crypto/bcrypt/bcrypt.go diff --git a/Makefile b/Makefile index 003d209ff09..95ce322b81a 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ LIBSECCOMP_COMMIT := release-2.3 EXTRA_LDFLAGS ?= BUILDAH_LDFLAGS := $(GO_LDFLAGS) '-X main.GitCommit=$(GIT_COMMIT) -X main.buildInfo=$(SOURCE_DATE_EPOCH) -X main.cniVersion=$(CNI_COMMIT) $(EXTRA_LDFLAGS)' -SOURCES=*.go imagebuildah/*.go bind/*.go chroot/*.go copier/*.go define/*.go docker/*.go manifests/*.go pkg/chrootuser/*.go pkg/cli/*.go pkg/completion/*.go pkg/formats/*.go pkg/overlay/*.go pkg/parse/*.go pkg/rusage/*.go pkg/sshagent/*.go pkg/umask/*.go pkg/util/*.go util/*.go +SOURCES=*.go imagebuildah/*.go bind/*.go chroot/*.go copier/*.go define/*.go docker/*.go internal/parse/*.go internal/source/*.go internal/util/*.go manifests/*.go pkg/chrootuser/*.go pkg/cli/*.go pkg/completion/*.go pkg/formats/*.go pkg/overlay/*.go pkg/parse/*.go pkg/rusage/*.go pkg/sshagent/*.go pkg/umask/*.go pkg/util/*.go util/*.go LINTFLAGS ?= diff --git a/cmd/buildah/passwd.go b/cmd/buildah/passwd.go new file mode 100644 index 00000000000..0cda81a8ab6 --- /dev/null +++ b/cmd/buildah/passwd.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + + "github.com/spf13/cobra" + "golang.org/x/crypto/bcrypt" +) + +var ( + passwdDescription = `Generate a password hash using golang.org/x/crypto/bcrypt.` + passwdCommand = &cobra.Command{ + Use: "passwd", + Short: "Generate a password hash", + Long: passwdDescription, + RunE: passwdCmd, + Example: `buildah passwd testpassword`, + Args: cobra.ExactArgs(1), + Hidden: true, + } +) + +func passwdCmd(c *cobra.Command, args []string) error { + passwd, err := bcrypt.GenerateFromPassword([]byte(args[0]), bcrypt.DefaultCost) + if err != nil { + return err + } + fmt.Println(string(passwd)) + return nil +} + +func init() { + rootCmd.AddCommand(passwdCommand) +} diff --git a/internal/parse/parse.go b/internal/parse/parse.go index 832b2b9abae..ec463821547 100644 --- a/internal/parse/parse.go +++ b/internal/parse/parse.go @@ -38,7 +38,7 @@ var ( errBadOptionArg = errors.New("must provide an argument for option") errBadVolDest = errors.New("must set volume destination") errBadVolSrc = errors.New("must set volume source") - errDuplicateDest = errors.Errorf("duplicate mount destination") + errDuplicateDest = errors.New("duplicate mount destination") ) // GetBindMount parses a single bind mount entry from the --mount flag. diff --git a/tests/authenticate.bats b/tests/authenticate.bats index 429d3498c35..379c53f6a81 100644 --- a/tests/authenticate.bats +++ b/tests/authenticate.bats @@ -3,58 +3,67 @@ load helpers @test "authenticate: login/logout" { - run_buildah 0 login --username testuserfoo --password testpassword docker.io + start_registry testuserfoo testpassword - run_buildah 0 logout docker.io + run_buildah 0 login --cert-dir $REGISTRY_DIR --username testuserfoo --password testpassword localhost:$REGISTRY_PORT + + run_buildah 0 logout localhost:$REGISTRY_PORT } @test "authenticate: login/logout should succeed with XDG_RUNTIME_DIR unset" { unset XDG_RUNTIME_DIR - run_buildah 0 login --username testuserfoo --password testpassword docker.io - run_buildah 0 logout docker.io + start_registry testuserfoo testpassword + + run_buildah 0 login --cert-dir $REGISTRY_DIR --username testuserfoo --password testpassword localhost:$REGISTRY_PORT + + run_buildah 0 logout localhost:$REGISTRY_PORT } @test "authenticate: logout should fail with nonexistent authfile" { - run_buildah 0 login --username testuserfoo --password testpassword docker.io + start_registry testuserfoo testpassword - run_buildah 125 logout --authfile /tmp/nonexistent docker.io + run_buildah 0 login --cert-dir $REGISTRY_DIR --username testuserfoo --password testpassword localhost:$REGISTRY_PORT + + run_buildah 125 logout --authfile /tmp/nonexistent localhost:$REGISTRY_PORT expect_output "checking authfile: stat /tmp/nonexistent: no such file or directory" - run_buildah 0 logout docker.io + run_buildah 0 logout localhost:$REGISTRY_PORT } @test "authenticate: cert and credentials" { - _prefetch alpine + testuser="testuser$RANDOM" + testpassword="testpassword$RANDOM" + start_registry "$testuser" "$testpassword" + # Basic test: should pass - run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword alpine localhost:5000/my-alpine + run_buildah push --cert-dir $REGISTRY_DIR --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds "$testuser":"$testpassword" alpine localhost:$REGISTRY_PORT/my-alpine expect_output --substring "Writing manifest to image destination" # With tls-verify=true, should fail due to self-signed cert - # The magic GODEBUG is needed for RHEL on 2021-01-20. Without it, - # we get the following error instead of 'unknown authority': - # x509: certificate relies on legacy Common Name field, use SANs or [...] - # It is possible that this is a temporary workaround, and Go - # may remove it without notice. We'll deal with that then. - GODEBUG=x509ignoreCN=0 run_buildah 125 push --signature-policy ${TESTSDIR}/policy.json --tls-verify=true alpine localhost:5000/my-alpine + run_buildah 125 push --signature-policy ${TESTSDIR}/policy.json --tls-verify=true alpine localhost:$REGISTRY_PORT/my-alpine expect_output --substring " x509: certificate signed by unknown authority" \ "push with --tls-verify=true" # wrong credentials: should fail - run_buildah 125 from --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds baduser:badpassword localhost:5000/my-alpine + run_buildah 125 from --cert-dir $REGISTRY_DIR --signature-policy ${TESTSDIR}/policy.json --creds baduser:badpassword localhost:$REGISTRY_PORT/my-alpine + expect_output --substring "unauthorized: authentication required" + run_buildah 125 from --cert-dir $REGISTRY_DIR --signature-policy ${TESTSDIR}/policy.json --creds "$testuser":badpassword localhost:$REGISTRY_PORT/my-alpine + expect_output --substring "unauthorized: authentication required" + run_buildah 125 from --cert-dir $REGISTRY_DIR --signature-policy ${TESTSDIR}/policy.json --creds baduser:"$testpassword" localhost:$REGISTRY_PORT/my-alpine expect_output --substring "unauthorized: authentication required" # This should work - run_buildah from --name "my-alpine-work-ctr" --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword localhost:5000/my-alpine + run_buildah from --cert-dir $REGISTRY_DIR --name "my-alpine-work-ctr" --signature-policy ${TESTSDIR}/policy.json --creds "$testuser":"$testpassword" localhost:$REGISTRY_PORT/my-alpine expect_output --from="${lines[-1]}" "my-alpine-work-ctr" # Create Dockerfile for bud tests mkdir -p ${TESTDIR}/dockerdir DOCKERFILE=${TESTDIR}/dockerdir/Dockerfile /bin/cat <$DOCKERFILE -FROM localhost:5000/my-alpine +FROM localhost:$REGISTRY_PORT/my-alpine EOM # Remove containers and images before bud tests @@ -62,51 +71,44 @@ EOM run_buildah rmi -f --all # bud test bad password should fail - run_buildah 125 bud -f $DOCKERFILE --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds=testuser:badpassword + run_buildah 125 bud -f $DOCKERFILE --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds="$testuser":badpassword expect_output --substring "unauthorized: authentication required" \ "buildah bud with wrong credentials" # bud test this should work - run_buildah bud -f $DOCKERFILE --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds=testuser:testpassword . - expect_output --from="${lines[0]}" "STEP 1/1: FROM localhost:5000/my-alpine" + run_buildah bud -f $DOCKERFILE --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds="$testuser":"$testpassword" . + expect_output --from="${lines[0]}" "STEP 1/1: FROM localhost:$REGISTRY_PORT/my-alpine" expect_output --substring "Writing manifest to image destination" } @test "authenticate: with --tls-verify=true" { - if [ -z "$BUILDAH_AUTHDIR" ]; then - # Special case: in Cirrus, the registry auth dir is hardcoded - if [ -n "$CIRRUS_CI" -a -e "$HOME/auth/domain.cert" ]; then - BUILDAH_AUTHDIR="$HOME/auth" - else - skip "\$BUILDAH_AUTHDIR undefined" - fi - fi - _prefetch alpine + start_registry + # Push with correct credentials: should pass - run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=true --cert-dir=$BUILDAH_AUTHDIR --creds testuser:testpassword alpine localhost:5000/my-alpine + run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=true --cert-dir=$REGISTRY_DIR --creds testuser:testpassword alpine localhost:$REGISTRY_PORT/my-alpine expect_output --substring "Writing manifest to image destination" # Push with wrong credentials: should fail - run_buildah 125 push --signature-policy ${TESTSDIR}/policy.json --tls-verify=true --cert-dir=$BUILDAH_AUTHDIR --creds testuser:WRONGPASSWORD alpine localhost:5000/my-alpine + run_buildah 125 push --signature-policy ${TESTSDIR}/policy.json --tls-verify=true --cert-dir=$REGISTRY_DIR --creds testuser:WRONGPASSWORD alpine localhost:$REGISTRY_PORT/my-alpine expect_output --substring "unauthorized: authentication required" # Make sure we can fetch it - run_buildah from --pull-always --cert-dir=$BUILDAH_AUTHDIR --tls-verify=true --creds=testuser:testpassword localhost:5000/my-alpine + run_buildah from --pull-always --cert-dir=$REGISTRY_DIR --tls-verify=true --creds=testuser:testpassword localhost:$REGISTRY_PORT/my-alpine expect_output --from="${lines[-1]}" "localhost-working-container" cid="${lines[-1]}" # Commit with correct credentials run_buildah run $cid touch testfile - run_buildah commit --signature-policy ${TESTSDIR}/policy.json --cert-dir=$BUILDAH_AUTHDIR --tls-verify=true --creds=testuser:testpassword $cid docker://localhost:5000/my-alpine + run_buildah commit --signature-policy ${TESTSDIR}/policy.json --cert-dir=$REGISTRY_DIR --tls-verify=true --creds=testuser:testpassword $cid docker://localhost:$REGISTRY_PORT/my-alpine # Create Dockerfile for bud tests mkdir -p ${TESTDIR}/dockerdir DOCKERFILE=${TESTDIR}/dockerdir/Dockerfile /bin/cat <$DOCKERFILE -FROM localhost:5000/my-alpine +FROM localhost:$REGISTRY_PORT/my-alpine RUN rm testfile EOM @@ -115,8 +117,8 @@ EOM run_buildah rmi -f --all # bud with correct credentials - run_buildah bud -f $DOCKERFILE --signature-policy ${TESTSDIR}/policy.json --cert-dir=$BUILDAH_AUTHDIR --tls-verify=true --creds=testuser:testpassword . - expect_output --from="${lines[0]}" "STEP 1/2: FROM localhost:5000/my-alpine" + run_buildah bud -f $DOCKERFILE --signature-policy ${TESTSDIR}/policy.json --cert-dir=$REGISTRY_DIR --tls-verify=true --creds=testuser:testpassword . + expect_output --from="${lines[0]}" "STEP 1/2: FROM localhost:$REGISTRY_PORT/my-alpine" expect_output --substring "Writing manifest to image destination" } @@ -124,21 +126,23 @@ EOM @test "authenticate: with cached (not command-line) credentials" { _prefetch alpine - run_buildah 0 login --tls-verify=false --username testuser --password testpassword localhost:5000 + start_registry + + run_buildah 0 login --tls-verify=false --username testuser --password testpassword localhost:$REGISTRY_PORT expect_output "Login Succeeded!" # After login, push should pass - run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false alpine localhost:5000/my-alpine + run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false alpine localhost:$REGISTRY_PORT/my-alpine expect_output --substring "Storing signatures" - run_buildah 125 login --tls-verify=false --username testuser --password WRONGPASSWORD localhost:5000 - expect_output 'error logging into "localhost:5000": invalid username/password' \ + run_buildah 125 login --tls-verify=false --username testuser --password WRONGPASSWORD localhost:$REGISTRY_PORT + expect_output 'error logging into "localhost:'"$REGISTRY_PORT"'": invalid username/password' \ "buildah login, wrong credentials" - run_buildah 0 logout localhost:5000 - expect_output "Removed login credentials for localhost:5000" + run_buildah 0 logout localhost:$REGISTRY_PORT + expect_output "Removed login credentials for localhost:$REGISTRY_PORT" - run_buildah 125 push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false alpine localhost:5000/my-alpine + run_buildah 125 push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false alpine localhost:$REGISTRY_PORT/my-alpine expect_output --substring "unauthorized: authentication required" \ "buildah push after buildah logout" } diff --git a/tests/bud.bats b/tests/bud.bats index b9ba47c782c..0a7152f07bc 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -2574,15 +2574,17 @@ EOM openssl genrsa -out ${TESTDIR}/tmp/mykey.pem 1024 openssl genrsa -out ${TESTDIR}/tmp/mykey2.pem 1024 openssl rsa -in ${TESTDIR}/tmp/mykey.pem -pubout > ${TESTDIR}/tmp/mykey.pub - run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --encryption-key jwe:${TESTDIR}/tmp/mykey.pub busybox docker://localhost:5000/buildah/busybox_encrypted:latest + start_registry + run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --encryption-key jwe:${TESTDIR}/tmp/mykey.pub busybox docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest target=busybox-image + echo FROM localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest > ${TESTDIR}/tmp/Dockerfile # Try to build from encrypted image without key - run_buildah 125 build --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword -t ${target} -f ${TESTSDIR}/bud/from-encrypted-image/Dockerfile + run_buildah 125 build --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword -t ${target} -f ${TESTDIR}/tmp/Dockerfile # Try to build from encrypted image with wrong key - run_buildah 125 build --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey2.pem -t ${target} -f ${TESTSDIR}/bud/from-encrypted-image/Dockerfile + run_buildah 125 build --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey2.pem -t ${target} -f ${TESTDIR}/tmp/Dockerfile # Try to build with the correct key - run_buildah build --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey.pem -t ${target} -f ${TESTSDIR}/bud/from-encrypted-image/Dockerfile + run_buildah build --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey.pem -t ${target} -f ${TESTDIR}/tmp/Dockerfile rm -rf ${TESTDIR}/tmp } @@ -3047,17 +3049,18 @@ _EOF @test "bud --authfile" { _prefetch alpine - run_buildah login --tls-verify=false --authfile ${TESTDIR}/test.auth --username testuser --password testpassword localhost:5000 - run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --authfile ${TESTDIR}/test.auth alpine docker://localhost:5000/buildah/alpine + start_registry + run_buildah login --tls-verify=false --authfile ${TESTDIR}/test.auth --username testuser --password testpassword localhost:${REGISTRY_PORT} + run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --authfile ${TESTDIR}/test.auth alpine docker://localhost:${REGISTRY_PORT}/buildah/alpine mytmpdir=${TESTDIR}/my-dir mkdir -p ${mytmpdir} cat > $mytmpdir/Containerfile << _EOF -FROM localhost:5000/buildah/alpine +FROM localhost:${REGISTRY_PORT}/buildah/alpine RUN touch /test _EOF run_buildah build -t myalpine --authfile ${TESTDIR}/test.auth --tls-verify=false --signature-policy ${TESTSDIR}/policy.json --file ${mytmpdir} . - run_buildah rmi localhost:5000/buildah/alpine + run_buildah rmi localhost:${REGISTRY_PORT}/buildah/alpine run_buildah rmi myalpine } @@ -3571,12 +3574,12 @@ _EOF # assume that emulation for other architectures is in place. os=`go env GOOS` run_buildah from --signature-policy ${TESTSDIR}/policy.json --name try-386 --platform=$os/386 alpine - run buildah run try-386 true + run_buildah '?' run try-386 true if test $status -ne 0 ; then skip "unable to run 386 container, assuming emulation is not available" fi run_buildah from --signature-policy ${TESTSDIR}/policy.json --name try-arm --platform=$os/arm alpine - run buildah run try-arm true + run_buildah '?' run try-arm true if test $status -ne 0 ; then skip "unable to run arm container, assuming emulation is not available" fi @@ -3607,12 +3610,12 @@ _EOF skip "test Dockerfile is ubi, we can't run it" fi run_buildah from --signature-policy ${TESTSDIR}/policy.json --name try-386 --platform=$os/386 alpine - run buildah run try-386 true + run_buildah '?' run try-386 true if test $status -ne 0 ; then skip "unable to run 386 container, assuming emulation is not available" fi run_buildah from --signature-policy ${TESTSDIR}/policy.json --name try-arm --platform=$os/arm alpine - run buildah run try-arm true + run_buildah '?' run try-arm true if test $status -ne 0 ; then skip "unable to run arm container, assuming emulation is not available" fi @@ -3714,10 +3717,7 @@ _EOF @test "bud with run should not leave mounts behind cleanup test" { skip_if_in_container - run which podman - if [[ $status -ne 0 ]]; then - skip "podman is not installed" - fi + skip_if_no_podman # Create target dir where we will export tar target=cleanable @@ -3725,7 +3725,7 @@ _EOF # Build and export container to tar run_buildah build --no-cache --signature-policy ${TESTSDIR}/policy.json -t ${target} -f ${TESTSDIR}/bud/containerfile/Containerfile.in ${TESTSDIR}/bud/containerfile - podman export $(podman create --name ${target} ${target}) --output=${TESTDIR}/${target}.tar + podman export $(podman create --name ${target} --net=host ${target}) --output=${TESTDIR}/${target}.tar # We are done exporting so remove images and containers which are not needed podman rm -f ${target} @@ -3740,10 +3740,7 @@ _EOF @test "bud with custom files in /run/ should persist cleanup test" { skip_if_in_container - run which podman - if [[ $status -ne 0 ]]; then - skip "podman is not installed" - fi + skip_if_no_podman # Create target dir where we will export tar target=cleanable @@ -3751,7 +3748,7 @@ _EOF # Build and export container to tar run_buildah build --no-cache --signature-policy ${TESTSDIR}/policy.json -t ${target} -f ${TESTSDIR}/bud/add-run-dir - podman export $(podman create --name ${target} ${target}) --output=${TESTDIR}/${target}.tar + podman export $(podman create --name ${target} --net=host ${target}) --output=${TESTDIR}/${target}.tar # We are done exporting so remove images and containers which are not needed podman rm -f ${target} diff --git a/tests/bud/from-encrypted-image/Dockerfile b/tests/bud/from-encrypted-image/Dockerfile deleted file mode 100644 index 7f4547999eb..00000000000 --- a/tests/bud/from-encrypted-image/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -FROM localhost:5000/buildah/busybox_encrypted:latest diff --git a/tests/commit.bats b/tests/commit.bats index 180697a5fc1..51a065082a6 100644 --- a/tests/commit.bats +++ b/tests/commit.bats @@ -199,8 +199,9 @@ load helpers @test "commit to docker-distribution" { _prefetch busybox run_buildah from --signature-policy ${TESTSDIR}/policy.json --name busyboxc busybox - run_buildah commit --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword busyboxc docker://localhost:5000/commit/busybox - run_buildah from --signature-policy ${TESTSDIR}/policy.json --name fromdocker --tls-verify=false --creds testuser:testpassword docker://localhost:5000/commit/busybox + start_registry + run_buildah commit --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword busyboxc docker://localhost:${REGISTRY_PORT}/commit/busybox + run_buildah from --signature-policy ${TESTSDIR}/policy.json --name fromdocker --tls-verify=false --creds testuser:testpassword docker://localhost:${REGISTRY_PORT}/commit/busybox } @test "commit encrypted local oci image" { @@ -221,9 +222,10 @@ load helpers mkdir ${TESTDIR}/tmp openssl genrsa -out ${TESTDIR}/tmp/mykey.pem 1024 openssl rsa -in ${TESTDIR}/tmp/mykey.pem -pubout > ${TESTDIR}/tmp/mykey.pub + start_registry run_buildah from --quiet --pull=false --signature-policy ${TESTSDIR}/policy.json busybox cid=$output - run_buildah commit --iidfile /dev/null --tls-verify=false --creds testuser:testpassword --signature-policy ${TESTSDIR}/policy.json --encryption-key jwe:${TESTDIR}/tmp/mykey.pub -q $cid docker://localhost:5000/buildah/busybox_encrypted:latest + run_buildah commit --iidfile /dev/null --tls-verify=false --creds testuser:testpassword --signature-policy ${TESTSDIR}/policy.json --encryption-key jwe:${TESTDIR}/tmp/mykey.pub -q $cid docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest # this test, just checks the ability to commit an image to a registry # there is no good way to test the details of the image unless with ./buildah pull, test will be in pull.bats rm -rf ${TESTDIR}/tmp @@ -275,7 +277,8 @@ load helpers cid=$output run_buildah run $cid touch /test - run_buildah login --authfile ${TESTDIR}/test.auth --username testuser --password testpassword --tls-verify=false localhost:5000 - run_buildah commit --authfile ${TESTDIR}/test.auth --signature-policy ${TESTSDIR}/policy.json --tls-verify=false $cid docker://localhost:5000/buildah/my-busybox + start_registry + run_buildah login --authfile ${TESTDIR}/test.auth --username testuser --password testpassword --tls-verify=false localhost:${REGISTRY_PORT} + run_buildah commit --authfile ${TESTDIR}/test.auth --signature-policy ${TESTSDIR}/policy.json --tls-verify=false $cid docker://localhost:${REGISTRY_PORT}/buildah/my-busybox expect_output --substring "Writing manifest to image destination" } diff --git a/tests/containers.bats b/tests/containers.bats index 8c732738be2..2cf0aa6a051 100644 --- a/tests/containers.bats +++ b/tests/containers.bats @@ -70,14 +70,11 @@ load helpers @test "containers all test" { skip_if_in_container - run which podman - if [[ $status -ne 0 ]]; then - skip "podman is not installed" - fi + skip_if_no_podman _prefetch alpine busybox run_buildah from --quiet --pull=false --signature-policy ${TESTSDIR}/policy.json alpine - podman create --root ${TESTDIR}/root --storage-driver ${STORAGE_DRIVER} busybox ls + podman create --root ${TESTDIR}/root --storage-driver ${STORAGE_DRIVER} --net=host busybox ls run_buildah containers expect_line_count 2 run_buildah containers -a diff --git a/tests/containers_conf.bats b/tests/containers_conf.bats index 4eeb9e79abc..198283f8551 100644 --- a/tests/containers_conf.bats +++ b/tests/containers_conf.bats @@ -4,76 +4,74 @@ load helpers @test "containers.conf selinux test" { if ! which selinuxenabled > /dev/null 2> /dev/null ; then - skip "No selinuxenabled executable" + skip "No selinuxenabled executable" elif ! selinuxenabled ; then - skip "selinux is disabled" + skip "selinux is disabled" fi - - export CONTAINERS_CONF=${TESTSDIR}/containers.conf - cid=$(buildah from --pull --signature-policy ${TESTSDIR}/policy.json docker.io/alpine) + _prefetch alpine + cid=$(buildah from --signature-policy ${TESTSDIR}/policy.json alpine) run_buildah --log-level=error run $cid sh -c "cat /proc/self/attr/current | grep container_t" - buildah rm $cid + run_buildah rm $cid - export CONTAINERS_CONF=${TESTSDIR}/containers1.conf - sed "s/^label = true/label = false/g" ${TESTSDIR}/containers.conf > ${TESTSDIR}/containers1.conf - cid=$(buildah from --pull --signature-policy ${TESTSDIR}/policy.json docker.io/alpine) - run_buildah 1 --log-level=error run $cid sh -c "cat /proc/self/attr/current | grep container_t" - rm ${TESTSDIR}/containers1.conf + sed "s/^label = true/label = false/g" ${TESTSDIR}/containers.conf > ${TESTDIR}/containers.conf + cid=$(buildah from --signature-policy ${TESTSDIR}/policy.json alpine) + CONTAINERS_CONF=${TESTDIR}/containers.conf run_buildah 1 --log-level=error run $cid sh -c "cat /proc/self/attr/current | grep container_t" } @test "containers.conf ulimit test" { if test "$BUILDAH_ISOLATION" = "chroot" -o "$BUILDAH_ISOLATION" = "rootless" ; then - skip "BUILDAH_ISOLATION = $BUILDAH_ISOLATION" - fi + skip "BUILDAH_ISOLATION = $BUILDAH_ISOLATION" + fi - export CONTAINERS_CONF=${TESTSDIR}/containers.conf - cid=$(buildah from --pull --signature-policy ${TESTSDIR}/policy.json docker.io/alpine) + _prefetch alpine + cid=$(buildah from --signature-policy ${TESTSDIR}/policy.json alpine) run_buildah --log-level=error run $cid awk '/open files/{print $4}' /proc/self/limits - expect_output "500" "limits: open files (w/file limit)" + expect_output "500" "limits: open files (w/file limit)" - cid=$(buildah from --pull --ulimit nofile=300:400 --signature-policy ${TESTSDIR}/policy.json docker.io/alpine) - run_buildah --log-level=error run $cid awk '/open files/{print $4}' /proc/self/limits - expect_output "300" "limits: open files (w/file limit)" + cid=$(buildah from --ulimit nofile=300:400 --signature-policy ${TESTSDIR}/policy.json alpine) + run_buildah --log-level=error run $cid awk '/open files/{print $4}' /proc/self/limits + expect_output "300" "limits: open files (w/file limit)" } @test "containers.conf additional devices test" { skip_if_rootless_environment if test "$BUILDAH_ISOLATION" = "chroot" -o "$BUILDAH_ISOLATION" = "rootless" ; then - skip "BUILDAH_ISOLATION = $BUILDAH_ISOLATION" + skip "BUILDAH_ISOLATION = $BUILDAH_ISOLATION" fi - export CONTAINERS_CONF=${TESTSDIR}/containers.conf - cid=$(buildah from --pull --signature-policy ${TESTSDIR}/policy.json docker.io/alpine) - run_buildah 1 --log-level=error run $cid ls /dev/foo1 - buildah rm $cid - sed '/^devices.*/a "/dev/foo:\/dev\/foo1:rmw",' ${TESTSDIR}/containers.conf > ${TESTSDIR}/containers1.conf + _prefetch alpine + cid=$(buildah from --signature-policy ${TESTSDIR}/policy.json alpine) + CONTAINERS_CONF=$CONTAINERS_CONF run_buildah 1 --log-level=error run $cid ls /dev/foo1 + run_buildah rm $cid + + sed '/^devices.*/a "\/dev\/foo:\/dev\/foo1:rmw",' ${TESTSDIR}/containers.conf > ${TESTDIR}/containers.conf rm -f /dev/foo; mknod /dev/foo c 1 1 - export CONTAINERS_CONF=${TESTSDIR}/containers1.conf - cid=$(buildah from --pull --signature-policy ${TESTSDIR}/policy.json docker.io/alpine) - run_buildah --log-level=error run $cid ls /dev/foo1 + CONTAINERS_CONF=${TESTDIR}/containers.conf run_buildah from --quiet --signature-policy ${TESTSDIR}/policy.json alpine + cid="$output" + CONTAINERS_CONF=${TESTDIR}/containers.conf run_buildah --log-level=error run $cid ls /dev/foo1 rm -f /dev/foo - rm ${TESTSDIR}/containers1.conf } @test "containers.conf capabilities test" { - export CONTAINERS_CONF=${TESTSDIR}/containers.conf - cid=$(buildah from --pull --signature-policy ${TESTSDIR}/policy.json docker.io/alpine) + _prefetch alpine + + run_buildah from --quiet --signature-policy ${TESTSDIR}/policy.json alpine + cid="$output" run_buildah --log-level=error run $cid sh -c 'grep CapEff /proc/self/status | cut -f2' - CapEff=$output + CapEff="$output" expect_output "00000000a80425fb" - buildah rm $cid + run_buildah rm $cid - sed "/AUDIT_WRITE/d" ${TESTSDIR}/containers.conf > ${TESTSDIR}/containers1.conf - export CONTAINERS_CONF=${TESTSDIR}/containers1.conf - cid=$(buildah from --pull --signature-policy ${TESTSDIR}/policy.json docker.io/alpine) + sed "/AUDIT_WRITE/d" ${TESTSDIR}/containers.conf > ${TESTDIR}/containers.conf + CONTAINERS_CONF=${TESTDIR}/containers.conf run_buildah from --quiet --signature-policy ${TESTSDIR}/policy.json alpine + cid="$output" - run_buildah --log-level=error run $cid sh -c 'grep CapEff /proc/self/status | cut -f2' - buildah rm $cid + CONTAINERS_CONF=${TESTDIR}/containers.conf run_buildah --log-level=error run $cid sh -c 'grep CapEff /proc/self/status | cut -f2' + run_buildah rm $cid test "$output" != "$CapEff" - rm ${TESTSDIR}/containers1.conf } @test "containers.conf /dev/shm test" { @@ -81,8 +79,9 @@ load helpers skip "BUILDAH_ISOLATION = $BUILDAH_ISOLATION" fi - export CONTAINERS_CONF=${TESTSDIR}/containers.conf - cid=$(buildah from --pull --signature-policy ${TESTSDIR}/policy.json docker.io/alpine) + _prefetch alpine + run_buildah from --quiet --signature-policy ${TESTSDIR}/policy.json alpine + cid="$output" run_buildah --log-level=error run $cid sh -c 'df /dev/shm | awk '\''/shm/{print $4}'\''' expect_output "200" } @@ -92,18 +91,18 @@ load helpers skip "BUILDAH_ISOLATION = $BUILDAH_ISOLATION" fi - test -e /usr/bin/crun || skip "/usr/bin/crun doesn't exist" + test -x /usr/bin/crun || skip "/usr/bin/crun doesn't exist" ln -s /usr/bin/crun ${TESTDIR}/runtime - cat >${TESTDIR}/containers_non_standard_runtime.conf << EOF + cat >${TESTDIR}/containers.conf << EOF [engine] runtime = "nonstandard_runtime_name" [engine.runtimes] nonstandard_runtime_name = ["${TESTDIR}/runtime"] EOF - export CONTAINERS_CONF=${TESTDIR}/containers_non_standard_runtime.conf - cid=$(buildah from --pull --signature-policy ${TESTSDIR}/policy.json docker.io/alpine) - run_buildah --log-level=error run $cid true + _prefetch alpine + cid=$(buildah from --signature-policy ${TESTSDIR}/policy.json alpine) + CONTAINERS_CONF=${TESTDIR}/containers.conf run_buildah --log-level=error run $cid true } diff --git a/tests/copy.bats b/tests/copy.bats index 799636005ed..214bd053c02 100644 --- a/tests/copy.bats +++ b/tests/copy.bats @@ -446,24 +446,36 @@ stuff/mystuff" @test "copy-preserving-extended-attributes" { createrandom ${TESTDIR}/randomfile + # if we need to change which image we use, any image that can provide a working setattr/setcap/getfattr will do image="quay.io/libpod/fedora-minimal:34" + if ! which setfattr > /dev/null 2> /dev/null; then + skip "setfattr not available, unable to check if it'll work in filesystem at ${TESTDIR}" + fi + run setfattr -n user.yeah -v butno ${TESTDIR}/root + if [ "$status" -ne 0 ] ; then + if [[ "$output" =~ "not supported" ]] ; then + skip "setfattr not supported in filesystem at ${TESTDIR}" + fi + skip "$output" + fi _prefetch $image run_buildah from --quiet --signature-policy ${TESTSDIR}/policy.json $image first="$output" - run_buildah run $first microdnf -y install /usr/bin/getfattr /usr/bin/setfattr /usr/sbin/setcap + run_buildah run $first microdnf -y install /usr/bin/setfattr /usr/sbin/setcap run_buildah copy $first ${TESTDIR}/randomfile / # set security.capability - run buildah run $first setcap cap_setuid=ep /randomfile + run_buildah run $first setcap cap_setuid=ep /randomfile # set user.something - run buildah run $first setfattr user.yeah=butno /randomfile + run_buildah run $first setfattr -n user.yeah -v butno /randomfile # copy the file to a second container run_buildah from --quiet --signature-policy ${TESTSDIR}/policy.json $image second="$output" + run_buildah run $second microdnf -y install /usr/bin/getfattr run_buildah copy --from $first $second /randomfile / # compare what the extended attributes look like. if we're on a system with SELinux, there's a label in here, too - run buildah run $first sh -c "getfattr -d -m . --absolute-names /randomfile | sort" + run_buildah run $first sh -c "getfattr -d -m . --absolute-names /randomfile | grep -v ^security.selinux | sort" expected="$output" - run buildah run $first sh -c "getfattr -d -m . --absolute-names /randomfile | sort" + run_buildah run $second sh -c "getfattr -d -m . --absolute-names /randomfile | grep -v ^security.selinux | sort" expect_output "$expected" } diff --git a/tests/from.bats b/tests/from.bats index 133fd9cbbc3..0acd9d02e31 100644 --- a/tests/from.bats +++ b/tests/from.bats @@ -397,7 +397,7 @@ load helpers _prefetch docker.io/busybox run_buildah inspect --format "{{.FromImageDigest}}" docker.io/busybox fromDigest="$output" - run buildah pull --signature-policy ${TESTSDIR}/policy.json docker.io/busybox + run_buildah pull --signature-policy ${TESTSDIR}/policy.json docker.io/busybox run_buildah from --signature-policy ${TESTSDIR}/policy.json --name busyboxc --pull-always docker.io/busybox expect_output --substring "Getting" run_buildah commit --signature-policy ${TESTSDIR}/policy.json busyboxc fakename-img @@ -446,34 +446,32 @@ load helpers openssl genrsa -out ${TESTDIR}/tmp/mykey.pem 2048 openssl genrsa -out ${TESTDIR}/tmp/mykey2.pem 2048 openssl rsa -in ${TESTDIR}/tmp/mykey.pem -pubout > ${TESTDIR}/tmp/mykey.pub - run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --encryption-key jwe:${TESTDIR}/tmp/mykey.pub busybox docker://localhost:5000/buildah/busybox_encrypted:latest + start_registry + run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --encryption-key jwe:${TESTDIR}/tmp/mykey.pub busybox docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest # Try encrypted image without key should fail - run_buildah 125 from --tls-verify=false --creds testuser:testpassword docker://localhost:5000/buildah/busybox_encrypted:latest + run_buildah 125 from --tls-verify=false --creds testuser:testpassword docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest expect_output --substring "decrypting layer .* missing private key needed for decryption" # Try encrypted image with wrong key should fail - run_buildah 125 from --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey2.pem docker://localhost:5000/buildah/busybox_encrypted:latest + run_buildah 125 from --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey2.pem docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest expect_output --substring "decrypting layer .* no suitable key unwrapper found or none of the private keys could be used for decryption" # Providing the right key should succeed - run_buildah from --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey.pem docker://localhost:5000/buildah/busybox_encrypted:latest + run_buildah from --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey.pem docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest run_buildah rm -a - run_buildah rmi localhost:5000/buildah/busybox_encrypted:latest + run_buildah rmi localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest rm -rf ${TESTDIR}/tmp } @test "from with non buildah container" { skip_if_in_container - run which podman - if [[ $status -ne 0 ]]; then - skip "podman is not installed" - fi + skip_if_no_podman - _prefetch docker.io/busybox - podman run --name busyboxc-podman -d docker.io/busybox top - run_buildah from --signature-policy ${TESTSDIR}/policy.json --name busyboxc docker.io/busybox + _prefetch busybox + podman create --net=host --name busyboxc-podman busybox top + run_buildah from --signature-policy ${TESTSDIR}/policy.json --name busyboxc busybox expect_output --substring "busyboxc" podman rm -f busyboxc-podman run_buildah rm busyboxc @@ -525,12 +523,13 @@ load helpers @test "from --authfile test" { _prefetch busybox - run_buildah login --tls-verify=false --authfile ${TESTDIR}/test.auth --username testuser --password testpassword localhost:5000 - run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --authfile ${TESTDIR}/test.auth busybox docker://localhost:5000/buildah/busybox:latest + start_registry + run_buildah login --tls-verify=false --authfile ${TESTDIR}/test.auth --username testuser --password testpassword localhost:${REGISTRY_PORT} + run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --authfile ${TESTDIR}/test.auth busybox docker://localhost:${REGISTRY_PORT}/buildah/busybox:latest target=busybox-image - run_buildah from -q --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --authfile ${TESTDIR}/test.auth docker://localhost:5000/buildah/busybox:latest + run_buildah from -q --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --authfile ${TESTDIR}/test.auth docker://localhost:${REGISTRY_PORT}/buildah/busybox:latest run_buildah rm $output - run_buildah rmi localhost:5000/buildah/busybox:latest + run_buildah rmi localhost:${REGISTRY_PORT}/buildah/busybox:latest } @test "from --cap-add/--cap-drop test" { diff --git a/tests/helpers.bash b/tests/helpers.bash index c56eee7e5ef..cd0a54f7fc8 100644 --- a/tests/helpers.bash +++ b/tests/helpers.bash @@ -84,6 +84,7 @@ function teardown(){ function teardown_tests() { stophttpd stop_git_daemon + stop_registry # Workaround for #1991 - buildah + overlayfs leaks mount points. # Many tests leave behind /var/tmp/.../root/overlay and sub-mounts; @@ -118,13 +119,18 @@ function _prefetch() { mkdir -p ${_BUILDAH_IMAGE_CACHEDIR} fi + local storage= for img in "$@"; do + if [[ "$img" =~ '[vfs@' ]] ; then + storage="$img" + continue + fi img=$(normalize_image_name "$img") echo "# [checking for: $img]" >&2 fname=$(tr -c a-zA-Z0-9.- - <<< "$img") if [ -d $_BUILDAH_IMAGE_CACHEDIR/$fname ]; then echo "# [restoring from cache: $_BUILDAH_IMAGE_CACHEDIR / $img]" >&2 - copy dir:$_BUILDAH_IMAGE_CACHEDIR/$fname containers-storage:"$img" + copy dir:$_BUILDAH_IMAGE_CACHEDIR/$fname containers-storage:"$storage""$img" else rm -fr $_BUILDAH_IMAGE_CACHEDIR/$fname echo "# [copy docker://$img dir:$_BUILDAH_IMAGE_CACHEDIR/$fname]" >&2 @@ -134,8 +140,8 @@ function _prefetch() { fi sleep 5 done - echo "# [copy dir:$_BUILDAH_IMAGE_CACHEDIR/$fname containers-storage:$img]" >&2 - copy dir:$_BUILDAH_IMAGE_CACHEDIR/$fname containers-storage:"$img" + echo "# [copy dir:$_BUILDAH_IMAGE_CACHEDIR/$fname containers-storage:$storage$img]" >&2 + copy dir:$_BUILDAH_IMAGE_CACHEDIR/$fname containers-storage:"$storage""$img" fi done } @@ -157,7 +163,7 @@ function copy() { } function podman() { - command podman ${PODMAN_REGISTRY_OPTS} ${ROOTDIR_OPTS} "$@" + command ${PODMAN_BINARY:-podman} ${PODMAN_REGISTRY_OPTS} ${ROOTDIR_OPTS} "$@" } # There are various scenarios where we would like to execute `tests` as rootless user, however certain commands like `buildah mount` @@ -505,6 +511,16 @@ function skip_if_no_runtime() { skip "runtime \"$OCI\" not found" } +####################### +# skip_if_no_podman # we need 'podman' to test how we interact with podman +####################### +function skip_if_no_podman() { + run which ${PODMAN_BINARY:-podman} + if [[ $status -ne 0 ]]; then + skip "podman is not installed" + fi +} + ################## # is_cgroupsv2 # Returns true if host system has cgroupsv2 enabled ################## @@ -568,3 +584,110 @@ function stop_git_daemon() { rm -f ${TESTDIR}/git-daemon/pid fi } + +# Bring up a registry server using buildah with vfs and chroot as a cheap +# substitute for podman, accessible only to user $1 using password $2 on the +# local system at a dynamically-allocated port. +# Requires openssl. +# A user name and password can be supplied as the two parameters, or default +# values of "testuser" and "testpassword" will be used. +# Sets REGISTRY_PID, REGISTRY_PORT (to append to "localhost:"), and +# REGISTRY_DIR (where the CA cert can be found) on success. +function start_registry() { + local testuser="${1:-testuser}" + local testpassword="${2:-testpassword}" + local REGISTRY_IMAGE=quay.io/libpod/registry:2.8 + local config=' +version: 0.1 +log: + fields: + service: registry +storage: + cache: + blobdescriptor: inmemory + filesystem: + rootdirectory: /var/lib/registry +http: + addr: :0 + headers: + X-Content-Type-Options: [nosniff] + tls: + certificate: /etc/docker/registry/localhost.crt + key: /etc/docker/registry/localhost.key +health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 +auth: + htpasswd: + realm: buildah-realm + path: /etc/docker/registry/htpasswd +' + # roughly equivalent to "htpasswd -nbB testuser testpassword", the registry uses + # the same package this does for verifying passwords against hashes in htpasswd files + htpasswd=${testuser}:$(buildah passwd ${testpassword}) + + # generate the htpasswd and config.yml files for the registry + mkdir -p "${TESTDIR}"/registry/root "${TESTDIR}"/registry/run "${TESTDIR}"/registry/certs "${TESTDIR}"/registry/config + cat > "${TESTDIR}"/registry/config/htpasswd <<< "$htpasswd" + cat > "${TESTDIR}"/registry/config/config.yml <<< "$config" + chmod 644 "${TESTDIR}"/registry/config/htpasswd "${TESTDIR}"/registry/config/config.yml + + # generate a new key and certificate + if ! openssl req -newkey rsa:4096 -nodes -sha256 -keyout "${TESTDIR}"/registry/certs/localhost.key -x509 -days 2 -addext "subjectAltName = DNS:localhost" -out "${TESTDIR}"/registry/certs/localhost.crt -subj "/CN=localhost" ; then + die error creating new key and certificate + fi + chmod 644 "${TESTDIR}"/registry/certs/localhost.crt + chmod 600 "${TESTDIR}"/registry/certs/localhost.key + # use a copy of the server's certificate for validation from a client + cp "${TESTDIR}"/registry/certs/localhost.crt "${TESTDIR}"/registry/ + + # create a container in its own storage + _prefetch "[vfs@${TESTDIR}/registry/root+${TESTDIR}/registry/run]" ${REGISTRY_IMAGE} + ctr=$(${BUILDAH_BINARY} --storage-driver vfs --root "${TESTDIR}"/registry/root --runroot "${TESTDIR}"/registry/run from --quiet --pull-never ${REGISTRY_IMAGE}) + ${BUILDAH_BINARY} --storage-driver vfs --root "${TESTDIR}"/registry/root --runroot "${TESTDIR}"/registry/run copy $ctr "${TESTDIR}"/registry/config/htpasswd "${TESTDIR}"/registry/config/config.yml "${TESTDIR}"/registry/certs/localhost.key "${TESTDIR}"/registry/certs/localhost.crt /etc/docker/registry/ + + # fire it up + coproc ${BUILDAH_BINARY} --storage-driver vfs --root "${TESTDIR}"/registry/root --runroot "${TESTDIR}"/registry/run run --net host "$ctr" /entrypoint.sh /etc/docker/registry/config.yml 2> "${TESTDIR}"/registry/registry.log + + # record the coprocess's ID and try to parse the listening port from the log + # we're separating all of this from the storage for any test that might call + # this function and using vfs to minimize the cleanup required + REGISTRY_PID="${COPROC_PID}" + REGISTRY_DIR="${TESTDIR}"/registry + REGISTRY_PORT= + local waited=0 + while [ -z "${REGISTRY_PORT}" ] ; do + if [ $waited -ge $BUILDAH_TIMEOUT ] ; then + echo Could not determine listening port from log: + sed -e 's/^/ >/' ${TESTDIR}/registry/registry.log + stop_registry + false + fi + waited=$((waited+1)) + sleep 1 + REGISTRY_PORT=$(sed -ne 's^.*listening on.*:\([0-9]\+\),.*^\1^p' ${TESTDIR}/registry/registry.log) + done + + # push the registry image we just started... to itself, as a confidence check + if ! ${BUILDAH_BINARY} --storage-driver vfs --root "${REGISTRY_DIR}"/root --runroot "${REGISTRY_DIR}"/run push --cert-dir "${REGISTRY_DIR}" --creds "${testuser}":"${testpassword}" "${REGISTRY_IMAGE}" localhost:"${REGISTRY_PORT}"/registry; then + echo error pushing to /registry repository at localhost:$REGISTRY_PORT + stop_registry + false + fi +} + +function stop_registry() { + if test -n "${REGISTRY_PID}" ; then + kill "${REGISTRY_PID}" + wait "${REGISTRY_PID}" || true + fi + unset REGISTRY_PID + unset REGISTRY_PORT + if test -n "${REGISTRY_DIR}" ; then + ${BUILDAH_BINARY} --storage-driver vfs --root "${REGISTRY_DIR}"/root --runroot "${REGISTRY_DIR}"/run rmi -a -f + rm -fr "${REGISTRY_DIR}" + fi + unset REGISTRY_DIR +} diff --git a/tests/pull.bats b/tests/pull.bats index 770fea78283..331aa9c3f53 100644 --- a/tests/pull.bats +++ b/tests/pull.bats @@ -108,13 +108,14 @@ load helpers } @test "pull-all-tags" { + start_registry declare -a tags=(0.9 0.9.1 1.1 alpha beta gamma2.0 latest) # setup: pull alpine, and push it repeatedly to localhost using those tags opts="--signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword" run_buildah --retry pull --quiet --signature-policy ${TESTSDIR}/policy.json alpine for tag in "${tags[@]}"; do - run_buildah push $opts alpine localhost:5000/myalpine:$tag + run_buildah push $opts alpine localhost:${REGISTRY_PORT}/myalpine:$tag done run_buildah images -q @@ -127,9 +128,9 @@ load helpers expect_output "" "After buildah rmi, there are no locally stored images" # Now pull with --all-tags, and confirm that we see all expected tag strings - run_buildah pull $opts --all-tags localhost:5000/myalpine + run_buildah pull $opts --all-tags localhost:${REGISTRY_PORT}/myalpine for tag in "${tags[@]}"; do - expect_output --substring "Trying to pull localhost:5000/myalpine:$tag" + expect_output --substring "Trying to pull localhost:${REGISTRY_PORT}/myalpine:$tag" done # Confirm that 'images -a' lists all of them. help confirm @@ -202,50 +203,52 @@ load helpers @test "pull encrypted registry image" { _prefetch busybox + start_registry mkdir ${TESTDIR}/tmp openssl genrsa -out ${TESTDIR}/tmp/mykey.pem 1024 openssl genrsa -out ${TESTDIR}/tmp/mykey2.pem 1024 openssl rsa -in ${TESTDIR}/tmp/mykey.pem -pubout > ${TESTDIR}/tmp/mykey.pub - run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --encryption-key jwe:${TESTDIR}/tmp/mykey.pub busybox docker://localhost:5000/buildah/busybox_encrypted:latest + run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --encryption-key jwe:${TESTDIR}/tmp/mykey.pub busybox docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest # Try to pull encrypted image without key should fail - run_buildah 125 pull --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword docker://localhost:5000/buildah/busybox_encrypted:latest + run_buildah 125 pull --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest expect_output --substring "decrypting layer .* missing private key needed for decryption" # Try to pull encrypted image with wrong key should fail, with diff. msg - run_buildah 125 pull --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey2.pem docker://localhost:5000/buildah/busybox_encrypted:latest + run_buildah 125 pull --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey2.pem docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest expect_output --substring "decrypting layer .* no suitable key unwrapper found or none of the private keys could be used for decryption" # Providing the right key should succeed - run_buildah pull --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey.pem docker://localhost:5000/buildah/busybox_encrypted:latest + run_buildah pull --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey.pem docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest - run_buildah rmi localhost:5000/buildah/busybox_encrypted:latest + run_buildah rmi localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest rm -rf ${TESTDIR}/tmp } @test "pull encrypted registry image from commit" { - _prefetch busybox + _prefetch busybox + start_registry mkdir ${TESTDIR}/tmp openssl genrsa -out ${TESTDIR}/tmp/mykey.pem 1024 openssl genrsa -out ${TESTDIR}/tmp/mykey2.pem 1024 openssl rsa -in ${TESTDIR}/tmp/mykey.pem -pubout > ${TESTDIR}/tmp/mykey.pub run_buildah from --quiet --pull=false --signature-policy ${TESTSDIR}/policy.json busybox cid=$output - run_buildah commit --iidfile /dev/null --tls-verify=false --creds testuser:testpassword --signature-policy ${TESTSDIR}/policy.json --encryption-key jwe:${TESTDIR}/tmp/mykey.pub -q $cid docker://localhost:5000/buildah/busybox_encrypted:latest + run_buildah commit --iidfile /dev/null --tls-verify=false --creds testuser:testpassword --signature-policy ${TESTSDIR}/policy.json --encryption-key jwe:${TESTDIR}/tmp/mykey.pub -q $cid docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest # Try to pull encrypted image without key should fail - run_buildah 125 pull --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword docker://localhost:5000/buildah/busybox_encrypted:latest + run_buildah 125 pull --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest expect_output --substring "decrypting layer .* missing private key needed for decryption" # Try to pull encrypted image with wrong key should fail - run_buildah 125 pull --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey2.pem docker://localhost:5000/buildah/busybox_encrypted:latest + run_buildah 125 pull --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey2.pem docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest expect_output --substring "decrypting layer .* no suitable key unwrapper found or none of the private keys could be used for decryption" # Providing the right key should succeed - run_buildah pull --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey.pem docker://localhost:5000/buildah/busybox_encrypted:latest + run_buildah pull --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --decryption-key ${TESTDIR}/tmp/mykey.pem docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest - run_buildah rmi localhost:5000/buildah/busybox_encrypted:latest + run_buildah rmi localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest rm -rf ${TESTDIR}/tmp } @@ -263,11 +266,12 @@ load helpers @test "pull with authfile" { _prefetch busybox + start_registry mkdir ${TESTDIR}/tmp - run_buildah push --creds testuser:testpassword --tls-verify=false busybox docker://localhost:5000/buildah/busybox:latest - run_buildah login --authfile ${TESTDIR}/tmp/test.auth --username testuser --password testpassword --tls-verify=false localhost:5000 - run_buildah pull --authfile ${TESTDIR}/tmp/test.auth --tls-verify=false docker://localhost:5000/buildah/busybox:latest - run_buildah rmi localhost:5000/buildah/busybox:latest + run_buildah push --creds testuser:testpassword --tls-verify=false busybox docker://localhost:${REGISTRY_PORT}/buildah/busybox:latest + run_buildah login --authfile ${TESTDIR}/tmp/test.auth --username testuser --password testpassword --tls-verify=false localhost:${REGISTRY_PORT} + run_buildah pull --authfile ${TESTDIR}/tmp/test.auth --tls-verify=false docker://localhost:${REGISTRY_PORT}/buildah/busybox:latest + run_buildah rmi localhost:${REGISTRY_PORT}/buildah/busybox:latest rm -rf ${TESTDIR}/tmp } diff --git a/tests/push.bats b/tests/push.bats index 0e1c55ea26b..364d329517d 100644 --- a/tests/push.bats +++ b/tests/push.bats @@ -148,13 +148,14 @@ load helpers expect_output --substring "buildah/busybox" docker rmi buildah/busybox - run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword docker.io/busybox:latest docker://localhost:5000/buildah/busybox:latest - docker login localhost:5000 --username testuser --password testpassword - docker pull localhost:5000/buildah/busybox:latest + start_registry + run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword docker.io/busybox:latest docker://localhost:${REGISTRY_PORT}/buildah/busybox:latest + docker login localhost:${REGISTRY_PORT} --username testuser --password testpassword + docker pull localhost:${REGISTRY_PORT}/buildah/busybox:latest output=$(docker images) expect_output --substring "buildah/busybox" - docker rmi localhost:5000/buildah/busybox:latest - docker logout localhost:5000 + docker rmi localhost:${REGISTRY_PORT}/buildah/busybox:latest + docker logout localhost:${REGISTRY_PORT} } @test "buildah oci encrypt and push local oci" { @@ -171,9 +172,10 @@ load helpers @test "buildah oci encrypt and push registry" { _prefetch busybox mkdir ${TESTDIR}/tmp + start_registry openssl genrsa -out ${TESTDIR}/tmp/mykey.pem 1024 openssl rsa -in ${TESTDIR}/tmp/mykey.pem -pubout > ${TESTDIR}/tmp/mykey.pub - run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --encryption-key jwe:${TESTDIR}/tmp/mykey.pub busybox docker://localhost:5000/buildah/busybox_encrypted:latest + run_buildah push --signature-policy ${TESTSDIR}/policy.json --tls-verify=false --creds testuser:testpassword --encryption-key jwe:${TESTDIR}/tmp/mykey.pub busybox docker://localhost:${REGISTRY_PORT}/buildah/busybox_encrypted:latest # this test, just checks the ability to push an image # there is no good way to test the details of the image unless with ./buildah pull, test will be in pull.bats rm -rf ${TESTDIR}/tmp @@ -181,19 +183,21 @@ load helpers @test "buildah push to registry allowed by BUILD_REGISTRY_SOURCES" { _prefetch busybox - export BUILD_REGISTRY_SOURCES='{"insecureRegistries": ["localhost:5000"]}' + start_registry + export BUILD_REGISTRY_SOURCES='{"insecureRegistries": ["localhost:${REGISTRY_PORT}"]}' - run_buildah 125 push --creds testuser:testpassword --signature-policy ${TESTSDIR}/policy.json --tls-verify=true busybox docker://localhost:5000/buildah/busybox:latest - expect_output --substring "can't require tls verification on an insecured registry" + run_buildah 125 push --creds testuser:testpassword --signature-policy ${TESTSDIR}/policy.json --tls-verify=true busybox docker://localhost:${REGISTRY_PORT}/buildah/busybox:latest + expect_output --substring "certificate signed by unknown authority" - run_buildah push --creds testuser:testpassword --signature-policy ${TESTSDIR}/policy.json busybox docker://localhost:5000/buildah/busybox:latest + run_buildah push --creds testuser:testpassword --signature-policy ${TESTSDIR}/policy.json --cert-dir ${TESTDIR}/registry busybox docker://localhost:${REGISTRY_PORT}/buildah/busybox:latest } @test "push with authfile" { _prefetch busybox mkdir ${TESTDIR}/tmp - run_buildah login --authfile ${TESTDIR}/tmp/test.auth --username testuser --password testpassword --tls-verify=false localhost:5000 - run_buildah push --authfile ${TESTDIR}/tmp/test.auth --signature-policy ${TESTSDIR}/policy.json --tls-verify=false busybox docker://localhost:5000/buildah/busybox:latest + start_registry + run_buildah login --authfile ${TESTDIR}/tmp/test.auth --username testuser --password testpassword --tls-verify=false localhost:${REGISTRY_PORT} + run_buildah push --authfile ${TESTDIR}/tmp/test.auth --signature-policy ${TESTSDIR}/policy.json --tls-verify=false busybox docker://localhost:${REGISTRY_PORT}/buildah/busybox:latest expect_output --substring "Copying" } diff --git a/tests/registries.conf b/tests/registries.conf index df2a610dc7a..010696a7076 100644 --- a/tests/registries.conf +++ b/tests/registries.conf @@ -13,8 +13,8 @@ location="mirror.gcr.io" # barfs spectacularly when trying to fetch them. We've hand-copied # those to quay, using skopeo copy --all ... [[registry]] -prefix="docker.io/library" -location="quay.io/libpod" +location="docker.io/library" +mirror=[{location="quay.io/libpod"}] # 2021-03-23 these are used in buildah system tests, but not (yet?) # listed in the global shortnames.conf. diff --git a/tests/source.bats b/tests/source.bats index 495593b4258..894df8a352a 100644 --- a/tests/source.bats +++ b/tests/source.bats @@ -124,10 +124,12 @@ load helpers echo 222... > ${TESTDIR}/file2 run_buildah source add $srcdir ${TESTDIR}/file2 - run_buildah source push --tls-verify=false --creds testuser:testpassword $srcdir localhost:5000/source:test + start_registry + + run_buildah source push --tls-verify=false --creds testuser:testpassword $srcdir localhost:${REGISTRY_PORT}/source:test pulldir=${TESTDIR}/pulledsource - run_buildah source pull --tls-verify=false --creds testuser:testpassword localhost:5000/source:test $pulldir + run_buildah source pull --tls-verify=false --creds testuser:testpassword localhost:${REGISTRY_PORT}/source:test $pulldir run diff -r $srcdir $pulldir [ "$status" -eq 0 ] diff --git a/vendor/golang.org/x/crypto/bcrypt/base64.go b/vendor/golang.org/x/crypto/bcrypt/base64.go new file mode 100644 index 00000000000..fc311609081 --- /dev/null +++ b/vendor/golang.org/x/crypto/bcrypt/base64.go @@ -0,0 +1,35 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bcrypt + +import "encoding/base64" + +const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + +var bcEncoding = base64.NewEncoding(alphabet) + +func base64Encode(src []byte) []byte { + n := bcEncoding.EncodedLen(len(src)) + dst := make([]byte, n) + bcEncoding.Encode(dst, src) + for dst[n-1] == '=' { + n-- + } + return dst[:n] +} + +func base64Decode(src []byte) ([]byte, error) { + numOfEquals := 4 - (len(src) % 4) + for i := 0; i < numOfEquals; i++ { + src = append(src, '=') + } + + dst := make([]byte, bcEncoding.DecodedLen(len(src))) + n, err := bcEncoding.Decode(dst, src) + if err != nil { + return nil, err + } + return dst[:n], nil +} diff --git a/vendor/golang.org/x/crypto/bcrypt/bcrypt.go b/vendor/golang.org/x/crypto/bcrypt/bcrypt.go new file mode 100644 index 00000000000..aeb73f81a14 --- /dev/null +++ b/vendor/golang.org/x/crypto/bcrypt/bcrypt.go @@ -0,0 +1,295 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing +// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf +package bcrypt // import "golang.org/x/crypto/bcrypt" + +// The code is a port of Provos and Mazières's C implementation. +import ( + "crypto/rand" + "crypto/subtle" + "errors" + "fmt" + "io" + "strconv" + + "golang.org/x/crypto/blowfish" +) + +const ( + MinCost int = 4 // the minimum allowable cost as passed in to GenerateFromPassword + MaxCost int = 31 // the maximum allowable cost as passed in to GenerateFromPassword + DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword +) + +// The error returned from CompareHashAndPassword when a password and hash do +// not match. +var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password") + +// The error returned from CompareHashAndPassword when a hash is too short to +// be a bcrypt hash. +var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password") + +// The error returned from CompareHashAndPassword when a hash was created with +// a bcrypt algorithm newer than this implementation. +type HashVersionTooNewError byte + +func (hv HashVersionTooNewError) Error() string { + return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion) +} + +// The error returned from CompareHashAndPassword when a hash starts with something other than '$' +type InvalidHashPrefixError byte + +func (ih InvalidHashPrefixError) Error() string { + return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih)) +} + +type InvalidCostError int + +func (ic InvalidCostError) Error() string { + return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost)) +} + +const ( + majorVersion = '2' + minorVersion = 'a' + maxSaltSize = 16 + maxCryptedHashSize = 23 + encodedSaltSize = 22 + encodedHashSize = 31 + minHashSize = 59 +) + +// magicCipherData is an IV for the 64 Blowfish encryption calls in +// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes. +var magicCipherData = []byte{ + 0x4f, 0x72, 0x70, 0x68, + 0x65, 0x61, 0x6e, 0x42, + 0x65, 0x68, 0x6f, 0x6c, + 0x64, 0x65, 0x72, 0x53, + 0x63, 0x72, 0x79, 0x44, + 0x6f, 0x75, 0x62, 0x74, +} + +type hashed struct { + hash []byte + salt []byte + cost int // allowed range is MinCost to MaxCost + major byte + minor byte +} + +// GenerateFromPassword returns the bcrypt hash of the password at the given +// cost. If the cost given is less than MinCost, the cost will be set to +// DefaultCost, instead. Use CompareHashAndPassword, as defined in this package, +// to compare the returned hashed password with its cleartext version. +func GenerateFromPassword(password []byte, cost int) ([]byte, error) { + p, err := newFromPassword(password, cost) + if err != nil { + return nil, err + } + return p.Hash(), nil +} + +// CompareHashAndPassword compares a bcrypt hashed password with its possible +// plaintext equivalent. Returns nil on success, or an error on failure. +func CompareHashAndPassword(hashedPassword, password []byte) error { + p, err := newFromHash(hashedPassword) + if err != nil { + return err + } + + otherHash, err := bcrypt(password, p.cost, p.salt) + if err != nil { + return err + } + + otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor} + if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 { + return nil + } + + return ErrMismatchedHashAndPassword +} + +// Cost returns the hashing cost used to create the given hashed +// password. When, in the future, the hashing cost of a password system needs +// to be increased in order to adjust for greater computational power, this +// function allows one to establish which passwords need to be updated. +func Cost(hashedPassword []byte) (int, error) { + p, err := newFromHash(hashedPassword) + if err != nil { + return 0, err + } + return p.cost, nil +} + +func newFromPassword(password []byte, cost int) (*hashed, error) { + if cost < MinCost { + cost = DefaultCost + } + p := new(hashed) + p.major = majorVersion + p.minor = minorVersion + + err := checkCost(cost) + if err != nil { + return nil, err + } + p.cost = cost + + unencodedSalt := make([]byte, maxSaltSize) + _, err = io.ReadFull(rand.Reader, unencodedSalt) + if err != nil { + return nil, err + } + + p.salt = base64Encode(unencodedSalt) + hash, err := bcrypt(password, p.cost, p.salt) + if err != nil { + return nil, err + } + p.hash = hash + return p, err +} + +func newFromHash(hashedSecret []byte) (*hashed, error) { + if len(hashedSecret) < minHashSize { + return nil, ErrHashTooShort + } + p := new(hashed) + n, err := p.decodeVersion(hashedSecret) + if err != nil { + return nil, err + } + hashedSecret = hashedSecret[n:] + n, err = p.decodeCost(hashedSecret) + if err != nil { + return nil, err + } + hashedSecret = hashedSecret[n:] + + // The "+2" is here because we'll have to append at most 2 '=' to the salt + // when base64 decoding it in expensiveBlowfishSetup(). + p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2) + copy(p.salt, hashedSecret[:encodedSaltSize]) + + hashedSecret = hashedSecret[encodedSaltSize:] + p.hash = make([]byte, len(hashedSecret)) + copy(p.hash, hashedSecret) + + return p, nil +} + +func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) { + cipherData := make([]byte, len(magicCipherData)) + copy(cipherData, magicCipherData) + + c, err := expensiveBlowfishSetup(password, uint32(cost), salt) + if err != nil { + return nil, err + } + + for i := 0; i < 24; i += 8 { + for j := 0; j < 64; j++ { + c.Encrypt(cipherData[i:i+8], cipherData[i:i+8]) + } + } + + // Bug compatibility with C bcrypt implementations. We only encode 23 of + // the 24 bytes encrypted. + hsh := base64Encode(cipherData[:maxCryptedHashSize]) + return hsh, nil +} + +func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) { + csalt, err := base64Decode(salt) + if err != nil { + return nil, err + } + + // Bug compatibility with C bcrypt implementations. They use the trailing + // NULL in the key string during expansion. + // We copy the key to prevent changing the underlying array. + ckey := append(key[:len(key):len(key)], 0) + + c, err := blowfish.NewSaltedCipher(ckey, csalt) + if err != nil { + return nil, err + } + + var i, rounds uint64 + rounds = 1 << cost + for i = 0; i < rounds; i++ { + blowfish.ExpandKey(ckey, c) + blowfish.ExpandKey(csalt, c) + } + + return c, nil +} + +func (p *hashed) Hash() []byte { + arr := make([]byte, 60) + arr[0] = '$' + arr[1] = p.major + n := 2 + if p.minor != 0 { + arr[2] = p.minor + n = 3 + } + arr[n] = '$' + n++ + copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost))) + n += 2 + arr[n] = '$' + n++ + copy(arr[n:], p.salt) + n += encodedSaltSize + copy(arr[n:], p.hash) + n += encodedHashSize + return arr[:n] +} + +func (p *hashed) decodeVersion(sbytes []byte) (int, error) { + if sbytes[0] != '$' { + return -1, InvalidHashPrefixError(sbytes[0]) + } + if sbytes[1] > majorVersion { + return -1, HashVersionTooNewError(sbytes[1]) + } + p.major = sbytes[1] + n := 3 + if sbytes[2] != '$' { + p.minor = sbytes[2] + n++ + } + return n, nil +} + +// sbytes should begin where decodeVersion left off. +func (p *hashed) decodeCost(sbytes []byte) (int, error) { + cost, err := strconv.Atoi(string(sbytes[0:2])) + if err != nil { + return -1, err + } + err = checkCost(cost) + if err != nil { + return -1, err + } + p.cost = cost + return 3, nil +} + +func (p *hashed) String() string { + return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor) +} + +func checkCost(cost int) error { + if cost < MinCost || cost > MaxCost { + return InvalidCostError(cost) + } + return nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 631dc166797..645ff44855b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -508,6 +508,7 @@ go.opencensus.io/trace go.opencensus.io/trace/internal go.opencensus.io/trace/tracestate # golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 +golang.org/x/crypto/bcrypt golang.org/x/crypto/blowfish golang.org/x/crypto/cast5 golang.org/x/crypto/chacha20