Add local channel install script for custom builds#19
Conversation
- timezone-spoofing.patch: per-context timezone via per-realm DateTimeInfo - geolocation-spoofing.patch: CAMOU_CONFIG backwards compatibility for geolocation - locale-spoofing.patch: add camoucfg LOCAL_INCLUDES - anti-font-fingerprinting.patch: add RoverfoxStorageManager exports to moz.build
- audio-fingerprint-manager.patch: per-context audio fingerprinting (all 6 API methods) - screen-spoofing.patch: per-context screen dimensions with global MaskConfig fallback - Disable webrtc-ip-spoofing.patch (will re-enable after fixing) - Remove screen-hijacker.patch (superseded by screen-spoofing.patch)
…urrency, and timezone (daijro#443) Fixes issue where global CAMOU_CONFIG settings for navigator.platform, navigator.hardwareConcurrency, and timezone were not applied in the main window Navigator (only WorkerNavigator was patched via fingerprint-injection.patch).
…ialized to prevent SIGSEGV
- navigator-spoofing.patch: Global config fixes for platform/hardwareConcurrency/timezone - timezone-spoofing.patch: Persistence across page navigation via SetNewDocument hook - audio-fingerprint-manager.patch: Full 6-method coverage with self-destruct pattern - screen-spoofing.patch: Per-context dimensions with self-destruct pattern - webrtc-ip-spoofing.patch: Re-enabled with getStats() sanitization + comprehensive IPv6 regex
…ion-spoofing CloverLabsAI#1 feat: timezone, geolocation, and locale spoofing patches
…fing CloverLabsAI#2 feat: per-context audio fingerprinting and screen spoofing patches
…-#443 CloverLabsAI#3 Fixed Issue daijro#443 + Detection Prevention + WebRTC Re-enablement
…oncurrency) with global fallback + docs update.
…nd hardwareConcurrency in workers
…pixels in canvas noise
…Media device-width/height
Upgraded tester
…cross-compatability-on-patches bidirectional patch
Installs build artifacts to browsers/local/ instead of overwriting official slots. Survives camoufox fetch. Handles permissions and version.json automatically.
📝 WalkthroughWalkthroughA new Bash script is added to install custom Camoufox builds into a local browser cache. The script resolves a target artifact ZIP, derives a version string, extracts the archive into a structured directory, applies permissions, generates version metadata, and updates the active browser configuration. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip CodeRabbit can use Trivy to scan for security misconfigurations and secrets in Infrastructure as Code files.Add a .trivyignore file to your project to customize which findings Trivy reports. |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
scripts/install-local-build.sh (3)
99-107: JSON generation via heredoc is fragile.If
BUILDcontains characters like"or\(from unusual filenames), the resulting JSON would be malformed. Consider usingjqorpython3for safe JSON generation.♻️ Safer JSON generation
# Write version.json -cat > "$INSTALL_DIR/version.json" <<VEOF -{ - "version": "$VERSION", - "build": "$BUILD", - "prerelease": false, - "local_build": true -} -VEOF +python3 -c " +import json +data = { + 'version': '''$VERSION''', + 'build': '''$BUILD''', + 'prerelease': False, + 'local_build': True +} +with open('$INSTALL_DIR/version.json', 'w') as f: + json.dump(data, f, indent=2) +"Or use
jq -nif available.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/install-local-build.sh` around lines 99 - 107, The heredoc writing version.json can produce invalid JSON if BUILD or VERSION contain quotes or backslashes; update the script (scripts/install-local-build.sh) to generate JSON using a JSON-safe tool instead of interpolation: replace the cat heredoc that writes "$INSTALL_DIR/version.json" with a jq -n invocation that sets "version","build","prerelease" and "local_build" via --arg, or run a short python3 -c snippet that constructs a dict with VERSION and BUILD and json.dump() to the target file; ensure you still write to the same path ($INSTALL_DIR/version.json) and preserve the boolean fields, and make the change around the existing variables VERSION, BUILD, and the version.json creation block.
31-31: Default artifact selection is hardcoded to macOS ARM64.The default glob pattern only matches
*-mac.arm64.zip, which limits usability for Linux users and Intel Mac users. Consider detecting the platform and adjusting the pattern:♻️ Suggested improvement for cross-platform default
ARTIFACT="${1:-}" if [[ -z "$ARTIFACT" ]]; then - ARTIFACT="$(ls -t "$REPO_ROOT"/dist/camoufox-*-mac.arm64.zip 2>/dev/null | head -1)" + # Detect platform for default artifact selection + if [[ "$(uname)" == "Darwin" ]]; then + if [[ "$(uname -m)" == "arm64" ]]; then + PATTERN="*-mac.arm64.zip" + else + PATTERN="*-mac.x86_64.zip" + fi + else + PATTERN="*-linux.*.zip" + fi + ARTIFACT="$(ls -t "$REPO_ROOT"/dist/camoufox-${PATTERN} 2>/dev/null | head -1)" if [[ -z "$ARTIFACT" ]]; then echo "No artifact found in dist/. Pass the zip path as an argument." exit 1🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/install-local-build.sh` at line 31, The ARTIFACT selection is hardcoded to macOS ARM64 by the ARTIFACT assignment; update the script (install-local-build.sh) to detect the current platform (e.g., via uname or OSTYPE) and set a platform-specific glob before the ls call (handle linux -> *-linux*.zip, mac arm64 -> *-mac.arm64.zip, mac intel -> *-mac.amd64.zip, etc.), then use that glob in the ARTIFACT assignment so the default artifact selection works across platforms and falls back gracefully if no match is found.
96-97: Overly broad permission setting.
chmod -R 755makes all files executable, including resources that shouldn't be (.json, images, etc.). Consider a more targeted approach that preserves proper file permissions.♻️ More precise permission handling
# Fix permissions (cp/unzip can strip executable bits) -chmod -R 755 "$INSTALL_DIR" +# Set directories to 755, files to 644 +find "$INSTALL_DIR" -type d -exec chmod 755 {} \; +find "$INSTALL_DIR" -type f -exec chmod 644 {} \; +# Restore executable bit on binaries +if [[ -d "$INSTALL_DIR/Camoufox.app" ]]; then + # macOS: framework binaries + find "$INSTALL_DIR/Camoufox.app/Contents/MacOS" -type f -exec chmod 755 {} \; +else + # Linux: main executable and libs + find "$INSTALL_DIR" -type f \( -name "camoufox*" -o -name "*.so" \) -exec chmod 755 {} \; +fi🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/install-local-build.sh` around lines 96 - 97, The current blanket chmod -R 755 "$INSTALL_DIR" makes every file executable; replace it with targeted permission fixes: set directories under INSTALL_DIR to 755, set regular files to 644, then re-enable execute on files that should be executable (e.g., those already marked executable or scripts detected via shebang) by setting them to 755; locate the existing chmod -R 755 "$INSTALL_DIR" line in the script and replace it with these targeted operations referencing INSTALL_DIR so non-executable resources (JSON, images, etc.) are not made executable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@scripts/install-local-build.sh`:
- Around line 91-94: The mv command using "$TMP_DIR"/* will skip hidden
dotfiles; update the else branch that moves artifacts so hidden files are
included by either enabling dotglob temporarily (shopt -s dotglob; mv
"$TMP_DIR"/* "$INSTALL_DIR/"; shopt -u dotglob to restore) or use the safe
directory-move pattern mv "$TMP_DIR"/. "$INSTALL_DIR/"; ensure you reference the
same TMP_DIR and INSTALL_DIR variables from this script when applying the
change.
- Around line 64-65: The script currently extracts VERSION from VERSION_BUILD
into the variable VERSION and computes BUILD from it, but it doesn't validate
that VERSION was successfully extracted; add a validation step after
VERSION="$(...)" to check if VERSION is non-empty and, if empty, print a clear
error (including the offending VERSION_BUILD value) and exit non‑zero so you
don't produce an invalid version.json. Only compute
BUILD="${VERSION_BUILD#${VERSION}-}" and continue when VERSION is valid;
otherwise abort early with the error message.
- Around line 116-123: The current inline Python here interpolates shell
variables into the code string (CONFIG_FILE and RELATIVE_PATH), risking syntax
breaks or injection; change the invocation so Python reads values from the
environment or from command-line arguments instead of embedding them.
Specifically, export or pass CONFIG_FILE and RELATIVE_PATH (or VERSION_BUILD) as
environment variables or use python -c with sys.argv, then in the Python code
(the block that opens and writes cfg and sets cfg['active_version']) reference
os.environ['CONFIG_FILE'] and os.environ['RELATIVE_PATH'] (or sys.argv[1]/[2])
rather than relying on shell interpolation; update the call site that currently
constructs the multiline string to pass these values safely.
---
Nitpick comments:
In `@scripts/install-local-build.sh`:
- Around line 99-107: The heredoc writing version.json can produce invalid JSON
if BUILD or VERSION contain quotes or backslashes; update the script
(scripts/install-local-build.sh) to generate JSON using a JSON-safe tool instead
of interpolation: replace the cat heredoc that writes
"$INSTALL_DIR/version.json" with a jq -n invocation that sets
"version","build","prerelease" and "local_build" via --arg, or run a short
python3 -c snippet that constructs a dict with VERSION and BUILD and json.dump()
to the target file; ensure you still write to the same path
($INSTALL_DIR/version.json) and preserve the boolean fields, and make the change
around the existing variables VERSION, BUILD, and the version.json creation
block.
- Line 31: The ARTIFACT selection is hardcoded to macOS ARM64 by the ARTIFACT
assignment; update the script (install-local-build.sh) to detect the current
platform (e.g., via uname or OSTYPE) and set a platform-specific glob before the
ls call (handle linux -> *-linux*.zip, mac arm64 -> *-mac.arm64.zip, mac intel
-> *-mac.amd64.zip, etc.), then use that glob in the ARTIFACT assignment so the
default artifact selection works across platforms and falls back gracefully if
no match is found.
- Around line 96-97: The current blanket chmod -R 755 "$INSTALL_DIR" makes every
file executable; replace it with targeted permission fixes: set directories
under INSTALL_DIR to 755, set regular files to 644, then re-enable execute on
files that should be executable (e.g., those already marked executable or
scripts detected via shebang) by setting them to 755; locate the existing chmod
-R 755 "$INSTALL_DIR" line in the script and replace it with these targeted
operations referencing INSTALL_DIR so non-executable resources (JSON, images,
etc.) are not made executable.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0628eaea-c0d8-4af1-aecd-bc3570e3c4a7
📒 Files selected for processing (1)
scripts/install-local-build.sh
| VERSION="$(echo "$VERSION_BUILD" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+')" | ||
| BUILD="${VERSION_BUILD#${VERSION}-}" |
There was a problem hiding this comment.
Missing validation when version extraction fails.
If VERSION_BUILD doesn't match the expected semver pattern (e.g., a malformed filename), grep returns an empty string. The script then proceeds with an empty VERSION and incorrect BUILD, resulting in an invalid version.json that could break the multiversion system.
🛡️ Proposed fix to validate VERSION extraction
VERSION="$(echo "$VERSION_BUILD" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+')"
+if [[ -z "$VERSION" ]]; then
+ echo "Error: Could not extract semver from version-build string: $VERSION_BUILD"
+ echo "Expected format: <major>.<minor>.<patch>-<build> (e.g., 146.0.1-my-fix.1)"
+ exit 1
+fi
BUILD="${VERSION_BUILD#${VERSION}-}"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| VERSION="$(echo "$VERSION_BUILD" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+')" | |
| BUILD="${VERSION_BUILD#${VERSION}-}" | |
| VERSION="$(echo "$VERSION_BUILD" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+')" | |
| if [[ -z "$VERSION" ]]; then | |
| echo "Error: Could not extract semver from version-build string: $VERSION_BUILD" | |
| echo "Expected format: <major>.<minor>.<patch>-<build> (e.g., 146.0.1-my-fix.1)" | |
| exit 1 | |
| fi | |
| BUILD="${VERSION_BUILD#${VERSION}-}" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/install-local-build.sh` around lines 64 - 65, The script currently
extracts VERSION from VERSION_BUILD into the variable VERSION and computes BUILD
from it, but it doesn't validate that VERSION was successfully extracted; add a
validation step after VERSION="$(...)" to check if VERSION is non-empty and, if
empty, print a clear error (including the offending VERSION_BUILD value) and
exit non‑zero so you don't produce an invalid version.json. Only compute
BUILD="${VERSION_BUILD#${VERSION}-}" and continue when VERSION is valid;
otherwise abort early with the error message.
| else | ||
| # Linux/Windows: move everything | ||
| mv "$TMP_DIR"/* "$INSTALL_DIR/" | ||
| fi |
There was a problem hiding this comment.
Hidden files (dotfiles) may not be moved.
The glob * doesn't match hidden files by default in bash. If the artifact contains dotfiles, they won't be copied to INSTALL_DIR. Consider using shopt -s dotglob temporarily or mv "$TMP_DIR"/. "$INSTALL_DIR/" pattern.
🔧 Suggested fix
else
# Linux/Windows: move everything
- mv "$TMP_DIR"/* "$INSTALL_DIR/"
+ # Use dotglob to include hidden files
+ shopt -s dotglob
+ mv "$TMP_DIR"/* "$INSTALL_DIR/"
+ shopt -u dotglob
fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| else | |
| # Linux/Windows: move everything | |
| mv "$TMP_DIR"/* "$INSTALL_DIR/" | |
| fi | |
| else | |
| # Linux/Windows: move everything | |
| # Use dotglob to include hidden files | |
| shopt -s dotglob | |
| mv "$TMP_DIR"/* "$INSTALL_DIR/" | |
| shopt -u dotglob | |
| fi |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/install-local-build.sh` around lines 91 - 94, The mv command using
"$TMP_DIR"/* will skip hidden dotfiles; update the else branch that moves
artifacts so hidden files are included by either enabling dotglob temporarily
(shopt -s dotglob; mv "$TMP_DIR"/* "$INSTALL_DIR/"; shopt -u dotglob to restore)
or use the safe directory-move pattern mv "$TMP_DIR"/. "$INSTALL_DIR/"; ensure
you reference the same TMP_DIR and INSTALL_DIR variables from this script when
applying the change.
| python3 -c " | ||
| import json, sys | ||
| with open('$CONFIG_FILE') as f: | ||
| cfg = json.load(f) | ||
| cfg['active_version'] = '$RELATIVE_PATH' | ||
| with open('$CONFIG_FILE', 'w') as f: | ||
| json.dump(cfg, f, indent=2) | ||
| " |
There was a problem hiding this comment.
Potential code injection via shell variable interpolation in Python.
The shell variables $CONFIG_FILE and $RELATIVE_PATH are interpolated directly into the Python code string. If VERSION_BUILD (and thus RELATIVE_PATH) contains single quotes or other special characters, it could break the Python syntax or enable code injection. While this is a local script, it's safer to pass values via environment variables.
🛡️ Safer approach using environment variables
if [[ -f "$CONFIG_FILE" ]]; then
# Use python for safe JSON manipulation
- python3 -c "
-import json, sys
-with open('$CONFIG_FILE') as f:
- cfg = json.load(f)
-cfg['active_version'] = '$RELATIVE_PATH'
-with open('$CONFIG_FILE', 'w') as f:
- json.dump(cfg, f, indent=2)
-"
+ CONFIG_FILE="$CONFIG_FILE" RELATIVE_PATH="$RELATIVE_PATH" python3 -c "
+import json, os
+config_file = os.environ['CONFIG_FILE']
+relative_path = os.environ['RELATIVE_PATH']
+with open(config_file) as f:
+ cfg = json.load(f)
+cfg['active_version'] = relative_path
+with open(config_file, 'w') as f:
+ json.dump(cfg, f, indent=2)
+"
else📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| python3 -c " | |
| import json, sys | |
| with open('$CONFIG_FILE') as f: | |
| cfg = json.load(f) | |
| cfg['active_version'] = '$RELATIVE_PATH' | |
| with open('$CONFIG_FILE', 'w') as f: | |
| json.dump(cfg, f, indent=2) | |
| " | |
| CONFIG_FILE="$CONFIG_FILE" RELATIVE_PATH="$RELATIVE_PATH" python3 -c " | |
| import json, os | |
| config_file = os.environ['CONFIG_FILE'] | |
| relative_path = os.environ['RELATIVE_PATH'] | |
| with open(config_file) as f: | |
| cfg = json.load(f) | |
| cfg['active_version'] = relative_path | |
| with open(config_file, 'w') as f: | |
| json.dump(cfg, f, indent=2) | |
| " |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/install-local-build.sh` around lines 116 - 123, The current inline
Python here interpolates shell variables into the code string (CONFIG_FILE and
RELATIVE_PATH), risking syntax breaks or injection; change the invocation so
Python reads values from the environment or from command-line arguments instead
of embedding them. Specifically, export or pass CONFIG_FILE and RELATIVE_PATH
(or VERSION_BUILD) as environment variables or use python -c with sys.argv, then
in the Python code (the block that opens and writes cfg and sets
cfg['active_version']) reference os.environ['CONFIG_FILE'] and
os.environ['RELATIVE_PATH'] (or sys.argv[1]/[2]) rather than relying on shell
interpolation; update the call site that currently constructs the multiline
string to pass these values safely.
Related Issue
N/A — feature request / discussion
Description
How do you lot manage local/custom builds?
I've been building Camoufox from source (patching things, testing fixes) and kept running into the same annoyance: after installing my custom build, a
camoufox fetchwould resetactive_versionand I'd be back on the upstream binary without realising. Cue 20 minutes of confused debugging before I notice the version string is wrong.The multiversion system already supports multiple repos under
browsers/— official, coryking, etc. So I started putting my local builds underbrowsers/local/and it works brilliantly:Each build gets a
version.jsonso the multiversion system picks it up:{ "version": "146.0.1", "build": "my-custom-build.1", "prerelease": false, "local_build": true }Then
active_versioninconfig.jsonpoints tobrowsers/local/146.0.1-my-custom-build.1and it survivescamoufox fetchbecause fetch only touches the official channel.This PR adds a small shell script (
scripts/install-local-build.sh) that automates this:dist/)browsers/local/<version-build>/version.jsonactive_versioncp -Rstrips executable bits problem)Usage
Discussion points
executable_pathworks but bypasses the Python package's version management entirelycamoufox install --local /path/to/artifact.zipwould be lovely. The multiversion system already handles the directory structure, it'd just need a new install pathlocal_build: trueflag in version.json — could be useful if the CLI wants to distinguish local builds from fetched ones (e.g. skip them duringcamoufox fetch --replace)Happy to rework this if there's a preferred approach. Just wanted to share what's been working for me.
Type of Change
Testing
Fingerprint Report
N/A — no changes to browser patches or fingerprint generation. This is purely a build management script.
Checklist
bash service_tests/run_tests.sh)Summary by CodeRabbit