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.
43 lines
1.5 KiB
Python
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')
|