From 566cbfcfcac39bd3d1e490ae2cf6d5e46f3d2314 Mon Sep 17 00:00:00 2001 From: Shrey Pandya Date: Tue, 30 Jun 2026 16:10:34 -0700 Subject: [PATCH 1/3] ci: publish browserbase/browse Docker image on browse release Build and push a minimal `browse` CLI image on every release, pinned 1:1 to the npm version. GHCR (ghcr.io/browserbase/browse) always publishes via the built-in GITHUB_TOKEN; Docker Hub (browserbase/browse) additionally publishes when DOCKERHUB_USERNAME + DOCKERHUB_TOKEN are set, so a missing secret degrades to GHCR-only instead of failing the release. This lets code sandboxes (E2B, Modal, Daytona, Vercel) consume the browse CLI by image reference with no Dockerfile -- no browser is bundled, browse connects out to a Browserbase cloud browser over CDP. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/release.yml | 71 +++++++++++++++++++++++++++++++++++ packages/cli/Dockerfile | 19 ++++++++++ 2 files changed, 90 insertions(+) create mode 100644 packages/cli/Dockerfile diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 16972dcaf..34e27f167 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,6 +9,7 @@ permissions: contents: write pull-requests: write id-token: write + packages: write concurrency: ${{ github.workflow }}-${{ github.ref }} @@ -146,6 +147,76 @@ jobs: git tag "$TAG" git push origin "$TAG" + # --- Publish the browse CLI as a Docker image, pinned to the npm version --- + # GHCR (ghcr.io/browserbase/browse) always publishes via the built-in + # GITHUB_TOKEN. Docker Hub (browserbase/browse) additionally publishes + # when DOCKERHUB_USERNAME + DOCKERHUB_TOKEN secrets are configured, so a + # missing secret degrades to GHCR-only instead of failing the release. + - name: Check Docker Hub credentials + id: dockerhub + if: steps.browse_cli.outputs.should_publish == 'true' && steps.browse_cli.outputs.already_published != 'true' + env: + DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} + run: | + if [ -n "$DOCKERHUB_TOKEN" ]; then + echo "enabled=true" >> "$GITHUB_OUTPUT" + else + echo "enabled=false" >> "$GITHUB_OUTPUT" + echo "::notice::DOCKERHUB_TOKEN not set — pushing browse image to GHCR only. Set DOCKERHUB_USERNAME + DOCKERHUB_TOKEN to also publish browserbase/browse on Docker Hub." + fi + + - name: Set up QEMU + if: steps.browse_cli.outputs.should_publish == 'true' && steps.browse_cli.outputs.already_published != 'true' + uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0 + + - name: Set up Docker Buildx + if: steps.browse_cli.outputs.should_publish == 'true' && steps.browse_cli.outputs.already_published != 'true' + uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 + + - name: Log in to GitHub Container Registry + if: steps.browse_cli.outputs.should_publish == 'true' && steps.browse_cli.outputs.already_published != 'true' + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Log in to Docker Hub + if: steps.dockerhub.outputs.enabled == 'true' + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Compute browse image tags + id: image_tags + if: steps.browse_cli.outputs.should_publish == 'true' && steps.browse_cli.outputs.already_published != 'true' + run: | + V="${{ steps.browse_cli.outputs.version }}" + { + echo "tags<> "$GITHUB_OUTPUT" + + - name: Build and push browse image + if: steps.browse_cli.outputs.should_publish == 'true' && steps.browse_cli.outputs.already_published != 'true' + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 + with: + context: packages/cli + file: packages/cli/Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + provenance: false + build-args: | + BROWSE_VERSION=${{ steps.browse_cli.outputs.version }} + tags: ${{ steps.image_tags.outputs.tags }} + - name: Publish browse canary if: github.ref == 'refs/heads/main' && steps.browse_cli.outputs.should_publish != 'true' run: | diff --git a/packages/cli/Dockerfile b/packages/cli/Dockerfile new file mode 100644 index 000000000..a10b2253b --- /dev/null +++ b/packages/cli/Dockerfile @@ -0,0 +1,19 @@ +# Minimal image that ships the `browse` CLI for use inside code sandboxes +# (E2B, Modal, Daytona, Vercel, ...). No browser is bundled on purpose: +# `browse` connects out to a Browserbase cloud browser over CDP, so the +# image stays small and the sandbox stays a thin client. +# +# Published automatically by .github/workflows/release.yml on every browse +# release, pinned 1:1 to the npm version: +# docker build --build-arg BROWSE_VERSION= -t browserbase/browse . +ARG NODE_VERSION=24 +FROM node:${NODE_VERSION}-slim + +# Pin to the exact published version so the image matches the npm release. +ARG BROWSE_VERSION +RUN test -n "$BROWSE_VERSION" \ + && npm install -g "browse@${BROWSE_VERSION}" \ + && npm cache clean --force + +WORKDIR /work +CMD ["browse", "--help"] From 38afe69dddb4066e5a6dcc51795e78c403e1002b Mon Sep 17 00:00:00 2001 From: Shrey Pandya Date: Tue, 30 Jun 2026 16:50:03 -0700 Subject: [PATCH 2/3] ci: trim Docker comments + align Dockerfile with repo conventions - Remove the redundant comment block above the Docker steps (the GHCR-vs-Docker Hub behavior is already surfaced by the step names + the runtime notice). - Dockerfile: drop the verbose header, use node:20-slim to match the repo's node 20.x standard (engines ^20.19.0), and drop the non-standard WORKDIR /work (sandbox runtimes set their own working directory). Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/release.yml | 5 ----- packages/cli/Dockerfile | 15 +++------------ 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 34e27f167..0e490b2fc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -147,11 +147,6 @@ jobs: git tag "$TAG" git push origin "$TAG" - # --- Publish the browse CLI as a Docker image, pinned to the npm version --- - # GHCR (ghcr.io/browserbase/browse) always publishes via the built-in - # GITHUB_TOKEN. Docker Hub (browserbase/browse) additionally publishes - # when DOCKERHUB_USERNAME + DOCKERHUB_TOKEN secrets are configured, so a - # missing secret degrades to GHCR-only instead of failing the release. - name: Check Docker Hub credentials id: dockerhub if: steps.browse_cli.outputs.should_publish == 'true' && steps.browse_cli.outputs.already_published != 'true' diff --git a/packages/cli/Dockerfile b/packages/cli/Dockerfile index a10b2253b..56d907345 100644 --- a/packages/cli/Dockerfile +++ b/packages/cli/Dockerfile @@ -1,19 +1,10 @@ -# Minimal image that ships the `browse` CLI for use inside code sandboxes -# (E2B, Modal, Daytona, Vercel, ...). No browser is bundled on purpose: -# `browse` connects out to a Browserbase cloud browser over CDP, so the -# image stays small and the sandbox stays a thin client. -# -# Published automatically by .github/workflows/release.yml on every browse -# release, pinned 1:1 to the npm version: -# docker build --build-arg BROWSE_VERSION= -t browserbase/browse . -ARG NODE_VERSION=24 -FROM node:${NODE_VERSION}-slim +# No browser is bundled: browse drives a remote Browserbase cloud browser over +# CDP, so the image stays a thin client. +FROM node:20-slim -# Pin to the exact published version so the image matches the npm release. ARG BROWSE_VERSION RUN test -n "$BROWSE_VERSION" \ && npm install -g "browse@${BROWSE_VERSION}" \ && npm cache clean --force -WORKDIR /work CMD ["browse", "--help"] From dcf2a4d6cde2a40bacaba90a129dd7fff571b68e Mon Sep 17 00:00:00 2001 From: Shrey Pandya Date: Tue, 30 Jun 2026 18:02:19 -0700 Subject: [PATCH 3/3] ci: publish browse image to GHCR only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the Docker Hub path for now — the `browserbase` Docker Hub namespace is taken/unclaimed by us, so shipping the Docker Hub steps would be dead code. GHCR (ghcr.io/browserbase/browse) uses the GitHub org we own and needs no new secrets. Docker Hub is tracked as a follow-up (STG-2449). Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/release.yml | 42 ++++------------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0e490b2fc..192d50865 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -147,19 +147,6 @@ jobs: git tag "$TAG" git push origin "$TAG" - - name: Check Docker Hub credentials - id: dockerhub - if: steps.browse_cli.outputs.should_publish == 'true' && steps.browse_cli.outputs.already_published != 'true' - env: - DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} - run: | - if [ -n "$DOCKERHUB_TOKEN" ]; then - echo "enabled=true" >> "$GITHUB_OUTPUT" - else - echo "enabled=false" >> "$GITHUB_OUTPUT" - echo "::notice::DOCKERHUB_TOKEN not set — pushing browse image to GHCR only. Set DOCKERHUB_USERNAME + DOCKERHUB_TOKEN to also publish browserbase/browse on Docker Hub." - fi - - name: Set up QEMU if: steps.browse_cli.outputs.should_publish == 'true' && steps.browse_cli.outputs.already_published != 'true' uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0 @@ -176,30 +163,7 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Log in to Docker Hub - if: steps.dockerhub.outputs.enabled == 'true' - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Compute browse image tags - id: image_tags - if: steps.browse_cli.outputs.should_publish == 'true' && steps.browse_cli.outputs.already_published != 'true' - run: | - V="${{ steps.browse_cli.outputs.version }}" - { - echo "tags<> "$GITHUB_OUTPUT" - - - name: Build and push browse image + - name: Build and push browse image to GHCR if: steps.browse_cli.outputs.should_publish == 'true' && steps.browse_cli.outputs.already_published != 'true' uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: @@ -210,7 +174,9 @@ jobs: provenance: false build-args: | BROWSE_VERSION=${{ steps.browse_cli.outputs.version }} - tags: ${{ steps.image_tags.outputs.tags }} + tags: | + ghcr.io/browserbase/browse:${{ steps.browse_cli.outputs.version }} + ghcr.io/browserbase/browse:latest - name: Publish browse canary if: github.ref == 'refs/heads/main' && steps.browse_cli.outputs.should_publish != 'true'