Repository: freedomofpress/securedrop

Issue:
Updated `manage.py` subcommands should have aliases
In #1347 we converted the subcommands for the `manage.py` script to use hyphens instead of underscores, e.g. `add_admin` -> `add-admin`. That works well for the most part, assuming existing Admins read the docs on the update, but it will cause problems for currently running instances, because a cron job exists for the `clean_tmp` subcommand, and that subcommand will no longer exist in 0.4. We should do two things to resolve:

1. Implement subcommand aliases in `manage.py` so that the old subcommands still work. 
2. Update the Ansible config to ensure state=absent on the old cronjob, and state=present on the new one. Doing so will ensure that Admins running the playbooks do not create duplicate cron jobs.

If we don't do this, the nightly cron job for cleaning the temp directory will fail on all Application Servers going forward. Therefore this'll need to go on the 0.4 milestone, lest we break the temp cleanup logic currently used in production.


Discussion:
Do you think we need to update all subcommands or would just the one be sufficient? @conorsch 
Let's do all—I still find myself typing `./manage.py add_admin` when setting up new accounts, and am frustrated by the lack of backwards compatibility every time.

Resolving patch:
diff --git a/securedrop/manage.py b/securedrop/manage.py
--- a/securedrop/manage.py
+++ b/securedrop/manage.py
@@ -224,12 +224,18 @@ def get_args():
     admin_subp = subps.add_parser('add-admin', help='Add an admin to the '
                                   'application.')
     admin_subp.set_defaults(func=add_admin)
+    admin_subp_a = subps.add_parser('add_admin', help='^')
+    admin_subp_a.set_defaults(func=add_admin)
     journalist_subp = subps.add_parser('add-journalist', help='Add a '
                                        'journalist to the application.')
     journalist_subp.set_defaults(func=add_journalist)
+    journalist_subp_a = subps.add_parser('add_journalist', help='^')
+    journalist_subp_a.set_defaults(func=add_journalist)
     delete_user_subp = subps.add_parser('delete-user', help='Delete a user '
                                         'from the application.')
     delete_user_subp.set_defaults(func=delete_user)
+    delete_user_subp_a = subps.add_parser('delete_user', help='^')
+    delete_user_subp_a.set_defaults(func=delete_user)
 
     # Reset application state
     reset_subp = subps.add_parser('reset', help='DANGER!!! Clears the '
@@ -239,6 +245,8 @@ def get_args():
     clean_tmp_subp = subps.add_parser('clean-tmp', help='Cleanup the '
                                       'SecureDrop temp directory.')
     clean_tmp_subp.set_defaults(func=clean_tmp)
+    clean_tmp_subp_a = subps.add_parser('clean_tmp', help='^')
+    clean_tmp_subp_a.set_defaults(func=clean_tmp)
 
     return parser
 


Test patch:
diff --git a/testinfra/development/test_development_application_settings.py b/testinfra/development/test_development_application_settings.py
--- a/testinfra/development/test_development_application_settings.py
+++ b/testinfra/development/test_development_application_settings.py
@@ -109,15 +109,20 @@ def test_development_app_directories_exist(File):
 
 def test_development_clean_tmp_cron_job(Command, Sudo):
     """
-    Ensure cron job for cleaning the temporary directory for the app code exists.
+    Ensure cron job for cleaning the temporary directory for the app code
+    exists. Also, ensure that the older format for the cron job is absent,
+    since we updated manage.py subcommands to use hyphens instead of
+    underscores (e.g. `clean_tmp` -> `clean-tmp`).
     """
 
     with Sudo():
         c = Command.check_output('crontab -l')
-    # TODO: this should be using property, but the ansible role
-    # doesn't use a var, it's hard-coded. update ansible, then fix test.
-    # it { should have_entry "@daily #{property['securedrop_code']}/manage.py clean-tmp" }
     assert "@daily {}/manage.py clean-tmp".format(sd_test_vars.securedrop_code) in c
+    assert "@daily {}/manage.py clean_tmp".format(sd_test_vars.securedrop_code) not in c
+    assert "clean_tmp".format(sd_test_vars.securedrop_code) not in c
+    # Make sure that the only cron lines are a comment and the actual job.
+    # We don't want any duplicates.
+    assert len(c.split("\n")) == 2
 
 
 def test_development_default_logo_exists(File):