diff --git a/molecule/testinfra/vars/staging.yml b/molecule/testinfra/vars/staging.yml
index c2bf91d776..fc98f372b4 100644
--- a/molecule/testinfra/vars/staging.yml
+++ b/molecule/testinfra/vars/staging.yml
@@ -146,6 +146,21 @@ log_events_without_ossec_alerts:
level: "0"
rule_id: "199996"
+ # OSSEC should not alert when "manage.py check-disconnected-{db,fs}-
+ # submissions" has logged that there are no disconnected submissions.
+ - name: test_no_disconnected_db_submissions_produces_alert
+ alert: >
+ ossec: output: 'cat /var/lib/securedrop/disconnected_db_submissions.txt':
+ No problems were found. All submissions' files are present.
+ level: "1"
+ rule_id: "400800"
+ - name: test_disconnected_fs_submissions_produces_alert
+ alert: >
+ ossec: output: 'cat /var/lib/securedrop/disconnected_fs_submissions.txt':
+ No unexpected files were found in the store.
+ level: "1"
+ rule_id: "400801"
+
# Log events we expect an OSSEC alert to occur for
log_events_with_ossec_alerts:
# Check that a denied RWX mmaping would produce an OSSEC alert
@@ -215,6 +230,24 @@ log_events_with_ossec_alerts:
level: "7"
rule_id: "400700"
+ # OSSEC should alert when "manage.py check-disconnected-{db,fs}-submissions"
+ # has logged that there are disconnected submissions.
+ - name: test_disconnected_db_submissions_produces_alert
+ alert: >
+ ossec: output: 'cat /var/lib/securedrop/disconnected_db_submissions.txt':
+ There are submissions in the database with no corresponding files. Run
+ "manage.py list-disconnected-db-submissions" for details.
+ level: "1"
+ rule_id: "400800"
+ - name: test_disconnected_fs_submissions_produces_alert
+ alert: >
+ ossec: output: 'cat /var/lib/securedrop/disconnected_fs_submissions.txt':
+ There are files in the submission area with no corresponding records in
+ the database. Run "manage.py list-disconnected-fs-submissions" for
+ details.
+ level: "1"
+ rule_id: "400801"
+
fpf_apt_repo_url: "https://apt-test.freedom.press"
daily_reboot_time: "4"
diff --git a/securedrop/debian/app-code/lib/systemd/system/securedrop-check-disconnected-db-submissions.service b/securedrop/debian/app-code/lib/systemd/system/securedrop-check-disconnected-db-submissions.service
new file mode 100644
index 0000000000..c341fb3e1a
--- /dev/null
+++ b/securedrop/debian/app-code/lib/systemd/system/securedrop-check-disconnected-db-submissions.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=job to check for disconnected submissions in the database
+
+[Service]
+ExecStart=/bin/bash -c "/var/www/securedrop/manage.py check-disconnected-db-submissions > /var/lib/securedrop/disconnected_db_submissions.txt"
+PrivateDevices=yes
+PrivateTmp=yes
+ProtectSystem=full
+ReadOnlyDirectories=/
+ReadWriteDirectories=/var/lib/securedrop
+User=www-data
+WorkingDirectory=/var/www/securedrop
diff --git a/securedrop/debian/app-code/lib/systemd/system/securedrop-check-disconnected-db-submissions.timer b/securedrop/debian/app-code/lib/systemd/system/securedrop-check-disconnected-db-submissions.timer
new file mode 100644
index 0000000000..f45c775a96
--- /dev/null
+++ b/securedrop/debian/app-code/lib/systemd/system/securedrop-check-disconnected-db-submissions.timer
@@ -0,0 +1,9 @@
+[Unit]
+Description=check for disconnected submissions in the database
+
+[Timer]
+# We want to run this 1 hour before reboot, or 23h after the last reboot
+OnBootSec=23h
+
+[Install]
+WantedBy=timers.target
diff --git a/securedrop/debian/app-code/lib/systemd/system/securedrop-check-disconnected-fs-submissions.service b/securedrop/debian/app-code/lib/systemd/system/securedrop-check-disconnected-fs-submissions.service
new file mode 100644
index 0000000000..c14e19ddb5
--- /dev/null
+++ b/securedrop/debian/app-code/lib/systemd/system/securedrop-check-disconnected-fs-submissions.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=job to check for disconnected submissions on the filesystem
+
+[Service]
+ExecStart=/bin/bash -c "/var/www/securedrop/manage.py check-disconnected-fs-submissions > /var/lib/securedrop/disconnected_fs_submissions.txt"
+PrivateDevices=yes
+PrivateTmp=yes
+ProtectSystem=full
+ReadOnlyDirectories=/
+ReadWriteDirectories=/var/lib/securedrop
+User=www-data
+WorkingDirectory=/var/www/securedrop
diff --git a/securedrop/debian/app-code/lib/systemd/system/securedrop-check-disconnected-fs-submissions.timer b/securedrop/debian/app-code/lib/systemd/system/securedrop-check-disconnected-fs-submissions.timer
new file mode 100644
index 0000000000..536589c67c
--- /dev/null
+++ b/securedrop/debian/app-code/lib/systemd/system/securedrop-check-disconnected-fs-submissions.timer
@@ -0,0 +1,9 @@
+[Unit]
+Description=check for disconnected submissions on the filesystem
+
+[Timer]
+# We want to run this 1 hour before reboot, or 23h after the last reboot
+OnBootSec=23h
+
+[Install]
+WantedBy=timers.target
diff --git a/securedrop/debian/ossec-agent/var/ossec/etc/ossec.conf b/securedrop/debian/ossec-agent/var/ossec/etc/ossec.conf
index 0ebc49e612..e67739fedf 100644
--- a/securedrop/debian/ossec-agent/var/ossec/etc/ossec.conf
+++ b/securedrop/debian/ossec-agent/var/ossec/etc/ossec.conf
@@ -52,6 +52,8 @@
/var/lib/securedrop/db.sqlite
/var/lib/securedrop/submissions_today.txt
+ /var/lib/securedrop/disconnected_db_submissions.txt
+ /var/lib/securedrop/disconnected_fs_submissions.txt
/var/lib/securedrop/shredder/tmp
@@ -128,13 +130,13 @@
command
- sudo -u www-data /opt/venvs/securedrop-app-code/bin/python3 /var/www/securedrop/manage.py check-disconnected-db-submissions
+ cat /var/lib/securedrop/disconnected_db_submissions.txt
90000
command
- sudo -u www-data /opt/venvs/securedrop-app-code/bin/python3 /var/www/securedrop/manage.py check-disconnected-fs-submissions
+ cat /var/lib/securedrop/disconnected_fs_submissions.txt
90000
diff --git a/securedrop/debian/ossec-server/var/ossec/rules/local_rules.xml b/securedrop/debian/ossec-server/var/ossec/rules/local_rules.xml
index 88a3c1c934..6f664ccccd 100644
--- a/securedrop/debian/ossec-server/var/ossec/rules/local_rules.xml
+++ b/securedrop/debian/ossec-server/var/ossec/rules/local_rules.xml
@@ -248,7 +248,7 @@
530
alert_by_email
- ossec: output: 'sudo -u www-data /opt/venvs/securedrop-app-code/bin/python3 /var/www/securedrop/manage.py check-disconnected-db-submissions'
+ ossec: output: 'cat /var/lib/securedrop/disconnected_db_submissions.txt'
There are submissions in the database with no corresponding files\.
Indicates that submissions in the database are missing their corresponding files.
@@ -256,7 +256,7 @@
530
alert_by_email
- ossec: output: 'sudo -u www-data /opt/venvs/securedrop-app-code/bin/python3 /var/www/securedrop/manage.py check-disconnected-fs-submissions'
+ ossec: output: 'cat /var/lib/securedrop/disconnected_fs_submissions.txt'
There are files in the submission area with no corresponding records in the database\.
Indicates that there are files in the submission area without corresponding submissions in the database.