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
32 changes: 0 additions & 32 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ jobs:
outputs:
macos: ${{ steps.detect.outputs.macos }}
web: ${{ steps.detect.outputs.web }}
go: ${{ steps.detect.outputs.go }}
agent_session_web: ${{ steps.detect.outputs.agent_session_web }}
steps:
- name: Checkout
Expand All @@ -55,7 +54,6 @@ jobs:
{
echo "macos=true"
echo "web=true"
echo "go=true"
echo "agent_session_web=true"
} >> "$GITHUB_OUTPUT"
}
Expand Down Expand Up @@ -110,7 +108,6 @@ jobs:
{
echo "macos=false"
echo "web=false"
echo "go=false"
echo "agent_session_web=false"
} >> "$GITHUB_OUTPUT"
exit 0
Expand Down Expand Up @@ -325,9 +322,6 @@ jobs:
- name: Validate CI change area filter
run: python3 tests/test_ci_change_areas.py

- name: Validate release attestation retry guard
run: ./tests/test_ci_attestation_retry.sh

- name: Validate Python R2 appcast upload guard
run: ./tests/test_ci_r2_upload_python.sh

Expand Down Expand Up @@ -423,27 +417,6 @@ jobs:
GHOSTTYKIT_DOWNLOAD_RETRY_DELAY: "1"
run: ./scripts/download-prebuilt-ghosttykit.sh --verify-only

remote-daemon-tests:
needs: changes
if: ${{ needs.changes.outputs.go == 'true' }}
runs-on: ${{ vars.LINUX_RUNNER || 'blacksmith-4vcpu-ubuntu-2404' }}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Setup Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: daemon/remote/go.mod
cache-dependency-path: daemon/remote/go.sum

- name: Run remote daemon tests
working-directory: daemon/remote
run: go test ./...

- name: Validate remote daemon release assets
run: ./tests/test_remote_daemon_release_assets.sh

web-typecheck:
needs: changes
if: ${{ needs.changes.outputs.web == 'true' }}
Expand Down Expand Up @@ -1820,7 +1793,6 @@ jobs:
- changes
- workflow-guard-tests
- ghosttykit-release-check
- remote-daemon-tests
- web-typecheck
- react-apps-check
- diff-sidecar-check
Expand All @@ -1842,7 +1814,6 @@ jobs:
needs = json.loads(os.environ["PREFLIGHT_NEEDS"])
required = ("changes", "workflow-guard-tests", "ghosttykit-release-check")
allowed_routed = {
"remote-daemon-tests",
"web-typecheck",
"react-apps-check",
"diff-sidecar-check",
Expand All @@ -1858,7 +1829,6 @@ jobs:

outputs = needs["changes"].get("outputs", {})
routed_outputs = {
"remote-daemon-tests": "go",
"web-typecheck": "web",
"react-apps-check": "web",
"diff-sidecar-check": "macos",
Expand All @@ -1883,7 +1853,6 @@ jobs:
"routes: "
f"macos={outputs.get('macos')} "
f"web={outputs.get('web')} "
f"go={outputs.get('go')} "
f"agent_session_web={outputs.get('agent_session_web')}"
)
for name, data in sorted(needs.items()):
Expand Down Expand Up @@ -2414,7 +2383,6 @@ jobs:
- changes
- workflow-guard-tests
- ghosttykit-release-check
- remote-daemon-tests
- web-typecheck
- react-apps-check
- diff-sidecar-check
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/cloud-vm-env-audit.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: Cloud VM env audit

# Guards against deployed-env / code drift: the 2026-08-26 outage shipped code
# that assumed CMUX_VM_DEFAULT_PROVIDER=blaxel while production still said
# freestyle, and every Cloud VM create 503ed for two days with nothing paging.
# that assumed one CMUX_VM_DEFAULT_PROVIDER while production still said
# another, and every Cloud VM create 503ed for two days with nothing paging.
# This audit pulls the real production env and fails when the default
# provider's image value is missing from the image manifest, so drift is a red
# workflow on merge (and daily) instead of a user-facing outage.
Expand Down
82 changes: 1 addition & 81 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ jobs:
if: needs.decide.outputs.should_build == 'true' && (github.event_name != 'schedule' || github.event.schedule == '47 8 * * *')
# Sign and notarize on the same macOS 26 lane proven by stable releases.
runs-on: ${{ vars.MACOS_RUNNER_26 || 'blacksmith-6vcpu-macos-26' }}
# Start the standalone helper submission before remote-daemon preparation so
# Start the standalone helper submission early so
# Apple's first wait overlaps useful work; finish it before the final DMG.
timeout-minutes: 60
env:
Expand Down Expand Up @@ -457,12 +457,6 @@ jobs:
chmod +x "$wrapper_dir/create-dmg"
echo "$wrapper_dir" >> "$GITHUB_PATH"

- name: Setup Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: daemon/remote/go.mod
cache-dependency-path: daemon/remote/go.sum

- name: Derive Sparkle public key from private key
env:
SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }}
Expand Down Expand Up @@ -547,7 +541,6 @@ jobs:
{
echo "NIGHTLY_BUILD=${NIGHTLY_BUILD}"
echo "NIGHTLY_MARKETING_VERSION=${NIGHTLY_MARKETING_VERSION}"
echo "NIGHTLY_REMOTE_DAEMON_VERSION=${NIGHTLY_MARKETING_VERSION}"
echo "NIGHTLY_DMG_IMMUTABLE=${NIGHTLY_DMG_IMMUTABLE}"
} >> "$GITHUB_ENV"

