Repository navigation
Conversation
74e64d9 to
1a59355
Compare
…check Browsers have no per-tool LLM setting; enterprises steer browser AI traffic with a PAC file pushed by MDM or GPO. The daemon now reports, per device, the PAC that browser machine policy sets: absent, found with its URL, or differs between browsers. - agent: Chrome, Edge, Chromium and Firefox policy readers for Linux (policy files) and Windows (registry; HKCU only when running as the user); the PAC URL is fetched directly and identified by SHA-256 and size, never its content; policy directories are watched - proto: Inventory.browser_pacs = 3, Inventory.pac_fetches = 4 - controller: migration 0004_browser_pacs; optional browserEgress.compliance.pacUrl in the controller configuration, evaluated at read time (compliant or not, with the reason); PAC versions grouped by URL and hash on the overview - UI: fleet device column, device card and overview tiles; desktop app card - README section, regenerated schemas Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Linux: merge the proxy keys across policy files the way Chrome merges policies, so ProxyMode and ProxyPacUrl in different files still give a PAC; the same key with different values is still a conflict - Linux: a policy directory that can't be read is reported instead of looking like "no policy" - inventory refresh: resync the file watch after every scan, not only when the inventory changed, so a policy file in a directory created empty first is seen without waiting for the interval (regression test) - fleet UI: when browsers set different PACs, the device page lists each PAC URL with its hash or fetch error Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Chromium policy files may contain comments and trailing commas, as Chromium's loader accepts them (JSON_PARSE_CHROMIUM_EXTENSIONS | JSON_ALLOW_TRAILING_COMMAS); the Firefox reader stays strict JSON - a conflict between legacy ProxyMode/ProxyPacUrl values no longer hides a ProxySettings dictionary, which overrides them - Linux Firefox: only the file Firefox uses counts (/etc/firefox/policies/policies.json when it exists, otherwise the install's distribution/ file), so a Proxy section in an ignored file can't be reported Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dev#160 agentdesktop-dev#160 added 0004_usage.sql; the browser PAC tables move to 0005_browser_pacs.sql. No content change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1a59355 to
c7d2abe
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Policy-source selection can attribute inactive installation policies to installed browsers and produce incorrect compliance results.
2 open issues
What changed in this PR
Adds read-only browser PAC reporting to device inventory, extending desktop security visibility with PAC identity tracking and optional fleet compliance checks.
Changes:
- Reads Linux and Windows browser policies and fetches PAC hashes and sizes.
- Stores PAC inventory and evaluates compliance against a controller-configured URL.
- Displays PAC status in the CLI, desktop app, and fleet UI, with documentation and tests.
| File | Description |
|---|---|
| schema/controller-config.md | Documents optional PAC compliance settings. |
| schema/controller-config.json | Adds the browser compliance configuration schema. |
| README.md | Explains reporting, platform support, and compliance. |
| frontend/ui/src/tools.tsx | Adds friendly browser names. |
| frontend/desktop/src/views/ToolsView.tsx | Displays browser PAC status and identity. |
| frontend/desktop/src/types.ts | Adds desktop PAC inventory types. |
| frontend/desktop/src/stories/fixtures.ts | Adds sample browser policies and hashes. |
| frontend/controller/src/views/OverviewView.tsx | Shows fleet PAC counts and version groups. |
| frontend/controller/src/views/DeviceView.tsx | Shows device policies, identities, and compliance. |
| frontend/controller/src/views/DeviceView.stories.tsx | Covers differing browser PACs. |
| frontend/controller/src/types.ts | Defines PAC report and compliance types. |
| frontend/controller/src/styles.css | Styles PAC status indicators. |
| frontend/controller/src/stories/fixtures.ts | Adds fleet PAC reporting scenarios. |
| frontend/controller/src/components/DeviceTable.tsx | Adds the Browser PAC column. |
| frontend/controller/src/components/BrowserPac.tsx | Adds PAC status and compliance indicators. |
| crates/proto/proto/fleet.proto | Extends inventory with policies and fetch results. |
| crates/core/src/model.rs | Defines PAC models and device-level aggregation. |
| crates/core/src/config.rs | Parses and validates optional compliance settings. |
| crates/controller/src/main.rs | Passes the expected PAC URL to admin state. |
| crates/controller/src/lib.rs | Exposes the PAC evaluation module. |
| crates/controller/src/database.rs | Validates, stores, and loads PAC inventory. |
| crates/controller/src/browser_pac.rs | Evaluates compliance and groups PAC identities. |
| crates/controller/src/admin.rs | Adds PAC summaries to admin responses. |
| crates/controller/migrations/0005_browser_pacs.sql | Creates policy and fetch-result tables. |
| crates/agent/src/remote.rs | Sends PAC inventory to the controller. |
| crates/agent/src/reconcile/mod.rs | Integrates policy discovery and PAC fetching. |
| crates/agent/src/provider/vscode/mod.rs | Initializes new inventory fields. |
| crates/agent/src/provider/opencode/mod.rs | Initializes new inventory fields. |
| crates/agent/src/provider/ollama/mod.rs | Initializes new inventory fields. |
| crates/agent/src/provider/grok/mod.rs | Initializes new inventory fields. |
| crates/agent/src/provider/cursor/mod.rs | Initializes new inventory fields. |
| crates/agent/src/provider/copilot/mod.rs | Initializes new inventory fields. |
| crates/agent/src/provider/codex/mod.rs | Initializes new inventory fields. |
| crates/agent/src/provider/claude_desktop/mod.rs | Initializes new inventory fields. |
| crates/agent/src/provider/claude_code/mod.rs | Initializes new inventory fields. |
| crates/agent/src/llm_proxy.rs | Updates test inventory fixtures. |
| crates/agent/src/lib.rs | Registers the PAC discovery module. |
| crates/agent/src/inventory_watch.rs | Watches browser policy directories. |
| crates/agent/src/daemon.rs | Logs PAC discovery and refreshes directory watches. |
| crates/agent/src/cli.rs | Prints PAC status and fetch results. |
| crates/agent/src/browser_pac.rs | Implements policy readers, bounded fetching, caching, and tests. |
| crates/agent/Cargo.toml | Enables Windows registry APIs. |
Review effort: Balanced
| let directories: Vec<PathBuf> = browser | ||
| .policy_roots | ||
| .iter() | ||
| .map(|policies| root.join(policies).join(level)) | ||
| .collect(); |
There was a problem hiding this comment.
Fixed in d5e19af. Each Chromium installation now reads only the policy it sees, one row per installation:
- snap:
/etc/chromium-browser/policiesonly (the root itssystem-filesplug exposes); a stale/etc/chromium/policiesno longer counts /usr/bin/chromium:/etc/chromium/policies/usr/bin/chromium-browser: both roots, since the path varies by distribution; skipped when the snap is present, because on Ubuntu it only launches the snap- Flatpak: only its
org.chromium.Chromium.Extension.*extensions (installed under/var/lib/flatpak/runtime/…/active/files/policies, unmanaged under/var/lib/flatpak/extension/…/policies), never host/etc - policy with no installation found: one row from all roots
each_installation_reads_only_its_own_policy covers a snap with stale system policy, the wrapper and a Flatpak extension. browser_pacs is now keyed by (device_id, browser, packaging).
| if let Some(file) = FIREFOX_POLICY_FILES | ||
| .iter() | ||
| .map(|file| root.join(file)) | ||
| .find(|file| file.is_file()) |
There was a problem hiding this comment.
Fixed in d5e19af. Firefox rows are now per installation:
- Linux:
/etc/firefox/policies/policies.jsonwhen it exists (it overrides every installation), otherwise that installation's owndistribution/policies.json(/usr/lib,/usr/lib64,/opt/firefox). The snap reads only/etc/firefox/policies. The Flatpak is reported with "policy of the Flatpak build is not read", so a device with one doesn't show as having a PAC. - Windows: registry policy first, then the installation's own
distribution\policies.json. TheProgram Files (x86)installation is its own row (x86), and a leftover file under%ProgramFiles%no longer counts for it. - Policy with no installation found: one row, from all locations.
Tests: each_installation_reads_only_its_own_policy (/opt/firefox with a leftover /usr/lib/firefox file, the global override, Flatpak) and firefox_rows_per_installation_with_registry_precedence (x86-only install with a stale x64 file, registry over file).
One row per installation, from the policy that installation reads: snap Chromium /etc/chromium-browser only, Flatpak Chromium its org.chromium.Chromium.Extension.* extensions only, Firefox /etc/firefox/policies or the installation's own distribution file, Flatpak Firefox reported as not read. A browser with policy but no installation found is one row from all its locations. Windows Firefox reads the registry, then each installation's distribution file. browser_pacs is keyed by (device_id, browser, packaging). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

agentdesktop points AI tools at the LLM gateway, but the same models are one browser tab away. Enterprises steer browser AI traffic with a PAC file pushed by MDM or GPO, and nobody sees per device whether it landed. This adds that report. Related: #154 (security posture in the desktop view).
What it does
PAC absent,PAC found <url>, ordiffers(browsers disagree), read from Chrome, Edge, Chromium and Firefox machine policy: Linux policy files, Windows registry (HKCUonly when the daemon runs as the user). Shown inagentdesktop discover, the desktop app and the fleet UI. Nothing is configured.controller.yaml:Transport:
Inventory.browser_pacs = 3andInventory.pac_fetches = 4; older controllers ignore them. No new dependencies (Windows adds theWin32_System_Registryfeature ofwindows-sys).Tested
Notes for review
0005_browser_pacs.sql(rebased on add usage and cost metrics #160, which took0004).Possible follow-up
This is meant as a first PR. A second one could add the other half for fleets without MDM (Linux, Windows) and for standalone use: agentdesktop writing the browser PAC policy itself, with the existing managed-file ownership and removal, verified by this report. Happy to hear whether that would fit before starting on it.
🤖 Generated with Claude Code