prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Restoring tarball to Focal shows error for v2
  ## Description
  
  When restoring a v2-only Xenial backup tarball to a v3-only Focal instance, the restore action fails. It fails even if the admin explicitly requests that the tor config be preserved as-is. 
  
  ## Steps to Reproduce
  I used libvirt-based VMs for testing, and performed all admin actions from a virtualized Tails v4.16 VM.
  
  1. Create a v2-only backup tarball from a Xenial host.
  2. Perform a clean install of Focal, with v3-only vars.
  3. Attempt to restore the backup: `./securedrop-admin --force restore --preserve-tor-config ~/Persistent/backups/xenial-v2-only/sd-backup-2021-02-26--15-57-06.tar.gz`
  
  ## Expected Behavior
  
  Restore action completes, old URLs are restored, and I can proceed with regenerating new v3 URL and finalizing the Xenial -> Focal migration. 
  
  
  ## Actual Behavior
  
  Restore action fails. Even when I include the `--preserve-tor-config` flag, it still fails. 
  
  ## Comments
  On one hand, the failure is expected, since Focal is v3-only, but in the context of a migration from Xenial, it's likely we're going to have admins migrating to Focal from a recently created backup, so I recommend we defer the fail-closed behavior to a subsequent release. That'd have bearing on WIP docs changes in e..g. https://github.com/freedomofpress/securedrop-docs/pull/133
  
  The above is a policy question, but this ticket is also pointing out some bugs that should be fixed. For one, `--preserve-tor-config` is not honored, and it should be.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `install_files/ansible-base/roles/restore/files/compare_torrc.py`
  Content:
  ```
  1 #!/usr/bin/env python
  2 
  3 #
  4 # Compares Tor configurations on the app server and from a backup. If
  5 # restoring the backup would alter the server's Tor configuration,
  6 # print a warning and exit.
  7 #
  8 
  9 from __future__ import print_function
  10 
  11 import os
  12 import re
  13 import sys
  14 
  15 
  16 def get_tor_versions(path):
  17     """
  18     Determine which service versions are offered in the given torrc.
  19     """
  20     service_re = re.compile(r"HiddenServiceDir\s+(?:.*)/(.*)")
  21     versions = set([])
  22     with open(path) as f:
  23         for line in f:
  24             m = service_re.match(line)
  25             if m:
  26                 service = m.group(1)
  27                 if "v3" in service:
  28                     versions.add(3)
  29                 else:
  30                     versions.add(2)
  31 
  32     return versions
  33 
  34 
  35 def strset(s):
  36     """
  37     Sort the given set and join members with "and".
  38     """
  39     return " and ".join(str(v) for v in sorted(s))
  40 
  41 
  42 if __name__ == "__main__":
  43     tempdir = sys.argv[1]
  44 
  45     server_versions = get_tor_versions(os.path.join(tempdir, "app/etc/tor/torrc"))
  46     backup_versions = get_tor_versions(os.path.join(tempdir, "backup/etc/tor/torrc"))
  47 
  48     if server_versions == backup_versions:
  49         print("The Tor configuration in the backup matches the server.")
  50         sys.exit(0)
  51 
  52     if (3 in server_versions) and (3 in backup_versions):
  53         print("V3 services detected in backup and server - proceeding with v3-only restore")
  54         sys.exit(0)
  55 
  56     print(
  57         "The Tor configuration on the app server offers version {} services.".format(
  58             strset(server_versions)
  59         )
  60     )
  61 
  62     print(
  63         "The Tor configuration in this backup offers version {} services.".format(
  64             strset(backup_versions)
  65         )
  66     )
  67 
  68     print("\nRestoring a backup with a different Tor configuration than the server ")
  69     print("is currently unsupported. If you require technical assistance, please ")
  70     print("contact the SecureDrop team via the support portal or at ")
  71     print("securedrop@freedom.press.")
  72 
  73     sys.exit(1)
  74
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/install_files/ansible-base/roles/restore/files/compare_torrc.py b/install_files/ansible-base/roles/restore/files/compare_torrc.py
  --- a/install_files/ansible-base/roles/restore/files/compare_torrc.py
  +++ b/install_files/ansible-base/roles/restore/files/compare_torrc.py
  @@ -46,11 +46,11 @@
       backup_versions = get_tor_versions(os.path.join(tempdir, "backup/etc/tor/torrc"))
   
       if server_versions == backup_versions:
  -        print("The Tor configuration in the backup matches the server.")
  +        print("Valid configuration: the Tor configuration in the backup matches the server.")
           sys.exit(0)
   
       if (3 in server_versions) and (3 in backup_versions):
  -        print("V3 services detected in backup and server - proceeding with v3-only restore")
  +        print("Valid configuration: V3 services only`")
           sys.exit(0)
   
       print(
  @@ -65,9 +65,11 @@
           )
       )
   
  -    print("\nRestoring a backup with a different Tor configuration than the server ")
  -    print("is currently unsupported. If you require technical assistance, please ")
  -    print("contact the SecureDrop team via the support portal or at ")
  +    print("\nIncompatible configuration: Restoring a backup including a different ")
  +    print("Tor configuration than the server Tor configuration is unsupported. ")
  +    print("Optionally, use --preserve-tor-config to apply a data-only backup.")
  +    print("If you require technical assistance, please contact the ")
  +    print("SecureDrop team via the support portal or at ")
       print("securedrop@freedom.press.")
   
       sys.exit(1)
  
