• 
      

    Add a Page for the Security Checklist in the Admin View

    Review Request #4952 — Created Nov. 13, 2013 and submitted

    Information

    Review Board
    master

    Reviewers

    With this review request I fixed a lot of style issues. This includes:
    - Making sure that includes are properly alphabetized;
    - Got rid of escaped characters by making the string double-quoted;
    - Renamed variables so they are more consistent;
    - Aligned strings;
    - Removed outer parenthesis where they are not needed on tuples;
    - Improved some of the user-visible descriptions;
    - Added a docstring for SecurityCheckRunner;
    - Fixed blank lines;
    - Fixed URLs;
    - Fixed indentation in the template;
    - Moved HTML styling into CSS tags.

    In terms of actual functionality, I changed the ExecutableCodeCheck test to be able to fail on multiple file types. Before it would end the test on the first failed file type and return that to the user. Now it will return a list of each file type that fails.

    I've also included some screenshots to show what various success/failure statuses look like.

    Ran through all tests and they succeeded when they should and also failed when they should when I introduced failure conditions.


    Description From Last Updated

    Since these names are presented to the user, we should mark them for localization. Basically, at the top of this …

    daviddavid

    This is a good start, but I think we'll want to have this go through a range of different file …

    daviddavid

    In order to be more consistent with python's unit test frameworks, can we capitalize this "setUp"? In unittest, the setUp …

    daviddavid

    And "tearDown" here.

    daviddavid

    This isn't catching any exceptions, and the open() call is leaking an open file. For the open file, you can …

    daviddavid

    Same thing here with localization. Perhaps call this one "Checking ALLOWED_HOSTS setting" ?

    daviddavid

    It's a little confusing to have "result" and "results" here. Can we name these better?

    daviddavid

    I think we're going to want a little bit more complexity in the results than just a true/false value. My …

    daviddavid

    While I think it would be nice to eventually use entry points for this, for now I think just using …

    daviddavid

    This probably doesn't need (and shouldn't have) the admin-dashboard ID.

    daviddavid

    This stuff looks like it was copied from the admin dashboard and can be removed.

    daviddavid

    Please indent HTML with 1 space.

    daviddavid

    I don't think you intended to change this file. Please revert it.

    daviddavid

    No blank space here (both "django" and "djblets" are "third party" with respect to the review board codebase).

    daviddavid

    Add an extra blank line here.

    daviddavid

    Remove this blank line.

    daviddavid

    Remove this blank line.

    daviddavid

    This is pretty good but I'd like to change the first sentence a bit. How about: "A misconfiguration in the …

    daviddavid

    Can we add one additional piece of metadata here for instructions to fix it? For this check, we'd want the …

    daviddavid

    This should probably be `settings.MEDIA_URL + 'uploaded/files/'

    daviddavid

    We should skip saving, tearing down, and the actual tests in the case that the user is using s3 (or …

    daviddavid

    This line looks too long (> 80 columns). There's also some changes I'd like to make to the string. Let's …

    daviddavid

    This should also use _() and string formatting instead of concatenation.

    daviddavid

    Remove this blank line.

    daviddavid

    Once again, we should include instructions for how to fix it (shown when the test fails). This one would say …

    daviddavid

    This string should be marked for translation.

    daviddavid

    This string, too.

    daviddavid

    Remove this blank line.

    daviddavid

    These lines are all indented 4 spaces too many.

    daviddavid

    Add an extra blank line here.

    daviddavid

    Should be in alphabetical order (base before storage).

    chipx86chipx86

    Two blank lines.

    chipx86chipx86

    These should just default to None.

    chipx86chipx86

    The camelCase in unittest is a holdover from early days of Python. We shouldn't duplicate it here. Instead, just call …

    chipx86chipx86

    And teardown.

    chipx86chipx86

    When you have to escape a single quote, it's best to just use double quotes for the string itself, to …

    chipx86chipx86

    Can we call this storage instead of fss? It's a more standard variable name for an instance of a Storage …

    chipx86chipx86

    Would be better as file_checks.

    chipx86chipx86

    The strings should all be aligned.

    chipx86chipx86

    Can you break this into two lines, mimicking the newline?

    chipx86chipx86

    Parameters should be aligned.

    chipx86chipx86

    The %s will automatically cast to the string, so no need for six.text_type(e) here.

    chipx86chipx86

    No need for the outer parens here, as it's one line and the comma will ensure it'll be returned as …

    chipx86chipx86

    Same here.

    chipx86chipx86

    Parameters need to align.

    chipx86chipx86

    Not really worth talking about Django. "That Review Board will consider valid for this server" is probably fine.

    chipx86chipx86

    Make sure the strings align.

    chipx86chipx86

    Lots of escaping. Should just use double quotes to solve this.

    chipx86chipx86

    A quicker way would be: if '*' in settings.ALLOWED_HOSTS: result = False ...

    chipx86chipx86

    Might be worth expanding on this, stating how it'll respond to any host, and how that's unsafe.

    chipx86chipx86

    No need for these parens.

    chipx86chipx86

    Mind adding a docstring?

    chipx86chipx86

    Blank line between these.

    chipx86chipx86

    Typically, you'd want iteritems(), since it doesn't make a copy of the list of items. Python 3 renames this to …

    chipx86chipx86

    The }) should align with all_test_results

    chipx86chipx86

    Should add a trailing comma.

    chipx86chipx86

    Two blank lines between things on the top level.

    chipx86chipx86

    Global variables should be at the top of the file, after the imports. Two blank lines on either side.

    chipx86chipx86

    "Returns" instead of "Gets"

    chipx86chipx86

    All one line.

    chipx86chipx86

    "site_domain_method" should only be indented 4 spaces from protocol =

    chipx86chipx86

    The widget-* URLs are wrong. This regex should be: r'^security/$' The $ prevents security/adfsfsa from matching.

    chipx86chipx86

    This should be in alphabetical order, so before reviewboard.admin.supports.

    chipx86chipx86

    Two blank lines.

    chipx86chipx86

    Should remove this. It'll actually break some server configurations, as many WSGI implementations don't like random things going on stdout.

    chipx86chipx86

    The })) needs to align with return.

    chipx86chipx86

    The URLs above based on views.dashboard are done for legacy reasons, but for this one, you should give the URL …

    chipx86chipx86

    You shouldn't need this. This was only for the graphs on the dashboard.

    chipx86chipx86

    So a word on indentation in templates. The content of the template, and the template language itself, are indented separately, …

    chipx86chipx86

    Need a {% trans %}.

    chipx86chipx86

    Things like border=1, style=, etc. don't belong. These should be defined solely in the CSS. It's not good to mix …

    chipx86chipx86

    No spaces inside a variable. {{check.name}} would be correct.

    chipx86chipx86

    This should be localized, and you can use ngettext (included in django.utils.translation) to do the pluralization. It's also ok to …

    daviddavid

    Two blank lines here.

    daviddavid

    Can you put quotes around the `*? Also, we've already explained why it's an issue in the desc text, so …

    daviddavid

    base_site.html already defines this block to be colM, so you shouldn't need this.

    daviddavid

    I don't think these are necessary, either.

    daviddavid

    This should include {{block.super}} as the first line of the block.

    daviddavid

    We shouldn't have any inline styles, only classes and IDs (all styles here should all be in the admin.less file). …

    daviddavid

    What is this here for?

    daviddavid
    AS
    david
    1. 
        
      1. Can you mark the issues below as fixed (if they are?)

    2. reviewboard/admin/security_checks.py (Diff revision 1)
       
       
      Show all issues

      Since these names are presented to the user, we should mark them for localization.

      Basically, at the top of this file, add this:

      from django.utils.translation import ugettext_lazy as _
      

      and then here:

      name = _("Executable Code Check")
      

      I think we may also want to think about a good user-visible name for this. Maybe Christian has a good idea?

    3. reviewboard/admin/security_checks.py (Diff revision 1)
       
       
      Show all issues

      This is a good start, but I think we'll want to have this go through a range of different file extensions (and file types), instead of just checking .php.

    4. reviewboard/admin/security_checks.py (Diff revision 1)
       
       
       
      Show all issues

      In order to be more consistent with python's unit test frameworks, can we capitalize this "setUp"?

      In unittest, the setUp and tearDown methods are called by the runner, not by the individual test function. We might want to do that here just to make it fit with prior expectations about this pattern.

    5. reviewboard/admin/security_checks.py (Diff revision 1)
       
       
      Show all issues

      And "tearDown" here.

    6. reviewboard/admin/security_checks.py (Diff revision 1)
       
       
       
      Show all issues

      This isn't catching any exceptions, and the open() call is leaking an open file.

      For the open file, you can use the file as a context manager:

      data = urllib2.urlopen(_get_url(self.directory) + to_download).read()
      with self.fss.open(to_download, 'r') as f:
          return data == f.read()
      

      That said, won't the value you get from fss.open(to_download).read() be the same as self.php_file?

    7. reviewboard/admin/security_checks.py (Diff revision 1)
       
       
      Show all issues

      Same thing here with localization. Perhaps call this one "Checking ALLOWED_HOSTS setting" ?

    8. reviewboard/admin/security_checks.py (Diff revision 1)
       
       
       
      Show all issues

      It's a little confusing to have "result" and "results" here. Can we name these better?

    9. reviewboard/admin/security_checks.py (Diff revision 1)
       
       
      Show all issues

      I think we're going to want a little bit more complexity in the results than just a true/false value.

      My instinct here would be to have one of three "results", either pass, fail, or error (if something went wrong during the check), and instructions (or a link to instructions) for how to fix it if it fails.

      We'll probably also want the individual checks to have a description field that can explain to the admin what's getting checked.

      1. I've changed it so that it's still pass/fail, but have added error information. The error information will contain why the test failed - whether it's due to a straight-up test-failure or because there was a problem in the actual test processing. I feel like it's a little cleaner than having the three values. What do you think? I can still change it if that's not ok.

    10. reviewboard/admin/security_checks.py (Diff revision 1)
       
       
       
       
       
       
       
       
       
       
      Show all issues

      While I think it would be nice to eventually use entry points for this, for now I think just using a statically defined dict is sufficient.

      Something like this would also let you get rid of the (un)register_security_check methods, too (which look unused):

      ```python
      _security_checks = {
      'test_check': TestSecurityCheck,
      'executable_check': ExecutableCodeCheck,
      'hosts_check': AllowedHostsCheck,
      }

    11. Show all issues

      This probably doesn't need (and shouldn't have) the admin-dashboard ID.

    12. reviewboard/templates/admin/security.html (Diff revision 1)
       
       
       
       
       
       
       
       
       
       
      Show all issues

      This stuff looks like it was copied from the admin dashboard and can be removed.

    13. reviewboard/templates/admin/security.html (Diff revision 1)
       
       
       
       
       
       
       
      Show all issues

      Please indent HTML with 1 space.

    14. Show all issues

      I don't think you intended to change this file. Please revert it.

    15. 
        
    AS
    AS
    david
    1. 
        
    2. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      No blank space here (both "django" and "djblets" are "third party" with respect to the review board codebase).

    3. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      Add an extra blank line here.

    4. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      Remove this blank line.

    5. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      Remove this blank line.

    6. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
       
       
       
      Show all issues

      This is pretty good but I'd like to change the first sentence a bit. How about:

      "A misconfiguration in the web server can cause files attached to review requests to be executed."

      I'd also change "The types of files being checked" to "The file types being checked".

    7. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      Can we add one additional piece of metadata here for instructions to fix it?

      For this check, we'd want the instructions to link to http://support.beanbaginc.com/support/solutions/articles/110173-securing-file-attachments

    8. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      This should probably be `settings.MEDIA_URL + 'uploaded/files/'

    9. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      We should skip saving, tearing down, and the actual tests in the case that the user is using s3 (or another) storage backend.

      I'd make setUp and tearDown no-ops if settings.DEFAULT_FILE_STORAGE != 'django.core.files.storage.FileSystemStorage' and have execute() just return success.

    10. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      This line looks too long (> 80 columns).

      There's also some changes I'd like to make to the string. Let's add translation, use the "six" library to convert to a text type (for python 2/3 compatibility) and use string formatting to include the exception:

      _('Uncaught exception during test: %s') % six.text_type(e)
      
    11. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      This should also use _() and string formatting instead of concatenation.

    12. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      Remove this blank line.

    13. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      Once again, we should include instructions for how to fix it (shown when the test fails).

      This one would say to edit the settings_local.py file in the site's conf directory and add a line like this with their site's URL:

      ALLOWED_HOSTS = ['example.com']

    14. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      This string should be marked for translation.

    15. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      This string, too.

    16. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      Remove this blank line.

    17. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
       
       
       
       
      Show all issues

      These lines are all indented 4 spaces too many.

    18. reviewboard/admin/security_checks.py (Diff revision 2)
       
       
      Show all issues

      Add an extra blank line here.

    19. 
        
    AS
    chipx86
    1. A handful of comments, but the good news is that they're almost entirely stylistic things.

      Can we see some screenshots showing success, failure, and a mix?

    2. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
      Show all issues

      Should be in alphabetical order (base before storage).

    3. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
       
      Show all issues

      Two blank lines.

    4. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
       
      Show all issues

      These should just default to None.

    5. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      The camelCase in unittest is a holdover from early days of Python. We shouldn't duplicate it here. Instead, just call this setup.

    6. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      And teardown.

    7. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      When you have to escape a single quote, it's best to just use double quotes for the string itself, to avoid the escape.

    8. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      Can we call this storage instead of fss? It's a more standard variable name for an instance of a Storage class.

    9. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      Would be better as file_checks.

    10. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
       
       
       
       
       
       
       
       
      Show all issues

      The strings should all be aligned.

    11. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      Can you break this into two lines, mimicking the newline?

    12. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
       
      Show all issues

      Parameters should be aligned.

    13. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      The %s will automatically cast to the string, so no need for six.text_type(e) here.

    14. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       

      Just to check for myself, this will fail on the first failed file, right?

      How hard would it be to still try every type, and present a list of failed file extensions? That'd prevent the admin from having to make a change, reload the web server, try the checks again, and repeating.

    15. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      No need for the outer parens here, as it's one line and the comma will ensure it'll be returned as a tuple.

    16. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      Same here.

    17. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
      Show all issues

      Parameters need to align.

    18. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      Not really worth talking about Django. "That Review Board will consider valid for this server" is probably fine.

    19. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
       
       
       
       
       
       
      Show all issues

      Make sure the strings align.

    20. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
       
      Show all issues

      Lots of escaping. Should just use double quotes to solve this.

    21. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
      Show all issues

      A quicker way would be:

      if '*' in settings.ALLOWED_HOSTS:
          result = False
          ...
      
    22. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      Might be worth expanding on this, stating how it'll respond to any host, and how that's unsafe.

    23. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      No need for these parens.

    24. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      Mind adding a docstring?

    25. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
      Show all issues

      Blank line between these.

    26. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      Typically, you'd want iteritems(), since it doesn't make a copy of the list of items.

      Python 3 renames this to items(), so we're now using this six module to provide abstraction.

      So, this should be:

      for name, cls in six.iteritems(checks):
      
    27. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
       
       
       
       
       
      Show all issues

      The }) should align with all_test_results

    28. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      Should add a trailing comma.

    29. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
       
      Show all issues

      Two blank lines between things on the top level.

    30. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      Global variables should be at the top of the file, after the imports. Two blank lines on either side.

    31. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
      Show all issues

      "Returns" instead of "Gets"

    32. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
       
      Show all issues

      All one line.

    33. reviewboard/admin/security_checks.py (Diff revision 3)
       
       
       
      Show all issues

      "site_domain_method" should only be indented 4 spaces from protocol =

    34. reviewboard/admin/urls.py (Diff revision 3)
       
       
      Show all issues

      The widget-* URLs are wrong. This regex should be:

      r'^security/$'
      

      The $ prevents security/adfsfsa from matching.

    35. reviewboard/admin/views.py (Diff revision 3)
       
       
      Show all issues

      This should be in alphabetical order, so before reviewboard.admin.supports.

    36. reviewboard/admin/views.py (Diff revision 3)
       
       
       
       
      Show all issues

      Two blank lines.

    37. reviewboard/admin/views.py (Diff revision 3)
       
       
      Show all issues

      Should remove this. It'll actually break some server configurations, as many WSGI implementations don't like random things going on stdout.

    38. reviewboard/admin/views.py (Diff revision 3)
       
       
       
       
      Show all issues

      The })) needs to align with return.

    39. Show all issues

      The URLs above based on views.dashboard are done for legacy reasons, but for this one, you should give the URL a name in the urls.py file by doing:

      url(r'^security/$', 'security', name='admin-security-checks')
      

      Then, here, you can do:

      {% url 'admin-security-checks' %}
      
    40. Show all issues

      You shouldn't need this. This was only for the graphs on the dashboard.

    41. reviewboard/templates/admin/security.html (Diff revision 3)
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
      Show all issues

      So a word on indentation in templates.

      The content of the template, and the template language itself, are indented separately, as there are times that they don't actually match up, and for some file types it would be flat-out wrong.

      So, template tags are indented like:

      {% block foo %}
      {%  if bar %}
      {%   for foobar in bar %}
      ...
      {%   endfor %}
      {%  endif %}
      {% endblock %}
      

      One space indentation within the template tag markup, relative to the parent template tag.

      HTML tags should be indented one space relative to their parent tag, and not to the template tag.

    42. Show all issues

      Need a {% trans %}.

    43. Show all issues

      Things like border=1, style=, etc. don't belong. These should be defined solely in the CSS. It's not good to mix presentation and content in HTML.

    44. Show all issues

      No spaces inside a variable. {{check.name}} would be correct.

    45. 
        
    AS
    1. 
        
    2. reviewboard/admin/security_checks.py (Diff revision 3)
       
       

      After discussion we determined it would be better to leave it in camelCase.

    3. reviewboard/admin/security_checks.py (Diff revision 3)
       
       

      Same as above.

    4. 
        
    AS
    david
    1. 
        
    2. reviewboard/admin/security_checks.py (Diff revision 4)
       
       
       
       
      Show all issues

      This should be localized, and you can use ngettext (included in django.utils.translation) to do the pluralization. It's also ok to use join on a single-element list, in which case it will just return the one element, regardless of joiner.

      I'd also like to tweak this text a bit.

      error_msg = (
          ngettext(
              'The web server incorrectly executed these file types: %s',
              'The web server incorrectly executed this file type: %s',
              len(failed_exts))
          % ', '.join(failed_exts))
      
    3. reviewboard/admin/security_checks.py (Diff revision 4)
       
       
      Show all issues

      Two blank lines here.

    4. reviewboard/admin/security_checks.py (Diff revision 4)
       
       
       
       
      Show all issues

      Can you put quotes around the `*?

      Also, we've already explained why it's an issue in the desc text, so this probably doesn't need to have the second sentence at all.

      1. Decided that we'll leave it as 'ALLOWED_HOSTS contains '*', which means that the server will respond to any host.'
        This is a little more descriptive about the error result specifically but is less redundant when considering the description.

    5. Show all issues

      base_site.html already defines this block to be colM, so you shouldn't need this.

    6. reviewboard/templates/admin/security.html (Diff revision 4)
       
       
       
      Show all issues

      I don't think these are necessary, either.

    7. reviewboard/templates/admin/security.html (Diff revision 4)
       
       
       
      Show all issues

      This should include {{block.super}} as the first line of the block.

    8. reviewboard/templates/admin/security.html (Diff revision 4)
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
      Show all issues

      We shouldn't have any inline styles, only classes and IDs (all styles here should all be in the admin.less file).

      Having the error message be a single-element <ul> is pretty weird. Can we just make it a text span?

      I'd also like to consider not doing this as a table with borders, but instead spacing it out with whitespace and headings. That said, changing the look is lower priority than the other fixes.

    9. Show all issues

      What is this here for?

    10. 
        
    AS
    david
    1. The code looks pretty good to me (aside from the CSS and layout changes, which we talked about). It looks like your review request description somehow got overwritten with a description of the changes in diff r4. Can you change the description on the review request to be a description of what the feature is and an overview of what code changes were done to implement it?

    2. 
        
    david
    1. I've gone through and updated the style and layout of the checklist page a bit to make it less boxy and more readable. I'll push this to master once 2.0 beta 2 is out.

      1. Actually, it'll be in beta 2. Woohoo!

    2. 
        
    AS
    Review request changed
    Status:
    Completed
    Change Summary:
    Pushed to master (807a2a3).