Back out app auto-seeding; fix report-status + PCTypesStrict bugs (manifest review)
A deep Fable review of the real manifest corpus (READ-ONLY reference) showed the manifests are an ENFORCEMENT PROGRAM, not an application inventory, and that auto-seeding the Applications catalog from entry Type + Name was wrong: - The catalog ALREADY tracks these apps from the classic-shopdb migration, with version histories (PC - DMIS, UDC x11 versions, eMX / eDNC, CLM, CSF, Oracle Database, FormTracePak). Seeding from manifest labels created DUPLICATES under different names (PC-DMIS 2016 vs PC - DMIS; eDNC (bundles NTLARS) vs eMX / eDNC; OpenText HostExplorer ShopFloor vs CSF). It also misclassified config drops (eMxInfo.txt) as apps and could never match a PC's reported ARP name. So the seed-applications command + service are removed. Properly linking manifest entries to the EXISTING catalog is a curated feature, not label-scraping. Two REAL bugs the review found are fixed and kept: - Report status (R4): every healthy cycle runs Always/no-detection scripts the engine counts as "installed", so keying self-heal off installed>0 marked the common scope selfhealed forever and made 'ok' unreachable. Status now derives from explicit per-entry self-heal flags only; the stored flag no longer infers from action=='installed'; the client kit doc reflects it. - PCTypesStrict (R5): the runtime engine has no strict handling (preinstall runner only). filters.matches_pctype now applies strict only when phase == 'preinstall'; simulate + parity thread the scope phase through; the strict test uses a preinstall scope. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -155,8 +155,13 @@ def test_duplicate_entry_name_is_400_not_500(client, db, auth_headers):
|
||||
|
||||
def test_simulate_pctypesstrict_disables_alias(client, db, auth_headers):
|
||||
"""A collections-only strict entry must NOT match a nocollections PC via the
|
||||
shared Standard alias group (mirrors the preinstall UDC entry)."""
|
||||
scopeid = _create_scope(client, auth_headers, 'preinstall')
|
||||
shared Standard alias group. PCTypesStrict is preinstall-only, so the scope
|
||||
must be the preinstall phase (the runtime engine ignores strict)."""
|
||||
resp = client.post('/api/geenforce/scopes',
|
||||
json={'scopename': 'preinstall', 'phase': 'preinstall'},
|
||||
headers=auth_headers)
|
||||
assert resp.status_code == 201, resp.get_json()
|
||||
scopeid = resp.get_json()['data']['scopeid']
|
||||
_add_entry(client, auth_headers, scopeid,
|
||||
{'Name': 'UDC (strict)', 'Type': 'EXE', 'Installer': 'apps/udc.exe',
|
||||
'PCTypes': ['gea-shopfloor-collections'], 'PCTypesStrict': True})
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
"""GE-Enforce seeds the core Applications catalog from what the manifests install.
|
||||
|
||||
Only installer entries (MSI/EXE/CMD/BAT) become Applications; File/Registry/PS1/
|
||||
INF config entries do not. Idempotent + deduped by appname.
|
||||
"""
|
||||
|
||||
from plugins.geenforce import service
|
||||
from shopdb.core.models import Application
|
||||
|
||||
|
||||
MANIFEST = {
|
||||
'Version': '2.6',
|
||||
'Applications': [
|
||||
{'Name': 'eDNC', 'Type': 'MSI', 'Installer': 'apps/edns.msi',
|
||||
'_comment': 'eDNC (Universal Data Collection). Bundles NTLARS.'},
|
||||
{'Name': 'UDC', 'Type': 'EXE', 'Installer': 'apps/udc.exe'},
|
||||
{'Name': 'Config drop', 'Type': 'File', 'Source': 'configs/x.json',
|
||||
'Destination': 'C:\\x.json'},
|
||||
{'Name': 'Firewall rule', 'Type': 'PS1', 'Script': 'scripts/fw.ps1'},
|
||||
{'Name': 'FMS host pin', 'Type': 'Registry', 'RegPath': 'HKLM:\\x',
|
||||
'RegName': 'y', 'RegValue': 1, 'RegType': 'DWord'},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def test_seed_only_installer_apps(db):
|
||||
result = service.seed_applications_from_manifests(
|
||||
[('gea-shopfloor-collections', 'runtime', MANIFEST)])
|
||||
service.db.session.commit()
|
||||
assert set(result['created']) == {'eDNC', 'UDC'}
|
||||
names = {a.appname for a in Application.query.all()}
|
||||
assert 'eDNC' in names and 'UDC' in names
|
||||
# config / script / registry entries are not applications
|
||||
assert 'Config drop' not in names
|
||||
assert 'Firewall rule' not in names
|
||||
assert 'FMS host pin' not in names
|
||||
edns = Application.query.filter_by(appname='eDNC').first()
|
||||
assert edns.isinstallable is True
|
||||
assert edns.installpath == 'apps/edns.msi'
|
||||
assert edns.appdescription.startswith('eDNC (Universal Data Collection)')
|
||||
|
||||
|
||||
def test_seed_is_idempotent_and_deduped(db):
|
||||
manifests = [('a', 'runtime', MANIFEST), ('b', 'runtime', MANIFEST)]
|
||||
first = service.seed_applications_from_manifests(manifests)
|
||||
service.db.session.commit()
|
||||
# deduped across the two manifests: 2 created, not 4
|
||||
assert len(first['created']) == 2
|
||||
# re-run: nothing new, both already tracked
|
||||
second = service.seed_applications_from_manifests(manifests)
|
||||
service.db.session.commit()
|
||||
assert second['created'] == []
|
||||
assert set(second['existing']) == {'eDNC', 'UDC'}
|
||||
assert Application.query.filter(Application.appname.in_(['eDNC', 'UDC'])).count() == 2
|
||||
Reference in New Issue
Block a user