Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
9dd3b70
wip: adding camoufox and integrating js
JWriter20 Aug 3, 2026
2165f34
feat(webgl): noise WebGL readback under EfficientCanvasRandomization
JWriter20 Aug 7, 2026
abf5e42
feat(canvas): seed the RFP randomization key from canvas:seed
JWriter20 Aug 7, 2026
b3a06bc
fix(ci): run pre-checkout cleanup step from the workspace root
JWriter20 Aug 7, 2026
314bcf7
ci: build macOS arm64 and x86_64 alongside linux x86_64
JWriter20 Aug 7, 2026
f85166d
ci: build linux x86_64 and macos arm64 only
JWriter20 Aug 7, 2026
7e404d8
CAPTCHA solving, and a watcher that handles them as they appear
JWriter20 Aug 18, 2026
aa7570a
Merge origin/main into feat/captchakrakenAndJSSupport
JWriter20 Aug 20, 2026
4e6fc37
style(ts): sort the captcha re-exports in index.ts
JWriter20 Aug 20, 2026
35a69f3
ci: verify every build on its own OS and publish the results
JWriter20 Aug 20, 2026
28a5a1d
ci: add a verify-only dispatch for an already-released build
JWriter20 Aug 20, 2026
bbe2444
Update README
daijro Aug 21, 2026
7dd6bd9
README: remove old upstream cloverlabs-camoufox package
daijro Aug 21, 2026
dbd511b
README: Fix link
daijro Aug 21, 2026
b2c21ea
Update README
daijro Aug 26, 2026
4edbcff
README: Remove outdated development note
daijro Aug 26, 2026
c74fade
fix(captcha): raise the CaptchaKraken floor to 2.6.0 and guard the wa…
JWriter20 Aug 27, 2026
06ab983
Merge upstream/main (daijro) into feat/captchakrakenAndJSSupport
JWriter20 Aug 27, 2026
2d0d3f1
ci: don't let one failed target cancel the other two builds
JWriter20 Aug 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
203 changes: 190 additions & 13 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,44 @@ name: Build and Release

on:
workflow_dispatch:
inputs:
fail_on_leaks:
description: "Fail the verify job when a suite comes back dirty"
type: boolean
default: false
push:
tags:
- "*"

jobs:
build:
runs-on: ubuntu-24.04
# The build system lives in browser/; python/ and typescript/ are the
# launcher packages and are not part of this job.
defaults:
run:
working-directory: browser
strategy:
# One target failing to cross-compile must not cancel the others: these
# are multi-hour builds, and the `verify` job below already documents
# this as the contract it relies on. Without it the matrix default
# (fail-fast: true) throws away two nearly-finished builds to report a
# failure that is already reported.
fail-fast: false
matrix:
target: [linux, windows, macos]
arch: [x86_64, arm64, i686]
exclude:
# Fails (.mozbuild does not include clang++-cl)
- target: windows
arch: arm64
# Unsupported
- target: macos
arch: i686
# Listed explicitly rather than as a cross product with exclusions, so
# adding an arch to one target cannot silently add it to the other.
# Each arch is picked to match a GitHub-hosted runner, because the
# `verify` job below has to *run* what this job cross-compiles:
# ubuntu-24.04 is x86_64, macos-latest is arm64, windows-latest is
# x86_64.
include:
- target: linux
arch: i686
arch: x86_64
- target: macos
arch: arm64
- target: windows
arch: x86_64

steps:
- name: Maximize build space
Expand All @@ -38,6 +56,10 @@ jobs:

- name: Remove unwanted tools
# Originally from here: https://github.com/AdityaGarg8/remove-unwanted-software/blob/master/action.yml
# Runs before actions/checkout, so the job-level `working-directory:
# browser` default does not exist yet -- override it to the workspace
# root or the step fails with "No such file or directory".
working-directory: ${{ github.workspace }}
run: |
sudo apt-get remove -y '^aspnetcore-.*' > /dev/null
sudo apt-get remove -y '^dotnet-.*' > /dev/null
Expand Down Expand Up @@ -120,25 +142,180 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: CamoufoxBuilds-${{ matrix.target }}-${{ matrix.arch }}
path: dist/*
path: browser/dist/*

release:
# Runs what `build` cross-compiled, on the OS it was compiled for. Every
# build therefore ships measured results rather than an assertion that it
# probably still works.
verify:
needs: build
# `always()`: `build` sets fail-fast: false so one target failing to
# compile does not stop the others, and the same has to hold here -- a
# broken Windows build must not cost us the Linux and macOS results. A leg
# whose artifact never got uploaded fails at the download step, which
# fail-fast: false below keeps contained to that leg.
if: always() && !cancelled()
strategy:
fail-fast: false
matrix:
include:
- target: linux
arch: x86_64
runner: ubuntu-24.04
- target: macos
arch: arm64
runner: macos-latest
- target: windows
arch: x86_64
runner: windows-latest
runs-on: ${{ matrix.runner }}
timeout-minutes: 150
defaults:
run:
shell: bash

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Read version and release
run: |
. browser/upstream.sh
echo "CAMOUFOX_VERSION=$version" >> "$GITHUB_ENV"
echo "CAMOUFOX_RELEASE=$release" >> "$GITHUB_ENV"

- name: Download the build
uses: actions/download-artifact@v4
with:
name: CamoufoxBuilds-${{ matrix.target }}-${{ matrix.arch }}
path: build-artifact

- name: Unpack the package
# zipfile rather than unzip/7z/Expand-Archive: it is the one extractor
# present and identical on all three runners.
run: |
python -c "
import glob, pathlib, sys, zipfile
zips = sorted(glob.glob('build-artifact/**/*.zip', recursive=True))
if not zips:
sys.exit('no package zip in build-artifact')
print('extracting', zips[0])
pathlib.Path('package').mkdir(exist_ok=True)
zipfile.ZipFile(zips[0]).extractall('package')
"

