Skip to content

Commit 90d76b0

Browse files
feat: add Nix flake and Devbox support
Adds a flake.nix wrapping the prebuilt release binaries (the same .deb/.zip artifacts nixpkgs brave uses) so the browser can be installed and run directly from GitHub: nix run github:brave/brave-browser nix profile install github:brave/brave-browser The flake reuses nixpkgs' brave packaging via overrideAttrs (swapping in upstream version + per-platform SRI hashes), avoiding ~150 lines of duplicated patchelf/wrapGApps/desktop-fixup logic. A scheduled lag-check workflow auto-bumps version + hashes and opens a PR when flake.nix falls behind the latest stable release. Supported platforms: x86_64-linux, aarch64-linux, x86_64-darwin, aarch64-darwin. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 3dcb571 commit 90d76b0

6 files changed

Lines changed: 263 additions & 0 deletions

File tree

.github/workflows/nix-release.yml

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
name: Update Nix flake
2+
3+
# Checks whether flake.nix lags behind the latest stable GitHub release. If it
4+
# does, prefetches the new release's per-platform SRI hashes, rewrites flake.nix,
5+
# and opens a PR.
6+
#
7+
# Runs on a schedule instead of release: published because:
8+
# 1. brave-browser releases are created by an external release pipeline (not
9+
# this repo's GITHUB_TOKEN), and
10+
# 2. a daily lag-check is fully decoupled from how releases are created and
11+
# needs no PAT.
12+
# The guard `github.repository == 'brave/brave-browser'` prevents the scheduled
13+
# job from running on forks.
14+
15+
on:
16+
schedule:
17+
- cron: "17 6 * * *"
18+
workflow_dispatch:
19+
20+
permissions:
21+
contents: write
22+
pull-requests: write
23+
24+
concurrency:
25+
group: nix-flake-release
26+
cancel-in-progress: true
27+
28+
jobs:
29+
update-flake:
30+
name: Bump flake version + hashes if lagging
31+
runs-on: ubuntu-latest
32+
if: github.repository == 'brave/brave-browser'
33+
steps:
34+
- name: Checkout
35+
uses: actions/checkout@v6
36+
with:
37+
persist-credentials: false
38+
39+
- name: Install Nix
40+
uses: cachix/install-nix-action@v31
41+
42+
- name: Check for lag and rewrite flake.nix
43+
env:
44+
# system|asset-filename-template — one per line. The template uses
45+
# {VERSION} as a placeholder for the version (without the leading v).
46+
# Brave's asset naming differs between Linux (.deb) and Darwin (.zip).
47+
ASSET_MAP: |
48+
x86_64-linux|brave-browser_{VERSION}_amd64.deb
49+
aarch64-linux|brave-browser_{VERSION}_arm64.deb
50+
x86_64-darwin|brave-v{VERSION}-darwin-x64.zip
51+
aarch64-darwin|brave-v{VERSION}-darwin-arm64.zip
52+
run: |
53+
set -euo pipefail
54+
tag=$(curl -fsSL -H "Accept: application/vnd.github+json" \
55+
"https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/latest" \
56+
| python3 -c 'import json,sys; print(json.load(sys.stdin)["tag_name"])')
57+
latest="${tag#v}"
58+
current=$(python3 -c 'import re; s=open("flake.nix").read(); m=re.search(r"version = \"([^\"]*)\";", s); print(m.group(1))')
59+
echo "flake.nix version: $current | latest release: $latest (tag $tag)"
60+
if [ "$current" = "$latest" ]; then
61+
echo "flake.nix is up to date; nothing to do."
62+
echo "LAGGING=no" >> "$GITHUB_ENV"
63+
exit 0
64+
fi
65+
echo "LAGGING=yes" >> "$GITHUB_ENV"
66+
echo "VERSION=$latest" >> "$GITHUB_ENV"
67+
export TAG="$tag"
68+
python3 <<'PYEOF'
69+
import os, re, subprocess
70+
tag = os.environ["TAG"]
71+
version = tag.lstrip("v")
72+
repo = os.environ["GITHUB_REPOSITORY"]
73+
asset_map = {}
74+
for line in os.environ["ASSET_MAP"].splitlines():
75+
line = line.strip()
76+
if not line or line.startswith("#"):
77+
continue
78+
sys_, tmpl = line.split("|", 1)
79+
asset_map[sys_.strip()] = tmpl.strip()
80+
src = open("flake.nix").read()
81+
src, n = re.subn(r'version = "[^"]*";', f'version = "{version}";', src, count=1)
82+
if n != 1:
83+
raise SystemExit('could not find version = "..." in flake.nix')
84+
for sys_, tmpl in asset_map.items():
85+
filename = tmpl.replace("{VERSION}", version)
86+
url = f"https://github.com/{repo}/releases/download/{tag}/{filename}"
87+
out = subprocess.check_output(
88+
["nix", "store", "prefetch-file", "--json", "--hash-type", "sha256", url])
89+
import json
90+
sri = json.loads(out)["hash"]
91+
# Replace the hash line within this system's asset block.
92+
pat = re.compile(r'("' + re.escape(sys_) + r'" = \{[^}]*\})', re.S)
93+
def repl(m):
94+
b = m.group(1)
95+
b = re.sub(r'hash = "[^"]*";', f'hash = "{sri}";', b, count=1)
96+
return b
97+
src, n = pat.subn(repl, src, count=1)
98+
if n != 1:
99+
raise SystemExit(f"could not find assets block for {sys_} in flake.nix")
100+
open("flake.nix", "w").write(src)
101+
print(f"bumped flake.nix to {version}: {list(asset_map)}")
102+
PYEOF
103+
104+
- name: Open PR
105+
if: env.LAGGING == 'yes'
106+
uses: peter-evans/create-pull-request@v7
107+
with:
108+
commit-message: "chore(nix): bump flake to v${{ env.VERSION }}"
109+
title: "chore(nix): bump flake to v${{ env.VERSION }}"
110+
branch: chore/nix-flake-v${{ env.VERSION }}
111+
base: master
112+
body: |
113+
Auto-generated by the `Update Nix flake` workflow (daily lag-check).
114+
The latest stable GitHub release is v${{ env.VERSION }} but `flake.nix` was
115+
pinned to an older version. This PR bumps `version` and refreshes the per-platform SRI
116+
hashes by prefetching the new release assets.
117+
118+
Note: PRs opened by `GITHUB_TOKEN` do not trigger downstream workflow runs (e.g. CI),
119+
so this PR will show no checks. The diff is a 5-line hash bump with no source changes —
120+
safe to merge as-is.

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
.Trashes
77
._*
88

