[VPN 2.0] BoringTun 3p dependency: Rust crate and vendoring script (#36229)
[VPN 2.0] BoringTun 3p dependency: Rust crate and vendoring script. This is a multi-part change to add BoringTun dependency to the brave-core, to be used later in the VPN 2.0 architecture by a privileged helper on desktop OSes. The dependency is added to the existing VPN to ensure it actually gets built with the browser, but not yet distributed. Part 4: the actual Rust crate for BoringTun dependency, and an update script used to generate and manually update BoringTun's vendored dependencies.
This commit is contained in:
@@ -24,6 +24,8 @@ vendor/omaha/
|
||||
node_modules/
|
||||
patches/**/*.patchinfo
|
||||
/third_party/argon2/src
|
||||
/third_party/boringtun/.cargo-home/
|
||||
/third_party/boringtun/target/
|
||||
/third_party/brave-vpn-wireguard-nt-dlls/
|
||||
/third_party/brave-vpn-wireguard-tunnel-dlls/
|
||||
/third_party/bip39wally-core-native/
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
# Cargo configuration for the BoringTun vendored build.
|
||||
#
|
||||
# Build environment is isolated; the build never reads
|
||||
# or writes Chromium's shared Rust caches.
|
||||
|
||||
[source.crates-io]
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/cloudflare/boringtun.git?rev=cdf3b24558441ff4dc62bf5992484c5457a36760"]
|
||||
git = "https://github.com/cloudflare/boringtun.git"
|
||||
rev = "cdf3b24558441ff4dc62bf5992484c5457a36760"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source.vendored-sources]
|
||||
directory = "vendor/"
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
# Copyright (c) 2026 The Brave Authors. All rights reserved.
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# This crate exists ONLY to pin BoringTun as a git dependency at a specific
|
||||
# commit. We never build this crate ourselves -- the actual cdylib shipped
|
||||
# to consumers is `boringtun` itself.
|
||||
|
||||
[package]
|
||||
name = "boringtun_pin"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
license = "MPL-2.0"
|
||||
description = "Internal pin of cloudflare/boringtun for Brave's vendored cdylib build."
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["rlib"]
|
||||
|
||||
[dependencies]
|
||||
boringtun = { git = "https://github.com/cloudflare/boringtun.git", rev = "cdf3b24558441ff4dc62bf5992484c5457a36760", default-features = false, features = ["ffi-bindings"] }
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2026 The Brave Authors. All rights reserved.
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
//! Empty stub. This crate exists solely so Cargo accepts the manifest at
|
||||
//! ../Cargo.toml as a valid package, which in turn lets us pin `boringtun`
|
||||
//! as a git dependency in Cargo.lock.
|
||||
//!
|
||||
//! We never build this crate. The actual library shipped to consumers is
|
||||
//! the `boringtun` cdylib produced by `cargo build -p boringtun --release`.
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2026 The Brave Authors. All rights reserved.
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
"""
|
||||
Update the vendored sources under brave/third_party/boringtun/vendor/.
|
||||
|
||||
Run the update after bumping the pinned BoringTun rev in Cargo.toml
|
||||
(and any explicit `cargo update` you want for transitive deps). It:
|
||||
|
||||
1. Backs up reviewer-owned files (per-crate README.chromium,
|
||||
the vendor .clang-format).
|
||||
2. Wipes and re-runs `cargo vendor --locked`, capturing the source
|
||||
replacement snippet cargo prints.
|
||||
3. Compares the captured snippet against .cargo/config.toml so a SHA
|
||||
bump that would desync the two is caught explicitly.
|
||||
4. Restores the backed-up files.
|
||||
5. Removes known-safe stray binaries.
|
||||
6. Prints a list of any files in vendor/ that are excluded by git,
|
||||
which should be fixed before committing.
|
||||
|
||||
The script does NOT regenerate per-crate README.chromium files. Run
|
||||
create_licenses.py after this when you want that.
|
||||
"""
|
||||
|
||||
import difflib
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add script directory to path for brave_chromium_utils import
|
||||
_SCRIPT_DIR = os.path.join(os.path.dirname(__file__), '..', '..', 'script')
|
||||
sys.path.insert(0, os.path.abspath(_SCRIPT_DIR))
|
||||
|
||||
import brave_chromium_utils
|
||||
|
||||
PRESERVE_PATTERNS = [
|
||||
'vendor/.clang-format',
|
||||
'vendor/*/README.chromium',
|
||||
]
|
||||
|
||||
|
||||
def back_up_files(patterns):
|
||||
"""Read text files matching `patterns` into memory.
|
||||
|
||||
Text-only; if a binary pattern is ever added, switch to shutil.copy2
|
||||
to a temp dir.
|
||||
"""
|
||||
backed_up_files = {}
|
||||
for pattern in patterns:
|
||||
for path in Path().glob(pattern):
|
||||
print(f'Backing up: {path}')
|
||||
backed_up_files[str(path)] = path.read_text(encoding='utf-8')
|
||||
return backed_up_files
|
||||
|
||||
|
||||
def restore_files(backed_up_files):
|
||||
for path_str, content in backed_up_files.items():
|
||||
path = Path(path_str)
|
||||
print(f'Restoring: {path}')
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
# newline='\n' keeps line endings stable across Windows re-runs.
|
||||
with open(path, 'w', encoding='utf-8', newline='\n') as f:
|
||||
f.write(content)
|
||||
|
||||
|
||||
def clean_up_files(patterns):
|
||||
for pattern in patterns:
|
||||
for path in Path().glob(pattern):
|
||||
print(f'Removing: {path}')
|
||||
path.unlink()
|
||||
|
||||
|
||||
def compare_cargo_snippet(captured: str) -> None:
|
||||
"""Compare cargo vendor's printed config snippet against config.toml.
|
||||
|
||||
cargo vendor prints a [source.crates-io] / [source."git+..."] block
|
||||
that must be present in .cargo/config.toml for offline builds to
|
||||
resolve vendored sources. When the pinned git rev changes, the
|
||||
"git+..." key changes, and config.toml silently goes stale unless
|
||||
someone updates it.
|
||||
|
||||
We don't attempt to auto-patch config.toml (its structure varies
|
||||
across edits). Instead we print a unified diff and exit non-zero if
|
||||
any [source...] section from the snippet isn't already present in
|
||||
config.toml verbatim. A human applies the diff.
|
||||
"""
|
||||
config_path = Path('.cargo/config.toml')
|
||||
if not config_path.is_file():
|
||||
print(f'warning: {config_path} not found; cannot verify source '
|
||||
'replacement. Paste this snippet into it manually:\n')
|
||||
print(captured)
|
||||
sys.exit(1)
|
||||
|
||||
current = config_path.read_text(encoding='utf-8')
|
||||
|
||||
# Coarse but effective: every non-empty line of the snippet should
|
||||
# appear somewhere in the current config. We look for [source...]
|
||||
# section headers specifically since those are the load-bearing
|
||||
# parts.
|
||||
missing = []
|
||||
for line in captured.splitlines():
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('[source') and stripped not in current:
|
||||
missing.append(stripped)
|
||||
|
||||
if not missing:
|
||||
return
|
||||
|
||||
print('\nERROR: .cargo/config.toml is out of sync with what cargo '
|
||||
'vendor just produced. The following [source...] stanzas are '
|
||||
'missing from config.toml:\n')
|
||||
for line in missing:
|
||||
print(f' {line}')
|
||||
print('\nUnified diff hint (section headers only):\n')
|
||||
diff = difflib.unified_diff(
|
||||
current.splitlines(keepends=True),
|
||||
(current + '\n' + captured).splitlines(keepends=True),
|
||||
fromfile='.cargo/config.toml (current)',
|
||||
tofile='.cargo/config.toml (with snippet appended)',
|
||||
n=1)
|
||||
sys.stdout.writelines(diff)
|
||||
print('\nUpdate .cargo/config.toml to match what cargo vendor printed, '
|
||||
'then re-run this script.')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_excluded_files(vendor_dir: str) -> list[str]:
|
||||
"""
|
||||
Returns the list of files inside `vendor` that git would exclude
|
||||
on commit.
|
||||
"""
|
||||
result = subprocess.run(
|
||||
[
|
||||
"git",
|
||||
"-C",
|
||||
str(vendor_dir),
|
||||
"ls-files",
|
||||
"--cached",
|
||||
"--others",
|
||||
"--ignored",
|
||||
"--exclude-standard",
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
return result.stdout.splitlines()
|
||||
|
||||
|
||||
with brave_chromium_utils.sys_path('//tools/rust'):
|
||||
import update_rust
|
||||
CARGO = os.path.join(update_rust.RUST_TOOLCHAIN_OUT_DIR, 'bin',
|
||||
'cargo' + ('.exe' if sys.platform == 'win32' else ''))
|
||||
|
||||
|
||||
def main():
|
||||
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
backed_up_files = back_up_files(PRESERVE_PATTERNS)
|
||||
|
||||
# Isolated env. Mirrors build.py's isolation so re-vendor
|
||||
# and re-build behave consistently. `cargo vendor` doesn't compile
|
||||
# anything, but rustup's shim on PATH can still try to manage
|
||||
# toolchains when invoked, so we blind it.
|
||||
env = os.environ.copy()
|
||||
env['CARGO_HOME'] = str(Path('.cargo-home').resolve())
|
||||
for v in ('RUSTFLAGS', 'CARGO_BUILD_RUSTFLAGS', 'CARGO_BUILD_TARGET',
|
||||
'RUSTC_WRAPPER', 'RUSTC_WORKSPACE_WRAPPER', 'RUSTUP_HOME',
|
||||
'RUSTUP_TOOLCHAIN', 'RUSTUP_DIST_SERVER', 'RUSTUP_UPDATE_ROOT'):
|
||||
env.pop(v, None)
|
||||
|
||||
shutil.rmtree('vendor', ignore_errors=True)
|
||||
|
||||
# --locked makes lockfile drift an error rather than a silent update.
|
||||
# If you're re-vendoring because you intentionally changed deps, run
|
||||
# `cargo update` (or edit Cargo.toml rev) beforehand -- the new
|
||||
# Cargo.lock needs to be consistent before this script runs.
|
||||
print(f'Running cargo vendor...')
|
||||
result = subprocess.run([CARGO, 'vendor', '--locked'],
|
||||
env=env,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True)
|
||||
|
||||
restore_files(backed_up_files)
|
||||
shutil.rmtree('.cargo-home', ignore_errors=True)
|
||||
|
||||
# After restoring files and cleaning up, confirm the config is in
|
||||
# sync with what vendor printed. This runs last so a config mismatch
|
||||
# doesn't leave the tree half-updated -- vendor/ is fully written
|
||||
# and reviewer files are restored before we check.
|
||||
compare_cargo_snippet(result.stdout)
|
||||
|
||||
excluded_files = get_excluded_files('vendor')
|
||||
if excluded_files:
|
||||
print('\nWARNING: The following files in "vendor" are excluded by git '
|
||||
'and will not be committed. Please fix the exclusion rules '
|
||||
'before committing changes.')
|
||||
for f in excluded_files:
|
||||
print(f' {f}')
|
||||
print(f'Total: {len(excluded_files)} file(s).')
|
||||
|
||||
print('Update complete. Now run `create_licenses.py` to re-generate '
|
||||
'Chromium licensing information.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user