Add GE-Enforce observed-state reporting: receipt + self-heal from PCs
PCs now report enforcement results back to shopdb, closing the desired-vs-observed loop. - POST /api/geenforce/report (geenforce.report service token): each cycle a PC posts the published version it applied, install/skip/fail/filtered counts, and per-entry outcomes. - Two tables: manifestenforcementreports (latest-per-host + history: applied version, enforcer version, counts, derived status ok/selfhealed/failed) and manifestenforcementresults (per entry: action installed/skipped/failed, selfhealed flag, exit code, warning/error message). - RECEIVED: reports carry the applied version; the admin view derives receivedlatest by comparing it to the scope's current published version, so the fleet view shows which PCs picked up an update. - SELF-HEAL: per-entry action captures drift correction (installed when it should already be present) vs skipped (already good) vs failed, with messages. - Admin reads: GET /reports (fleet compliance rollup) and GET /reports/<id> (per-entry detail). New geenforce.report permission. - Tables added to the (undeployed) 0001 baseline; geenforce.post_report is a service-token endpoint so it is exempt from the JWT authz sweep, like the collector blueprint. 8 reporting tests; full suite green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -173,6 +173,46 @@ def upgrade():
|
||||
sa.PrimaryKeyConstraint('payloadid'),
|
||||
)
|
||||
op.create_index('idx_payload_entry', 'manifestpayloads', ['entryid'])
|
||||
op.create_table(
|
||||
'manifestenforcementreports',
|
||||
sa.Column('reportid', sa.Integer(), nullable=False),
|
||||
sa.Column('hostname', sa.String(length=100), nullable=False),
|
||||
sa.Column('scopename', sa.String(length=64), nullable=False),
|
||||
sa.Column('phase', sa.String(length=16), nullable=False),
|
||||
sa.Column('appliedversion', sa.Integer(), nullable=True),
|
||||
sa.Column('enforcerversion', sa.String(length=20), nullable=True),
|
||||
sa.Column('installedcount', sa.Integer(), nullable=False),
|
||||
sa.Column('skippedcount', sa.Integer(), nullable=False),
|
||||
sa.Column('failedcount', sa.Integer(), nullable=False),
|
||||
sa.Column('filteredcount', sa.Integer(), nullable=False),
|
||||
sa.Column('status', sa.String(length=16), nullable=False),
|
||||
sa.Column('lastcheckin', sa.DateTime(), nullable=True),
|
||||
sa.Column('receivedat', sa.DateTime(), nullable=False),
|
||||
sa.Column('iscurrent', sa.Boolean(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('reportid'),
|
||||
)
|
||||
op.create_index('idx_report_host', 'manifestenforcementreports',
|
||||
['hostname'])
|
||||
op.create_index('idx_report_current', 'manifestenforcementreports',
|
||||
['iscurrent'])
|
||||
op.create_index('idx_report_host_scope', 'manifestenforcementreports',
|
||||
['hostname', 'scopename', 'phase'])
|
||||
op.create_table(
|
||||
'manifestenforcementresults',
|
||||
sa.Column('resultid', sa.Integer(), nullable=False),
|
||||
sa.Column('reportid', sa.Integer(), nullable=False),
|
||||
sa.Column('entryname', sa.String(length=128), nullable=False),
|
||||
sa.Column('action', sa.String(length=16), nullable=False),
|
||||
sa.Column('selfhealed', sa.Boolean(), nullable=False),
|
||||
sa.Column('exitcode', sa.Integer(), nullable=True),
|
||||
sa.Column('message', sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['reportid'],
|
||||
['manifestenforcementreports.reportid'],
|
||||
ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('resultid'),
|
||||
)
|
||||
op.create_index('idx_result_report', 'manifestenforcementresults',
|
||||
['reportid'])
|
||||
op.create_table(
|
||||
'pctypealiases',
|
||||
sa.Column('aliasid', sa.Integer(), nullable=False),
|
||||
@@ -187,6 +227,8 @@ def upgrade():
|
||||
|
||||
def downgrade():
|
||||
op.drop_table('pctypealiases')
|
||||
op.drop_table('manifestenforcementresults')
|
||||
op.drop_table('manifestenforcementreports')
|
||||
op.drop_table('manifestpayloads')
|
||||
op.drop_table('manifestpublishedversions')
|
||||
op.drop_table('manifestinusecheckprocesses')
|
||||
|
||||
Reference in New Issue
Block a user