Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes related to Debian packaging work #86

Merged
merged 9 commits into from
Nov 1, 2018
Merged

Conversation

kushaldas
Copy link
Contributor

Fixes #2 #30 #31.

Now we have securedrop-client script, which will execute the steps required to run the application following all standard default paths (from the Debian package).

We are trying to apply any alembic revision at the start of the tool, that way, when ever the user restarts the application, it will have the right database structure.

One can improve the ./run.sh in future. For now I kept it as simple as possible.

How to test?

  • ./run.sh to use the tool like previously and connect to the server using web API
  • Inside of qubes and a proxy vm, use ./run.sh -p to connect using the Proxy VM.

run.sh Outdated
@@ -16,14 +16,20 @@ while [ -n "$1" ]; do
done

SDC_HOME=${SDC_HOME:-$(mktemp -d)}
DB_HOME=$SDC_HOME/data
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic should be kept inside the app. There should only be a single injection of SDC_HOME, and the app should figure everything else out from there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helps to make sure that I am creating the directory structure properly, as I need that directory structure to create the DB file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this logic is inside the app. Doing it in two places runs the risk of us relying on something we shouldn't.

run.sh Outdated
from securedrop_client.models import Base, make_engine
Base.metadata.create_all(make_engine("$SDC_HOME"))
EOF
./createdb.py $DB_HOME
Copy link
Contributor

@heartsucker heartsucker Oct 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine to leave this as a here-doc since run.sh is a dev-only tool to help people with launching the app while iterating. Additionally, this doesn't solve the "bootstrap at first run" ticket.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bootstrapping in production is handled by the securedrop-client script.

@@ -16,6 +16,8 @@
# add your model's MetaData object here
# for 'autogenerate' support
sys.path.insert(0, path.realpath(path.join(path.dirname(__file__), '..')))
# This path is purely for alembic to work on the packaged application
sys.path.insert(1, "/opt/venvs/securedrop-client/lib/python3.5/site-packages")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary? Shouldn't we keep the alembic directory in a fix position relative to the app? The first path insertion should catch every case, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is how it can help in packaging. We need static config files to able to package them easily and without any dynamic magic at runtime.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't understand. What is the exact case that you're describing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first path is for the development environment, and the second path is for the case where we are running using Debian package. The alembic directory is installed in the standard /usr/share/securedrop-workstation/ location.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't the alembic directory placed somewhere relative to the source code? Wouldn't that be simpler?


[alembic]
# path to migration scripts
script_location = /usr/share/securedrop-client/alembic
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're going to be running alembic, we shouldn't be using a hard coded value you like this. We should use a template and a %%ALEMBIC_PATH%% or something similar to replace the values in a pre-alembic step.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to help the Debian packaging. All packaged applications (as far as I know) in Fedora land also uses the same idea.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but the alembic.ini is useless without this line

sqlalchemy.url = sqlite:////path/to/database.sqlite

The app at boot could pull an alembic.ini.tmpl from /var/lib/ or /usr/share and then inject that value before running alembic upgrade head.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

files/client.ini Outdated
@@ -0,0 +1,3 @@
[client]
homedir=~/.securedrop_client
use_securedrop_proxy=True
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: missing newline at EOF

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, will add this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will wait for all the other issues to be discussed and resolved, I will fix at the very end :)