Expand Down Expand Up @@ -629,52 +622,6 @@ jobs:
cmux.nightly.entitlements \
"$APPLE_SIGNING_IDENTITY"

- name: Build remote daemon nightly assets and inject manifest
run: |
set -euo pipefail
# Build with --asset-suffix so manifest download URLs point to
# immutable, build-specific asset names (e.g. cmuxd-remote-darwin-arm64-2362248028801).
# This prevents checksum mismatches when a newer nightly overwrites
# the shared "latest" assets on the release.
./scripts/build_remote_daemon_release_assets.sh \
--version "$NIGHTLY_REMOTE_DAEMON_VERSION" \
--release-tag "nightly" \
--repo "manaflow-ai/cmux" \
--output-dir "remote-daemon-assets" \
--asset-suffix "$NIGHTLY_BUILD"
MANIFEST_JSON="$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1], encoding="utf-8")), separators=(",",":")))' "remote-daemon-assets/cmuxd-remote-manifest-${NIGHTLY_BUILD}.json")"
APP_PLIST="build-universal/Build/Products/Release/cmux NIGHTLY.app/Contents/Info.plist"
if [ ! -f "$APP_PLIST" ]; then
echo "Missing nightly app Info.plist at $APP_PLIST" >&2
exit 1
fi
plutil -remove CMUXRemoteDaemonManifestJSON "$APP_PLIST" >/dev/null 2>&1 || true
plutil -insert CMUXRemoteDaemonManifestJSON -string "$MANIFEST_JSON" "$APP_PLIST"
# Also create unsuffixed "latest" copies for the release page and
# any tooling that fetches the generic asset names. The manifest's
# downloadURLs still point to the versioned filenames (intentional:
# the live manifest is used by the client-side checksum fallback
# which only reads sha256, not downloadURL). The unsuffixed copies
# are convenience aliases and don't carry build-provenance
# attestation (attested versioned files are canonical).
for platform in darwin-arm64 darwin-amd64 linux-arm64 linux-amd64; do
cp "remote-daemon-assets/cmuxd-remote-${platform}-${NIGHTLY_BUILD}" \
"remote-daemon-assets/cmuxd-remote-${platform}"
done
# Regenerate unsuffixed checksums with generic filenames so
# `shasum -c cmuxd-remote-checksums.txt` works against the aliases.
(
cd remote-daemon-assets
shasum -a 256 \
cmuxd-remote-darwin-arm64 \
cmuxd-remote-darwin-amd64 \
cmuxd-remote-linux-arm64 \
cmuxd-remote-linux-amd64 \
> cmuxd-remote-checksums.txt
)
cp "remote-daemon-assets/cmuxd-remote-manifest-${NIGHTLY_BUILD}.json" \
"remote-daemon-assets/cmuxd-remote-manifest.json"

