mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 04:32:32 +00:00
ConfigMgr Watcher: the ConfigMgr client check is opt-in per tenant (D-382)
The check from d4e67cdb now runs only for tenants that enable it, like the
RealmJoin Watcher: TenantConfiguration.EnableConfigMgrWatcher feeds
AnalyzerConfiguration.EnableConfigMgrWatcher (default off, ConfigVersion
42). With the setting off, DefaultComponentFactory does not create the
ConfigMgrClientHost, so other tenants' devices run no check at all.
- Portal: toggle "ConfigMgr Watcher" in Agent Settings, section field map,
tenant config report.
- Privacy page: the check is named as optional.
- Shared manifest and the web and MCP wire types regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+22
-1
@@ -40,7 +40,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Tests.Orchestration
|
||||
/// enabled by default) and system-boundary fakes only: temp state dir, fake ingress,
|
||||
/// virtual clock, no network metrics, no telemetry spool.
|
||||
/// </summary>
|
||||
private CollectorSurfaces CreateSurfaces()
|
||||
private CollectorSurfaces CreateSurfaces(AnalyzerConfiguration? analyzers = null)
|
||||
{
|
||||
var factory = new DefaultComponentFactory(
|
||||
agentConfig: new AgentConfiguration
|
||||
@@ -52,6 +52,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Tests.Orchestration
|
||||
remoteConfig: new AgentConfigResponse
|
||||
{
|
||||
Collectors = CollectorConfiguration.CreateDefault(),
|
||||
Analyzers = analyzers ?? new AnalyzerConfiguration(),
|
||||
},
|
||||
networkMetrics: null,
|
||||
agentVersion: "test",
|
||||
@@ -142,6 +143,26 @@ namespace AutopilotMonitor.Agent.V2.Core.Tests.Orchestration
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false, 0)]
|
||||
[InlineData(true, 1)]
|
||||
public void ConfigMgr_client_host_exists_only_when_the_tenant_enables_the_watcher(bool enabled, int expected)
|
||||
{
|
||||
// Opt-in (D-382): with the watcher off the check must not run at all, not merely stay quiet.
|
||||
var hosts = CreateSurfaces(new AnalyzerConfiguration { EnableConfigMgrWatcher = enabled }).Hosts;
|
||||
try
|
||||
{
|
||||
Assert.Equal(expected, hosts.Count(h => h is ConfigMgrClientHost));
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var host in hosts)
|
||||
{
|
||||
try { host.Dispose(); } catch { /* construction-only test — best-effort cleanup */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Ime_app_state_callback_is_chained_into_the_user_apps_settled_recheck()
|
||||
{
|
||||
|
||||
@@ -517,14 +517,23 @@ namespace AutopilotMonitor.Agent.V2.Core.Orchestration
|
||||
startupGate: _startupEventGate));
|
||||
}
|
||||
|
||||
// ConfigMgr client presence (the V1 check) — always-on, no config gate, on every flow.
|
||||
hosts.Add(new ConfigMgrClientHost(
|
||||
sessionId: sessionId,
|
||||
tenantId: tenantId,
|
||||
logger: logger,
|
||||
ingress: ingress,
|
||||
clock: clock,
|
||||
startupGate: _startupEventGate));
|
||||
// ConfigMgr client presence (the V1 check) — opt-in per tenant (portal toggle →
|
||||
// AnalyzerConfiguration.EnableConfigMgrWatcher, default off). When off, the host is
|
||||
// never created, so devices of other tenants run no check at all.
|
||||
if (analyzers.EnableConfigMgrWatcher)
|
||||
{
|
||||
hosts.Add(new ConfigMgrClientHost(
|
||||
sessionId: sessionId,
|
||||
tenantId: tenantId,
|
||||
logger: logger,
|
||||
ingress: ingress,
|
||||
clock: clock,
|
||||
startupGate: _startupEventGate));
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info("DefaultComponentFactory: ConfigMgrClientHost not created (EnableConfigMgrWatcher=false)");
|
||||
}
|
||||
|
||||
// Registry second pillar (audit 2026-08-17): IME's authoritative per-app state from
|
||||
// HKLM\...\IntuneManagementExtension (Win32Apps EnforcementStateMessage,
|
||||
|
||||
@@ -12,7 +12,8 @@ namespace AutopilotMonitor.Agent.V2.Core.Orchestration
|
||||
/// <summary>
|
||||
/// Drives the <see cref="ConfigMgrClientDetector"/>: a first check shortly after start (the
|
||||
/// client may already be installed) and one per minute after that (it may arrive later, e.g.
|
||||
/// as a Win32 app). Always-on, no config gate — like the V1 check it replaces.
|
||||
/// as a Win32 app). Created only when the tenant enables the ConfigMgr watcher
|
||||
/// (<c>AnalyzerConfiguration.EnableConfigMgrWatcher</c>).
|
||||
/// </summary>
|
||||
internal sealed class ConfigMgrClientHost : ICollectorHost
|
||||
{
|
||||
|
||||
@@ -72,10 +72,19 @@ public class AgentConfigResolverTests
|
||||
Assert.False(r.Analyzers.EnableSoftwareInventoryAnalyzer);
|
||||
Assert.True(r.Analyzers.EnableIntegrityBypassAnalyzer);
|
||||
Assert.False(r.Analyzers.EnableRealmJoinWatcher);
|
||||
Assert.False(r.Analyzers.EnableConfigMgrWatcher);
|
||||
Assert.False(r.Analyzers.KeepAwakeDuringUserEsp);
|
||||
Assert.True(r.Analyzers.EnableConsoleBypassDetection);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void The_tenant_switches_the_ConfigMgr_watcher_on()
|
||||
{
|
||||
var r = Build(Tenant(t => t.EnableConfigMgrWatcher = true));
|
||||
|
||||
Assert.True(r.Analyzers.EnableConfigMgrWatcher);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "CustomerSas", "Off", false)]
|
||||
[InlineData(null, "Hosted", "Off", true)] // hosted destination needs no SAS
|
||||
|
||||
+2
@@ -859,6 +859,7 @@ namespace AutopilotMonitor.Functions.DataAccess.TableStorage
|
||||
{ "EnableSoftwareInventoryAnalyzer", config.EnableSoftwareInventoryAnalyzer },
|
||||
{ "EnableIntegrityBypassAnalyzer", config.EnableIntegrityBypassAnalyzer },
|
||||
{ "EnableRealmJoinWatcher", config.EnableRealmJoinWatcher },
|
||||
{ "EnableConfigMgrWatcher", config.EnableConfigMgrWatcher },
|
||||
{ "KeepAwakeDuringUserEsp", config.KeepAwakeDuringUserEsp },
|
||||
{ "EnableConsoleBypassDetection", config.EnableConsoleBypassDetection },
|
||||
{ "LocalAdminAllowedAccountsJson", config.LocalAdminAllowedAccountsJson },
|
||||
@@ -980,6 +981,7 @@ namespace AutopilotMonitor.Functions.DataAccess.TableStorage
|
||||
EnableSoftwareInventoryAnalyzer = entity.GetBoolean("EnableSoftwareInventoryAnalyzer"),
|
||||
EnableIntegrityBypassAnalyzer = entity.GetBoolean("EnableIntegrityBypassAnalyzer"),
|
||||
EnableRealmJoinWatcher = entity.GetBoolean("EnableRealmJoinWatcher"),
|
||||
EnableConfigMgrWatcher = entity.GetBoolean("EnableConfigMgrWatcher"),
|
||||
KeepAwakeDuringUserEsp = entity.GetBoolean("KeepAwakeDuringUserEsp"),
|
||||
EnableConsoleBypassDetection = entity.GetBoolean("EnableConsoleBypassDetection"),
|
||||
LocalAdminAllowedAccountsJson = entity.GetString("LocalAdminAllowedAccountsJson"),
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace AutopilotMonitor.Functions.Services
|
||||
public class AgentConfigResolver
|
||||
{
|
||||
/// <summary>Bumped when the wire shape gains a field the agent must understand.</summary>
|
||||
public const int ConfigVersion = 41; // InterceptedRegistrationRetryBoots (boots after an intercepted registration)
|
||||
public const int ConfigVersion = 42; // Analyzers.EnableConfigMgrWatcher (ConfigMgr client check, opt-in)
|
||||
|
||||
/// <summary>
|
||||
/// Served as <see cref="AgentConfigResponse.InterceptedRegistrationRetryBoots"/>. A code
|
||||
@@ -154,6 +154,7 @@ namespace AutopilotMonitor.Functions.Services
|
||||
EnableSoftwareInventoryAnalyzer = tenantConfig.EnableSoftwareInventoryAnalyzer ?? false,
|
||||
EnableIntegrityBypassAnalyzer = tenantConfig.EnableIntegrityBypassAnalyzer ?? true,
|
||||
EnableRealmJoinWatcher = tenantConfig.EnableRealmJoinWatcher ?? false,
|
||||
EnableConfigMgrWatcher = tenantConfig.EnableConfigMgrWatcher ?? false,
|
||||
KeepAwakeDuringUserEsp = tenantConfig.KeepAwakeDuringUserEsp ?? false,
|
||||
EnableConsoleBypassDetection = tenantConfig.EnableConsoleBypassDetection ?? true
|
||||
},
|
||||
|
||||
@@ -421,6 +421,8 @@ export interface AnalyzerConfiguration {
|
||||
enableIntegrityBypassAnalyzer: boolean;
|
||||
/** Whether to enable the RealmJoin watcher, which tracks RealmJoin deployment state and enrollment packages during provisioning. This is not an IAgentAnalyzer; the flag gates creation of the RealmJoin collector host in the agent runtime. Default: false (opt-in; most tenants do not deploy via RealmJoin). */
|
||||
enableRealmJoinWatcher: boolean;
|
||||
/** Whether to enable the ConfigMgr watcher, which reports whether the Configuration Manager client is installed (service state, version, site code). This is not an IAgentAnalyzer; the flag gates creation of the ConfigMgr client host in the agent runtime. Default: false (opt-in; most tenants do not co-manage with ConfigMgr). */
|
||||
enableConfigMgrWatcher: boolean;
|
||||
/** Whether to keep the device awake (system + display) during the User-ESP (AccountSetup) phase so idle standby/sleep cannot stall app installs or account provisioning. This is not an IAgentAnalyzer; the flag gates creation of the UserEspKeepAwake host in the agent runtime. Reboots are unaffected (the hold only resets idle timers). Default: false (opt-in per tenant). */
|
||||
keepAwakeDuringUserEsp: boolean;
|
||||
/** Whether to detect an interactive console opened during enrollment — the classic Shift+F10 OOBE bypass. Gates BOTH the live ConsoleBypass host (an interactive-session cmd.exe with a bare, non-scripted command line; stopped on real-user desktop arrival) and the startup ConsolePrefetchScanner (CMD.EXE-*.pf ran after boot). Detection is best-effort, not gapless — a press before the agent installs is only coarsely covered by the prefetch artifact. Security-sensitive; not an IAgentAnalyzer toggle in the usual sense (it also gates a collector host). Default: true (opt-out per tenant — a Shift+F10 console during enrollment is a finding worth surfacing by default; tenants that knowingly use Shift+F10 for support can disable it). */
|
||||
@@ -5359,6 +5361,8 @@ export interface TenantConfiguration {
|
||||
enableIntegrityBypassAnalyzer?: boolean | null;
|
||||
/** Whether the RealmJoin watcher is enabled for this tenant's devices. RealmJoin enrollment-package tracking is off by default; enable only for tenants that deploy via RealmJoin. null = use agent default (false). */
|
||||
enableRealmJoinWatcher?: boolean | null;
|
||||
/** Whether the ConfigMgr watcher is enabled for this tenant's devices: the agent reports whether the Configuration Manager client is installed (service state, version, site code). Off by default; enable for tenants that co-manage with ConfigMgr. null = use agent default (false). */
|
||||
enableConfigMgrWatcher?: boolean | null;
|
||||
/** Whether to keep the device awake during the User-ESP (AccountSetup) phase for this tenant's devices. Prevents idle standby/sleep from stalling app installs / account provisioning; reboots are unaffected. Off by default. null = use agent default (false). */
|
||||
keepAwakeDuringUserEsp?: boolean | null;
|
||||
/** Whether to detect a SYSTEM console opened during enrollment (Shift+F10 OOBE bypass) for this tenant's devices. Gates the live ConsoleBypass watcher + the startup prefetch scanner. On by default (opt-out); tenants that knowingly use Shift+F10 for support can disable it. null = use agent default (true). */
|
||||
|
||||
@@ -742,7 +742,7 @@ namespace AutopilotMonitor.Shared
|
||||
public const string SessionParkedWithoutDeadline = "session_parked_without_deadline"; // One-shot Warning tripwire (liveness plan PR1): a non-terminal session entered the post-AccountSetup dead-end zone (ESP final exit or advisory failure) with NO resolution-capable deadline armed. After the 2026-06-12 dead-end fixes this must never fire in production — every occurrence is a bug report for an unknown parking variant.
|
||||
public const string DiskSpaceLow = "disk_space_low"; // One-shot Warning (state-change-only, 1 GB hysteresis — NOT periodic) when the system drive drops below 2 GB free. Review MON-B10: disk-full was previously only visible inside Debug performance_snapshot payloads (filtered out of timelines), so a disk-starved enrollment carried no actionable threshold signal.
|
||||
public const string EspPolicyProviderStalled = "esp_policy_provider_stalled"; // One-shot-per-provider Warning: a registered EnrollmentStatusTracking CSP policy provider stayed incomplete >= 15 min (Setup/Apps TrackingPoliciesCreated != 1, or DevicePreparation InstallationState not in {2,3} while device preparation is still open). The ESP waits on Setup/Apps providers WITHOUT any OS timeout — e.g. pre-provisioning + co-management leaves only "ConfigMgr" registered (no "Sidecar" = IME) and the user ESP sits at "Apps (Identifying)" for days. Observational only; payload carries the full provider list. See EspPolicyProviderProbe.
|
||||
public const string ConfigMgrClientDetected = "configmgr_client_detected"; // Info when the ConfigMgr client is first seen and again when its reported state changes (CCM key, CCMSetup version, assigned site code, %windir%\CCM, CcmExec state; V1 confidence score), capped per run. The V1 check, restored in V2 (D-382).
|
||||
public const string ConfigMgrClientDetected = "configmgr_client_detected"; // Info when the ConfigMgr client is first seen and again when its reported state changes (CCM key, CCMSetup version, assigned site code, %windir%\CCM, CcmExec state; V1 confidence score), capped per run. The V1 check, restored in V2 and opt-in per tenant (AnalyzerConfiguration.EnableConfigMgrWatcher, D-382).
|
||||
public const string KeepAwakeEngaged = "keep_awake_engaged"; // Info (state-change, NOT periodic) emitted by the opt-in UserEspKeepAwake host when it holds the device awake (system + display) on entering the User-ESP/AccountSetup phase, so idle standby cannot stall app installs / account provisioning. Reboots are unaffected. Per-tenant toggle (AnalyzerConfiguration.KeepAwakeDuringUserEsp, default off).
|
||||
public const string KeepAwakeReleased = "keep_awake_released"; // Info (Warning when reason=safety_cap) emitted when the keep-awake hold is released — reason = user_esp_exited (Shell-Core 62407 after AccountSetup progress, i.e. the user-ESP page closed; agents before 2026-09-04 wrote account_setup_complete for the synthesized completion, which fired minutes early) | host_stop | safety_cap. Brackets KeepAwakeEngaged; the OS also auto-clears the hold on process exit/reboot.
|
||||
|
||||
|
||||
@@ -659,6 +659,14 @@ namespace AutopilotMonitor.Shared.Models
|
||||
/// </summary>
|
||||
public bool EnableRealmJoinWatcher { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to enable the ConfigMgr watcher, which reports whether the Configuration
|
||||
/// Manager client is installed (service state, version, site code). This is not an
|
||||
/// IAgentAnalyzer; the flag gates creation of the ConfigMgr client host in the agent runtime.
|
||||
/// Default: false (opt-in; most tenants do not co-manage with ConfigMgr).
|
||||
/// </summary>
|
||||
public bool EnableConfigMgrWatcher { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to keep the device awake (system + display) during the User-ESP (AccountSetup)
|
||||
/// phase so idle standby/sleep cannot stall app installs or account provisioning. This is
|
||||
|
||||
@@ -603,6 +603,14 @@ namespace AutopilotMonitor.Shared.Models
|
||||
/// </summary>
|
||||
public bool? EnableRealmJoinWatcher { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the ConfigMgr watcher is enabled for this tenant's devices: the agent reports
|
||||
/// whether the Configuration Manager client is installed (service state, version, site
|
||||
/// code). Off by default; enable for tenants that co-manage with ConfigMgr.
|
||||
/// null = use agent default (false).
|
||||
/// </summary>
|
||||
public bool? EnableConfigMgrWatcher { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to keep the device awake during the User-ESP (AccountSetup) phase for this
|
||||
/// tenant's devices. Prevents idle standby/sleep from stalling app installs / account
|
||||
|
||||
+1
@@ -145,6 +145,7 @@ describe("runtime catalogs parity with the agent-config defaults manifest", () =
|
||||
expect(agentDefaults.collectorDefaults.collectorIdleTimeoutMinutes).toBe(15);
|
||||
expect(agentDefaults.analyzerDefaults.enableIntegrityBypassAnalyzer).toBe(true);
|
||||
expect(agentDefaults.analyzerDefaults.enableRealmJoinWatcher).toBe(false);
|
||||
expect(agentDefaults.analyzerDefaults.enableConfigMgrWatcher).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -190,6 +190,7 @@ export const TENANT_FIELDS: Record<keyof TenantConfiguration, TenantRow | Exclud
|
||||
enableIntegrityBypassAnalyzer: { section: "Analyzers", label: "Integrity Bypass Analyzer" },
|
||||
enableConsoleBypassDetection: { section: "Analyzers", label: "Console Bypass Detection" },
|
||||
enableRealmJoinWatcher: { section: "Analyzers", label: "Realm Join Watcher" },
|
||||
enableConfigMgrWatcher: { section: "Analyzers", label: "ConfigMgr Watcher" },
|
||||
|
||||
// Webhooks — channel list plus the legacy single-webhook fields it falls back to
|
||||
notificationChannelsJson: CHANNEL_BLOCK,
|
||||
@@ -341,6 +342,7 @@ export const ANALYZER_FIELDS: Record<keyof AnalyzerConfiguration, RuntimeRow | E
|
||||
enableSoftwareInventoryAnalyzer: { section: "Analyzers", label: "Software Inventory Analyzer", source: "tenant" },
|
||||
enableIntegrityBypassAnalyzer: { section: "Analyzers", label: "Integrity Bypass Analyzer", source: "tenant" },
|
||||
enableRealmJoinWatcher: { section: "Analyzers", label: "Realm Join Watcher", source: "tenant" },
|
||||
enableConfigMgrWatcher: { section: "Analyzers", label: "ConfigMgr Watcher", source: "tenant" },
|
||||
keepAwakeDuringUserEsp: { section: "Analyzers", label: "Keep Awake During User ESP", source: "tenant" },
|
||||
enableConsoleBypassDetection: { section: "Analyzers", label: "Console Bypass Detection", source: "tenant" },
|
||||
};
|
||||
|
||||
@@ -71,7 +71,7 @@ export default function PrivacyPage() {
|
||||
<ul className="list-disc list-inside space-y-2 text-gray-700 ml-4">
|
||||
<li><strong>Device identity</strong> — serial number, device name, manufacturer, model, and the Entra ID tenant the device enrolls into</li>
|
||||
<li><strong>Enrollment progress</strong> — phases, ESP stages, application and script results, policy activity, Windows updates installed during the enrollment, reboots, timings, and failure codes</li>
|
||||
<li><strong>Device context</strong> — OS build, hardware characteristics, disk and network state, whether the Configuration Manager client is installed (service state, version, site code), plus whatever your own gather rules request</li>
|
||||
<li><strong>Device context</strong> — OS build, hardware characteristics, disk and network state, plus whatever your own gather rules request; with the ConfigMgr Watcher enabled, also whether the Configuration Manager client is installed (service state, version, site code)</li>
|
||||
<li><strong>Approximate location</strong> — country, region, city, and approximate coordinates, if geolocation is enabled for your tenant</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -222,6 +222,8 @@ interface TenantConfigContextValue {
|
||||
setEnrollmentSummaryLaunchRetrySeconds: (v: number) => void;
|
||||
enableRealmJoinWatcher: boolean;
|
||||
setEnableRealmJoinWatcher: (v: boolean) => void;
|
||||
enableConfigMgrWatcher: boolean;
|
||||
setEnableConfigMgrWatcher: (v: boolean) => void;
|
||||
handleSaveAgentSettings: () => void;
|
||||
handleResetAgentSettings: () => void;
|
||||
|
||||
@@ -432,6 +434,7 @@ export function TenantConfigProvider({ children }: { children: React.ReactNode }
|
||||
const [enrollmentSummaryBrandingImageUrl, setEnrollmentSummaryBrandingImageUrl] = useState("");
|
||||
const [enrollmentSummaryLaunchRetrySeconds, setEnrollmentSummaryLaunchRetrySeconds] = useState(120);
|
||||
const [enableRealmJoinWatcher, setEnableRealmJoinWatcher] = useState(false);
|
||||
const [enableConfigMgrWatcher, setEnableConfigMgrWatcher] = useState(false);
|
||||
const [keepAwakeDuringUserEsp, setKeepAwakeDuringUserEsp] = useState(false);
|
||||
|
||||
// Notification channels
|
||||
@@ -592,6 +595,7 @@ export function TenantConfigProvider({ children }: { children: React.ReactNode }
|
||||
setEnrollmentSummaryBrandingImageUrl(data.enrollmentSummaryBrandingImageUrl ?? "");
|
||||
setEnrollmentSummaryLaunchRetrySeconds(data.enrollmentSummaryLaunchRetrySeconds ?? 120);
|
||||
setEnableRealmJoinWatcher(data.enableRealmJoinWatcher ?? false);
|
||||
setEnableConfigMgrWatcher(data.enableConfigMgrWatcher ?? false);
|
||||
setKeepAwakeDuringUserEsp(data.keepAwakeDuringUserEsp ?? false);
|
||||
// Notification channels (auto-migrates from the legacy single-webhook fields)
|
||||
setNotificationChannels(channelsFromConfig(data));
|
||||
@@ -785,6 +789,7 @@ export function TenantConfigProvider({ children }: { children: React.ReactNode }
|
||||
enrollmentSummaryBrandingImageUrl: enrollmentSummaryBrandingImageUrl || undefined,
|
||||
enrollmentSummaryLaunchRetrySeconds,
|
||||
enableRealmJoinWatcher,
|
||||
enableConfigMgrWatcher,
|
||||
keepAwakeDuringUserEsp,
|
||||
// Notification channels are the authoritative config; the legacy single-webhook
|
||||
// fields are cleared on save so deleting the last channel can't resurrect a zombie
|
||||
@@ -853,7 +858,7 @@ export function TenantConfigProvider({ children }: { children: React.ReactNode }
|
||||
helloWaitTimeoutSeconds, selfDestructOnComplete, keepLogFile, rebootOnComplete, rebootDelaySeconds,
|
||||
contactEmail, companyName, enableGeoLocation, enableTimezoneAutoSet, enableDoGroupIdAutoSet, enableImeMatchLog, enableGatherRuleDebugLog, logLevel, showScriptOutput, showEnrollmentSummary,
|
||||
enrollmentSummaryTimeoutSeconds, enrollmentSummaryBrandingImageUrl, enrollmentSummaryLaunchRetrySeconds,
|
||||
enableRealmJoinWatcher, keepAwakeDuringUserEsp,
|
||||
enableRealmJoinWatcher, enableConfigMgrWatcher, keepAwakeDuringUserEsp,
|
||||
notificationChannels,
|
||||
slaTargetSuccessRate, slaTargetMaxDurationMinutes, slaTargetAppInstallSuccessRate,
|
||||
slaNotifyOnSuccessRateBreach, slaSuccessRateNotifyThreshold, slaNotifyOnDurationBreach,
|
||||
@@ -1226,6 +1231,7 @@ export function TenantConfigProvider({ children }: { children: React.ReactNode }
|
||||
setEnrollmentSummaryBrandingImageUrl(config.enrollmentSummaryBrandingImageUrl ?? "");
|
||||
setEnrollmentSummaryLaunchRetrySeconds(config.enrollmentSummaryLaunchRetrySeconds ?? 120);
|
||||
setEnableRealmJoinWatcher(config.enableRealmJoinWatcher ?? false);
|
||||
setEnableConfigMgrWatcher(config.enableConfigMgrWatcher ?? false);
|
||||
setKeepAwakeDuringUserEsp(config.keepAwakeDuringUserEsp ?? false);
|
||||
}, [config]);
|
||||
|
||||
@@ -1607,6 +1613,7 @@ export function TenantConfigProvider({ children }: { children: React.ReactNode }
|
||||
enrollmentSummaryBrandingImageUrl, setEnrollmentSummaryBrandingImageUrl,
|
||||
enrollmentSummaryLaunchRetrySeconds, setEnrollmentSummaryLaunchRetrySeconds,
|
||||
enableRealmJoinWatcher, setEnableRealmJoinWatcher,
|
||||
enableConfigMgrWatcher, setEnableConfigMgrWatcher,
|
||||
keepAwakeDuringUserEsp, setKeepAwakeDuringUserEsp,
|
||||
handleSaveAgentSettings, handleResetAgentSettings,
|
||||
|
||||
@@ -1690,7 +1697,7 @@ export function TenantConfigProvider({ children }: { children: React.ReactNode }
|
||||
enableGeoLocation, enableTimezoneAutoSet, enableDoGroupIdAutoSet, enableImeMatchLog, enableGatherRuleDebugLog,
|
||||
logLevel, showScriptOutput, showEnrollmentSummary, enrollmentSummaryTimeoutSeconds,
|
||||
enrollmentSummaryBrandingImageUrl, enrollmentSummaryLaunchRetrySeconds,
|
||||
enableRealmJoinWatcher, keepAwakeDuringUserEsp,
|
||||
enableRealmJoinWatcher, enableConfigMgrWatcher, keepAwakeDuringUserEsp,
|
||||
handleSaveAgentSettings, handleResetAgentSettings,
|
||||
enableLocalAdminAnalyzer, localAdminAllowedAccounts, newAllowedAccount,
|
||||
enableSoftwareInventoryAnalyzer, enableIntegrityBypassAnalyzer, enableConsoleBypassDetection,
|
||||
|
||||
@@ -34,7 +34,7 @@ const EXPECTED_OWNED_FIELDS = [
|
||||
"contactEmail", "companyName",
|
||||
// agentSettings
|
||||
"enablePerformanceCollector", "performanceCollectorIntervalSeconds", "helloWaitTimeoutSeconds",
|
||||
"enableRealmJoinWatcher",
|
||||
"enableRealmJoinWatcher", "enableConfigMgrWatcher",
|
||||
"selfDestructOnComplete", "keepLogFile", "rebootOnComplete", "rebootDelaySeconds",
|
||||
"enableGeoLocation", "enableTimezoneAutoSet", "enableDoGroupIdAutoSet", "keepAwakeDuringUserEsp",
|
||||
"enableImeMatchLog", "enableGatherRuleDebugLog",
|
||||
|
||||
@@ -11,6 +11,7 @@ export function SectionAgentSettings() {
|
||||
performanceCollectorInterval, setPerformanceCollectorInterval,
|
||||
helloWaitTimeoutSeconds, setHelloWaitTimeoutSeconds,
|
||||
enableRealmJoinWatcher, setEnableRealmJoinWatcher,
|
||||
enableConfigMgrWatcher, setEnableConfigMgrWatcher,
|
||||
selfDestructOnComplete, setSelfDestructOnComplete,
|
||||
keepLogFile, setKeepLogFile,
|
||||
rebootOnComplete, setRebootOnComplete,
|
||||
@@ -43,6 +44,8 @@ export function SectionAgentSettings() {
|
||||
setHelloWaitTimeoutSeconds={setHelloWaitTimeoutSeconds}
|
||||
enableRealmJoinWatcher={enableRealmJoinWatcher}
|
||||
setEnableRealmJoinWatcher={setEnableRealmJoinWatcher}
|
||||
enableConfigMgrWatcher={enableConfigMgrWatcher}
|
||||
setEnableConfigMgrWatcher={setEnableConfigMgrWatcher}
|
||||
selfDestructOnComplete={selfDestructOnComplete}
|
||||
setSelfDestructOnComplete={setSelfDestructOnComplete}
|
||||
keepLogFile={keepLogFile}
|
||||
|
||||
@@ -20,6 +20,8 @@ interface AgentSettingsSectionProps {
|
||||
setHelloWaitTimeoutSeconds: (value: number) => void;
|
||||
enableRealmJoinWatcher: boolean;
|
||||
setEnableRealmJoinWatcher: (value: boolean) => void;
|
||||
enableConfigMgrWatcher: boolean;
|
||||
setEnableConfigMgrWatcher: (value: boolean) => void;
|
||||
selfDestructOnComplete: boolean;
|
||||
setSelfDestructOnComplete: (value: boolean) => void;
|
||||
keepLogFile: boolean;
|
||||
@@ -68,6 +70,8 @@ export default function AgentSettingsSection({
|
||||
setHelloWaitTimeoutSeconds,
|
||||
enableRealmJoinWatcher,
|
||||
setEnableRealmJoinWatcher,
|
||||
enableConfigMgrWatcher,
|
||||
setEnableConfigMgrWatcher,
|
||||
selfDestructOnComplete,
|
||||
setSelfDestructOnComplete,
|
||||
keepLogFile,
|
||||
@@ -423,6 +427,20 @@ export default function AgentSettingsSection({
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* ConfigMgr Watcher */}
|
||||
<div className="flex items-center justify-between p-4 rounded-lg border border-gray-200 hover:border-emerald-200 transition-colors">
|
||||
<div className="flex-1">
|
||||
<p className="font-medium text-gray-900">ConfigMgr Watcher</p>
|
||||
<p className="text-sm text-gray-500 mt-1">Shows in Session Info whether the Configuration Manager client is installed, with its service state, version and site code. Off by default; enable for tenants that co-manage devices with Configuration Manager.</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setEnableConfigMgrWatcher(!enableConfigMgrWatcher)}
|
||||
className={`relative inline-flex h-6 w-11 flex-shrink-0 items-center rounded-full transition-colors ${enableConfigMgrWatcher ? 'bg-emerald-500' : 'bg-gray-300'}`}
|
||||
>
|
||||
<span className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${enableConfigMgrWatcher ? 'translate-x-6' : 'translate-x-1'}`} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Hello Wait Timeout */}
|
||||
<div className="flex items-center justify-between p-4 rounded-lg border border-gray-200 hover:border-emerald-200 transition-colors">
|
||||
<div className="flex-1">
|
||||
|
||||
@@ -67,6 +67,7 @@ export const SECTION_FIELD_MAP = {
|
||||
"performanceCollectorIntervalSeconds",
|
||||
"helloWaitTimeoutSeconds",
|
||||
"enableRealmJoinWatcher",
|
||||
"enableConfigMgrWatcher",
|
||||
"selfDestructOnComplete",
|
||||
"keepLogFile",
|
||||
"rebootOnComplete",
|
||||
|
||||
@@ -130,6 +130,7 @@ export interface TenantConfiguration {
|
||||
enableSoftwareInventoryAnalyzer?: boolean;
|
||||
enableIntegrityBypassAnalyzer?: boolean;
|
||||
enableRealmJoinWatcher?: boolean;
|
||||
enableConfigMgrWatcher?: boolean;
|
||||
keepAwakeDuringUserEsp?: boolean;
|
||||
enableConsoleBypassDetection?: boolean;
|
||||
// Bootstrap token
|
||||
|
||||
@@ -199,6 +199,7 @@ export const SHARED_MANIFEST = {
|
||||
"enableSoftwareInventoryAnalyzer",
|
||||
"enableIntegrityBypassAnalyzer",
|
||||
"enableRealmJoinWatcher",
|
||||
"enableConfigMgrWatcher",
|
||||
"keepAwakeDuringUserEsp",
|
||||
"enableConsoleBypassDetection",
|
||||
"localAdminAllowedAccountsJson",
|
||||
@@ -304,6 +305,7 @@ export const SHARED_MANIFEST = {
|
||||
"enableSoftwareInventoryAnalyzer": null,
|
||||
"enableIntegrityBypassAnalyzer": null,
|
||||
"enableRealmJoinWatcher": null,
|
||||
"enableConfigMgrWatcher": null,
|
||||
"keepAwakeDuringUserEsp": null,
|
||||
"enableConsoleBypassDetection": null,
|
||||
"localAdminAllowedAccountsJson": null,
|
||||
@@ -446,6 +448,7 @@ export const SHARED_MANIFEST = {
|
||||
"enableSoftwareInventoryAnalyzer": false,
|
||||
"enableIntegrityBypassAnalyzer": true,
|
||||
"enableRealmJoinWatcher": false,
|
||||
"enableConfigMgrWatcher": false,
|
||||
"keepAwakeDuringUserEsp": false,
|
||||
"enableConsoleBypassDetection": true
|
||||
}
|
||||
|
||||
@@ -195,6 +195,7 @@
|
||||
"enableSoftwareInventoryAnalyzer",
|
||||
"enableIntegrityBypassAnalyzer",
|
||||
"enableRealmJoinWatcher",
|
||||
"enableConfigMgrWatcher",
|
||||
"keepAwakeDuringUserEsp",
|
||||
"enableConsoleBypassDetection",
|
||||
"localAdminAllowedAccountsJson",
|
||||
@@ -300,6 +301,7 @@
|
||||
"enableSoftwareInventoryAnalyzer": null,
|
||||
"enableIntegrityBypassAnalyzer": null,
|
||||
"enableRealmJoinWatcher": null,
|
||||
"enableConfigMgrWatcher": null,
|
||||
"keepAwakeDuringUserEsp": null,
|
||||
"enableConsoleBypassDetection": null,
|
||||
"localAdminAllowedAccountsJson": null,
|
||||
@@ -442,6 +444,7 @@
|
||||
"enableSoftwareInventoryAnalyzer": false,
|
||||
"enableIntegrityBypassAnalyzer": true,
|
||||
"enableRealmJoinWatcher": false,
|
||||
"enableConfigMgrWatcher": false,
|
||||
"keepAwakeDuringUserEsp": false,
|
||||
"enableConsoleBypassDetection": true
|
||||
}
|
||||
@@ -2945,6 +2948,14 @@
|
||||
},
|
||||
"doc": "Whether to enable the RealmJoin watcher, which tracks RealmJoin deployment state and enrollment packages during provisioning. This is not an IAgentAnalyzer; the flag gates creation of the RealmJoin collector host in the agent runtime. Default: false (opt-in; most tenants do not deploy via RealmJoin)."
|
||||
},
|
||||
{
|
||||
"name": "enableConfigMgrWatcher",
|
||||
"type": {
|
||||
"kind": "primitive",
|
||||
"name": "boolean"
|
||||
},
|
||||
"doc": "Whether to enable the ConfigMgr watcher, which reports whether the Configuration Manager client is installed (service state, version, site code). This is not an IAgentAnalyzer; the flag gates creation of the ConfigMgr client host in the agent runtime. Default: false (opt-in; most tenants do not co-manage with ConfigMgr)."
|
||||
},
|
||||
{
|
||||
"name": "keepAwakeDuringUserEsp",
|
||||
"type": {
|
||||
@@ -24648,6 +24659,16 @@
|
||||
"optional": true,
|
||||
"doc": "Whether the RealmJoin watcher is enabled for this tenant's devices. RealmJoin enrollment-package tracking is off by default; enable only for tenants that deploy via RealmJoin. null = use agent default (false)."
|
||||
},
|
||||
{
|
||||
"name": "enableConfigMgrWatcher",
|
||||
"type": {
|
||||
"kind": "primitive",
|
||||
"name": "boolean",
|
||||
"nullable": true
|
||||
},
|
||||
"optional": true,
|
||||
"doc": "Whether the ConfigMgr watcher is enabled for this tenant's devices: the agent reports whether the Configuration Manager client is installed (service state, version, site code). Off by default; enable for tenants that co-manage with ConfigMgr. null = use agent default (false)."
|
||||
},
|
||||
{
|
||||
"name": "keepAwakeDuringUserEsp",
|
||||
"type": {
|
||||
|
||||
@@ -421,6 +421,8 @@ export interface AnalyzerConfiguration {
|
||||
enableIntegrityBypassAnalyzer: boolean;
|
||||
/** Whether to enable the RealmJoin watcher, which tracks RealmJoin deployment state and enrollment packages during provisioning. This is not an IAgentAnalyzer; the flag gates creation of the RealmJoin collector host in the agent runtime. Default: false (opt-in; most tenants do not deploy via RealmJoin). */
|
||||
enableRealmJoinWatcher: boolean;
|
||||
/** Whether to enable the ConfigMgr watcher, which reports whether the Configuration Manager client is installed (service state, version, site code). This is not an IAgentAnalyzer; the flag gates creation of the ConfigMgr client host in the agent runtime. Default: false (opt-in; most tenants do not co-manage with ConfigMgr). */
|
||||
enableConfigMgrWatcher: boolean;
|
||||
/** Whether to keep the device awake (system + display) during the User-ESP (AccountSetup) phase so idle standby/sleep cannot stall app installs or account provisioning. This is not an IAgentAnalyzer; the flag gates creation of the UserEspKeepAwake host in the agent runtime. Reboots are unaffected (the hold only resets idle timers). Default: false (opt-in per tenant). */
|
||||
keepAwakeDuringUserEsp: boolean;
|
||||
/** Whether to detect an interactive console opened during enrollment — the classic Shift+F10 OOBE bypass. Gates BOTH the live ConsoleBypass host (an interactive-session cmd.exe with a bare, non-scripted command line; stopped on real-user desktop arrival) and the startup ConsolePrefetchScanner (CMD.EXE-*.pf ran after boot). Detection is best-effort, not gapless — a press before the agent installs is only coarsely covered by the prefetch artifact. Security-sensitive; not an IAgentAnalyzer toggle in the usual sense (it also gates a collector host). Default: true (opt-out per tenant — a Shift+F10 console during enrollment is a finding worth surfacing by default; tenants that knowingly use Shift+F10 for support can disable it). */
|
||||
@@ -5359,6 +5361,8 @@ export interface TenantConfiguration {
|
||||
enableIntegrityBypassAnalyzer?: boolean | null;
|
||||
/** Whether the RealmJoin watcher is enabled for this tenant's devices. RealmJoin enrollment-package tracking is off by default; enable only for tenants that deploy via RealmJoin. null = use agent default (false). */
|
||||
enableRealmJoinWatcher?: boolean | null;
|
||||
/** Whether the ConfigMgr watcher is enabled for this tenant's devices: the agent reports whether the Configuration Manager client is installed (service state, version, site code). Off by default; enable for tenants that co-manage with ConfigMgr. null = use agent default (false). */
|
||||
enableConfigMgrWatcher?: boolean | null;
|
||||
/** Whether to keep the device awake during the User-ESP (AccountSetup) phase for this tenant's devices. Prevents idle standby/sleep from stalling app installs / account provisioning; reboots are unaffected. Off by default. null = use agent default (false). */
|
||||
keepAwakeDuringUserEsp?: boolean | null;
|
||||
/** Whether to detect a SYSTEM console opened during enrollment (Shift+F10 OOBE bypass) for this tenant's devices. Gates the live ConsoleBypass watcher + the startup prefetch scanner. On by default (opt-out); tenants that knowingly use Shift+F10 for support can disable it. null = use agent default (true). */
|
||||
|
||||
Reference in New Issue
Block a user