Skip to content

feat(camoufox): add beta/alpha release channel with dynamic version resolution - #4906

Closed
payne0420 wants to merge 1 commit into
jo-inc:masterfrom
payne0420:feat/camoufox-release-channel
Closed

feat(camoufox): add beta/alpha release channel with dynamic version resolution#4906
payne0420 wants to merge 1 commit into
jo-inc:masterfrom
payne0420:feat/camoufox-release-channel

Conversation

@payne0420

Copy link
Copy Markdown
Contributor

Summary

Adds a CHANNEL toggle (beta | alpha) and resolves the exact Camoufox version/release at build time from the GitHub releases API, instead of hardcoding a single VERSION/RELEASE pin in every build file.

Default is beta everywhere, so existing behavior (135.0.1-beta.24) and the published image are unchanged. alpha is strictly opt-in.

Why this is needed

Today the Camoufox version is pinned identically in four places (Makefile, Dockerfile, Dockerfile.ci, build.ps1). Bumping it means editing each file by hand — and for some upstream releases a single pin can't work at all:

  • Per-arch suffix drift. Upstream bumps each asset's release suffix independently per architecture. v150.0.2, for example, shipped alpha.26 for x86_64 but alpha.25 for arm64, under a git tag (v150.0.2-beta.25) whose name matches neither asset. A single shared RELEASE variable can't express that; resolving per-arch can.
  • camoufox-js version guard. camoufox-js@0.10.2 enforces a supported release range (>=beta.19, <1) at launch (Version.isSupported in its pkgman.js) and its comparator sorts alpha.* below beta.*. So any alpha build is rejected by the guard — both the runtime fetch and the launch-time path check.

The alpha channel handles the guard by declaring a passing beta.N string in version.json while shipping the real alpha binary (the real release is kept in the resolver output for traceability). version.json is the only thing camoufox-js checks; it never cross-verifies it against the binary.

What changed

  • scripts/resolve-camoufox.js (new): queries the releases API, picks the newest asset matching camoufox-<ver>-<channel>.<n>-lin.<arch>.zip using its actual browser_download_url (so the tag/asset name mismatch is irrelevant), and emits CAMOUFOX_VERSION / CAMOUFOX_RELEASE / CAMOUFOX_DECLARED_RELEASE / CAMOUFOX_URL. Supports --json for PowerShell. Mirrors how camoufox-js resolves a download.
  • Makefile: CHANNEL from env > .env > default beta; resolves into a sidecar .env consumed by the zip download and build-args. Artifacts and image tags are namespaced by channel (camofox-browser:alpha-x86_64, etc.) so switching never reuses the wrong cached binary.
  • Dockerfile / Dockerfile.ci: accept CHANNEL + CAMOUFOX_DECLARED_RELEASE; Dockerfile.ci resolves in-build per TARGETARCH (multi-arch path unchanged).
  • build.ps1: -Channel param + .env fallback, resolver via --json.
  • .github/workflows/docker.yml: optional channel dispatch input (default beta); release-triggered builds stay on beta.
  • README.md: documents the toggle and an "alpha is for testing" caveat (the camoufox-js driver predates v150, so anti-detection config may apply incompletely against a much newer browser — keep production on beta).

How to use

make up CHANNEL=alpha     # latest alpha line (e.g. v150)
make up CHANNEL=beta      # stable (default)
# or set CHANNEL= in a local .env file

Verification

Verified end-to-end with make build CHANNEL=alpha:

  • Resolver picked v150.0.2 (alpha.26 for x86_64, alpha.25 for arm64).
  • Baked version.json{"version":"150.0.2","release":"beta.26"}.
  • camoufox-bin launches and self-reports Camoufox 150.0.2.
  • camoufox-js accepts the declared version.json (camoufoxPath() returns OK; would throw UnsupportedVersion otherwise).
  • Headless launch via camoufox-js loads a page; navigator.userAgent reports Firefox/150.0.
  • Ran the resulting image; /health reports browserConnected: true and live navigation works.

beta resolves to the current 135.0.1-beta.24 with no change in behavior.

🤖 Generated with Claude Code

…esolution

Previously the Camoufox version was hardcoded as a single VERSION/RELEASE
pin (135.0.1-beta.24) across the Makefile, Dockerfile, Dockerfile.ci and
build.ps1. Tracking a newer upstream line meant hand-editing every file, and
it could not be done at all for releases whose assets break the single-pin
assumption.

This adds a CHANNEL toggle (beta | alpha) and resolves the exact
version/release at build time from the GitHub releases API, mirroring how
camoufox-js itself selects a download.

Why this is needed:
- Upstream bumps each asset's suffix independently per arch. v150.0.2, for
  example, shipped alpha.26 for x86_64 but alpha.25 for arm64 under a single
  git tag (v150.0.2-beta.25) whose name matches neither asset. A shared
  RELEASE var cannot express that; resolving per arch can.
- camoufox-js@0.10.2 enforces a supported release range (>=beta.19, <1) at
  launch and sorts alpha.* below beta.*, so an alpha build is rejected by the
  version guard. The alpha channel works around this by declaring a passing
  beta.N string in version.json while shipping the real alpha binary (the real
  release is preserved in the resolver output for traceability).

What changed:
- scripts/resolve-camoufox.js (new): queries the releases API, picks the
  newest asset matching camoufox-<ver>-<channel>.<n>-lin.<arch>.zip using its
  actual browser_download_url (so the tag/asset name mismatch is irrelevant),
  and emits CAMOUFOX_VERSION / CAMOUFOX_RELEASE / CAMOUFOX_DECLARED_RELEASE /
  CAMOUFOX_URL. Supports --json for PowerShell.
- Makefile: CHANNEL (env > .env > default beta); resolves into a sidecar .env
  consumed by the zip download and build args. Artifacts and image tags are
  namespaced by channel so switching never reuses the wrong cached binary.
- Dockerfile / Dockerfile.ci: accept CHANNEL + CAMOUFOX_DECLARED_RELEASE;
  Dockerfile.ci resolves in-build per TARGETARCH (multi-arch unchanged).
- build.ps1: -Channel param + .env fallback, resolver via --json.
- .github/workflows/docker.yml: optional channel dispatch input (default beta);
  release-triggered builds stay on beta.
- README: documents the toggle and the alpha-is-for-testing caveat.

Default channel is beta everywhere, so existing behavior (135.0.1-beta.24) and
the published image are unchanged; alpha is strictly opt-in.

Verified end-to-end: make build CHANNEL=alpha resolves v150.0.2 (alpha.26 /
arm64 alpha.25), the binary launches (Camoufox 150.0.2), camoufox-js accepts
the declared version.json, and a headless page reports navigator.userAgent
Firefox/150.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@payne0420
payne0420 requested a review from skyfallsin as a code owner May 31, 2026 21:02
@skyfallsin

Copy link
Copy Markdown
Contributor

Thanks for exploring release-channel support.

We cannot merge this version because it resolves mutable upstream GitHub release assets during Docker builds. The same repository commit could then produce different browser binaries at different times. The alpha path also writes beta metadata for an alpha binary, which bypasses the driver compatibility check rather than proving compatibility.

Master now has a checksum-backed Camoufox mirror workflow. We need pinned, reviewed artifacts in release builds.

I am closing this PR. Please open a new focused proposal if channel support is still wanted. It should use the mirrored/pinned artifact flow, preserve reproducible builds, and validate against the current camoufox-js version.

@skyfallsin skyfallsin closed this Aug 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants