Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 69 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,39 @@ on:
tags:
- "v*"
workflow_dispatch:
inputs:
check_auth:
description: Check AMO credentials and add-on ownership without publishing
type: boolean
default: false

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

permissions:
contents: write
id-token: write

jobs:
auth-check:
if: (github.event_name == 'push' && github.ref_type == 'tag') || inputs.check_auth == true
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
- name: Verify AMO credentials and add-on ownership
env:
AMO_JWT_ISSUER: ${{ secrets.AMO_JWT_ISSUER }}
AMO_JWT_SECRET: ${{ secrets.AMO_JWT_SECRET }}
run: node scripts/check-amo-auth.mjs

verify:
if: inputs.check_auth != true
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -27,6 +53,7 @@ jobs:
path: dist/*

windows-companion:
if: inputs.check_auth != true
runs-on: windows-latest
env:
WINDOWS_SIGNING_CERTIFICATE_PFX: ${{ secrets.WINDOWS_SIGNING_CERTIFICATE_PFX }}
Expand Down Expand Up @@ -76,6 +103,7 @@ jobs:
path: dist/*

macos-companion:
if: inputs.check_auth != true
runs-on: macos-14
env:
MACOS_INSTALLER_CERTIFICATE_P12: ${{ secrets.MACOS_INSTALLER_CERTIFICATE_P12 }}
Expand Down Expand Up @@ -160,6 +188,7 @@ jobs:
path: dist/*

linux-companion:
if: inputs.check_auth != true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -189,6 +218,7 @@ jobs:
path: dist/*

npm-package:
if: inputs.check_auth != true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -207,8 +237,8 @@ jobs:
path: dist/*.tgz

publish:
if: github.ref_type == 'tag'
needs: [verify, windows-companion, macos-companion, linux-companion, npm-package]
if: github.event_name == 'push' && github.ref_type == 'tag'
needs: [auth-check, verify, windows-companion, macos-companion, linux-companion, npm-package]
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
Expand All @@ -221,8 +251,8 @@ jobs:
files: release/*

publish-npm:
if: github.ref_type == 'tag' || github.event_name == 'workflow_dispatch'
needs: npm-package
if: github.event_name == 'push' && github.ref_type == 'tag'
needs: [npm-package, publish]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -234,7 +264,7 @@ jobs:
run: npm publish ./npm --access public --provenance

release-smoke:
if: github.ref_type == 'tag'
if: github.event_name == 'push' && github.ref_type == 'tag'
needs: [publish, publish-npm]
runs-on: macos-14
steps:
Expand Down Expand Up @@ -289,7 +319,7 @@ jobs:
test "$("$binary" --version)" = "$version"

linux-release-smoke:
if: github.ref_type == 'tag'
if: github.event_name == 'push' && github.ref_type == 'tag'
needs: [publish, publish-npm]
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -330,3 +360,36 @@ jobs:
test "$("$binary" --version)" = "$version"
zen_binary="$(node -p "JSON.parse(require('fs').readFileSync(process.argv[1], 'utf8')).path" "$zen_manifest")"
test "$binary" = "$zen_binary"

publish-amo:
if: github.event_name == 'push' && github.ref_type == 'tag'
needs: [auth-check, release-smoke, linux-release-smoke]
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
- uses: actions/download-artifact@v4
with:
name: firefox-extension
path: dist
- name: Prepare matching source and release notes
run: node scripts/prepare-amo-metadata.mjs
- name: Submit update to the existing Firefox Add-ons listing
env:
WEB_EXT_API_KEY: ${{ secrets.AMO_JWT_ISSUER }}
WEB_EXT_API_SECRET: ${{ secrets.AMO_JWT_SECRET }}
run: |
set -euo pipefail
version="$(node -p "require('./version.json').version")"
npx --yes web-ext@10.6.0 sign \
--source-dir extension \
--channel listed \
--upload-source-code "dist/codex-computer-use-firefox-zen-${version}-source.zip" \
--amo-metadata dist/amo-metadata.json \
--approval-timeout 0 \
--no-input
echo "Submitted to AMO; Mozilla approval may still be pending." >> "$GITHUB_STEP_SUMMARY"
34 changes: 34 additions & 0 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Verify
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-14, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
- uses: dtolnay/rust-toolchain@stable
- run: npm test
- run: npm test --prefix npm
- run: cargo test --locked --manifest-path native-host/Cargo.toml
- name: Package extension and matching review source
if: runner.os == 'Windows'
run: npm run package
- name: Pack npm installer
if: runner.os == 'Windows'
run: npm pack ./npm --pack-destination dist
- uses: actions/upload-artifact@v4
if: runner.os == 'Windows'
with:
name: release-candidate
path: dist/*
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@ This project follows semantic versioning. The Firefox add-on and native companio
always share one version and are released from a matching `vMAJOR.MINOR.PATCH`
Git tag.

## 1.4.11 - Unreleased

- Automate Firefox Add-ons submission after tagged npm releases, with a read-only AMO authentication check and matching review-source upload.

- Support `Page.setLifecycleEventsEnabled` during Codex tab attachment, fixing
the unsupported-command error that prevented direct Firefox/Zen control.
- Translate navigation init, DOMContentLoaded, and load notifications into
session-scoped lifecycle events with consistent frame loader IDs.
- Keep navigation, lifecycle, request, redirect, and response loader IDs aligned,
retaining the original document identity for late network responses.
- Cover background-tab attachment, lifecycle toggling, and detach cleanup in
the protocol regression suite. Attachment does not activate the target tab.

## 1.4.10 - 2026-08-15

- Completed the strict-CSP Browser Use path for `playwright.domSnapshot()`,
Expand Down
18 changes: 18 additions & 0 deletions PORT_STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,21 @@ Developer ID-sign, notarize, and staple the macOS package when the repository
signing secrets are configured. Unsigned workflow-dispatch artifacts remain
suitable for development testing but should not be presented as production
installers.

## 1.4.11 lifecycle compatibility

`Page.setLifecycleEventsEnabled` accepts enable/disable requests without
activating the tab. Firefox webNavigation notifications provide `init`,
`DOMContentLoaded`, and `load` events, with a loader ID shared by the committed
frame and frame tree. Subscriptions are cleared on detach and tab close.
Network-idle lifecycle events and replay of events predating subscription are
not synthesized. Screenshot fallbacks elsewhere can still briefly activate a
tab; this change only makes attachment and lifecycle subscription passive.

Regression: the updated protocol test fails against 1.4.10 with the exact
`Page.setLifecycleEventsEnabled` error and passes against the patched source.

The isolated headless Zen smoke test passed on macOS on 2026-09-10: real
WebExtension attach, lifecycle notifications, matching loader IDs, and unchanged
foreground tab. The signed-in Codex transport has not been retested in the
user's profile; the installed add-on remains untouched.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ npm run package

`npm test` checks synchronized release versions, the manifest and compatibility surface, bridge/extension version reporting, and the native protocol, upload, and WebSocket-relay integrations. Packaging writes the unsigned extension archive, a matching review-source archive, and SHA-256 checksums to `dist/`.

Pushing a semantic-version tag such as `v1.4.7` runs the release workflow. It builds and tests the extension, Windows installer, universal macOS package, and Linux x64 binary; verifies all release versions; publishes npm with provenance; attaches release artifacts; and smoke-tests a clean install of the exact public npm version on macOS and Linux. Submit the matching signed Firefox add-on to AMO only after that smoke test passes.
Pushing a semantic-version tag such as `v1.4.11` runs the release workflow. It checks Mozilla Add-ons credentials, builds and tests every platform, publishes GitHub assets and then npm with OIDC provenance, and smoke-tests the public npm install on macOS and Linux. After those checks pass, CI submits the listed Firefox add-on with its matching review source and release notes. Mozilla approval may remain pending after submission.

Configure `AMO_JWT_ISSUER` and `AMO_JWT_SECRET` as repository Actions secrets using an author's [Mozilla API credentials](https://addons.mozilla.org/developers/addon/api/key/). npm uses the existing trusted publisher for `release.yml` and does not need an npm token. Run `gh workflow run release.yml --ref main -f check_auth=true` to verify AMO access without uploading a version. Other manual runs build candidates only; publishing requires a tag push. See [release authentication and publication steps](RELEASE_1.4.11.md).

Prepare a release with:

Expand All @@ -179,3 +181,15 @@ npm run version:set -- MAJOR.MINOR.PATCH
Read [PRIVACY.md](PRIVACY.md) for the data-handling disclosure. The native adapter pins its relay origin to the official OpenAI extension ID and rejects unrelated messages.

`extension/codex-sidepanel` and `extension/background.js` are OpenAI's packaged distribution, not a clean-room source reimplementation. Those upstream assets remain subject to OpenAI's applicable terms. The compatibility code in this repository is provided for review and development; no additional license is granted for the bundled upstream assets.

### Isolated lifecycle smoke test

```sh
FIREFOX_BINARY=/path/to/firefox npm run test:live
# macOS Zen: /Applications/Zen.app/Contents/MacOS/zen
```

This optional test uses `web-ext` and a disposable headless profile, never your
signed-in profile. It exercises the real compatibility layer against local
HTTP fixtures and verifies lifecycle delivery and foreground-tab preservation.
It does not exercise the signed-in Codex native transport.
80 changes: 80 additions & 0 deletions RELEASE_1.4.11.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# 1.4.11 release candidate

Fixes direct Codex tab attachment failing with
`Firefox CDP compatibility layer does not implement Page.setLifecycleEventsEnabled`.
The add-on and native/npm companion versions are synchronized at 1.4.11.
No new add-on permissions or upstream bundle changes are included.

## Verification

- `npm test`: passed, including the regression that fails against 1.4.10.
- `npm test --prefix npm`: passed on macOS (Linux-only install tests run in CI).
- `FIREFOX_BINARY=/Applications/Zen.app/Contents/MacOS/zen npm run test:live`:
passed using a disposable headless profile, with foreground-tab preservation.
- `npx --yes web-ext lint --source-dir extension --no-input`: zero errors,
zero notices, 72 warnings from the existing distribution.
- PR Verify workflow tests Windows, macOS, and Linux and attaches a
`release-candidate` artifact containing the extension ZIP, matching source ZIP,
SHA-256 files, and npm tarball.

The isolated test verifies real Firefox WebExtension behavior, not the full
signed-in Codex transport. Before publishing, test the release candidate in a
separate signed-in development profile: attach to an inactive tab with
`cua.getTab`, read its state, and confirm the user's active tab stays selected.
The user's installed extension and native bridge have not been replaced.

## CI authentication

npm uses its existing trusted publisher for GitHub Actions: owner
`SunkenInTime`, repository `codex-computer-use-firefox-zen`, workflow
`release.yml`. `publish-npm` requests a short-lived OIDC identity and publishes
with provenance; no npm token secret is required. The 1.4.10 release successfully
used this path. Current account-side trust settings still require npm account
access to inspect; a local unauthenticated `npm trust list` does not test CI auth.

For Firefox Add-ons, create or retrieve API credentials from
<https://addons.mozilla.org/developers/addon/api/key/> using an account that is
an author of the existing add-on. Add these repository Actions secrets:

- `AMO_JWT_ISSUER`: the JWT issuer/API key.
- `AMO_JWT_SECRET`: the JWT secret/API secret.

Do not commit or paste the secret into an issue, PR, or chat. Test access without
uploading a version:

```sh
gh workflow run release.yml --ref main -f check_auth=true
```

Before this PR is merged, use `--ref fix/firefox-lifecycle-attachment` instead.
This mode runs only the authenticated, read-only add-on ownership check. The
same check gates tag publication so missing or invalid AMO credentials prevent
the GitHub/npm release from starting. Manual dispatch with `check_auth=false`
builds candidates only, including when the selected ref is a tag.

## Publication sequence

1. Merge the reviewed PR and confirm Verify is green for the merged commit.
2. Update the changelog's Unreleased date if needed. Tag the chosen release
commit `v1.4.11` and push that tag to run Release.
3. Wait for the AMO auth check, all release builds, GitHub asset publication, npm provenance
publication, and macOS/Linux public-install smoke tests to succeed.
npm now waits for the GitHub assets its installer downloads; manual
workflow_dispatch only builds candidates and does not publish npm.
4. The `publish-amo` job then submits an update to the existing listed add-on,
using the manifest ID, matching source archive, changelog release notes, and
AMO_LISTING.md reviewer notes. It submits with `web-ext sign --channel listed`
and `--approval-timeout 0`: CI does not wait for human approval. A successful
job confirms submission, not Mozilla approval or public availability. Check
the AMO developer dashboard for validation/signing or requests from reviewers.
5. Verify the signed AMO version with `codex-firefox-bridge@1.4.11 doctor` and
repeat background-tab attachment on a separate development profile.

No tag, public npm version, or AMO submission is created by this PR.

## Store release notes

Fixed a compatibility error that prevented Codex from connecting directly to
Firefox and Zen tabs. Added page lifecycle notifications and regression
coverage to keep tab attachment from switching the active tab. Update the
native bridge to 1.4.11 to match the add-on version.
Loading
Loading