- name: Install test dependencies
run: |
python -m pip install --upgrade pip
# The Playwright suite's own pins, and the launcher (for the sundial
# scan) from this checkout rather than PyPI -- the point is to test
# what this commit produces.
# ci-requirements, not local-requirements: the developer set pulls
# auditwheel, which is manylinux tooling with nothing to do on a
# macOS or Windows runner.
pip install -r browser/tests/ci-requirements.txt
# NOT -e: poetry-core cannot express this project's
# `packages = [{include = "*", from = "src", to = "camoufox"}]`
# remap in an editable install -- it just drops python/src on
# sys.path, which makes `import utils` work and `import camoufox`
# fail. A real build applies the mapping. (python/conftest.py is
# the equivalent shim for an uninstalled working tree.)
pip install "./python[geoip]"
pip install -r release-tester/requirements.txt
# playwright-python refuses to start when its own Firefox is absent,
# even though every launch here overrides the executable path.
python -m playwright install firefox

- name: Install Linux browser dependencies
if: matrix.target == 'linux'
run: python -m playwright install-deps firefox

- name: Verify the build
env:
# NOT a username/password: sundial's /automated route is matched
# before its cookie session check and authenticates on this key
# alone. Use AUTOMATION_PRIVATE_KEY -- the guest key silently serves
# fewer detection vectors. Absent (forks, PRs) the scan is skipped
# and the Playwright half still reports.
SUNDIAL_AUTOMATION_KEY: ${{ secrets.SUNDIAL_AUTOMATION_KEY }}
run: |
python release-tester/run.py \
--package-dir package \
--target ${{ matrix.target }} \
--arch ${{ matrix.arch }} \
--version "$CAMOUFOX_VERSION" \
--release "$CAMOUFOX_RELEASE" \
--out "results/${{ matrix.target }}-${{ matrix.arch }}" \
${{ (github.event_name == 'workflow_dispatch' && inputs.fail_on_leaks) && '--fail-on-leaks' || '' }}

- name: Publish to the job summary
# `always()`: a dirty build is exactly when the numbers are worth
# reading, and --fail-on-leaks would otherwise skip this step.
if: always()
run: |
summary="results/${{ matrix.target }}-${{ matrix.arch }}/summary.md"
if [ -f "$summary" ]; then
cat "$summary" >> "$GITHUB_STEP_SUMMARY"
else
echo "## ${{ matrix.target }}/${{ matrix.arch }}" >> "$GITHUB_STEP_SUMMARY"
echo "Verification produced no summary; see the job log." >> "$GITHUB_STEP_SUMMARY"
fi

- name: Upload results
if: always()
uses: actions/upload-artifact@v4
with:
name: CamoufoxResults-${{ matrix.target }}-${{ matrix.arch }}
path: results/**

release:
# `always()` so a build whose verification came back dirty is still
# published -- as a draft prerelease carrying the report that says so,
# which is more useful than no artifacts at all. `build` must still have
# succeeded; there is nothing to release otherwise.
needs: [build, verify]
if: always() && needs.build.result == 'success'
permissions:
contents: write
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts

- name: Build the combined report
run: |
python release-tester/combine.py \
--results-root artifacts \
--out RESULTS.md \
--assets-dir release-assets
cat RESULTS.md >> "$GITHUB_STEP_SUMMARY"

- name: Create Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: artifacts/**/*
# The binaries, plus one report per build. Release assets are a flat
# namespace, so the reports come from release-assets/ where
# combine.py has already renamed them per build -- uploading
# artifacts/**/* directly would have three results.json collide.
files: |
artifacts/**/*.zip
release-assets/*
body_path: RESULTS.md
generate_release_notes: true
draft: true
prerelease: true
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
defaults:
run:
working-directory: pythonlib
working-directory: python

steps:
- name: Check out repository
Expand All @@ -26,7 +26,7 @@ jobs:
run: pip install vermin build twine

- name: Check Python compatibility
run: vermin . --eval-annotations --target=3.8 --violations camoufox/ || exit 1
run: vermin . --eval-annotations --target=3.8 --violations src/ || exit 1

- name: Build package
run: python -m build
Expand Down
Loading
Loading