Skip to content

Commit

Permalink
Merge pull request #5335 from freedomofpress/fix-5334
Browse files Browse the repository at this point in the history
Fix onion service version validation in securedrop-admin install
  • Loading branch information
zenmonkeykstop authored Jun 24, 2020
2 parents 6e90844 + 79d2e98 commit b5f8eb0
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 36 deletions.
13 changes: 6 additions & 7 deletions admin/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@ RUN apt-get update && \
apt-get install -y python3 sudo lsb-release gnupg2 git
RUN if test $USER_NAME != root ; then useradd --no-create-home --home-dir /tmp --uid $USER_ID $USER_NAME && echo "$USER_NAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers ; fi

WORKDIR /opt
COPY bootstrap.py .
COPY requirements.txt .
RUN python3 bootstrap.py -v
ENV VIRTUAL_ENV /opt/.venv
WORKDIR /opt/admin
COPY . /opt
RUN rm -rf /opt/admin/.venv3
RUN cd /opt/admin && python3 bootstrap.py -v
ENV VIRTUAL_ENV /opt/admin/.venv3
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
COPY requirements-dev.txt .
RUN pip3 install --no-deps --require-hashes -r requirements-dev.txt
RUN pip3 install --no-deps --require-hashes -r /opt/admin/requirements-dev.txt

RUN chown -R $USER_NAME /opt
35 changes: 6 additions & 29 deletions admin/bin/dev-shell
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,22 @@ set -euo pipefail
TOPLEVEL=$(git rev-parse --show-toplevel)
source "${BASH_SOURCE%/*}/../../devops/scripts/ticker"

function docker_image_circle() {
function docker_image() {
local out
out="$(mktemp)"
( cat Dockerfile ; echo COPY . . ) > circle.docker
if ! docker build ${DOCKER_BUILD_ARGUMENTS:-} -t securedrop-admin -f circle.docker . >& "$out" ; then
cd "${TOPLEVEL}"
if ! docker build ${DOCKER_BUILD_ARGUMENTS:-} -t securedrop-admin -f admin/Dockerfile . >& "$out" ; then
cat "$out"
status=1
else
status=0
fi
rm circle.docker
return $status
}

function docker_run_circle() {
docker run --rm -ti ${DOCKER_RUN_ARGUMENTS:-} securedrop-admin "$@"
}

function docker_image() {
docker build \
${DOCKER_BUILD_ARGUMENTS:-} \
--build-arg=USER_ID="$(id -u)" \
--build-arg=USER_NAME="${USER:-root}" \
-t securedrop-admin "${TOPLEVEL}/admin"
}

function docker_run() {
docker run \
--rm \
--user "${USER:-root}" \
--volume "${TOPLEVEL}:${TOPLEVEL}" \
--workdir "${TOPLEVEL}/admin" \
-ti ${DOCKER_RUN_ARGUMENTS:-} securedrop-admin "$@"
docker run --rm -ti ${DOCKER_RUN_ARGUMENTS:-} securedrop-admin "$@"
}

if test -n "${CIRCLE_SHA1:-}" ; then
docker_image_circle
docker_run_circle "$@"
else
ticker docker_image
docker_run "$@"
fi
docker_image
docker_run "$@"
5 changes: 5 additions & 0 deletions admin/securedrop_admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,9 @@ def __init__(self, args):
def load_and_update_config(self, validate: bool = True, prompt: bool = True):
if self.exists():
self.config = self.load(validate)
elif not prompt:
sdlog.error('Please run "securedrop-admin sdconfig" first.')
sys.exit(1)

return self.update_config(prompt)

Expand Down Expand Up @@ -624,6 +627,8 @@ def clean_config(self, config: dict) -> dict:
)
raise
clean_config[var] = transform(text) if transform else text
if var not in self._config_in_progress:
self._config_in_progress[var] = clean_config[var]
return clean_config

def load(self, validate=True):
Expand Down
47 changes: 47 additions & 0 deletions admin/tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pytest
import re
import requests
import shutil
import subprocess
import tempfile