- name: Embed nightly provisioning profile
env:
APPLE_NIGHTLY_PROVISIONING_PROFILE_BASE64: ${{ secrets.APPLE_NIGHTLY_PROVISIONING_PROFILE_BASE64 }}
Expand Down Expand Up @@ -757,31 +704,6 @@ jobs:
# installs to migrate onto the unified nightly appcast.
cp appcast.xml appcast-universal.xml

- name: Attest remote daemon nightly assets
id: attest-remote-daemon-nightly-assets
continue-on-error: true
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: |
remote-daemon-assets/cmuxd-remote-darwin-arm64-${{ env.NIGHTLY_BUILD }}
remote-daemon-assets/cmuxd-remote-darwin-amd64-${{ env.NIGHTLY_BUILD }}
remote-daemon-assets/cmuxd-remote-linux-arm64-${{ env.NIGHTLY_BUILD }}
remote-daemon-assets/cmuxd-remote-linux-amd64-${{ env.NIGHTLY_BUILD }}
remote-daemon-assets/cmuxd-remote-checksums-${{ env.NIGHTLY_BUILD }}.txt
remote-daemon-assets/cmuxd-remote-manifest-${{ env.NIGHTLY_BUILD }}.json

- name: Retry remote daemon nightly asset attestation
if: steps.attest-remote-daemon-nightly-assets.outcome == 'failure'
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: |
remote-daemon-assets/cmuxd-remote-darwin-arm64-${{ env.NIGHTLY_BUILD }}
remote-daemon-assets/cmuxd-remote-darwin-amd64-${{ env.NIGHTLY_BUILD }}
remote-daemon-assets/cmuxd-remote-linux-arm64-${{ env.NIGHTLY_BUILD }}
remote-daemon-assets/cmuxd-remote-linux-amd64-${{ env.NIGHTLY_BUILD }}
remote-daemon-assets/cmuxd-remote-checksums-${{ env.NIGHTLY_BUILD }}.txt
remote-daemon-assets/cmuxd-remote-manifest-${{ env.NIGHTLY_BUILD }}.json

- name: Upload branch nightly artifacts
if: needs.decide.outputs.should_publish != 'true'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand All @@ -790,7 +712,6 @@ jobs:
path: |
cmux-nightly-macos*.dmg
appcast.xml
remote-daemon-assets/cmuxd-remote-*
appcast-universal.xml
if-no-files-found: error

Expand Down Expand Up @@ -827,7 +748,6 @@ jobs:
cmux-nightly-macos-${{ github.run_id }}*.dmg
cmux-nightly-macos.dmg
appcast.xml
remote-daemon-assets/cmuxd-remote-*
appcast-universal.xml
overwrite_files: true

Expand Down
55 changes: 0 additions & 55 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,6 @@ jobs:
if: steps.guard_release_assets.outputs.skip_all != 'true'
run: python3 scripts/ci/sanitize-xcode-source-packages-cache.py .spm-cache

- name: Setup Go
if: steps.guard_release_assets.outputs.skip_all != 'true'
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: daemon/remote/go.mod
cache-dependency-path: daemon/remote/go.sum

- name: Derive Sparkle public key from private key
if: steps.guard_release_assets.outputs.skip_all != 'true'
env:
Expand Down Expand Up @@ -336,21 +329,6 @@ jobs:
./scripts/verify-diff-sidecar-artifact.sh "$DIFF_SIDECAR"
[[ "$SDK_VERSION" == 26.* ]]

- name: Build remote daemon release assets and inject manifest
if: steps.guard_release_assets.outputs.skip_all != 'true'
run: |
set -euo pipefail
APP_PLIST="build-universal/Build/Products/Release/cmux.app/Contents/Info.plist"
APP_VERSION=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$APP_PLIST")
./scripts/build_remote_daemon_release_assets.sh \
--version "$APP_VERSION" \
--release-tag "$GITHUB_REF_NAME" \
--repo "manaflow-ai/cmux" \
--output-dir "remote-daemon-assets"
MANIFEST_JSON="$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1], encoding="utf-8")), separators=(",",":")))' remote-daemon-assets/cmuxd-remote-manifest.json)"
plutil -remove CMUXRemoteDaemonManifestJSON "$APP_PLIST" >/dev/null 2>&1 || true
plutil -insert CMUXRemoteDaemonManifestJSON -string "$MANIFEST_JSON" "$APP_PLIST"

