From 11d971bc07ceb4359565e6611ae03a0c0134d153 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Fri, 19 Feb 2021 23:22:15 +0100 Subject: Add test suite against Let's Encrypt's staging environment. https://letsencrypt.org/docs/staging-environment/ --- test | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100755 test (limited to 'test') diff --git a/test b/test new file mode 100755 index 0000000..ffee0ec --- /dev/null +++ b/test @@ -0,0 +1,237 @@ +#!/bin/bash + +#---------------------------------------------------------------------- +# ACME client written with process isolation and minimal privileges in mind +# (test suite) +# Copyright © 2015-2021 Guilhem Moulin +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +#---------------------------------------------------------------------- + +set -ue +PATH="/usr/bin:/bin" +export PATH + +usage() { + local rv="${1-0}" + echo "Usage: $0 [--deb|--dev] [TEST..]" >&2 + exit $rv +} + +# Setup: for any subdomain under $DOMAINNAME, +# http://$subdomain.$DOMAINNAME/.well-known/acme-challenge/$challenge +# must be routed to this machine. +# This can be done with a wildcard DNS record and opening tcp/80 in firewall. +DOMAINNAME="lacme-test.guilhem.org" + +MODE="dev" +DISTRIBUTION="sid" +BUILDDIR="build/test" +while [ $# -gt 0 ]; do + case "$1" in + --deb) MODE="deb"; shift;; + --dev) MODE="dev"; shift;; + --help|-h) usage 0;; + -*) echo "Error: Unknown option $1" >&2; usage 1;; + --) shift; break;; + *) break; + esac +done + +cd "$(dirname -- "$0")" +declare -a TESTS=() +if [ $# -eq 0 ]; then + # always start with registration, the account key might be new + TESTS+=( "register" ) + for t in tests/*; do + if [ "$t" != "tests/register" ] && [ -f "$t" ]; then + TESTS+=( "${t#tests/}" ) + fi + done +else + for t in "$@"; do + if [ -f "tests/$t" ]; then + TESTS+=( "$t" ) + else + echo "Error: '$1': no such test" >&2 + exit 1 + fi + done +fi + +if [ "$MODE" = "deb" ]; then + DISTRIBUTION="$(dpkg-parsechangelog -S Distribution)" + [ "$DISTRIBUTION" != "UNRELEASED" ] || DISTRIBUTION="sid" + PKG_DESTDIR="${XDG_CACHE_HOME:-"$HOME/.cache"}/build-area" +elif [ "$MODE" = "dev" ]; then + make all -- \ + BUILDDIR="$BUILDDIR" \ + DESTDIR="" \ + exec_prefix="/usr" \ + datadir="/usr/share" \ + runstatedir="/run" \ + lacme_www_user=_lacme-www \ + lacme_www_group=nogroup \ + lacme_client_user=_lacme-client \ + lacme_client_group=nogroup +fi + +ACCOUNT_KEY="$BUILDDIR/account.key" +if [ ! -f "$ACCOUNT_KEY" ]; then + # keep the account key (up to `make clean`) to avoid hitting + # rate-liming -- currently 50 registrations per 3h per IP, see + # https://letsencrypt.org/docs/staging-environment/ + echo "Generating account key $ACCOUNT_KEY..." >&2 + openssl genpkey -algorithm RSA -out "$ACCOUNT_KEY" +fi + +ARCH="$(dpkg-architecture -qDEB_BUILD_ARCH)" +CHROOT="" + +cleanup() { + if [ -n "$CHROOT" ]; then + schroot -c "$CHROOT" -e + fi +} +trap cleanup EXIT INT TERM + +run() { + local t="tests/$1" rootdir version sub + if [ ! -f "$t" ]; then + echo "Error: '$1': no such test" >&2 + exit 1 + fi + + CHROOT="$(schroot -c "$DISTRIBUTION-$ARCH-sbuild" -b)" + rootdir="/run/schroot/mount/$CHROOT" + + if [ "$MODE" = "deb" ]; then + version="$(dpkg-parsechangelog -S Version)" + echo "Installing lacme $version into $CHROOT..." >&2 + install -vt "$rootdir/dev/shm" -m0644 -- \ + "$PKG_DESTDIR/lacme_${version}_all.deb" \ + "$PKG_DESTDIR/lacme-accountd_${version}_all.deb" + sudo schroot -d"/" -c "$CHROOT" -r -- \ + env DEBIAN_FRONTEND="noninteractive" apt install -y \ + "/dev/shm/lacme_${version}_all.deb" \ + "/dev/shm/lacme-accountd_${version}_all.deb" + + elif [ "$MODE" = "dev" ]; then + echo "Installing lacme dev into $CHROOT..." >&2 + sudo make install -- \ + BUILDDIR="$BUILDDIR" \ + DESTDIR="$rootdir" \ + exec_prefix="$rootdir/usr" \ + datadir="$rootdir/usr/share" \ + runstatedir="$rootdir/run" + sudo schroot -d"/" -c "$CHROOT" -r -- \ + env DEBIAN_FRONTEND="noninteractive" apt install -y \ + adduser \ + libconfig-tiny-perl \ + libcrypt-openssl-rsa-perl \ + libjson-perl \ + libnet-ssleay-perl \ + libtimedate-perl \ + libwww-perl \ + openssl + sudo schroot -d"/" -c "$CHROOT" -r -- \ + adduser --force-badname --system \ + --home /nonexistent --no-create-home \ + --gecos "lacme www user" \ + --quiet _lacme-www + sudo schroot -d"/" -c "$CHROOT" -r -- \ + adduser --force-badname --system \ + --home /nonexistent --no-create-home \ + --gecos "lacme client user" \ + --quiet _lacme-client + fi + + # set up staging environment, see https://letsencrypt.org/docs/staging-environment/ + sudo install -oroot -groot -m0644 -vt "$rootdir/usr/share/lacme" certs-staging/*.pem + sudo install -oroot -groot -m0644 -vT "$BUILDDIR/certs-staging/ca-certificates.crt" \ + "$rootdir/usr/share/lacme/ca-certificates.crt" + sudo schroot -d"/" -c "$CHROOT" -r -- perl -pi -e \ + 's|\b\Qhttps://acme-v02.api.letsencrypt.org/\E\b|https://acme-staging-v02.api.letsencrypt.org/|' \ + "/usr/libexec/lacme/client" "/etc/lacme/lacme.conf" + + # install account key and configure lacme accordingly + sudo install -oroot -groot -m0600 -vT -- "$BUILDDIR/account.key" \ + "$rootdir/etc/lacme/account.key" + sudo schroot -d"/" -c "$CHROOT" -r -- \ + sed -ri '0,\|^#?privkey\s*=.*| {s||privkey = file:/etc/lacme/account.key|}' \ + /etc/lacme/lacme-accountd.conf + + # use lacme's internal webserver bound to INADDR_ANY port 80 + sudo schroot -d"/" -c "$CHROOT" -r -- \ + sed -ri 's|^#?listen\s*=.*|listen = 0.0.0.0|' /etc/lacme/lacme.conf + + # use a sample lacme-certs.conf, with a random subdomain so we can + # verify that challenges are answered correctly + sub="$(head -c10 /dev/urandom | base32 -w0)" + sudo tee "$rootdir/etc/lacme/lacme-certs.conf.d/simpletest-rsa.conf" >/dev/null <<- EOF + [simpletest-rsa] + certificate-key = /etc/lacme/simpletest.rsa.key + certificate-chain = /etc/lacme/simpletest.rsa.crt + subject = /CN=${sub,,[A-Z]}.$DOMAINNAME + EOF + sudo schroot -d"/" -c "$CHROOT" -r -- \ + openssl genpkey -algorithm RSA -out /etc/lacme/simpletest.rsa.key + + # copy test wrapper and unit file + local testdir="/dev/shm/lacme.test" + sudo install -oroot -groot -m0700 -d -- "$rootdir$testdir" + sudo install -oroot -groot -m0755 -T -- /dev/stdin "$rootdir$testdir/run" <<-EOF + STDERR="$testdir/stderr" + touch "\$STDERR" + fail() { + set +x + local rv=\$? i + if [ \$rv -eq 0 ]; then rv=1; fi + echo "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv" + cat <"\$STDERR" >&2 + echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" + [ \$# -eq 0 ] || echo "Error: \$*" >&2 + exit \$rv + } + grepstderr() { + grep "\$@" <"\$STDERR" || fail + } + ngrepstderr() { + ! grep "\$@" <"\$STDERR" || fail + } + set -x + EOF + sudo tee -a "$rootdir$testdir/run" >/dev/null <"$t" + + sudo schroot -d"/" -c "$CHROOT" -r -- env -i \ + USER="root" \ + HOME="/root" \ + SHELL="/bin/sh" \ + LOGNAME="root" \ + TERM="$TERM" \ + PATH="/usr/sbin:/usr/bin:/sbin:/bin" \ + DOMAINNAME="$DOMAINNAME" \ + sh -ue "$testdir/run" || return $? + + # clean up + schroot -c "$CHROOT" -e + CHROOT="" +} + +for t in "${TESTS[@]}"; do + if ! run "$t"; then + echo "FAILED: $t" >&2 + exit 1 + fi +done -- cgit v1.2.3 From 95534d55bd27ec9311a484ddc4e4a550191aa496 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sat, 20 Feb 2021 20:15:20 +0100 Subject: Add tests for OpenSSL- and GnuPG-encrypted account keys. These tests are not interactive! --- test | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/test b/test index ffee0ec..50b7382 100755 --- a/test +++ b/test @@ -55,7 +55,8 @@ if [ $# -eq 0 ]; then # always start with registration, the account key might be new TESTS+=( "register" ) for t in tests/*; do - if [ "$t" != "tests/register" ] && [ -f "$t" ]; then + if [ "$t" != "tests/register" ] && [ "${t#tests/account-encrypted-}" = "$t" ] && [ -f "$t" ]; then + # skip registration and non-interactive tests TESTS+=( "${t#tests/}" ) fi done -- cgit v1.2.3 From 626c0418b3d8c3747a7be8e2620d7c85a8c2c613 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 21 Feb 2021 02:55:46 +0100 Subject: Make the ACME API server URL configurable at build time. --- test | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test b/test index 50b7382..2be9303 100755 --- a/test +++ b/test @@ -85,7 +85,8 @@ elif [ "$MODE" = "dev" ]; then lacme_www_user=_lacme-www \ lacme_www_group=nogroup \ lacme_client_user=_lacme-client \ - lacme_client_group=nogroup + lacme_client_group=nogroup \ + acmeapi_server="https://acme-staging-v02.api.letsencrypt.org/directory" fi ACCOUNT_KEY="$BUILDDIR/account.key" @@ -162,9 +163,6 @@ run() { sudo install -oroot -groot -m0644 -vt "$rootdir/usr/share/lacme" certs-staging/*.pem sudo install -oroot -groot -m0644 -vT "$BUILDDIR/certs-staging/ca-certificates.crt" \ "$rootdir/usr/share/lacme/ca-certificates.crt" - sudo schroot -d"/" -c "$CHROOT" -r -- perl -pi -e \ - 's|\b\Qhttps://acme-v02.api.letsencrypt.org/\E\b|https://acme-staging-v02.api.letsencrypt.org/|' \ - "/usr/libexec/lacme/client" "/etc/lacme/lacme.conf" # install account key and configure lacme accordingly sudo install -oroot -groot -m0600 -vT -- "$BUILDDIR/account.key" \ -- cgit v1.2.3 From 543578b20187836a83d84c7cd669cb2448e3a3d7 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 21 Feb 2021 12:01:28 +0100 Subject: test suite: Indicate which tests have passed. --- test | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'test') diff --git a/test b/test index 2be9303..c9aaef8 100755 --- a/test +++ b/test @@ -222,15 +222,31 @@ run() { PATH="/usr/sbin:/usr/bin:/sbin:/bin" \ DOMAINNAME="$DOMAINNAME" \ sh -ue "$testdir/run" || return $? - - # clean up - schroot -c "$CHROOT" -e - CHROOT="" } +RV=0 +declare -a PASSED=() FAILED=() for t in "${TESTS[@]}"; do - if ! run "$t"; then - echo "FAILED: $t" >&2 - exit 1 + run "$t" && rv=0 || rv=$? + if [ -n "$CHROOT" ]; then + # clean up + schroot -c "$CHROOT" -e + CHROOT="" + fi + if [ $rv -eq 0 ]; then + PASSED+=( "$t" ) + else + FAILED+=( "$t" ) + RV=$rv + break # stop at the first failure fi done + +echo >&2 +echo "================================================================================" >&2 + +echo "PASSED: ${PASSED[*]:-"(none)"}" >&2 +if [ ${#FAILED[@]} -gt 0 ]; then + echo "FAILED: ${FAILED[*]}" >&2 +fi +exit $RV -- cgit v1.2.3 From 7545130ac74c5a6f3dfa62087ac0287686248eec Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 21 Feb 2021 12:22:06 +0100 Subject: test suite: Don't try to show stderr if it's empty. --- test | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test b/test index c9aaef8..4fdfdbc 100755 --- a/test +++ b/test @@ -197,9 +197,11 @@ run() { set +x local rv=\$? i if [ \$rv -eq 0 ]; then rv=1; fi - echo "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv" - cat <"\$STDERR" >&2 - echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" + if [ -s "\$STDERR" ]; then + echo "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv" + cat <"\$STDERR" >&2 + echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" + fi [ \$# -eq 0 ] || echo "Error: \$*" >&2 exit \$rv } -- cgit v1.2.3 From d9c91dc92f4d6af2d9f537a5f30a2cb40715da71 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Mon, 22 Feb 2021 01:49:27 +0100 Subject: space damage --- test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test b/test index 4fdfdbc..dc80751 100755 --- a/test +++ b/test @@ -213,7 +213,7 @@ run() { } set -x EOF - sudo tee -a "$rootdir$testdir/run" >/dev/null <"$t" + sudo tee -a "$rootdir$testdir/run" >/dev/null <"$t" sudo schroot -d"/" -c "$CHROOT" -r -- env -i \ USER="root" \ -- cgit v1.2.3 From 9a6a7824a009e1fb1f97afd227181191bc10f0a6 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Mon, 22 Feb 2021 02:43:48 +0100 Subject: Fix `./test --deb`. The staging environment wasn't set properly for the Debian packages. --- test | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'test') diff --git a/test b/test index dc80751..81d910c 100755 --- a/test +++ b/test @@ -75,21 +75,10 @@ if [ "$MODE" = "deb" ]; then DISTRIBUTION="$(dpkg-parsechangelog -S Distribution)" [ "$DISTRIBUTION" != "UNRELEASED" ] || DISTRIBUTION="sid" PKG_DESTDIR="${XDG_CACHE_HOME:-"$HOME/.cache"}/build-area" -elif [ "$MODE" = "dev" ]; then - make all -- \ - BUILDDIR="$BUILDDIR" \ - DESTDIR="" \ - exec_prefix="/usr" \ - datadir="/usr/share" \ - runstatedir="/run" \ - lacme_www_user=_lacme-www \ - lacme_www_group=nogroup \ - lacme_client_user=_lacme-client \ - lacme_client_group=nogroup \ - acmeapi_server="https://acme-staging-v02.api.letsencrypt.org/directory" fi ACCOUNT_KEY="$BUILDDIR/account.key" +mkdir -pv -- "$BUILDDIR" if [ ! -f "$ACCOUNT_KEY" ]; then # keep the account key (up to `make clean`) to avoid hitting # rate-liming -- currently 50 registrations per 3h per IP, see @@ -115,6 +104,20 @@ run() { exit 1 fi + # Don't need to rebuild for each test, but editing the code at the + # same time might cause `make install` to rebuild a wrong version + make all -- \ + BUILDDIR="$BUILDDIR" \ + DESTDIR="" \ + exec_prefix="/usr" \ + datadir="/usr/share" \ + runstatedir="/run" \ + lacme_www_user=_lacme-www \ + lacme_www_group=nogroup \ + lacme_client_user=_lacme-client \ + lacme_client_group=nogroup \ + acmeapi_server="https://acme-staging-v02.api.letsencrypt.org/directory" + CHROOT="$(schroot -c "$DISTRIBUTION-$ARCH-sbuild" -b)" rootdir="/run/schroot/mount/$CHROOT" @@ -163,6 +166,9 @@ run() { sudo install -oroot -groot -m0644 -vt "$rootdir/usr/share/lacme" certs-staging/*.pem sudo install -oroot -groot -m0644 -vT "$BUILDDIR/certs-staging/ca-certificates.crt" \ "$rootdir/usr/share/lacme/ca-certificates.crt" + sudo schroot -d"/" -c "$CHROOT" -r -- \ + sed -ri '0,/^#?server\s*=.*/ {s||server = https://acme-staging-v02.api.letsencrypt.org/directory|}' \ + /etc/lacme/lacme.conf # install account key and configure lacme accordingly sudo install -oroot -groot -m0600 -vT -- "$BUILDDIR/account.key" \ -- cgit v1.2.3