Expand Down Expand Up @@ -191,6 +192,19 @@ def setup_function(function):
global SD_DIR
SD_DIR = tempfile.mkdtemp()
ANSIBLE_BASE = '{0}/install_files/ansible-base'.format(SD_DIR)

for name in ["roles", "tasks"]:
shutil.copytree(
os.path.join(CURRENT_DIR, "../../install_files/ansible-base", name),
os.path.join(ANSIBLE_BASE, name)
)

for name in ["ansible.cfg", "securedrop-prod.yml"]:
shutil.copy(
os.path.join(CURRENT_DIR, '../../install_files/ansible-base', name),
ANSIBLE_BASE
)

cmd = 'mkdir -p {0}/group_vars/all'.format(ANSIBLE_BASE).split()
subprocess.check_call(cmd)
for name in ['sd_admin_test.pub', 'ca.crt', 'sd.crt', 'key.asc']:
Expand Down Expand Up @@ -340,6 +354,29 @@ def verify_v3_onion_when_v2_is_enabled(child):
assert ANSI_ESCAPE.sub('', child.buffer.decode("utf-8")).strip() == 'yes' # noqa: E501


def verify_install_has_valid_config():
"""
Checks that securedrop-admin install validates the configuration.
"""
cmd = os.path.join(os.path.dirname(CURRENT_DIR), 'securedrop_admin/__init__.py')
child = pexpect.spawn('python {0} --root {1} install'.format(cmd, SD_DIR))
child.expect(b"SUDO password:", timeout=5)
child.close()


def test_install_with_no_config():
"""
Checks that securedrop-admin install complains about a missing config file.
"""
cmd = os.path.join(os.path.dirname(CURRENT_DIR), 'securedrop_admin/__init__.py')
child = pexpect.spawn('python {0} --root {1} install'.format(cmd, SD_DIR))
child.expect(b'ERROR: Please run "securedrop-admin sdconfig" first.', timeout=5)
child.expect(pexpect.EOF, timeout=5)
child.close()
assert child.exitstatus == 1
assert child.signalstatus is None


def test_sdconfig_on_first_run():
cmd = os.path.join(os.path.dirname(CURRENT_DIR),
'securedrop_admin/__init__.py')
Expand Down Expand Up @@ -401,6 +438,8 @@ def test_sdconfig_on_first_run():
data = fobj.read()
assert data == OUTPUT1

verify_install_has_valid_config()


def test_sdconfig_both_v2_v3_true():
cmd = os.path.join(os.path.dirname(CURRENT_DIR),
Expand Down Expand Up @@ -463,6 +502,8 @@ def test_sdconfig_both_v2_v3_true():
data = fobj.read()
assert data == WHEN_BOTH_TRUE

verify_install_has_valid_config()


def test_sdconfig_only_v2_true():
cmd = os.path.join(os.path.dirname(CURRENT_DIR),
Expand Down Expand Up @@ -525,6 +566,8 @@ def test_sdconfig_only_v2_true():
data = fobj.read()
assert data == WHEN_ONLY_V2

verify_install_has_valid_config()


def test_sdconfig_enable_journalist_alerts():
cmd = os.path.join(os.path.dirname(CURRENT_DIR),
Expand Down Expand Up @@ -592,6 +635,8 @@ def test_sdconfig_enable_journalist_alerts():
data = fobj.read()
assert JOURNALIST_ALERT_OUTPUT == data

verify_install_has_valid_config()


def test_sdconfig_enable_https_on_source_interface():
cmd = os.path.join(os.path.dirname(CURRENT_DIR),
Expand Down Expand Up @@ -666,6 +711,8 @@ def test_sdconfig_enable_https_on_source_interface():
data = fobj.read()
assert HTTPS_OUTPUT == data

verify_install_has_valid_config()


# The following is the minimal git configuration which can be used to fetch
# from the SecureDrop Github repository. We want to use this because the
Expand Down

0 comments on commit b5f8eb0

Please sign in to comment.