Skip to content

manage.py delete-user fails on a user with SeenMessage records #6616

@cfm

Description

@cfm

Description

If a user X has SeenMessage records—i.e., has logged in via the SecureDrop Client—X cannot be deleted via manage.py delete-user.

Steps to Reproduce

Discovered during #6597, but this is not a regression in v2.5.0.

On an instance with messages submitted:

  1. Application Server: Create a new user.
  2. Eyeball the number of SeenMessages recorded, e.g.: sudo -u www-data sqlite3 /var/lib/securedrop/db.sqlite3 "SELECT COUNT(*) FROM seen_messages"
  3. Workstation: Log in as user via the SecureDrop Client.
  4. Read one or more messages.
  5. Application Server: Repeat step (2) to confirm that new SeenMessages have been recorded.
  6. sudo -u www-data /var/www/securedrop/manage.py delete-user and enter user.

Expected Behavior

user is deleted.

Actual Behavior

Deletion fails:

sdadmin@app:~$ sudo -u www-data /var/www/securedrop/manage.py delete-user
Username to delete: cfm
Are you sure you want to delete user "cfm" (y/n)?y
Traceback (most recent call last):
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1243, in _execute_context
    self.dialect.do_execute(
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/engine/default.py", line 552, in do_execute
    cursor.execute(statement, parameters)
sqlite3.IntegrityError: NOT NULL constraint failed: seen_messages.journalist_id

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/var/www/securedrop/manage.py", line 276, in delete_user
    db.session.commit()
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/scoping.py", line 162, in do
    return getattr(self.registry(), name)(*args, **kwargs)
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 1026, in commit
    self.transaction.commit()
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 493, in commit
    self._prepare_impl()
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 472, in _prepare_impl
    self.session.flush()
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 2451, in flush
    self._flush(objects)
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 2589, in _flush
    transaction.rollback(_capture_exception=True)
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/util/langhelpers.py", line 68, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/util/compat.py", line 129, in reraise
    raise value
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 2549, in _flush
    flush_context.execute()
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/unitofwork.py", line 422, in execute
    rec.execute(self)
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/unitofwork.py", line 586, in execute
    persistence.save_obj(
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/persistence.py", line 230, in save_obj
    _emit_update_statements(
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/persistence.py", line 977, in _emit_update_statements
    c = cached_connections[connection].execute(
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 988, in execute
    return meth(self, multiparams, params)
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/sql/elements.py", line 287, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1101, in _execute_clauseelement
    ret = self._execute_context(
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1247, in _execute_context
    self._handle_dbapi_exception(
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1466, in _handle_dbapi_exception
    util.raise_from_cause(sqlalchemy_exception, exc_info)
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/util/compat.py", line 383, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=cause)
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/util/compat.py", line 128, in reraise
    raise value.with_traceback(tb)
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1243, in _execute_context
    self.dialect.do_execute(
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/engine/default.py", line 552, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed: seen_messages.journalist_id
[SQL: UPDATE seen_messages SET journalist_id=? WHERE seen_messages.id = ?]
[parameters: (None, 2645)]
(Background on this error at: http://sqlalche.me/e/gkpj)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/var/www/securedrop/manage.py", line 435, in <module>
    _run_from_commandline()
  File "/var/www/securedrop/manage.py", line 425, in _run_from_commandline
    rc = args.func(args)
  File "/var/www/securedrop/manage.py", line 283, in delete_user
    Journalist.query.filter_by(username=username).one()
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 3275, in one
    ret = self.one_or_none()
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 3244, in one_or_none
    ret = list(self)
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 3317, in __iter__
    return self._execute_and_instances(context)
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 3338, in _execute_and_instances
    conn = self._get_bind_args(
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 3353, in _get_bind_args
    return fn(
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 3332, in _connection_from_session
    conn = self.session.connection(**kw)
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 1120, in connection
    return self._connection_for_bind(
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 1128, in _connection_for_bind
    return self.transaction._connection_for_bind(
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 407, in _connection_for_bind
    self._assert_active()
  File "/opt/venvs/securedrop-app-code/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 288, in _assert_active
    raise sa_exc.InvalidRequestError(
sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlite3.IntegrityError) NOT NULL constraint failed: seen_messages.journalist_id
[SQL: UPDATE seen_messages SET journalist_id=? WHERE seen_messages.id = ?]
[parameters: (None, 2645)]
(Background on this error at: http://sqlalche.me/e/gkpj)

Comments

user can be deleted via the Admin Interface, but manage.py was not updated for #6225.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions