mirror of
https://github.com/feder-cr/invisible_playwright.git
synced 2026-07-22 11:51:11 +02:00
ci: move the binary-release workflows to firefox_antidetect_patch
The release/verify-assets/verify-cloak/republish workflows now live on the source repo (feder-cr/firefox_antidetect_patch), so the built binaries are published there — the natural home next to the source they are built from, and reachable the same way by every consumer of invisible-core. The wrapper keeps its own test workflows (tests/e2e/webrtc-e2e/ firefox-launch-matrix) and the scripts the source-side release jobs check out from here (ci_drive_gate.py, gen_release_notes.py, playwright_pin.txt, tests/test_cloak.py).
This commit is contained in:
parent
3c018f7bbf
commit
17bab0cca4
4 changed files with 0 additions and 907 deletions
479
.github/workflows/release.yml
vendored
479
.github/workflows/release.yml
vendored
|
|
@ -1,479 +0,0 @@
|
|||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# release.yml — build all 5 patched-Firefox targets at $0 and publish them as
|
||||
# DRAFT GitHub Release assets, named per the wrapper contract (constants.ARCHIVE_NAME).
|
||||
# DRAFT on purpose: a human runs the realness gate and only THEN un-drafts + bumps
|
||||
# BINARY_VERSION. Nothing auto-ships (issue #14 lesson).
|
||||
#
|
||||
# PACKAGING (issue #14: dangling symlinks broke 265 downloads — never again):
|
||||
# Linux → cp -aL (dereference ALL symlinks into real files) + rm dev tools +
|
||||
# strip + sanitize + tar at ROOT, then validate_release.py as a HARD
|
||||
# in-pipeline gate (the exact battle-tested script from the source repo).
|
||||
# Win → mach package; zip the CONTENTS of dist/firefox (clean tree, NOT
|
||||
# dist/bin) so firefox.exe sits at the zip ROOT.
|
||||
# macOS → mach package; ad-hoc codesign the .app; PRESERVE its internal relative
|
||||
# symlinks (a .app legitimately has them — cp -aL would break it); verify
|
||||
# every symlink is relative+internal; tar the bundle. --version self-gate.
|
||||
#
|
||||
# DRIVE GATE (the firefox-8 catcher): after build, every binary is DRIVEN by
|
||||
# Playwright on its native runner (launch via juggler + real page + JS roundtrip,
|
||||
# headless, no screenshot → GPU-free, zero proxy). A juggler-less binary renders
|
||||
# a screenshot fine but is undrivable — only an actual drive catches that. The
|
||||
# proxy realness gate (fppro/webrtc) stays LOCAL — it needs secrets.
|
||||
#
|
||||
# Trigger: push a tag `firefox-N`, or run manually. Hybrid runners, all free.
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ['firefox-*']
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
source_ref:
|
||||
description: 'firefox_antidetect_patch ref to build'
|
||||
default: 'stealth/150'
|
||||
release_tag:
|
||||
description: 'release tag to publish the draft under (e.g. firefox-9)'
|
||||
required: true
|
||||
|
||||
env:
|
||||
SOURCE_REPO: feder-cr/firefox_antidetect_patch
|
||||
SOURCE_REF: ${{ github.event.inputs.source_ref || 'stealth/150' }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: build-${{ matrix.leg }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 350
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- leg: linux-x86_64
|
||||
runner: ubuntu-24.04
|
||||
family: linux
|
||||
target: ''
|
||||
rust_target: x86_64-unknown-linux-gnu
|
||||
win_disables: 'no'
|
||||
extra_pkgs: ''
|
||||
asset: firefox-150.0.1-stealth-linux-x86_64.tar.gz
|
||||
- leg: linux-arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
family: linux
|
||||
target: ''
|
||||
rust_target: aarch64-unknown-linux-gnu
|
||||
win_disables: 'no'
|
||||
extra_pkgs: ''
|
||||
asset: firefox-150.0.1-stealth-linux-arm64.tar.gz
|
||||
- leg: win-x86_64
|
||||
runner: ubuntu-24.04
|
||||
family: win
|
||||
target: x86_64-pc-windows-msvc
|
||||
rust_target: x86_64-pc-windows-msvc
|
||||
win_disables: 'yes'
|
||||
extra_pkgs: 'msitools p7zip-full zip'
|
||||
asset: firefox-150.0.1-stealth-win-x86_64.zip
|
||||
- leg: macos-arm64
|
||||
runner: macos-15
|
||||
family: mac
|
||||
target: aarch64-apple-darwin
|
||||
rust_target: aarch64-apple-darwin
|
||||
win_disables: 'no'
|
||||
extra_pkgs: ''
|
||||
asset: firefox-150.0.1-stealth-macos-arm64.tar.gz
|
||||
- leg: macos-x86_64
|
||||
runner: macos-15-intel
|
||||
family: mac
|
||||
target: x86_64-apple-darwin
|
||||
rust_target: x86_64-apple-darwin
|
||||
win_disables: 'no'
|
||||
extra_pkgs: ''
|
||||
asset: firefox-150.0.1-stealth-macos-x86_64.tar.gz
|
||||
steps:
|
||||
- name: Free disk + 16G swap (Linux runners)
|
||||
if: matrix.family != 'mac'
|
||||
run: |
|
||||
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android \
|
||||
/usr/local/share/boost "${AGENT_TOOLSDIRECTORY:-/opt/hostedtoolcache}" 2>/dev/null || true
|
||||
sudo fallocate -l 16G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile || true
|
||||
|
||||
- name: Checkout patched Firefox source
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
repository: ${{ env.SOURCE_REPO }}
|
||||
ref: ${{ env.SOURCE_REF }}
|
||||
fetch-depth: 1
|
||||
|
||||
# Record which firefox_antidetect_patch commit this build came from. The publish
|
||||
# job turns the range previous-release..this commit into the release notes
|
||||
# (scripts/gen_release_notes.py), and re-publishes it as a source-commit.txt
|
||||
# asset so the NEXT release knows where to start the changelog. One leg is
|
||||
# enough — all legs check out the same SOURCE_REF.
|
||||
- name: Record source commit (for auto release notes)
|
||||
if: matrix.leg == 'linux-x86_64'
|
||||
shell: bash
|
||||
run: git rev-parse HEAD > source-commit.txt && cat source-commit.txt
|
||||
- name: Upload source-commit artifact
|
||||
if: matrix.leg == 'linux-x86_64'
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: source-commit
|
||||
path: source-commit.txt
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with: { python-version: '3.11' }
|
||||
|
||||
- name: Install Linux build tools
|
||||
if: matrix.family != 'mac'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y util-linux binutils ${{ matrix.extra_pkgs }}
|
||||
|
||||
- name: Select Xcode 26.2 + export SDK path (macOS)
|
||||
if: matrix.family == 'mac'
|
||||
run: |
|
||||
sudo xcode-select -s /Applications/Xcode_26.2.app
|
||||
SDKP="$(xcrun --show-sdk-path)"
|
||||
echo "SDK_PATH=$SDKP" >> "$GITHUB_ENV"
|
||||
echo "macOS SDK $(xcrun --sdk macosx --show-sdk-version) at $SDKP"
|
||||
|
||||
- name: Add Rust target
|
||||
run: rustup target add ${{ matrix.rust_target }} || true
|
||||
|
||||
- name: Extend the repo .mozconfig (NO mold; +target/SDK as needed)
|
||||
run: |
|
||||
test -f .mozconfig || { echo "ERROR: no .mozconfig in source"; exit 1; }
|
||||
rm -f mozconfig
|
||||
{
|
||||
echo ""
|
||||
echo "# --- release CI levers for ${{ matrix.leg }} (mold intentionally OFF — it segfaults libxul) ---"
|
||||
echo "ac_add_options --disable-debug-symbols"
|
||||
} >> .mozconfig
|
||||
if [ -n "${{ matrix.target }}" ]; then echo "ac_add_options --target=${{ matrix.target }}" >> .mozconfig; fi
|
||||
if [ "${{ matrix.family }}" = "mac" ]; then echo "ac_add_options --with-macos-sdk=$SDK_PATH" >> .mozconfig; fi
|
||||
if [ "${{ matrix.win_disables }}" = "yes" ]; then
|
||||
{ echo "ac_add_options --disable-default-browser-agent";
|
||||
echo "ac_add_options --disable-maintenance-service";
|
||||
echo "ac_add_options --disable-update-agent"; } >> .mozconfig
|
||||
fi
|
||||
if [ "${{ matrix.family }}" = "mac" ]; then NCPU=$(sysctl -n hw.ncpu); else NCPU=4; fi
|
||||
{ echo "mk_add_options MOZ_PARALLEL_BUILD=$NCPU";
|
||||
echo "mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-rel"; } >> .mozconfig
|
||||
echo "----- final .mozconfig -----"; cat .mozconfig
|
||||
|
||||
- name: Build
|
||||
run: ./mach build
|
||||
|
||||
# ── LINUX: dereference symlinks (issue #14) + strip + sanitize + tar@root + GATE
|
||||
- name: Package + validate (Linux)
|
||||
if: matrix.family == 'linux'
|
||||
run: |
|
||||
set -e
|
||||
DIST=obj-rel/dist/bin
|
||||
STAGING=staging
|
||||
rm -rf "$STAGING"; mkdir -p "$STAGING" out
|
||||
cp -aL "$DIST/." "$STAGING/" # -L: dereference ALL symlinks into real files
|
||||
N=$(find "$STAGING" -type l | wc -l)
|
||||
[ "$N" -eq 0 ] || { echo "ERROR: $N symlinks remain after cp -aL"; exit 1; }
|
||||
for t in xpcshell certutil pk12util rapl; do rm -f "$STAGING/$t"; done
|
||||
# JUGGLER GATE: the binary is undrivable by Playwright without it (see 70-known-bugs)
|
||||
{ [ -e "$STAGING/chrome/juggler.manifest" ] && [ -d "$STAGING/chrome/juggler" ]; } \
|
||||
|| { echo "ERROR: juggler missing from package (chrome/juggler) — Playwright can't drive it"; exit 1; }
|
||||
echo "juggler GATE OK (loose chrome/juggler present)"
|
||||
find "$STAGING" -type f \
|
||||
\( -name '*.so' -o -name firefox -o -name firefox-bin -o -name plugin-container \
|
||||
-o -name pingsender -o -name glxtest -o -name vaapitest -o -name updater \) \
|
||||
-exec strip --strip-debug {} + 2>/dev/null || true
|
||||
STAGING="$STAGING" python3 scripts/linux_sanitize.py || true # no-op in CI (no /home/feder), defensive
|
||||
tar --owner=0 --group=0 --numeric-owner --mtime="2026-01-01 00:00:00 UTC" \
|
||||
-czf "out/${{ matrix.asset }}" -C "$STAGING" . # firefox at ROOT
|
||||
echo "=== HARD GATE: scripts/validate_release.py (the issue-#14 protector) ==="
|
||||
python3 scripts/validate_release.py --linux "out/${{ matrix.asset }}" --linux-only
|
||||
ls -la out/
|
||||
|
||||
# ── WINDOWS (cross): zip the CLEAN dist/firefox tree, firefox.exe at root
|
||||
- name: Package (Windows cross)
|
||||
if: matrix.family == 'win'
|
||||
run: |
|
||||
set -e
|
||||
# Do NOT swallow a mach failure: `./mach package || echo` lets set -e pass
|
||||
# and would fall through to a stale tree. A release MUST come from the clean
|
||||
# dist/firefox; dist/bin is the dev tree (cruft + loose juggler that masked
|
||||
# the firefox-7/8 packaging bugs), never acceptable for a release.
|
||||
./mach package
|
||||
[ -f obj-rel/dist/firefox/firefox.exe ] \
|
||||
|| { echo "ERROR: mach package did not produce a clean dist/firefox tree"; exit 1; }
|
||||
WIN_APP=obj-rel/dist/firefox
|
||||
echo "packaging from: $WIN_APP"
|
||||
# JUGGLER GATE: omni.ja must carry juggler (else Playwright can't drive it)
|
||||
[ -f "$WIN_APP/omni.ja" ] || { echo "ERROR: no omni.ja in $WIN_APP"; exit 1; }
|
||||
python3 -c "import zipfile,sys; sys.exit(0 if any('juggler' in n.lower() for n in zipfile.ZipFile('$WIN_APP/omni.ja').namelist()) else 1)" \
|
||||
|| { echo "ERROR: juggler missing from $WIN_APP/omni.ja — Playwright can't drive it"; exit 1; }
|
||||
echo "juggler GATE OK (win)"
|
||||
mkdir -p out
|
||||
( cd "$WIN_APP" && zip -qr "$GITHUB_WORKSPACE/out/${{ matrix.asset }}" . ) # firefox.exe at zip ROOT
|
||||
ls -la out/
|
||||
|
||||
# ── macOS: package .app, ad-hoc sign, verify relative-internal symlinks, --version gate, tar
|
||||
- name: Package + validate (macOS)
|
||||
if: matrix.family == 'mac'
|
||||
run: |
|
||||
set -e
|
||||
./mach package
|
||||
APP="$(find obj-rel/dist -maxdepth 2 -name '*.app' -type d | head -1)"
|
||||
[ -n "$APP" ] || { echo "ERROR: no .app produced"; exit 1; }
|
||||
echo "built app: $APP"
|
||||
# JUGGLER GATE: the .app's omni.ja must carry juggler (else Playwright can't drive it)
|
||||
python3 -c "import zipfile,sys,glob; jas=glob.glob('$APP/Contents/Resources/omni.ja')+glob.glob('$APP/Contents/Resources/browser/omni.ja'); sys.exit(0 if jas and any(any('juggler' in n.lower() for n in zipfile.ZipFile(j).namelist()) for j in jas) else 1)" \
|
||||
|| { echo "ERROR: juggler missing from .app omni.ja — Playwright can't drive it"; exit 1; }
|
||||
echo "juggler GATE OK (mac)"
|
||||
codesign --force --deep --sign - --timestamp=none "$APP"
|
||||
codesign --verify --deep --strict --verbose=2 "$APP"
|
||||
echo "=== --version GATE ==="
|
||||
"$APP/Contents/MacOS/firefox" --version
|
||||
echo "=== critical files present ==="
|
||||
for need in "Contents/MacOS/firefox" "Contents/Info.plist"; do
|
||||
[ -e "$APP/$need" ] || { echo "ERROR: missing $need"; exit 1; }
|
||||
done
|
||||
echo "=== Info.plist well-formed + required keys (a malformed plist → Finder 'damaged') ==="
|
||||
plutil -lint "$APP/Contents/Info.plist"
|
||||
for key in CFBundleExecutable CFBundleIdentifier CFBundleShortVersionString; do
|
||||
plutil -extract "$key" raw -o - "$APP/Contents/Info.plist" >/dev/null \
|
||||
|| { echo "ERROR: Info.plist missing $key"; exit 1; }
|
||||
done
|
||||
EXEC="$(plutil -extract CFBundleExecutable raw -o - "$APP/Contents/Info.plist")"
|
||||
[ -e "$APP/Contents/MacOS/$EXEC" ] \
|
||||
|| { echo "ERROR: CFBundleExecutable '$EXEC' has no matching binary in Contents/MacOS"; exit 1; }
|
||||
echo "=== verify NO absolute symlinks in the .app (relative-internal ones are fine) ==="
|
||||
BAD="$(find "$APP" -type l -print0 | xargs -0 -I{} sh -c 't=$(readlink "{}"); case "$t" in /*) echo "{} -> $t";; esac')"
|
||||
[ -z "$BAD" ] || { echo "ERROR: absolute symlinks in .app (break on user machines):"; echo "$BAD" | head -5; exit 1; }
|
||||
echo "mac .app OK: critical files present, no absolute symlinks"
|
||||
STABLE="$(dirname "$APP")/Firefox.app"
|
||||
[ "$APP" = "$STABLE" ] || mv "$APP" "$STABLE"
|
||||
mkdir -p out
|
||||
tar -czf "out/${{ matrix.asset }}" -C "$(dirname "$STABLE")" Firefox.app # preserves internal symlinks
|
||||
ls -la out/
|
||||
|
||||
- name: Upload build artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: asset-${{ matrix.leg }}
|
||||
path: out/${{ matrix.asset }}
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
# DRIVE GATE — the firefox-8 catcher. A raw `firefox --screenshot` proves
|
||||
# nothing about automation: a juggler-less binary renders fine and ships
|
||||
# broken (firefox-8 did exactly that). So we DRIVE every binary the way users
|
||||
# will: Playwright launches it over the juggler pipe, loads a real page, and
|
||||
# round-trips JS. A binary missing/broken juggler throws TargetClosedError
|
||||
# here and the release never publishes. Headless, NO screenshot → GPU-free,
|
||||
# so it can't false-fail on the GPU-less hosted runners. Zero proxy / zero
|
||||
# secrets → safe in public CI (the proxy realness gate stays local, by design).
|
||||
# Each leg runs on its NATIVE runner so we test the real artifact, not a cross
|
||||
# surrogate. Playwright is pinned to a version validated against this build's
|
||||
# juggler; bump it in lockstep when the juggler is re-synced from upstream.
|
||||
gate:
|
||||
name: gate-${{ matrix.leg }}
|
||||
needs: build
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 25
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# `extra: --full` adds the mouse/keyboard/canvas/navsurface interaction
|
||||
# checks. Only on linux-x86_64 (historically the most reliable hosted
|
||||
# runner): the interaction code is platform-identical JS (omni.ja), so
|
||||
# one reliable full run catches a firefox-2-class regression for all
|
||||
# platforms. The other legs run SMOKE (launch+http+UA+webdriver) — the
|
||||
# firefox-8/juggler catcher — which is robust even on the flaky
|
||||
# windows-latest runner. See scripts/ci_drive_gate.py.
|
||||
- leg: linux-x86_64
|
||||
runner: ubuntu-24.04
|
||||
kind: linux
|
||||
asset: firefox-150.0.1-stealth-linux-x86_64.tar.gz
|
||||
extra: '--full'
|
||||
- leg: linux-arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
kind: linux
|
||||
asset: firefox-150.0.1-stealth-linux-arm64.tar.gz
|
||||
extra: ''
|
||||
- leg: win-x86_64
|
||||
runner: windows-latest
|
||||
kind: win
|
||||
asset: firefox-150.0.1-stealth-win-x86_64.zip
|
||||
extra: ''
|
||||
- leg: macos-arm64
|
||||
runner: macos-15
|
||||
kind: mac
|
||||
asset: firefox-150.0.1-stealth-macos-arm64.tar.gz
|
||||
extra: ''
|
||||
- leg: macos-x86_64
|
||||
runner: macos-15-intel
|
||||
kind: mac
|
||||
asset: firefox-150.0.1-stealth-macos-x86_64.tar.gz
|
||||
extra: ''
|
||||
steps:
|
||||
- name: Checkout wrapper (for scripts/ci_drive_gate.py)
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with: { fetch-depth: 1 }
|
||||
- name: Download asset
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
with:
|
||||
name: asset-${{ matrix.leg }}
|
||||
path: art
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with: { python-version: '3.11' }
|
||||
- name: Install Playwright driver (no bundled browser — we override executable_path)
|
||||
# Pin from a SINGLE source (scripts/playwright_pin.txt) so release.yml and
|
||||
# verify-assets.yml can't drift to different versions. The drive gate then
|
||||
# ENFORCES playwright↔juggler compatibility: an incompatible pin fails the
|
||||
# launch/drive (TargetClosedError / protocol error) and nothing publishes.
|
||||
# Bump the pin file in lockstep when the juggler is re-synced from upstream.
|
||||
shell: bash
|
||||
run: python -m pip install --quiet "playwright==$(cat scripts/playwright_pin.txt)"
|
||||
- name: Linux system deps for headless firefox
|
||||
if: matrix.kind == 'linux'
|
||||
run: sudo "$(which python)" -m playwright install-deps firefox
|
||||
- name: Extract + locate firefox binary
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
mkdir -p ff
|
||||
A="art/${{ matrix.asset }}"
|
||||
case "${{ matrix.kind }}" in
|
||||
win) python -c "import zipfile; zipfile.ZipFile('$A').extractall('ff')"; EXE="ff/firefox.exe";;
|
||||
linux) tar xzf "$A" -C ff; EXE="ff/firefox";;
|
||||
mac) tar xzf "$A" -C ff; EXE="ff/Firefox.app/Contents/MacOS/firefox";;
|
||||
esac
|
||||
[ -e "$EXE" ] || { echo "ERROR: firefox binary not found at $EXE"; exit 1; }
|
||||
chmod +x "$EXE" 2>/dev/null || true
|
||||
echo "FF_EXE=$EXE" >> "$GITHUB_ENV"
|
||||
echo "located: $EXE"
|
||||
- name: DRIVE GATE — Playwright launch via juggler + real page (+ interaction on --full)
|
||||
shell: bash
|
||||
run: python scripts/ci_drive_gate.py "$FF_EXE" ${{ matrix.extra }}
|
||||
|
||||
# CLOAK + WEBGL-MASKING GUARDS — run the wrapper's e2e cloak/gamma checks
|
||||
# against THIS leg's freshly-built artifact, on its native runner. The
|
||||
# wrapper's headless=True is headed+hidden (cloak on Win/macOS, its own
|
||||
# Xvfb on Linux). Linux (Xvfb + llvmpipe) and Windows (WARP) give a
|
||||
# software WebGL context on the GPU-less hosts, so the WebGL-dependent
|
||||
# assertions run there. macOS GitHub runners expose NO WebGL in the CI
|
||||
# session at all (even vanilla Firefox; macOS has no software-GL fallback),
|
||||
# so on the mac legs the WebGL checks self-skip and the cloak is validated
|
||||
# via its non-blank screenshot + CGWindowAlpha == 0. test_cloak asserts the
|
||||
# window is hidden (Windows DWMWA_CLOAKED / macOS CGWindowAlpha) AND still
|
||||
# renders — the macOS leg is the only place the cocoa cloak patch gets RUN.
|
||||
# The webgl guard catches a regression of the gamma readPixels noise back to
|
||||
# the pixelscan-maskable ±1 spike form (covered on Linux + Windows).
|
||||
- name: Install pyobjc Quartz (macOS — to read the cloak window alpha)
|
||||
if: matrix.kind == 'mac'
|
||||
run: python -m pip install --quiet pyobjc-framework-Quartz
|
||||
- name: Cloak + WebGL-masking guards (headed)
|
||||
shell: bash
|
||||
run: |
|
||||
python -m pip install --quiet ".[dev]"
|
||||
INVPW_BINARY_PATH="$FF_EXE" python -m pytest \
|
||||
tests/test_cloak.py \
|
||||
"tests/test_fingerprint_surface.py::test_webgl_readpixels_no_masking_signature" \
|
||||
-m e2e -o addopts='' -q
|
||||
|
||||
publish:
|
||||
name: publish-draft-release
|
||||
needs: [build, gate]
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout wrapper (for scripts/gen_release_notes.py)
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with: { fetch-depth: 1 }
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with: { python-version: '3.11' }
|
||||
- name: Download all build assets
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
with: { pattern: asset-*, path: dl, merge-multiple: true }
|
||||
- name: Download source-commit metadata
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
with: { name: source-commit, path: src-meta }
|
||||
- name: Assert all 5 target archives present (no silent partial release)
|
||||
run: |
|
||||
cd dl
|
||||
EXPECTED="
|
||||
firefox-150.0.1-stealth-linux-x86_64.tar.gz
|
||||
firefox-150.0.1-stealth-linux-arm64.tar.gz
|
||||
firefox-150.0.1-stealth-win-x86_64.zip
|
||||
firefox-150.0.1-stealth-macos-arm64.tar.gz
|
||||
firefox-150.0.1-stealth-macos-x86_64.tar.gz
|
||||
"
|
||||
for a in $EXPECTED; do
|
||||
[ -s "$a" ] || { echo "ERROR: missing/empty release asset: $a (a build leg silently dropped out?)"; exit 1; }
|
||||
done
|
||||
echo "all 5 target archives present"
|
||||
- name: Generate checksums.txt
|
||||
run: |
|
||||
cd dl; ls -la
|
||||
# explicit glob — never include checksums.txt itself (the `*`-includes-itself trap)
|
||||
sha256sum firefox-150.0.1-stealth-* > checksums.txt
|
||||
echo "----- checksums.txt -----"; cat checksums.txt
|
||||
- name: Resolve release tag
|
||||
id: tag
|
||||
run: |
|
||||
TAG="${{ github.event.inputs.release_tag }}"
|
||||
[ -z "$TAG" ] && TAG="${GITHUB_REF_NAME}"
|
||||
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
||||
# bare revision number for the release title: firefox-10 -> 10
|
||||
N="${TAG#firefox-}"
|
||||
echo "num=$N" >> "$GITHUB_OUTPUT"
|
||||
# previous release tag, for the changelog range (firefox-10 -> firefox-9)
|
||||
case "$N" in (*[!0-9]*|'') echo "prevtag=" >> "$GITHUB_OUTPUT";;
|
||||
(*) echo "prevtag=firefox-$((N-1))" >> "$GITHUB_OUTPUT";; esac
|
||||
echo "publishing DRAFT release for tag: $TAG"
|
||||
- name: Build release notes from the source commits
|
||||
id: notes
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -e
|
||||
CUR="$(cat src-meta/source-commit.txt 2>/dev/null | tr -d '[:space:]')"
|
||||
echo "this build's source commit: ${CUR:-<none>}"
|
||||
# previous release's recorded source commit — gives the changelog range.
|
||||
# Missing (first automated notes / firefox-0) -> notes omit the changelog.
|
||||
PREV=""
|
||||
PREVTAG="${{ steps.tag.outputs.prevtag }}"
|
||||
if [ -n "$PREVTAG" ] && gh release download "$PREVTAG" -R "${{ github.repository }}" \
|
||||
--pattern source-commit.txt --dir prev 2>/dev/null; then
|
||||
PREV="$(cat prev/source-commit.txt | tr -d '[:space:]')"
|
||||
echo "previous ($PREVTAG) source commit: $PREV"
|
||||
else
|
||||
echo "no previous source-commit.txt — changelog section omitted this time"
|
||||
fi
|
||||
python scripts/gen_release_notes.py --tag "${{ steps.tag.outputs.tag }}" \
|
||||
--current "$CUR" --prev-sha "$PREV" --source-repo "${{ env.SOURCE_REPO }}" > body.md
|
||||
echo "----- generated body.md -----"; cat body.md
|
||||
# publish THIS build's source commit so the next release can diff from it
|
||||
cp src-meta/source-commit.txt dl/source-commit.txt
|
||||
- name: Create DRAFT release with all assets
|
||||
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
|
||||
with:
|
||||
tag_name: ${{ steps.tag.outputs.tag }}
|
||||
name: firefox_antidetect_patch (150.0.1) rev ${{ steps.tag.outputs.num }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
fail_on_unmatched_files: true
|
||||
files: |
|
||||
dl/*.tar.gz
|
||||
dl/*.zip
|
||||
dl/checksums.txt
|
||||
dl/source-commit.txt
|
||||
body_path: body.md
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
214
.github/workflows/republish.yml
vendored
214
.github/workflows/republish.yml
vendored
|
|
@ -1,214 +0,0 @@
|
|||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# republish.yml — re-gate + publish an EXISTING build's artifacts WITHOUT rebuilding.
|
||||
#
|
||||
# When a release run's 5 builds all SUCCEEDED but the publish was blocked by a
|
||||
# GATE/TEST bug (not a binary defect), rebuilding all five targets (hours) just to
|
||||
# re-run a few-minute test is wasteful. This workflow downloads the binary artifacts
|
||||
# from a prior `release` run, re-runs the (now-fixed) drive gate + cloak/WebGL guards
|
||||
# against those exact byte-identical binaries on their native runners, and — only if
|
||||
# green — publishes the DRAFT release. Same publish logic as release.yml (draft, notes,
|
||||
# checksums, source-commit) so the human still runs the realness gate before un-drafting.
|
||||
#
|
||||
# Inputs:
|
||||
# build_run_id : the `release` run whose `asset-*` + `source-commit` artifacts to reuse
|
||||
# (must be within the 7-day artifact retention window).
|
||||
# release_tag : tag to publish the draft under (e.g. firefox-11).
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
name: republish
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build_run_id:
|
||||
description: 'release run id whose built artifacts to reuse (no rebuild)'
|
||||
required: true
|
||||
release_tag:
|
||||
description: 'release tag to publish the draft under (e.g. firefox-11)'
|
||||
required: true
|
||||
|
||||
env:
|
||||
SOURCE_REPO: feder-cr/firefox_antidetect_patch
|
||||
|
||||
jobs:
|
||||
gate:
|
||||
name: gate-${{ matrix.leg }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 25
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- leg: linux-x86_64
|
||||
runner: ubuntu-24.04
|
||||
kind: linux
|
||||
asset: firefox-150.0.1-stealth-linux-x86_64.tar.gz
|
||||
extra: '--full'
|
||||
- leg: linux-arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
kind: linux
|
||||
asset: firefox-150.0.1-stealth-linux-arm64.tar.gz
|
||||
extra: ''
|
||||
- leg: win-x86_64
|
||||
runner: windows-latest
|
||||
kind: win
|
||||
asset: firefox-150.0.1-stealth-win-x86_64.zip
|
||||
extra: ''
|
||||
- leg: macos-arm64
|
||||
runner: macos-15
|
||||
kind: mac
|
||||
asset: firefox-150.0.1-stealth-macos-arm64.tar.gz
|
||||
extra: ''
|
||||
- leg: macos-x86_64
|
||||
runner: macos-15-intel
|
||||
kind: mac
|
||||
asset: firefox-150.0.1-stealth-macos-x86_64.tar.gz
|
||||
extra: ''
|
||||
steps:
|
||||
- name: Checkout wrapper (for scripts/ci_drive_gate.py — the FIXED gate)
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with: { fetch-depth: 1 }
|
||||
- name: Download asset from the existing build run (no rebuild)
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
with:
|
||||
name: asset-${{ matrix.leg }}
|
||||
path: art
|
||||
run-id: ${{ github.event.inputs.build_run_id }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with: { python-version: '3.11' }
|
||||
- name: Install Playwright driver (pinned, no bundled browser)
|
||||
shell: bash
|
||||
run: python -m pip install --quiet "playwright==$(cat scripts/playwright_pin.txt)"
|
||||
- name: Linux system deps for headless firefox
|
||||
if: matrix.kind == 'linux'
|
||||
run: sudo "$(which python)" -m playwright install-deps firefox
|
||||
- name: Extract + locate firefox binary
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
mkdir -p ff
|
||||
A="art/${{ matrix.asset }}"
|
||||
case "${{ matrix.kind }}" in
|
||||
win) python -c "import zipfile; zipfile.ZipFile('$A').extractall('ff')"; EXE="ff/firefox.exe";;
|
||||
linux) tar xzf "$A" -C ff; EXE="ff/firefox";;
|
||||
mac) tar xzf "$A" -C ff; EXE="ff/Firefox.app/Contents/MacOS/firefox";;
|
||||
esac
|
||||
[ -e "$EXE" ] || { echo "ERROR: firefox binary not found at $EXE"; exit 1; }
|
||||
chmod +x "$EXE" 2>/dev/null || true
|
||||
echo "FF_EXE=$EXE" >> "$GITHUB_ENV"
|
||||
echo "located: $EXE"
|
||||
- name: DRIVE GATE — Playwright launch via juggler + real page (+ interaction on --full)
|
||||
shell: bash
|
||||
run: python scripts/ci_drive_gate.py "$FF_EXE" ${{ matrix.extra }}
|
||||
- name: Install pyobjc Quartz (macOS — to read the cloak window alpha)
|
||||
if: matrix.kind == 'mac'
|
||||
run: python -m pip install --quiet pyobjc-framework-Quartz
|
||||
- name: Cloak + WebGL-masking guards (headed)
|
||||
shell: bash
|
||||
run: |
|
||||
python -m pip install --quiet ".[dev]"
|
||||
INVPW_BINARY_PATH="$FF_EXE" python -m pytest \
|
||||
tests/test_cloak.py \
|
||||
"tests/test_fingerprint_surface.py::test_webgl_readpixels_no_masking_signature" \
|
||||
-m e2e -o addopts='' -q
|
||||
|
||||
publish:
|
||||
name: publish-draft-release
|
||||
needs: [gate]
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
actions: read
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout wrapper (for scripts/gen_release_notes.py)
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with: { fetch-depth: 1 }
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with: { python-version: '3.11' }
|
||||
- name: Download all build assets from the existing build run (no rebuild)
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
with:
|
||||
pattern: asset-*
|
||||
path: dl
|
||||
merge-multiple: true
|
||||
run-id: ${{ github.event.inputs.build_run_id }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Download source-commit metadata from the existing build run
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
with:
|
||||
name: source-commit
|
||||
path: src-meta
|
||||
run-id: ${{ github.event.inputs.build_run_id }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Assert all 5 target archives present (no silent partial release)
|
||||
run: |
|
||||
cd dl
|
||||
EXPECTED="
|
||||
firefox-150.0.1-stealth-linux-x86_64.tar.gz
|
||||
firefox-150.0.1-stealth-linux-arm64.tar.gz
|
||||
firefox-150.0.1-stealth-win-x86_64.zip
|
||||
firefox-150.0.1-stealth-macos-arm64.tar.gz
|
||||
firefox-150.0.1-stealth-macos-x86_64.tar.gz
|
||||
"
|
||||
for a in $EXPECTED; do
|
||||
[ -s "$a" ] || { echo "ERROR: missing/empty release asset: $a (a build leg silently dropped out?)"; exit 1; }
|
||||
done
|
||||
echo "all 5 target archives present"
|
||||
- name: Generate checksums.txt
|
||||
run: |
|
||||
cd dl; ls -la
|
||||
sha256sum firefox-150.0.1-stealth-* > checksums.txt
|
||||
echo "----- checksums.txt -----"; cat checksums.txt
|
||||
- name: Resolve release tag
|
||||
id: tag
|
||||
run: |
|
||||
TAG="${{ github.event.inputs.release_tag }}"
|
||||
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
||||
N="${TAG#firefox-}"
|
||||
echo "num=$N" >> "$GITHUB_OUTPUT"
|
||||
case "$N" in (*[!0-9]*|'') echo "prevtag=" >> "$GITHUB_OUTPUT";;
|
||||
(*) echo "prevtag=firefox-$((N-1))" >> "$GITHUB_OUTPUT";; esac
|
||||
echo "publishing DRAFT release for tag: $TAG"
|
||||
- name: Build release notes from the source commits
|
||||
id: notes
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -e
|
||||
CUR="$(cat src-meta/source-commit.txt 2>/dev/null | tr -d '[:space:]')"
|
||||
echo "this build's source commit: ${CUR:-<none>}"
|
||||
PREV=""
|
||||
PREVTAG="${{ steps.tag.outputs.prevtag }}"
|
||||
if [ -n "$PREVTAG" ] && gh release download "$PREVTAG" -R "${{ github.repository }}" \
|
||||
--pattern source-commit.txt --dir prev 2>/dev/null; then
|
||||
PREV="$(cat prev/source-commit.txt | tr -d '[:space:]')"
|
||||
echo "previous ($PREVTAG) source commit: $PREV"
|
||||
else
|
||||
echo "no previous source-commit.txt — changelog section omitted this time"
|
||||
fi
|
||||
python scripts/gen_release_notes.py --tag "${{ steps.tag.outputs.tag }}" \
|
||||
--current "$CUR" --prev-sha "$PREV" --source-repo "${{ env.SOURCE_REPO }}" > body.md
|
||||
echo "----- generated body.md -----"; cat body.md
|
||||
cp src-meta/source-commit.txt dl/source-commit.txt
|
||||
- name: Create DRAFT release with all assets
|
||||
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
|
||||
with:
|
||||
tag_name: ${{ steps.tag.outputs.tag }}
|
||||
name: firefox_antidetect_patch (150.0.1) rev ${{ steps.tag.outputs.num }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
fail_on_unmatched_files: true
|
||||
files: |
|
||||
dl/*.tar.gz
|
||||
dl/*.zip
|
||||
dl/checksums.txt
|
||||
dl/source-commit.txt
|
||||
body_path: body.md
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
111
.github/workflows/verify-assets.yml
vendored
111
.github/workflows/verify-assets.yml
vendored
|
|
@ -1,111 +0,0 @@
|
|||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# verify-assets.yml — re-runnable DRIVE GATE for an EXISTING release's assets.
|
||||
#
|
||||
# release.yml drive-gates every binary it builds. This does the same drive test
|
||||
# WITHOUT rebuilding: it downloads a release's already-published assets (works on
|
||||
# DRAFT releases too via GITHUB_TOKEN) and drives each one on its native runner.
|
||||
#
|
||||
# Use it to:
|
||||
# • drive-test a release that was built before the in-pipeline gate existed
|
||||
# (e.g. firefox-9, built on the old release.yml), or
|
||||
# • re-verify any shipped release on demand (regression check).
|
||||
#
|
||||
# Same single-source-of-truth drive logic as release.yml: scripts/ci_drive_gate.py.
|
||||
# Headless, no screenshot → GPU-free. Zero proxy / zero secrets.
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
name: verify-assets
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
description: 'release tag whose assets to drive-test (e.g. firefox-9)'
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
# write (not read) is required: GitHub only exposes DRAFT releases to tokens
|
||||
# with push access. With contents:read, `gh release download` on a draft tag
|
||||
# 404s ("release not found"). This workflow only READS assets — the elevated
|
||||
# scope is solely to make draft releases visible to GITHUB_TOKEN.
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
drive:
|
||||
name: drive-${{ matrix.leg }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 25
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# --full (interaction) only on the reliable linux-x86_64 leg; others run
|
||||
# the robust SMOKE drive. Same rationale as release.yml's gate.
|
||||
- leg: linux-x86_64
|
||||
runner: ubuntu-24.04
|
||||
kind: linux
|
||||
asset: firefox-150.0.1-stealth-linux-x86_64.tar.gz
|
||||
extra: '--full'
|
||||
- leg: linux-arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
kind: linux
|
||||
asset: firefox-150.0.1-stealth-linux-arm64.tar.gz
|
||||
extra: ''
|
||||
- leg: win-x86_64
|
||||
runner: windows-latest
|
||||
kind: win
|
||||
asset: firefox-150.0.1-stealth-win-x86_64.zip
|
||||
extra: ''
|
||||
- leg: macos-arm64
|
||||
runner: macos-15
|
||||
kind: mac
|
||||
asset: firefox-150.0.1-stealth-macos-arm64.tar.gz
|
||||
extra: ''
|
||||
- leg: macos-x86_64
|
||||
runner: macos-15-intel
|
||||
kind: mac
|
||||
asset: firefox-150.0.1-stealth-macos-x86_64.tar.gz
|
||||
extra: ''
|
||||
steps:
|
||||
- name: Checkout wrapper (for scripts/ci_drive_gate.py)
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with: { fetch-depth: 1 }
|
||||
- name: Download the release asset (draft releases included)
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -e
|
||||
mkdir -p art
|
||||
gh release download "${{ github.event.inputs.release_tag }}" \
|
||||
--repo "${{ github.repository }}" \
|
||||
--pattern "${{ matrix.asset }}" \
|
||||
--dir art
|
||||
ls -la art/
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with: { python-version: '3.11' }
|
||||
- name: Install Playwright driver (no bundled browser — we override executable_path)
|
||||
# Single-source pin (see release.yml); the drive gate enforces juggler compat.
|
||||
shell: bash
|
||||
run: python -m pip install --quiet "playwright==$(cat scripts/playwright_pin.txt)"
|
||||
- name: Linux system deps for headless firefox
|
||||
if: matrix.kind == 'linux'
|
||||
run: sudo "$(which python)" -m playwright install-deps firefox
|
||||
- name: Extract + locate firefox binary
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
mkdir -p ff
|
||||
A="art/${{ matrix.asset }}"
|
||||
case "${{ matrix.kind }}" in
|
||||
win) python -c "import zipfile; zipfile.ZipFile('$A').extractall('ff')"; EXE="ff/firefox.exe";;
|
||||
linux) tar xzf "$A" -C ff; EXE="ff/firefox";;
|
||||
mac) tar xzf "$A" -C ff; EXE="ff/Firefox.app/Contents/MacOS/firefox";;
|
||||
esac
|
||||
[ -e "$EXE" ] || { echo "ERROR: firefox binary not found at $EXE"; exit 1; }
|
||||
chmod +x "$EXE" 2>/dev/null || true
|
||||
echo "FF_EXE=$EXE" >> "$GITHUB_ENV"
|
||||
echo "located: $EXE"
|
||||
- name: DRIVE GATE — Playwright launch via juggler + real page (+ interaction on --full)
|
||||
shell: bash
|
||||
run: python scripts/ci_drive_gate.py "$FF_EXE" ${{ matrix.extra }}
|
||||
103
.github/workflows/verify-cloak.yml
vendored
103
.github/workflows/verify-cloak.yml
vendored
|
|
@ -1,103 +0,0 @@
|
|||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# verify-cloak.yml — re-runnable CLOAK + WEBGL-MASKING GUARDS for an EXISTING
|
||||
# build run's artifacts, WITHOUT rebuilding Firefox (~3h on the mac legs).
|
||||
#
|
||||
# release.yml runs these same guards in its `gate` job against each freshly-built
|
||||
# artifact. This re-runs them against the artifacts of a PRIOR build run (input
|
||||
# `run_id`) using the CURRENT wrapper code on the default branch — so a test-only
|
||||
# fix (e.g. making the macOS leg tolerant of the runner's missing WebGL) can be
|
||||
# validated against the real binaries in ~10 min instead of paying a full rebuild.
|
||||
#
|
||||
# Same guard command as release.yml's gate. Headed-but-cloaked; zero proxy / zero
|
||||
# secrets. The macOS legs are the only place the cocoa cloak patch actually RUNS.
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
name: verify-cloak
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
run_id:
|
||||
description: 'build run id whose asset-* artifacts to re-gate (e.g. 27346856197)'
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read # download-artifact needs this to read another run's artifacts
|
||||
|
||||
jobs:
|
||||
guard:
|
||||
name: guard-${{ matrix.leg }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 25
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Same legs/runners/assets as release.yml's gate matrix.
|
||||
include:
|
||||
- leg: linux-x86_64
|
||||
runner: ubuntu-24.04
|
||||
kind: linux
|
||||
asset: firefox-150.0.1-stealth-linux-x86_64.tar.gz
|
||||
- leg: linux-arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
kind: linux
|
||||
asset: firefox-150.0.1-stealth-linux-arm64.tar.gz
|
||||
- leg: win-x86_64
|
||||
runner: windows-latest
|
||||
kind: win
|
||||
asset: firefox-150.0.1-stealth-win-x86_64.zip
|
||||
- leg: macos-arm64
|
||||
runner: macos-15
|
||||
kind: mac
|
||||
asset: firefox-150.0.1-stealth-macos-arm64.tar.gz
|
||||
- leg: macos-x86_64
|
||||
runner: macos-15-intel
|
||||
kind: mac
|
||||
asset: firefox-150.0.1-stealth-macos-x86_64.tar.gz
|
||||
steps:
|
||||
- name: Checkout wrapper (current default branch — the FIXED tests)
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with: { fetch-depth: 1 }
|
||||
- name: Download build asset from the prior run (no rebuild)
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
with:
|
||||
name: asset-${{ matrix.leg }}
|
||||
path: art
|
||||
run-id: ${{ github.event.inputs.run_id }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with: { python-version: '3.11' }
|
||||
- name: Install Playwright driver (no bundled browser — we override executable_path)
|
||||
# Single-source pin (see release.yml); the wrapper enforces juggler compat.
|
||||
shell: bash
|
||||
run: python -m pip install --quiet "playwright==$(cat scripts/playwright_pin.txt)"
|
||||
- name: Linux system deps for headless firefox
|
||||
if: matrix.kind == 'linux'
|
||||
run: sudo "$(which python)" -m playwright install-deps firefox
|
||||
- name: Extract + locate firefox binary
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
mkdir -p ff
|
||||
A="art/${{ matrix.asset }}"
|
||||
case "${{ matrix.kind }}" in
|
||||
win) python -c "import zipfile; zipfile.ZipFile('$A').extractall('ff')"; EXE="ff/firefox.exe";;
|
||||
linux) tar xzf "$A" -C ff; EXE="ff/firefox";;
|
||||
mac) tar xzf "$A" -C ff; EXE="ff/Firefox.app/Contents/MacOS/firefox";;
|
||||
esac
|
||||
[ -e "$EXE" ] || { echo "ERROR: firefox binary not found at $EXE"; exit 1; }
|
||||
chmod +x "$EXE" 2>/dev/null || true
|
||||
echo "FF_EXE=$EXE" >> "$GITHUB_ENV"
|
||||
echo "located: $EXE"
|
||||
- name: Install pyobjc Quartz (macOS — to read the cloak window alpha)
|
||||
if: matrix.kind == 'mac'
|
||||
run: python -m pip install --quiet pyobjc-framework-Quartz
|
||||
- name: Cloak + WebGL-masking guards (headed)
|
||||
shell: bash
|
||||
run: |
|
||||
python -m pip install --quiet ".[dev]"
|
||||
INVPW_BINARY_PATH="$FF_EXE" python -m pytest \
|
||||
tests/test_cloak.py \
|
||||
"tests/test_fingerprint_surface.py::test_webgl_readpixels_no_masking_signature" \
|
||||
-m e2e -o addopts='' -q
|
||||
Loading…
Add table
Add a link
Reference in a new issue