- name: Run CLI version memory guard regression
if: steps.guard_release_assets.outputs.skip_all != 'true'
run: |
Expand Down Expand Up @@ -516,32 +494,6 @@ jobs:
fi
./scripts/sparkle_generate_appcast.sh cmux-macos.dmg "$GITHUB_REF_NAME" appcast.xml

- name: Attest remote daemon release assets
id: attest-remote-daemon-release-assets
if: steps.guard_release_assets.outputs.skip_all != 'true'
continue-on-error: true
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: |
remote-daemon-assets/cmuxd-remote-darwin-arm64
remote-daemon-assets/cmuxd-remote-darwin-amd64
remote-daemon-assets/cmuxd-remote-linux-arm64
remote-daemon-assets/cmuxd-remote-linux-amd64
remote-daemon-assets/cmuxd-remote-checksums.txt
remote-daemon-assets/cmuxd-remote-manifest.json

- name: Retry remote daemon release asset attestation
if: steps.guard_release_assets.outputs.skip_all != 'true' && steps.attest-remote-daemon-release-assets.outcome == 'failure'
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: |
remote-daemon-assets/cmuxd-remote-darwin-arm64
remote-daemon-assets/cmuxd-remote-darwin-amd64
remote-daemon-assets/cmuxd-remote-linux-arm64
remote-daemon-assets/cmuxd-remote-linux-amd64
remote-daemon-assets/cmuxd-remote-checksums.txt
remote-daemon-assets/cmuxd-remote-manifest.json

- name: Upload build artifacts (dry-run)
if: steps.guard_release_assets.outputs.skip_upload != 'true' && github.event_name == 'workflow_dispatch'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand All @@ -550,7 +502,6 @@ jobs:
path: |
cmux-macos.dmg
appcast.xml
remote-daemon-assets/cmuxd-remote-*
if-no-files-found: error

- name: Upload release asset
Expand All @@ -560,12 +511,6 @@ jobs:
files: |
cmux-macos.dmg
appcast.xml
remote-daemon-assets/cmuxd-remote-darwin-arm64
remote-daemon-assets/cmuxd-remote-darwin-amd64
remote-daemon-assets/cmuxd-remote-linux-arm64
remote-daemon-assets/cmuxd-remote-linux-amd64
remote-daemon-assets/cmuxd-remote-checksums.txt
remote-daemon-assets/cmuxd-remote-manifest.json
generate_release_notes: true
overwrite_files: false

Expand Down
43 changes: 1 addition & 42 deletions .github/workflows/tmux-corpus.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
name: tmux corpus
name: terminal nightly

on:
# Temporarily manual-only beginning 2026-07-13 to pause automatic CI.
workflow_dispatch:
inputs:
fuzztime:
description: Time per Go fuzz target
required: false
default: 2m

permissions:
actions: write
Expand All @@ -18,42 +13,6 @@ concurrency:
cancel-in-progress: false

jobs:
remote-daemon-fuzz:
runs-on: ${{ vars.LINUX_RUNNER || 'blacksmith-4vcpu-ubuntu-2404' }}
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Setup Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: daemon/remote/go.mod
cache-dependency-path: daemon/remote/go.sum

- name: Run deterministic tmux corpus tests
working-directory: daemon/remote
run: go test ./...

- name: Run tmux corpus fuzz targets
working-directory: daemon/remote
env:
FUZZTIME: ${{ github.event_name == 'pull_request' && '30s' || github.event.inputs.fuzztime || '2m' }}
run: |
set -euo pipefail
for target in \
FuzzTmuxCompatArgParser \
FuzzTmuxRenderFormatSupportedSubset \
FuzzTmuxSendKeysTokens \
FuzzConsumeWebSocketLease \
FuzzNormalizePTYSize \
FuzzWebSocketPTYControlFrame
do
go test ./cmd/cmuxd-remote -run '^$' -fuzz "^${target}$" -fuzztime "$FUZZTIME"
done

terminal-nightly:
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: ${{ vars.MACOS_RUNNER_15 || 'blacksmith-6vcpu-macos-15' }}
Expand Down
Loading
Loading