Skip to content

Commit

Permalink
Add update_check_required decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
eloquence committed Feb 11, 2021
1 parent c007e1b commit 4192093
Showing 1 changed file with 47 additions and 18 deletions.
65 changes: 47 additions & 18 deletions admin/securedrop_admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"""

import argparse
import functools
import ipaddress
import logging
import os
Expand Down Expand Up @@ -690,6 +691,45 @@ def setup_logger(verbose: bool = False) -> None:
sdlog.addHandler(stdout)


def update_check_required(cmd_name: str):
"""
This decorator can be added to any subcommand that is part of securedrop-admin
via `@update_check_required("name_of_subcommand")`. It forces a check for
updates, and aborts if the locally installed code is out of date. It should
be generally added to all subcommands that make modifications on the
server or on the Admin Workstation.
The user can override this check by specifying the --force argument before
any subcommand.
"""
def decorator_update_check(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
cli_args = args[0]
if cli_args.force:
sdlog.info("Skipping update check because --force argument was provided.")
return func(*args, **kwargs)

update_status, latest_tag = check_for_updates(cli_args)
if update_status is True:
sdlog.error("You are not running the most recent signed SecureDrop release "
"on this workstation.")
sdlog.error("Latest available version: {}".format(latest_tag))
sdlog.error("Running outdated or mismatched code can cause significant "
"technical issues.")
sdlog.error("If you are certain you want to proceed, run:\n\n\t"
"./securedrop-admin --force {}\n".format(cmd_name))
sdlog.error("To apply the latest updates, run:\n\n\t"
"./securedrop-admin update\n")
sdlog.error("If this fails, see the latest upgrade guide on "
"https://docs.securedrop.org/ for instructions.")
sys.exit(1)
return func(*args, **kwargs)
return wrapper
return decorator_update_check


@update_check_required("sdconfig")
def sdconfig(args: argparse.Namespace) -> int:
"""Configure SD site settings"""
SiteConfig(args).load_and_update_config(validate=False)
Expand Down Expand Up @@ -752,27 +792,10 @@ def find_or_generate_new_torv3_keys(args: argparse.Namespace) -> int:
return 0


@update_check_required("install")
def install_securedrop(args: argparse.Namespace) -> int:
"""Install/Update SecureDrop"""

if not args.force:
update_status, latest_tag = check_for_updates(args)
if update_status is True:
sdlog.error("You are not running the most recent signed SecureDrop release "
"on this workstation.")
sdlog.error("Latest available version: {}".format(latest_tag))
sdlog.error("Running the wrong installation playbook is a common cause "
"of technical issues.")
sdlog.error("If you are certain you want to proceed, run:\n\n\t"
"./securedrop-admin --force install\n")
sdlog.error("To apply the latest updates, run:\n\n\t"
"./securedrop-admin update\n")
sdlog.error("If this fails, see the latest upgrade guide on "
"https://docs.securedrop.org/ for instructions.")
sys.exit(1)
else:
sdlog.info("Skipping update check.")

SiteConfig(args).load_and_update_config(prompt=False)

sdlog.info("Now installing SecureDrop on remote servers.")
Expand All @@ -786,6 +809,7 @@ def install_securedrop(args: argparse.Namespace) -> int:
)


@update_check_required("verify")
def verify_install(args: argparse.Namespace) -> int:
"""Run configuration tests against SecureDrop servers"""

Expand All @@ -795,6 +819,7 @@ def verify_install(args: argparse.Namespace) -> int:
cwd=os.getcwd())


@update_check_required("backup")
def backup_securedrop(args: argparse.Namespace) -> int:
"""Perform backup of the SecureDrop Application Server.
Creates a tarball of submissions and server config, and fetches
Expand All @@ -808,6 +833,7 @@ def backup_securedrop(args: argparse.Namespace) -> int:
return subprocess.check_call(ansible_cmd, cwd=args.ansible_path)


@update_check_required("restore")
def restore_securedrop(args: argparse.Namespace) -> int:
"""Perform restore of the SecureDrop Application Server.
Requires a tarball of submissions and server config, created via
Expand Down Expand Up @@ -844,6 +870,7 @@ def restore_securedrop(args: argparse.Namespace) -> int:
return subprocess.check_call(ansible_cmd, cwd=args.ansible_path)


@update_check_required("tailsconfig")
def run_tails_config(args: argparse.Namespace) -> int:
"""Configure Tails environment post SD install"""
sdlog.info("Configuring Tails workstation environment")
Expand Down Expand Up @@ -991,6 +1018,7 @@ def update(args: argparse.Namespace) -> int:
return 0


@update_check_required("logs")
def get_logs(args: argparse.Namespace) -> int:
"""Get logs for forensics and debugging purposes"""
sdlog.info("Gathering logs for forensics and debugging")
Expand All @@ -1017,6 +1045,7 @@ def set_default_paths(args: argparse.Namespace) -> argparse.Namespace:
return args


@update_check_required("reset_admin_access")
def reset_admin_access(args: argparse.Namespace) -> int:
"""Resets SSH access to the SecureDrop servers, locking it to
this Admin Workstation."""
Expand Down

0 comments on commit 4192093

Please sign in to comment.