verification_info: {"golden_diff": "diff --git a/install_files/ansible-base/roles/restore/files/compare_torrc.py b/install_files/ansible-base/roles/restore/files/compare_torrc.py\n--- a/install_files/ansible-base/roles/restore/files/compare_torrc.py\n+++ b/install_files/ansible-base/roles/restore/files/compare_torrc.py\n@@ -46,11 +46,11 @@\n     backup_versions = get_tor_versions(os.path.join(tempdir, \"backup/etc/tor/torrc\"))\n \n     if server_versions == backup_versions:\n-        print(\"The Tor configuration in the backup matches the server.\")\n+        print(\"Valid configuration: the Tor configuration in the backup matches the server.\")\n         sys.exit(0)\n \n     if (3 in server_versions) and (3 in backup_versions):\n-        print(\"V3 services detected in backup and server - proceeding with v3-only restore\")\n+        print(\"Valid configuration: V3 services only`\")\n         sys.exit(0)\n \n     print(\n@@ -65,9 +65,11 @@\n         )\n     )\n \n-    print(\"\\nRestoring a backup with a different Tor configuration than the server \")\n-    print(\"is currently unsupported. If you require technical assistance, please \")\n-    print(\"contact the SecureDrop team via the support portal or at \")\n+    print(\"\\nIncompatible configuration: Restoring a backup including a different \")\n+    print(\"Tor configuration than the server Tor configuration is unsupported. \")\n+    print(\"Optionally, use --preserve-tor-config to apply a data-only backup.\")\n+    print(\"If you require technical assistance, please contact the \")\n+    print(\"SecureDrop team via the support portal or at \")\n     print(\"securedrop@freedom.press.\")\n \n     sys.exit(1)\n", "issue": "Restoring tarball to Focal shows error for v2\n## Description\r\n\r\nWhen restoring a v2-only Xenial backup tarball to a v3-only Focal instance, the restore action fails. It fails even if the admin explicitly requests that the tor config be preserved as-is. \r\n\r\n## Steps to Reproduce\r\nI used libvirt-based VMs for testing, and performed all admin actions from a virtualized Tails v4.16 VM.\r\n\r\n1. Create a v2-only backup tarball from a Xenial host.\r\n2. Perform a clean install of Focal, with v3-only vars.\r\n3. Attempt to restore the backup: `./securedrop-admin --force restore --preserve-tor-config ~/Persistent/backups/xenial-v2-only/sd-backup-2021-02-26--15-57-06.tar.gz`\r\n\r\n## Expected Behavior\r\n\r\nRestore action completes, old URLs are restored, and I can proceed with regenerating new v3 URL and finalizing the Xenial -> Focal migration. \r\n\r\n\r\n## Actual Behavior\r\n\r\nRestore action fails. Even when I include the `--preserve-tor-config` flag, it still fails. \r\n\r\n## Comments\r\nOn one hand, the failure is expected, since Focal is v3-only, but in the context of a migration from Xenial, it's likely we're going to have admins migrating to Focal from a recently created backup, so I recommend we defer the fail-closed behavior to a subsequent release. That'd have bearing on WIP docs changes in e..g. https://github.com/freedomofpress/securedrop-docs/pull/133\r\n\r\nThe above is a policy question, but this ticket is also pointing out some bugs that should be fixed. For one, `--preserve-tor-config` is not honored, and it should be.\r\n\n", "before_files": [{"content": "#!/usr/bin/env python\n\n#\n# Compares Tor configurations on the app server and from a backup. If\n# restoring the backup would alter the server's Tor configuration,\n# print a warning and exit.\n#\n\nfrom __future__ import print_function\n\nimport os\nimport re\nimport sys\n\n\ndef get_tor_versions(path):\n    \"\"\"\n    Determine which service versions are offered in the given torrc.\n    \"\"\"\n    service_re = re.compile(r\"HiddenServiceDir\\s+(?:.*)/(.*)\")\n    versions = set([])\n    with open(path) as f:\n        for line in f:\n            m = service_re.match(line)\n            if m:\n                service = m.group(1)\n                if \"v3\" in service:\n                    versions.add(3)\n                else:\n                    versions.add(2)\n\n    return versions\n\n\ndef strset(s):\n    \"\"\"\n    Sort the given set and join members with \"and\".\n    \"\"\"\n    return \" and \".join(str(v) for v in sorted(s))\n\n\nif __name__ == \"__main__\":\n    tempdir = sys.argv[1]\n\n    server_versions = get_tor_versions(os.path.join(tempdir, \"app/etc/tor/torrc\"))\n    backup_versions = get_tor_versions(os.path.join(tempdir, \"backup/etc/tor/torrc\"))\n\n    if server_versions == backup_versions:\n        print(\"The Tor configuration in the backup matches the server.\")\n        sys.exit(0)\n\n    if (3 in server_versions) and (3 in backup_versions):\n        print(\"V3 services detected in backup and server - proceeding with v3-only restore\")\n        sys.exit(0)\n\n    print(\n        \"The Tor configuration on the app server offers version {} services.\".format(\n            strset(server_versions)\n        )\n    )\n\n    print(\n        \"The Tor configuration in this backup offers version {} services.\".format(\n            strset(backup_versions)\n        )\n    )\n\n    print(\"\\nRestoring a backup with a different Tor configuration than the server \")\n    print(\"is currently unsupported. If you require technical assistance, please \")\n    print(\"contact the SecureDrop team via the support portal or at \")\n    print(\"securedrop@freedom.press.\")\n\n    sys.exit(1)\n", "path": "install_files/ansible-base/roles/restore/files/compare_torrc.py"}], "after_files": [{"content": "#!/usr/bin/env python\n\n#\n# Compares Tor configurations on the app server and from a backup. If\n# restoring the backup would alter the server's Tor configuration,\n# print a warning and exit.\n#\n\nfrom __future__ import print_function\n\nimport os\nimport re\nimport sys\n\n\ndef get_tor_versions(path):\n    \"\"\"\n    Determine which service versions are offered in the given torrc.\n    \"\"\"\n    service_re = re.compile(r\"HiddenServiceDir\\s+(?:.*)/(.*)\")\n    versions = set([])\n    with open(path) as f:\n        for line in f:\n            m = service_re.match(line)\n            if m:\n                service = m.group(1)\n                if \"v3\" in service:\n                    versions.add(3)\n                else:\n                    versions.add(2)\n\n    return versions\n\n\ndef strset(s):\n    \"\"\"\n    Sort the given set and join members with \"and\".\n    \"\"\"\n    return \" and \".join(str(v) for v in sorted(s))\n\n\nif __name__ == \"__main__\":\n    tempdir = sys.argv[1]\n\n    server_versions = get_tor_versions(os.path.join(tempdir, \"app/etc/tor/torrc\"))\n    backup_versions = get_tor_versions(os.path.join(tempdir, \"backup/etc/tor/torrc\"))\n\n    if server_versions == backup_versions:\n        print(\"Valid configuration: the Tor configuration in the backup matches the server.\")\n        sys.exit(0)\n\n    if (3 in server_versions) and (3 in backup_versions):\n        print(\"Valid configuration: V3 services only`\")\n        sys.exit(0)\n\n    print(\n        \"The Tor configuration on the app server offers version {} services.\".format(\n            strset(server_versions)\n        )\n    )\n\n    print(\n        \"The Tor configuration in this backup offers version {} services.\".format(\n            strset(backup_versions)\n        )\n    )\n\n    print(\"\\nIncompatible configuration: Restoring a backup including a different \")\n    print(\"Tor configuration than the server Tor configuration is unsupported. \")\n    print(\"Optionally, use --preserve-tor-config to apply a data-only backup.\")\n    print(\"If you require technical assistance, please contact the \")\n    print(\"SecureDrop team via the support portal or at \")\n    print(\"securedrop@freedom.press.\")\n\n    sys.exit(1)\n", "path": "install_files/ansible-base/roles/restore/files/compare_torrc.py"}]}