@@ -104,6 +105,9 @@ def arg_parser() -> ArgumentParser:
type=expand_to_absolute,
help=('SecureDrop Client home directory for storing files and state. '
'(Default {})'.format(DEFAULT_SDC_HOME)))
parser.add_argument(
'-p', '--proxy', action='store_true',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm somewhat not a fan of using single letters for boolean values because of the chances for confusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can remove that.

@@ -120,6 +124,7 @@ def start_app(args, qt_args) -> None:
- configure the client (logic) object.
- ensure the application is setup in the default safe starting state.
"""
print(args.proxy)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you left a debug print here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, will be removed.

@@ -150,7 +156,14 @@ def start_app(args, qt_args) -> None:


def run() -> None:
config_file = "/etc/securdrop-client/client.ini"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not be configuring from /etc. Configs should be at the root of sdc_home.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should configure with /etc/ as that will be useful to update through the Debian package. The package will be installed at the template, and we should have the default values already in the config for the same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused on the goals then. Is the securedrop-client so hyper targeted toward Qubes that we aren't going to work in having it operate anywhere else ever? Or should we use some patterns that allow us to be able to run it in other linux-y environments? Because what I don't like about SecureDrop core is that the Debian packages are useless without running ansible first. IMO configuration should be entirely outside the Debian side and use defaults in the Python code to handle the no-config cases.

os.path.exists(config_file): # pragma: no cover
config = configparser.ConfigParser()
config.read(config_file)
args.sdc_home = config["client"]["homedir"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you overriding the sdc_home after reading a config from sdc_home?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am reading the config from /etc/securdrop-client/client.ini file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I still think this make no sense. The client is passed a sdc_home, then we read another value, then we sed that other value to sdc_home. I feel like this isn't a good pattern and is kind confusing.

config = configparser.ConfigParser()
config.read(config_file)
args.sdc_home = config["client"]["homedir"]
args.proxy = config["client"]["use_securedrop_proxy"]
# reinsert the program's name
qt_args.insert(0, 'securedrop-client')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More generally, I think that the CLI parsing should all happen outside the app, and then we pass those as args to start_app (or run_app, whatever the name was). In side there, we handle the logic of how to include values from the configs. I think reusing the Namespace from argparse as the "master config" seems wrong. We might want to have a Config class that does all this logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am going to leave this for a future PR.

@kushaldas kushaldas force-pushed the packaging_db_config branch from a9c9e5c to 1dd9570 Compare October 30, 2018 15:09
@kushaldas kushaldas mentioned this pull request Oct 30, 2018
@kushaldas
Copy link
Contributor Author

Notes from the video call with @heartsucker .

@heartsucker's point of view

Having any configuration file under /etc/ means dpkg will try to merge it in case of updates, and there is a chance of failure. That is why he suggested to keep configuration files outside of /etc/.
He is also okay to have a sane default application where it will think that it is running under Qubes with all default values and will not require any configuration file.

@kushaldas's point of view

I thought (as a packager) that any configuration should be under /etc/, that way the system package management tool will take care of it. I am also totally okay with a sane default application which will just work thinking that it is running inside of Qubes.

Another option is to keep alembic.ini or any other such configuration file under /usr/share/securdrop-client/ directory and the tools to keep using those paths as default values. The + point in this is that the application will always use the version of config file which came with the Debianpackage.

run.sh Outdated
mkdir -p $LOGS_HOME
chmod 0700 $SDC_HOME
chmod 0700 $DB_HOME
chmod 0700 $LOGS_HOME
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again isn't this also done in the app itself?

Copy link
Contributor Author

@kushaldas kushaldas Oct 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we want to have the db file as ~/.securedrop_client/data, if we have it under ~/.securedrop_client/ then I can remove these lines (keeping the lines only for $SDC_HOME). As the database must come up (using Alembic) before the application starts.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, we gotta create the database before starting the application - but see my comment here, we can at least delegate these folder creation to the application (the less logic we have duplicated the better)

@@ -85,7 +85,8 @@ class Client(QObject):

finish_api_call = pyqtSignal() # Acknowledges reciept of an API call.

def __init__(self, hostname, gui, session, home: str) -> None:
def __init__(self, hostname, gui, session,
home: str, proxy: bool = False) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

proxy should be True if the default application is Qubes first

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay.

# are written from script.py.mako
# output_encoding = utf-8

sqlalchemy.url = sqlite:////home/user/.securedrop_client/data/svs.sqlite
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note right now the db path is:

/home/user/.securedrop_client/svs.sqlite

(which I think is actually good as the data directory contains only downloaded messages / files)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I misread this line

~/.securedrop_client/data -> config, database, files (submissions, messages)

#2 (comment)

So, I will modify to change the path.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry that's my bad :-(

@kushaldas kushaldas force-pushed the packaging_db_config branch from e2d3aca to 187c5be Compare October 31, 2018 06:23
@kushaldas
Copy link
Contributor Author

Updates config locations and making proxy default for Client

Now we have all the configurations under
/usr/share/securedrop-client/ including the alembic.ini file.

The database file is now located at ~/securedrop_client/

Based on the PR review comments from @heartsucker @redshiftzero

Copy link
Contributor

@redshiftzero redshiftzero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was able to successfully build a deb package on this, thanks for this @kushaldas and for making the changes!

I will flag that in the coming weeks we do need to invest some time into build automation, as building deb packages manually like I just did is a bit tedious and error-prone

anyway, for now I think we should continue onwards - @heartsucker - even if you have no blocking issues here can you file followups for anything else that you think should be addressed/discussed packaging wise for beta? (reason is that beta is when this will get installed in news orgs so we really need to have anything that impacts the long term maintenance plan nailed down - if all goes well we'll be supporting those beta installations for maybe years)

@heartsucker
Copy link
Contributor

Just got off a call with Jen were were talked about this PR. Here's my issues.

  • the alembic migrations should be in a fixed relative path to the source code
  • no configs, even defaults should be shipped with the packages
    • however, templates could/should be shipped
  • configs (config.json or alembic.ini) need to be in the sdc_home directory

The only config that would need to be shipped with the package so far is the alembic.ini, and this can be rendered to the sdc_home. We already do somthing like that here, and we could probably just copy the code completely.

To auto-handle configs and load a local config if present, we should probably have a Config class that does the default handling / Qubes detection. This should be injected into the app / logic / controller and passed around that way. Def do not want a global reference (because testing).

If we have a "master" config in /var/lib or /usr/share or where ever*, then we have configs and data in many places, and IMO this should all be in sdc_home. It also raises the problem that we are foreced to always use the known home /root/.securedrop-client because alembic will have to have a hardcoded value in it's alembic.ini. If we want to be able to debug / test on a workstation or just keep with the the current pattern of configuration and isolation, then we need to have a per-sdc_home config.

* please not /etc/ because these "configs" are actually hardcoded and shouldn't be edited by a user, and they need to be updated by dpkg without intervention

Last, I don't want to have to rely on ansible or salt to manage configs. I know we've kinda discussed "config-less", and I really think that that also means not needing ops tools to get it to work. I don't want to have us end up how we have in SecureDrop core where a whole bunch of would-be-nice changes are blocked by not wanting to make an admin run the ops tools to push out the changes we need.

Addressing Jen's concern, there should be a Makefile target called debian that Just Works, and this should be part of CI.

@heartsucker
Copy link
Contributor

heartsucker commented Nov 1, 2018

One thing. Can you remove the fixes #31 line, because this doesn't call alembic upgrade head anywhere, so we're not actually bootstrapping the DB. That ticket needs to stay open.

edit: Just kidding, ignore this.

@@ -0,0 +1,3 @@
[client]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use .json as the config type because it allows for deeper nesting, lists, and also ops tools have nice functions for mangling/merging JSON?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we stick with ini for simplicity for now?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

os.path.exists(config_file): # pragma: no cover
config = configparser.ConfigParser()
config.read(config_file)
args.sdc_home = config["client"]["homedir"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I still think this make no sense. The client is passed a sdc_home, then we read another value, then we sed that other value to sdc_home. I feel like this isn't a good pattern and is kind confusing.

os.path.exists(config_file): # pragma: no cover
config = configparser.ConfigParser()
config.read(config_file)
args.sdc_home = config["client"]["homedir"]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done to make sure that we use the whatever values are there in the config file. This part is to be used only after installing via debian package, and we can improve this in future.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a hardcoded home directory in Qubes, so we're using that hard coded value to read a hardcoded config to then switch the home to something else hardcoded. This seems like a lot of indirection.

@heartsucker heartsucker dismissed their stale review November 1, 2018 18:44

Dismissing review to unblock. I'm generally fine with this, for the alpha, but there's things I still think should be changed.

import sys

from securedrop_client.models import Base, make_engine
Base.metadata.create_all(make_engine(sys.argv[1]))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the comment got lost, but I still think this is better as a here-doc since it's just for the dev env and it's simple enough to just shove into the bash script.

We need these config files for the Debian packaging.
The securedrop-client script will make sure that we have the right
database structure, or will apply the migration as required.

We will need a future PR to fix ./run.sh to work with the changes
related to Debian packaging.
We are now using the similar directory structure in run.sh
and also in securdrop-client. We are also using the createdb.py
to create the db in the local environment.
Use ./run.sh --proxy to connect to the proxy vm.
Now we have all the configurations under
/usr/share/securedrop-client/ including the alembic.ini file.

The database file is now located at ~/securedrop_client/

Based on the PR review comments.
@redshiftzero
Copy link
Contributor

hey @heartsucker, I've filed #97 and added it to the beta milestone so we can continue this discussion there, and please feel free to open other issues as followups to this. For now, merging so that we resolve the must-do issues for alpha

@redshiftzero redshiftzero merged commit 2b2f6fc into master Nov 1, 2018
@redshiftzero redshiftzero deleted the packaging_db_config branch November 1, 2018 21:52
legoktm pushed a commit that referenced this pull request Dec 11, 2023
Add link to Code of Conduct to README
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants