You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Merge PR #25: Brave Origin on Linux - detection, proven policy dir, inert rows for what Origin compiles out
Origin reads /etc/brave/policies/managed like regular Brave (verified on a real install); detected as origin / origin-beta / origin-nightly on Arch, deb, rpm and PATH; the 13 rows Origin compiles out are shown inert on Origin-only machines and stay live beside a regular Brave. Linux only. TESTING-brave-origin.md carries the remaining per-machine checks.
Copy file name to clipboardExpand all lines: AUDIT.md
+32-1Lines changed: 32 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -35,6 +35,37 @@ against them instead of re-verifying every key from scratch. A row marked
35
35
original wording is kept because the *reasoning* is the audit trail, and
36
36
knowing why a decision was made — and what changed under it — is the point.
37
37
38
+
### 2026-09-11 — targeted: Brave Origin on Linux — detection added, policy directory proven
39
+
40
+
**Not a policy pass.** Issue #13 asked for Brave Origin support; the July
41
+
answer declined on two doubts — that Origin might not read
42
+
`/etc/brave/policies`, and that most rows would be dead there. Both
43
+
re-examined on the maintainer's machine with Origin installed (CachyOS,
44
+
`brave-origin-bin 1:1.94.121-1`; the AUR PKGBUILD carries
45
+
`Maintainer: brave <aur-release@brave.com>`, and CachyOS mirrors it).
46
+
Linux only: Origin is a paid upgrade elsewhere and the Windows and macOS
47
+
scripts are untouched.
48
+
49
+
-**Read at:** brave-core `v1.94.121` (`e894693`), and the shipped artifacts rather than the docs about them — the AUR install of `brave-origin-1.94.121-linux-amd64.zip`, `brave-origin_1.94.121_amd64.deb` (130,821,188 B, sha256 `0f76ec5f…1495`, the same bytes the apt repo's `Packages` index lists) and `brave-origin-1.94.121-1.x86_64.rpm` (132,609,317 B, sha256 `9844f1b9…6b3e`, same as the rpm repo's `primary.xml`), both fetched from the GitHub release and unpacked with bsdtar; the Flathub API and `flathub/com.brave.Browser`; the Snap store API; brave.com/origin/linux (stable, beta, nightly) and dl.brave.com/install.sh. Seven readers, one per packaging or source modality, two refuters each — one re-reading every cited source, one re-deriving each claim by a different method — with the refuters' corrections folded in before anything reached this file.
50
+
- **The policy directory is `/etc/brave/policies/managed`, Origin included — proven four ways.** (1) Source: `app/brave_main_delegate.cc:166-170` overrides `chrome::DIR_POLICY_FILES` to `/etc/brave/policies` under `IS_POSIX && !IS_MAC` with no branding or channel guard, and Chromium's `config_dir_policy_loader.cc`, which brave-core does not patch, appends `managed` and `recommended`. (2) Binary: `strings` on the Origin ELF — byte-identical across the zip, the deb and the rpm, sha256 `e2061ff6…05c5`, 301,268,288 B — holds `/etc/brave/policies` and `BraveSoftware/Brave-Origin` and no `/etc/brave-origin` string at all. (3) Runtime: the running Origin process's inotify watches, read from `/proc/<pid>/fdinfo`. Before `/etc/brave` existed they sat on `/` and `/etc` and not on the existing `/etc/chromium` — Chromium's `FilePathWatcher` parked on the deepest existing ancestor of `/etc/brave/policies/managed`, and `/etc/chromium/policies` would have parked it one level lower. After the directory was created, a fresh Origin process watched `/etc/brave`, `/etc/brave/policies` and `/etc/brave/policies/managed` themselves. (4) End to end: a managed `ExtensionInstallForcelist` written to that directory installed all six listed extensions into `~/.config/BraveSoftware/Brave-Origin/Default`, each recorded in `Preferences` as `extensions.settings.<id>.location = 7` — `ManifestLocation::kExternalPolicyDownload` — with no browser restart. And with this tool itself: `--import` of the Brave Origin preset wrote the fifteen keys to `slimbrave.json`, and `chrome://policy` in a throwaway Origin profile — read over the DevTools pipe, since the page's shadow DOM defeats `--dump-dom` — listed every one as `Platform`, `Machine`, `Mandatory`, status `OK`; `--export` round-tripped them and `--reset` removed only its own file. The "untested" in the July comment is closed.
51
+
-**`/etc/brave-origin` is a red herring.**`chromium_src/chrome/installer/linux/common/brave-origin/chromium-browser.info` sets `ENROLLMENTDIR=/etc/brave-origin/policies/enrollment` — Chrome Browser Cloud Management's enrollment-token directory, touched only by the deb and rpm post-install scripts and only when `/etc/default/brave-origin` opts into the device-trust key. Managed policy never reads it, and the binary never names it. Do not write policies there.
52
+
-**Where Origin lives on Linux**, every row from the artifact:
53
+
54
+
| Packaging | Install dir | Binary | Launcher | On `PATH`| Profile |
55
+
|---|---|---|---|---|---|
56
+
| Arch: AUR `brave-origin-bin` (CachyOS repo mirrors it); unpacks the upstream zip |`/opt/brave-origin-bin/`|`brave`|`brave-origin`, Chromium's stock wrapper |`/usr/bin/brave-origin`, a bash script that reads `~/.config/brave-origin-flags.conf` and execs the launcher |`~/.config/BraveSoftware/Brave-Origin`|
57
+
| deb: `brave-origin`, from the same `brave-browser-apt-release.s3.brave.com` repo as `brave-browser`; no Conflicts, so both co-install |`/opt/brave.com/brave-origin/`|`brave`|`brave-origin`|`/usr/bin/brave-origin-stable`, a shipped symlink; bare `/usr/bin/brave-origin` comes from `update-alternatives` in postinst (priority 201) | same |
58
+
| rpm: `brave-origin`, from `brave-browser-rpm-release.s3.brave.com` (dnf, zypper, rpm-ostree; the bucket also serves `brave-browser-origin.repo` plus `-beta` and `-nightly` variants, byte-identical to `brave-browser.repo`) |`/opt/brave.com/brave-origin/`|`brave`|`brave-origin`|`/usr/bin/brave-origin-stable`, shipped; bare `/usr/bin/brave-origin` is a `%ghost` that `%post`'s `update-alternatives` creates (priority 200) | same |
59
+
| Beta, Nightly: `brave-origin-beta`, `brave-origin-nightly` (the apt and rpm beta and nightly repos; AUR `brave-origin-beta-bin` and `-nightly-bin` repackage the deb) |`/opt/brave.com/brave-origin-beta/`, `…-nightly/`|`brave`|`brave-origin-beta`, `-nightly`|`/usr/bin/brave-origin-beta`, `-nightly`, direct symlinks |`Brave-Origin-Beta`, `Brave-Origin-Nightly` — the `-Beta`/`-Nightly` suffixes of `brave_channel_info_posix.cc:27-38`|
60
+
| Flatpak | none. Flathub has only `com.brave.Browser`; every Origin-shaped id 404s; `flathub/com.brave.Browser` has no Origin branch, issue or PR across 994 of them; brave/brave-browser #55196 asking for one is open and unanswered. Brave's own RDN for Origin, `com.brave.Origin` (the `.info` file), is used only by a one-star unofficial bundle with no remote. Nothing to probe. |||||
61
+
| Snap | none. The store has `brave` only, publisher Brave Software, verified; `brave-origin` is `resource-not-found`, and the `brave` snap's channel map is `latest/{stable,candidate,beta,edge}` with no Origin track. Its rev-678 squashfs was downloaded and listed: `opt/brave.com/brave/` only, and its binary carries `BraveSoftware/Brave-Browser` and not `Brave-Origin` — regular Brave. `brave-core`'s `snapcraft.yaml` dumps the `brave-browser` deb and never mentions Origin. Side finding, likely rather than confirmed: snapd's `browser-support` interface grants the snap `/etc/opt/chrome` and `/etc/chromium` and nothing under `/etc/brave`, which is the mechanism behind this tool's long-standing Snap warning. |||||
62
+
63
+
- **Names the detector relies on.** Profile: `chromium_src/chrome/common/chrome_paths_linux.cc:26-27` — `BraveSoftware/Brave-Origin` plus the channel suffix under `IS_BRAVE_ORIGIN_BRANDED`. Package: `build/config.gni:71-79` (`brave_linux_package_name = "brave-origin"`) and `installer/linux/sources.gni:8-9`. Desktop ids: `chromium_src/chrome/common/channel_info_posix.cc:64-74` — `brave-origin[-beta|-nightly|-dev].desktop`, `StartupWMClass=brave-origin`. Processes: the browser's comm is `brave` on every packaging (its `exe` sits under the install dir), so the stable row's `pgrep -x brave` already sees a running Origin; the launcher's bash process stays alive around it — brave-core's `chrome-installer-linux-common-wrapper.patch` drops Chromium's `exec -a` — with the comm it was started by — `brave-origin` from the AUR wrapper, `brave-origin-st` (comm's 15-character cap) from the deb/rpm desktop file's `/usr/bin/brave-origin-stable`; the new rows carry `brave-origin` as `process_name`, and the profile's `SingletonLock` covers the truncated case as it does for every channel whose name overruns the cap. The shipped man page's `$HOME/.config/brave-origin` is Chromium template text and wrong.
64
+
-**Detection shipped.**`LINUX_CHANNELS` gains `origin`, `origin-beta` and `origin-nightly` — no `origin-dev`: `channel_info_posix.cc` names it, nothing publishes it. `detect_brave()` probes `/opt/brave-origin-bin/brave`, `/opt/brave.com/brave-origin/brave-origin`, `/opt/brave.com/brave-origin/brave`, then `brave-origin-stable` and `brave-origin` on `PATH`, and reports `arch (Brave Origin)`, `deb/rpm (Brave Origin)`, `unknown (Brave Origin)`, or `arch: Stable, Origin` beside a regular Brave; beta and nightly Origin are found by profile directory or launcher, as Brave's own are. Origin's profiles join prefs repair and the running check, and `--channels` accepts the three ids. A `notes` list — a new key beside `warnings`, so the status line keeps the success colour — says on launch that policies apply and the rows Origin removes are inert, or, beside a regular Brave, that every row stays live. Both scripts, README, and the tests.
65
+
-**Regular Brave in "Origin mode" is still regular Brave.** On Linux the free tier is a click at `brave://settings/origin` (`components/brave_origin/brave_origin_settings_handler_impl.cc`, `ProceedFree` → `BraveOriginService::AcceptFreeTier`); it sets `brave.origin.free_tier_accepted` and `policies_were_enforced` in `Local State` and keeps its toggles in `brave.brave_origin.policies` there. Same binary, same `Brave-Browser` profile, every feature still compiled in — the Flatpak included. Nothing for the detector to do, and every row is live.
66
+
-**A managed file outranks Origin's own layer; it cannot revive what Origin compiled out.** Origin enforces its debloat through two `ConfigurationPolicyProvider`s (`BraveBrowserPolicyProvider`, `BraveProfilePolicyProvider`) that emit `POLICY_SOURCE_BRAVE` at `kBravePriority`, which brave-core inserts below `kEnterpriseDefault` — the lowest browser-policy priority there is, and its own test `BravePolicySourceTest.BraveHasLowerPriority` says so. `PolicyMap::MergeFrom` resolves on (level, priority), so a mandatory platform entry from `/etc/brave/policies/managed` wins every conflict: `{"BraveP3AEnabled": true}` there would switch P3A back on in Origin. Nothing this tool writes points that way, and for the compiled-out features the question is moot — no handler, no pref, no feature to switch.
67
+
- **Which rows are dead on Origin — the inventory, and what the tool does with it.** Thirteen keys. Each one's entry in `browser/policy/brave_simple_policy_map.h` sits under a `BUILDFLAG` — `ENABLE_BRAVE_REWARDS`, `ENABLE_BRAVE_WALLET`, `ENABLE_TOR`, `ENABLE_BRAVE_VPN`, `ENABLE_AI_CHAT`, `ENABLE_LOCAL_AI`, `ENABLE_PLAYLIST`, `ENABLE_WEB_DISCOVERY`, `ENABLE_BRAVE_NEWS`, `ENABLE_BRAVE_TALK`, `ENABLE_SPEEDREADER`, `ENABLE_BRAVE_WAYBACK_MACHINE`, `ENABLE_EMAIL_ALIASES` — and every one of those flags is `… && !is_brave_origin_branded` in its `components/<feature>/…/buildflags.gni` (`enable_brave_vpn` already lacked `is_linux`). The keys: `BraveRewardsDisabled`, `BraveWalletDisabled`, `TorDisabled`, `BraveVPNDisabled`, `BraveAIChatEnabled`, `BraveLocalAIEnabled`, `BravePlaylistEnabled`, `BraveWebDiscoveryEnabled`, `BraveNewsDisabled`, `BraveTalkDisabled`, `BraveSpeedreaderEnabled`, `BraveWaybackMachineEnabled`, `EmailAliasesEnabled`. Confirmed on the shipped binary: the target prefs are not registered at all (a `chrome://prefs-internals` dump of a throwaway profile has nothing under `brave.wallet`, `brave.ai_chat`, `brave.playlist`, `brave.speedreader`, `brave.news`, `brave.talk`, `brave.email_aliases`, `brave.web_discovery` or `brave.wayback`, and `Local State` no `tor.*`), and injecting every SlimBrave Brave key as a mandatory machine platform policy through `chrome://policy/test` made none of those thirteen prefs managed — while `brave://policy` listed each as applied, status OK, the same blind spot the `BraveVPNDisabled` row already documents. `BraveP3AEnabled` and `BraveStatsPingEnabled` are the other two of the preset's fifteen: unguarded, dispatched, and Origin's own provider sets them `false` at the lowest priority, so a managed `false` is redundant but pins them. `MetricsReportingEnabled` is live too, against a default Origin already forces to `false`. Everything else — the five unguarded Brave privacy toggles, both Shields lists, the `DefaultBrave*` content settings, every Chromium key — is live. The 2026-09-07 parity bullet under Cross-cutting describes the metadata tables as compiled into regular Brave; on the branded build only those two of the fifteen are enforced by Origin itself. **In the tool:** `ORIGIN_BUILTIN_KEYS` in both scripts carries the thirteen. When every detected Brave is Origin (`is_origin_only`), `build_rows` marks them inert: drawn `[-]`, dimmed, `(built into Origin)`, out of the header counts, untoggleable, never written or exported, unticked on sync so the next Apply drops a stale key, and an import that names them reports `13 keys built into Brave Origin left unmanaged`. Beside any regular Brave every row stays live, because the one file serves both — and "beside" is judged on the whole machine: a regular Brave found by package, Flatpak, Snap or launcher but never started still gets its record next to Origin's, and every record carries the machine-wide `origin_only` verdict, so `--channels origin` cannot narrow a mixed machine into an Origin-only one. Under `--policy-file` the rows come from the override record and stay live, and the launch note stays off.
68
+
38
69
### 2026-09-07 — all 77 keys re-verified against the shipping tag; one dead key found
39
70
40
71
-**Read at:** Chromium **152.0.7977.83** — the tag brave-core `v1.94.121` pins, i.e. the browser installed here — policy_definitions tree `04b4c4f` (1,518 YAML, 66 group files, **1,452 policies**), and `chromium/main``34e8449` (tree `2546ed1`; 1,525 YAML, 67 group files, **1,458 policies**). brave-core `v1.94.121` (tag `76a06f2` → `e894693`) and master `20512a1`, **30 policies each**, with the `1.95.x` and `1.96.x` release branches for probes.
@@ -212,7 +243,7 @@ case.
212
243
## Cross-cutting checks
213
244
214
245
-**Windows registry path** — `HKLM:\SOFTWARE\Policies\BraveSoftware\Brave` confirmed correct against Brave's official Group Policy documentation (`BraveSoftware\Brave-Browser` is the *install* dir name, not the policy path). **Source-confirmed 2026-09-07:** Chromium generates the key — `components/policy/tools/generate_policy_source.py` emits `kRegistryChromePolicyKey` from `CHROMIUM_POLICY_KEY` for non-Google branding, and brave-core's `chromium_src/components/policy/tools/generate_policy_source.py` overrides that constant to `SOFTWARE\Policies\BraveSoftware\Brave`; `chrome_browser_policy_connector.cc` hands the constant to `PolicyLoaderWin`, which brave-core does not touch. The key carries no channel or Brave Origin suffix (`install_static` varies only the install-dir names), so the same path serves stable, beta, nightly and Origin.
215
-
-**Linux policy directory** — `/etc/brave/policies/managed` (2026-09-07). Chromium's default is `/etc/chromium/policies` (`policy_paths.cc`); brave-core does not patch that file — `app/brave_main_delegate.cc` overrides `chrome::DIR_POLICY_FILES` to `/etc/brave/policies` at startup under `IS_POSIX && !IS_MAC`, unconditionally, and Chromium's `config_dir_policy_loader.cc` appends `managed` / `recommended`. Channel- and Origin-independent. `slimbrave-mac.py`'s comment citing `brave_main_delegate.cc` is correct.
246
+
-**Linux policy directory** — `/etc/brave/policies/managed` (2026-09-07). Chromium's default is `/etc/chromium/policies` (`policy_paths.cc`); brave-core does not patch that file — `app/brave_main_delegate.cc` overrides `chrome::DIR_POLICY_FILES` to `/etc/brave/policies` at startup under `IS_POSIX && !IS_MAC`, unconditionally, and Chromium's `config_dir_policy_loader.cc` appends `managed` / `recommended`. Channel- and Origin-independent. `slimbrave-mac.py`'s comment citing `brave_main_delegate.cc` is correct.**Confirmed at runtime on Brave Origin 1.94.121, 2026-09-11** — inotify watches on the directory itself and a managed policy seen taking effect; see that pass.
216
247
-**macOS managed-preferences plists** — `com.brave.Browser` / `.beta` / `.nightly` (2026-09-07). Chromium's `chrome_browser_policy_connector.cc` uses the running app's own bundle id for non-Google branding, and `policy_loader_mac.mm` builds `/Library/Managed Preferences/<bundle id>.plist` from it; the ids come from brave-core `app/theme/brave/BRANDING*` via `branding.gni`. `MAC_CHANNELS` matches those files exactly; a Dev channel (`com.brave.Browser.dev`) exists and is not listed — low priority.
217
248
- **`ForUrls` wildcard patterns** — Brave's docs say "wildcards are not supported", meaning patterns like `*.example.com`. The scheme-wide patterns SlimBrave uses (`https://*`, `http://*`) are valid ContentSettingsPattern syntax and are applied correctly. They are **not** written to your profile: `PolicyProvider` keeps policy content settings in an in-memory `OriginValueMap` (`content_settings_policy_provider.h`) and never writes them back to `Preferences`. The `profile.content_settings.exceptions.braveShields` entries the repair logic in all three scripts scrubs were written by **pre-1.x SlimBrave**, which set them as ordinary user content settings; the repair undoes that old damage rather than anything current Brave does. **Re-verified 2026-09-07** at 152.0.7977.83 (`PolicyProvider` is read-only: `SetWebsiteSetting` returns false, `ClearAllContentSettingsRules` is empty) — and the Shields keys take the same in-memory path, wired by brave-core's `patches/components-content_settings-core-browser-content_settings_policy_provider.cc.patch` and its `rewrite/…content_settings_policy_provider.cc.yaml` twin, both present at the tag and on master.
218
249
- **Ad Block Only Mode writes policies too (2026-09-07).** brave-core `v1.94.121` ships `components/brave_policy/ad_block_only_mode/ad_block_only_mode_policy_manager.cc`: when `brave_shields::features::kAdblockOnlyMode` is on **and** the local-state opt-in `kAdBlockOnlyModeEnabled` is true, `BraveProfilePolicyProvider` injects thirteen values at `MANDATORY / USER / POLICY_SOURCE_BRAVE` — `BlockThirdPartyCookies=false`, `DefaultCookiesSetting=1`, `DefaultJavaScriptSetting=1`, `DefaultBraveAdblockSetting=2`, `DefaultBraveFingerprintingV2Setting=1`, `DefaultBraveHttpsUpgradeSetting=3`, `DefaultBraveReferrersSetting=1`, `DefaultBraveRemember1PStorageSetting=1`, and `BraveReduceLanguageEnabled` / `BraveDeAmpEnabled` / `BraveDebouncingEnabled` / `BraveTrackingQueryParametersFilteringEnabled` / `BraveGlobalPrivacyControlEnabled` all `false` — eleven of them keys this project writes, mostly to the opposite value. The feature is off at `v1.94.121` and `1.95.x` and **on by default on desktop from `1.96.x`**; the opt-in pref defaults to false, so nothing happens until a user turns the mode on in Shields. Precedence is settled in SlimBrave's favour: brave-core's `chromium_src/components/policy/core/common/policy_types.h` inserts `kBravePriority` as the **lowest** browser priority, below `kEnterpriseDefault`, and `policy_map.cc` maps `POLICY_SOURCE_BRAVE` to it; a registry or policy-file value is `MANDATORY / kPlatformMachine` and wins in `EntryHasHigherPriority`. The loser is kept as a conflict, so from 1.96 a user with the mode on will see `IDS_POLICY_CONFLICT_DIFF_VALUE` warnings on `brave://policy` for those keys. No script change; worth a README sentence when 1.96 ships.
0 commit comments