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:
benjamin.baker
2026-09-07 15:04:21 -04:00
parent 79545db96e
commit 0134eaa219
17 changed files with 1600 additions and 148 deletions

View File

@@ -215,7 +215,8 @@ def list_endpoints():
query = (db.session.query(EndpointState, Computer.computerid,
Computer.computertypeid, ComputerType.computertype,
Asset.assetnumber, statusrank.label('statusrank'))
Asset.assetnumber, Asset.name,
statusrank.label('statusrank'))
.join(Asset, Asset.assetid == EndpointState.assetid)
.join(Computer, Computer.assetid == EndpointState.assetid)
.outerjoin(ComputerType,
@@ -227,7 +228,8 @@ def list_endpoints():
if search := (request.args.get('search') or '').strip():
like = f'%{search}%'
machinehits = _assetids_serving_machine_like(like)
clauses = [EndpointState.hostname.ilike(like), Asset.assetnumber.ilike(like)]
clauses = [EndpointState.hostname.ilike(like), Asset.assetnumber.ilike(like),
Asset.name.ilike(like)]
if machinehits:
clauses.append(EndpointState.assetid.in_(machinehits))
query = query.filter(db.or_(*clauses))
@@ -265,10 +267,14 @@ def list_endpoints():
health = _health_for_assets(states, computertypes)
data = []
for state, computerid, computertypeid, computertype, assetnumber, rank in items:
for (state, computerid, computertypeid, computertype, assetnumber, alias,
rank) in items:
row = state.to_dict()
row['computerid'] = computerid
row['assetnumber'] = assetnumber
# Named 'alias' rather than 'name' because the fleet row already
# carries a hostname; 'name' next to 'hostname' reads as a duplicate.
row['alias'] = alias
row['computertypeid'] = computertypeid
row['computertype'] = computertype
row['uptimedisplay'] = _format_uptime(state.uptimeseconds)