diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 213ebde5..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,29 +0,0 @@ -# Changelog - -## 2026-03-29 — Agent Integrity Verification (SHA-256) - -### Security Enhancement - -The bootstrapper script and agent self-updater now verify the SHA-256 hash of downloaded -agent packages against `version.json`. Additionally, the backend serves the expected hash -via the agent config endpoint as a second trust channel. - -**What changed:** -- `version.json` now includes a `sha256` field with the SHA-256 hash of the agent ZIP -- Bootstrapper (`Install-AutopilotMonitor.ps1`) verifies the hash before installation -- Self-Updater (`SelfUpdater.cs`) verifies the hash before applying updates -- Backend delivers `LatestAgentSha256` via the agent config response (defense in depth) -- CI/CD pipeline and local build scripts compute and publish the hash automatically - -**Action required:** Update your Intune bootstrapper script to the latest version -to benefit from SHA-256 integrity verification. Existing deployments continue to work -without changes (fully backward compatible). - -The updated bootstrap script is available at: -- Blob Storage: `https://autopilotmonitor.blob.core.windows.net/agent/Install-AutopilotMonitor.ps1` -- GitHub: `scripts/Bootstrap/Install-AutopilotMonitor.ps1` - -**Backward compatibility:** -- Old bootstrapper scripts (without hash check) continue to work unchanged -- Old agents (without hash check) continue to self-update normally -- New agents with old `version.json` (no `sha256` field) skip the check gracefully diff --git a/docs/decisions/001-sas-url-on-demand.md b/docs/decisions/001-sas-url-on-demand.md deleted file mode 100644 index 81b7bfa2..00000000 --- a/docs/decisions/001-sas-url-on-demand.md +++ /dev/null @@ -1,30 +0,0 @@ -# ADR-001: On-Demand SAS URL Delivery for Diagnostics Upload - -**Status:** Accepted -**Date:** 2026-02 -**Supersedes:** Original design with SAS URL in agent config response stored on disk - -## Context - -The agent needs to upload diagnostics ZIP packages to Azure Blob Storage. The original design included the long-lived SAS URL directly in the `agent/config` response, which was then persisted in `remote-config.json` on the device. - -**Problems with the original approach:** -- SAS URL persisted on disk in plaintext (`remote-config.json`) — accessible to any local admin -- URL visible in agent logs -- No per-device access control — every device with the cached URL could upload at any time - -## Decision - -Instead of delivering the SAS URL via the config response, the agent calls `POST /api/diagnostics/upload-url` immediately before each upload. The backend returns the long-lived SAS URL (configured in tenant settings) in the response body. The agent uses it in-memory for the upload and discards it — it is never written to disk or cached in config. - -**Config response changes:** -- Removed: `DiagnosticsBlobSasUrl` from agent config delivery -- Added: `DiagnosticsUploadEnabled` (bool) — controls whether the agent attempts upload -- Added: `POST /api/diagnostics/upload-url` endpoint (`GetDiagnosticsUploadUrlFunction`) - -## Consequences - -- SAS URL never persisted on device — only held in-memory for the duration of the upload -- Backend can deny the URL per-device (blocked devices, rate limiting, disabled tenants) -- Old agents that still read from `remote-config.json` fall back gracefully — they won't have a SAS URL and simply skip upload -- Slightly higher latency (one extra HTTP call before upload) — acceptable since uploads are infrequent diff --git a/docs/decisions/002-idle-timeout-replaces-max-duration.md b/docs/decisions/002-idle-timeout-replaces-max-duration.md deleted file mode 100644 index b44ca892..00000000 --- a/docs/decisions/002-idle-timeout-replaces-max-duration.md +++ /dev/null @@ -1,33 +0,0 @@ -# ADR-002: Activity-Aware Idle Timeout Replaces Static Max Duration - -**Status:** Accepted -**Date:** 2026-02 -**Supersedes:** Static `MaxCollectorDurationHours` (4h hard cutoff) - -## Context - -The original design stopped all collectors after a fixed 4-hour window (`MaxCollectorDurationHours`). This caused problems: -- Long enrollments with many apps (>50) were cut off mid-collection -- Sessions with slow network or large downloads lost data -- No way to distinguish "still actively enrolling" from "enrollment finished, agent idle" - -## Decision - -Replace the static cutoff with an activity-aware idle timeout: - -- **`CollectorIdleTimeoutMinutes`** (default: 15) — stops collectors when no "real" events arrive for this duration -- **"Real" events** = everything except `performance_snapshot`, `agent_metrics_snapshot`, and their `_stopped` variants -- Collectors auto-restart when new real activity arrives after idle stop -- `AgentMaxLifetimeMinutes` (default: 360/6h) remains as an absolute safety net - -**Implementation:** -- `MonitoringService` tracks `_lastRealEventTime` -- Idle check timer fires every 60 seconds -- Global setting in `AdminConfiguration.CollectorIdleTimeoutMinutes`, delivered via `CollectorConfiguration` - -## Consequences - -- Long enrollments run to completion — no arbitrary cutoff -- Idle devices stop wasting CPU/network within 15 minutes -- Old agents (not updated) fall back to their built-in 4h default — no breaking change -- The 6h max lifetime timer prevents runaway agents regardless diff --git a/docs/decisions/003-multi-signal-session-completion.md b/docs/decisions/003-multi-signal-session-completion.md deleted file mode 100644 index 80f40a47..00000000 --- a/docs/decisions/003-multi-signal-session-completion.md +++ /dev/null @@ -1,43 +0,0 @@ -# ADR-003: Multi-Signal Session Completion - -**Status:** Accepted -**Date:** 2026-03 - -## Context - -Windows Autopilot enrollment can follow multiple paths, and no single event reliably indicates "enrollment is done" across all scenarios: - -- **ESP (Enrollment Status Page)** may or may not be present -- **Windows Hello** provisioning may be skipped, succeed, or time out -- **Windows Device Preparation (v2)** has no ESP at all -- **White Glove (Pre-Provisioning)** splits enrollment into two distinct phases -- Devices may reboot mid-enrollment, losing in-memory state - -## Decision - -Implement 3 independent completion paths, any of which can trigger `enrollment_complete`: - -1. **IME Pattern Path** — The existing pattern-based detection from Intune Management Extension logs (legacy, most reliable for app-centric enrollments) - -2. **ESP + Hello Composite Path** — ESP final exit event + Hello completion/skip/timeout. For device-only ESP (no Account Setup), a 5-minute timer after Device Setup exit classifies as device-only. - -3. **Desktop + Hello Path (No-ESP)** — Desktop arrival (explorer.exe under real user) + Hello completion. Used when ESP is absent (e.g., WDP v2). - -**Supporting infrastructure:** -- `EnrollmentStatePersistence` — crash recovery for completion signals (persists seen signals to disk) -- `DesktopArrivalDetector` — polls explorer.exe every 30s, validates user identity (excludes SYSTEM, DefaultUser*) -- Signal audit trail — terminal events include `signalsSeen` and `signalTimestamps` -- Completion check throttling — observability events at 1x/min/source -- WDP v2 gate skip — `enrollmentType == "v2"` skips desktop arrival gate - -**Hello behavior:** -- `HelloCompletionTimeoutSeconds` = 300 (5 minutes) -- `HelloOutcome` tracks: `completed`, `skipped`, `timed_out` - -## Consequences - -- Covers all known Autopilot enrollment paths (Classic ESP, WDP v2, White Glove, device-only) -- State persists across reboots — no lost completions -- Each path is independently testable -- Adding new completion signals requires only extending `EnrollmentTracker.CompletionLogic.cs` -- Complexity concentrated in one partial class file (~789 lines) — acceptable given the domain complexity