9+
# nix
10+
/result
11+
/result-*
12+
913
# editors
1014
CMakeLists.txt
1115
cmake-build-debug

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,31 @@ This repository is not needed for building the browser and only holds issues, re
1313

1414
You can [visit our website](https://brave.com/download) to get the latest stable release.
1515

16+
### Nix
17+
18+
The repository provides a Nix flake that wraps the prebuilt release binary (the
19+
same prebuilt `.deb`/`.zip` artifacts that
20+
[nixpkgs `brave`](https://github.com/NixOS/nixpkgs/blob/nixos-26.05/pkgs/by-name/br/brave/make-brave.nix)
21+
uses). It is not built from source.
22+
23+
```bash
24+
# Run without installing
25+
nix run github:brave/brave-browser
26+
27+
# Install into your profile
28+
nix profile install github:brave/brave-browser
29+
```
30+
31+
The flake tracks the default branch and is auto-bumped to the latest stable
32+
release by a daily [workflow](.github/workflows/nix-release.yml), so
33+
`github:brave/brave-browser` always serves the current release. (Release tags
34+
are cut before the bump lands, so `github:brave/brave-browser/vX.Y.Z` is not a
35+
valid pin — use the nixpkgs package or a specific commit SHA if you need
36+
reproducibility.)
37+
38+
Supported platforms: `x86_64-linux`, `aarch64-linux`, `x86_64-darwin`,
39+
`aarch64-darwin`.
40+
1641
## Contributing
1742

1843
Please see the [contributing guidelines](https://github.com/brave/brave-core/blob/master/CONTRIBUTING.md).

devbox.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.12.0/.schema/devbox.schema.json",
3+
"packages": [
4+
"nix"
5+
],
6+
"shell": {
7+
"init_hook": [
8+
"echo 'Welcome to the brave-browser devbox. Use nix run .#brave to test the flake.'"
9+
],
10+
"scripts": {
11+
"check": "nix flake check --no-build",
12+
"build": "nix build .#brave --no-link",
13+
"run": "nix run .#brave -- --version"
14+
}
15+
}
16+
}

flake.lock

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
{
2+
description = "Brave browser — privacy-oriented browser (prebuilt binaries from upstream releases)";
3+
4+
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
5+
6+
outputs = { self, nixpkgs }:
7+
let
8+
# Bumped by .github/workflows/update-brave-hashes.yml (daily lag-check).
9+
# Tag-pinning does NOT work for this flake: the hash bump lands AFTER the
10+
# upstream release tag is cut, so github:brave/brave-browser/vX.Y.Z may
11+
# predate the flake.nix update. Pin the flake ref or commit instead.
12+
version = "1.92.134";
13+
14+
assets = {
15+
x86_64-linux = {
16+
url = "https://github.com/brave/brave-browser/releases/download/v${version}/brave-browser_${version}_amd64.deb";
17+
hash = "sha256-T3A/ejmLkIRYGWc8GXQmvIAZvQFwYEyhQJxssNDalhQ=";
18+
};
19+
aarch64-linux = {
20+
url = "https://github.com/brave/brave-browser/releases/download/v${version}/brave-browser_${version}_arm64.deb";
21+
hash = "sha256-qo40t+PGl1RO2ajJ2Hev4G1FWvzTx7Ak5CVxjdxabLI=";
22+
};
23+
x86_64-darwin = {
24+
url = "https://github.com/brave/brave-browser/releases/download/v${version}/brave-v${version}-darwin-x64.zip";
25+
hash = "sha256-IrhvRVFZGLoGSVNy10ppFL9rEy7MRTb/HIhzspDsrs8=";
26+
};
27+
aarch64-darwin = {
28+
url = "https://github.com/brave/brave-browser/releases/download/v${version}/brave-v${version}-darwin-arm64.zip";
29+
hash = "sha256-K1p5mAYfEDJNZFSmoOQV7kHNsA5RQuyUl3T2KVsNcbw=";
30+
};
31+
};
32+
33+
systems = builtins.attrNames assets;
34+
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
35+
36+
# Reuse nixpkgs' brave packaging (patchelf, wrapGAppsHook3, desktop-file
37+
# fixup, icon symlinks, OutdatedBuildDetector disable, darwin .app install)
38+
# by overriding only version + src to track upstream releases. Vendoring
39+
# make-brave.nix would duplicate ~150 lines that upstream already maintains.
40+
braveFor = system:
41+
let
42+
pkgs = nixpkgs.legacyPackages.${system};
43+
asset = assets.${system};
44+
in
45+
pkgs.brave.overrideAttrs (old: {
46+
inherit version;
47+
src = pkgs.fetchurl { inherit (asset) url hash; };
48+
meta = old.meta // {
49+
changelog = "https://github.com/brave/brave-browser/blob/master/CHANGELOG_DESKTOP.md#"
50+
+ nixpkgs.lib.replaceStrings [ "." ] [ "" ] version;
51+
};
52+
});
53+
in
54+
{
55+
packages = forAllSystems (system: rec {
56+
brave = braveFor system;
57+
default = brave;
58+
});
59+
60+
apps = forAllSystems (system: {
61+
brave = {
62+
type = "app";
63+
program = nixpkgs.lib.getExe (braveFor system);
64+
};
65+
default = {
66+
type = "app";
67+
program = nixpkgs.lib.getExe (braveFor system);
68+
};
69+
});
70+
};
71+
}

0 commit comments

Comments
 (0)