Files
shopdb-flask/migrations/versions/7d44_application_monitorable.py
benjamin.baker aa9dafc5ca Add application-driven policy generation with an acknowledgement gate
Ticking "Required on all PCs" now generates a configuration policy that
installs the application on every non-server endpoint it matches, rather
than only flagging a software-compliance report row.

Because that save is a fleet-wide deployment, it requires explicit
acknowledgement. The gate is enforced in the API, not only in the form:
a confirmation dialog that can be sidestepped by POSTing directly is
decoration, not a safeguard. It fires only on the transition INTO the
required state, since re-saving an already-required application deploys
nothing new.

Generated policies carry a new 'autoapp' source. They stay editable, and
hand-editing one transfers ownership to 'local' so it survives a later
uncheck; 'shipped' remains read-only. Existing required applications are
not migrated retroactively - policies are only created on save.

Also adds the monitorable fields that the shipped-policy breakup will
build on, and repairs a mangled non-ASCII byte in copilot-instructions.md
that was failing the style gate.
2026-09-07 13:27:59 -04:00

43 lines
1.5 KiB
Python

"""Add applications monitorable fields
Backs the "monitorable" checkbox on the Application form: an app that the
endpoint agent can watch as a process monitor. A monitor needs something to look
for (the Windows image name) and something to start when it is missing (the
launch path), so the API refuses to save ismonitorable without both.
The two text columns stay NULLABLE rather than carrying a constraint, because
every application row that existed before this migration has neither value and
must remain valid. The pairing rule is enforced in shopdb/core/api/applications.py
where it can return a useful message, not in the schema where it would only
produce an IntegrityError.
Revision ID: 7d44_app_monitorable
Revises: 7d43_userpermissions
Create Date: 2026-09-08
"""
from alembic import op
import sqlalchemy as sa
revision = '7d44_app_monitorable'
down_revision = '7d43_userpermissions'
branch_labels = None
depends_on = None
def upgrade():
op.add_column('applications', sa.Column(
'ismonitorable', sa.Boolean(), nullable=True, server_default=sa.false(),
comment='Can be watched by the endpoint agent (needs launch path + process name)'))
op.add_column('applications', sa.Column(
'monitorlaunchpath', sa.String(length=512), nullable=True))
op.add_column('applications', sa.Column(
'monitorprocessname', sa.String(length=255), nullable=True))
def downgrade():
op.drop_column('applications', 'monitorprocessname')
op.drop_column('applications', 'monitorlaunchpath')
op.drop_column('applications', 'ismonitorable')