Hard delete applications, nest installer packages, detect PE versions
Soft delete left orphaned executables on disk and let a deleted name collide with a fresh import, so delete is now a hard delete that removes the associated files. The destructive paths (delete, revert-to-record) require a typed OK because neither can be undone. Installers keep their filename at import and nest per application/version, which stops repeat imports doubling up. Version now comes from the same PE detection the endpoints agent uses; when no version can be read the caller is asked for one rather than silently storing a blank. Applications also surface Version and a monitorable toggle, with launch path and process name required only while monitorable is ticked. Fleet shows the PC alias, matching PC Details.
This commit is contained in:
86
migrations/versions/7d45_purge_inactive_apps.py
Normal file
86
migrations/versions/7d45_purge_inactive_apps.py
Normal file
@@ -0,0 +1,86 @@
|
||||
"""Purge soft-deleted applications that still reserve their names.
|
||||
|
||||
Delete used to set isactive=False and leave the row in place. The uniqueness
|
||||
check on create looks at every row regardless of isactive, so each of those
|
||||
rows kept its name reserved permanently: creating an application with the same
|
||||
name failed with "already exists" against a row no screen would display, and
|
||||
nothing in the UI could clear it.
|
||||
|
||||
Delete is a hard delete now, but that only fixes rows deleted from here on.
|
||||
This clears the ones already stranded, in every environment rather than just
|
||||
the one where the bug was noticed.
|
||||
|
||||
Dependent rows are cleared the same way the API does it, and for the same
|
||||
reasons: appversions and computerinstalledapps are NOT NULL and meaningless
|
||||
without their application, while knowledgebase.appid is nullable and the
|
||||
article is somebody's writing, so it is unlinked rather than destroyed.
|
||||
|
||||
Uploaded installers belonging to these rows are deliberately NOT touched. A
|
||||
migration that deletes files cannot be rolled back and cannot be dry-run, and a
|
||||
stray file is harmless next to that risk. Deletes made through the API do clean
|
||||
them up.
|
||||
|
||||
Revision ID: 7d45_purge_inactive_apps
|
||||
Revises: 7d44_app_monitorable
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision = '7d45_purge_inactive_apps'
|
||||
down_revision = '7d44_app_monitorable'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def _table_exists(bind, name):
|
||||
"""True when a table is present.
|
||||
|
||||
The plugin tables are only there when the plugin is installed, so each is
|
||||
checked before being touched.
|
||||
"""
|
||||
return sa.inspect(bind).has_table(name)
|
||||
|
||||
|
||||
def upgrade():
|
||||
bind = op.get_bind()
|
||||
|
||||
if not _table_exists(bind, 'applications'):
|
||||
return
|
||||
|
||||
doomed = [row[0] for row in bind.execute(sa.text(
|
||||
'SELECT appid FROM applications WHERE isactive = false'
|
||||
))]
|
||||
|
||||
if not doomed:
|
||||
return
|
||||
|
||||
for appid in doomed:
|
||||
params = {'appid': appid}
|
||||
|
||||
if _table_exists(bind, 'knowledgebase'):
|
||||
bind.execute(sa.text(
|
||||
'UPDATE knowledgebase SET appid = NULL WHERE appid = :appid'
|
||||
), params)
|
||||
|
||||
if _table_exists(bind, 'computerinstalledapps'):
|
||||
bind.execute(sa.text(
|
||||
'DELETE FROM computerinstalledapps WHERE appid = :appid'
|
||||
), params)
|
||||
|
||||
if _table_exists(bind, 'appversions'):
|
||||
bind.execute(sa.text(
|
||||
'DELETE FROM appversions WHERE appid = :appid'
|
||||
), params)
|
||||
|
||||
bind.execute(sa.text(
|
||||
'DELETE FROM applications WHERE appid = :appid'
|
||||
), params)
|
||||
|
||||
|
||||
def downgrade():
|
||||
# The rows are gone and their contents were not captured, so there is
|
||||
# nothing to restore. Failing loudly is better than pretending otherwise.
|
||||
raise NotImplementedError(
|
||||
'Purged applications cannot be restored; recover from a backup.')
|
||||
Reference in New Issue
Block a user