@@ -497,6 +506,7 @@
+ What to do when a process below is running: Defer skips this cycle, CloseAndReopen restarts it, ForceClose kills it, ScheduleForReboot defers to next reboot.
@@ -569,7 +579,7 @@ import {
describeEntry, availableEntryTypes as availableEntryTypesFor,
availableDetectionMethods as availableDetectionMethodsFor,
targetingGates as targetingGatesFor, targetingHint as targetingHintFor,
- scopeSummary as scopeSummaryFor,
+ scopeSummary as scopeSummaryFor, detectionMethodHint as detectionMethodHintFor,
} from './entryForm'
const scopes = ref([])
@@ -588,6 +598,8 @@ const availableEntryTypes = computed(() =>
availableEntryTypesFor(isPreinstallScope.value, entryForm.value?.Type))
const availableDetectionMethods = computed(() =>
availableDetectionMethodsFor(isPreinstallScope.value, entryForm.value?.DetectionMethod))
+const detectionMethodHint = computed(() =>
+ detectionMethodHintFor(entryForm.value?.DetectionMethod))
const scopeSummary = computed(() => scopeSummaryFor(detail.value))
const showAllTargeting = ref(false)
const targetingGates = computed(() => targetingGatesFor(detail.value))
diff --git a/frontend/src/views/geenforce/entryForm.js b/frontend/src/views/geenforce/entryForm.js
index c5cbc17..7384f63 100644
--- a/frontend/src/views/geenforce/entryForm.js
+++ b/frontend/src/views/geenforce/entryForm.js
@@ -1,11 +1,8 @@
// Pure, framework-free helpers for the GE-Enforce manifest editor.
//
-// These functions are lifted verbatim (behavior-for-behavior) from
-// ManifestEditor.vue so they can be unit tested without mounting the whole
-// component. ManifestEditor.vue still hosts its own copies today; a follow-up
-// should point the component at this module (import from here) so the tested
-// code and the shipped code are the same source. Until then keep the two in
-// sync: any change to the editor logic must land here too.
+// ManifestEditor.vue imports these directly (the component no longer keeps its
+// own copies), so the unit tests in entryForm.spec.js exercise the shipped
+// code path. Change the editor logic HERE.
//
// Everything here is a plain function of its inputs. No Vue, no reactivity,
// no network. That is the whole point - deterministic logic we can pin down.
@@ -16,6 +13,26 @@ export const DETECTION_METHODS = ['Registry', 'File', 'FileVersion', 'Hash', 'Ma
'ValueMatches', 'pnputil', 'Always']
export const INUSE_BEHAVIORS = ['Defer', 'CloseAndReopen', 'ForceClose', 'ScheduleForReboot']
+// Plain-language description of each detection method, shown under the Detection
+// method dropdown so a first-time site admin understands what "present" means
+// for the method they picked. Key '' is the no-detection case.
+export const DETECTION_METHOD_HINTS = {
+ '': 'No detection rule: the action runs every cycle.',
+ Registry: 'Already correct if the registry value at Detection path/name exists (and equals Detection value when one is set).',
+ File: 'Already correct if the file at Detection path exists.',
+ FileVersion: 'Already correct if the file at Detection path is at Detection value or newer. This target feeds the Compliance panel.',
+ Hash: 'Already correct if the file at Detection path matches the SHA256 in Detection value. Re-copies when the file changed.',
+ MarkerFile: 'Already correct if the marker file at Detection path exists. Installs once, then the marker suppresses reruns.',
+ ValueMatches: 'Already correct if the registry value at Detection path/name equals Detection value exactly.',
+ pnputil: 'Already correct if a driver matching Detection pattern is staged in the Windows driver store. For INF entries.',
+ Always: 'Never counts as present, so the action runs every cycle. Same effect as no detection rule.',
+}
+
+// Description for the currently selected detection method, or '' if unknown.
+export function detectionMethodHint(method) {
+ return DETECTION_METHOD_HINTS[method || ''] || ''
+}
+
// One blank entry form, matching the shape ManifestEditor seeds for a new entry.
export function blankEntry() {
return { Type: 'MSI', DetectionMethod: '', RegType: 'String',
diff --git a/frontend/src/views/geenforce/entryForm.spec.js b/frontend/src/views/geenforce/entryForm.spec.js
index f5591a4..bd29923 100644
--- a/frontend/src/views/geenforce/entryForm.spec.js
+++ b/frontend/src/views/geenforce/entryForm.spec.js
@@ -9,6 +9,7 @@ import {
targetingHint,
scopeSummary,
describeEntry,
+ detectionMethodHint,
ENTRY_TYPES,
DETECTION_METHODS,
} from './entryForm.js'
@@ -300,3 +301,21 @@ describe('describeEntry', () => {
expect(describeEntry({ Type: 'Weird', Name: 'x' })).toMatch(/^Applies x/)
})
})
+
+describe('detectionMethodHint', () => {
+ it('has a non-empty hint for every detection method', () => {
+ for (const method of DETECTION_METHODS) {
+ expect(detectionMethodHint(method).length).toBeGreaterThan(0)
+ }
+ })
+ it('describes the no-detection case for empty/undefined', () => {
+ expect(detectionMethodHint('')).toMatch(/every cycle/)
+ expect(detectionMethodHint(undefined)).toMatch(/every cycle/)
+ })
+ it('ties FileVersion to the compliance panel', () => {
+ expect(detectionMethodHint('FileVersion')).toMatch(/Compliance/)
+ })
+ it('returns empty string for an unknown method', () => {
+ expect(detectionMethodHint('Nonsense')).toBe('')
+ })
+})